12 #include <sys/types.h>
14 #include <sys/ioctl.h>
16 #include <sys/epoll.h>
17 #include <sys/signalfd.h>
20 typedef struct tty_t {
33 /* Helper functions */
34 void error(const char *fmt, ...)
38 fprintf(stderr, "Error ");
39 vfprintf(stderr, fmt, ap);
40 fprintf(stderr, ": %s\n", strerror(errno));
46 int add_poll(int fd, void *ptr)
48 struct epoll_event ctl = {
52 return epoll_ctl(epoll, EPOLL_CTL_ADD, fd, &ctl);
57 return epoll_ctl(epoll, EPOLL_CTL_DEL, fd, NULL);
60 static int start_tty(tty_t *tty)
62 const char *prompt = "[Press enter to login]";
65 if (chown(tty->path, 0, 0) < 0)
67 if (chmod(tty->path, 0600) < 0)
69 if ((tty->fd = open(tty->path, O_RDWR|O_NOCTTY|O_NONBLOCK|O_CLOEXEC, 0)) < 0)
71 if (add_poll(tty->fd, tty) < 0)
74 tcgetattr(tty->fd, &attr);
75 attr.c_lflag &= ~ECHO;
76 tcsetattr(tty->fd, TCSANOW, &attr);
78 write(tty->fd, "\033c", 2);
79 write(tty->fd, "\033[?1c", 5);
80 write(tty->fd, prompt, strlen(prompt));
85 static void read_tty(tty_t *tty)
89 while (read(tty->fd, &ch, 1) == 1)
90 if (ch == '\n' || ch == '\r')
94 if ((tty->pid = fork()) < 0)
97 if (putenv("TERM=linux"))
98 error("setting environment");
100 error("setting sid");
101 if (write(tty->fd, "\033c", 2) < 0)
102 error("resetting tty");
103 if ((flags = fcntl(tty->fd, F_GETFL)) < 0)
104 error("getting fd flags");
105 if (fcntl(tty->fd, F_SETFL, flags&~O_NONBLOCK) < 0)
106 error("setting blocking flags");
107 if (ioctl(tty->fd, TIOCSCTTY, 0) < 0)
108 error("setting ctty");
109 if (dup2(tty->fd, 0) != 0)
110 error("setting stdin");
111 if (dup2(tty->fd, 1) != 1)
112 error("setting stdout");
113 if (dup2(tty->fd, 2) != 2)
114 error("setting stderr");
115 if (execl("/bin/login", "login", NULL) < 0)
116 error("execing login program");
124 struct signalfd_siginfo info;
125 if (read(sigs, &info, sizeof(info)) != sizeof(info))
127 if (info.ssi_signo != SIGCHLD)
133 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
134 for (tty = ttys; tty; tty = tty->next) {
135 if (pid == tty->pid) {
144 int main(int argc, char **argv)
150 /* Check arguments */
152 printf("usage: gettyd <tty> ...\n");
158 sigaddset(&mask, SIGCHLD);
159 sigaddset(&mask, SIGHUP);
160 if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
161 error("blocking signals");
162 if ((sigs = signalfd(-1, &mask, SFD_CLOEXEC)) < 0)
163 error("creating signal fd");
164 if ((epoll = epoll_create1(EPOLL_CLOEXEC)) < 0)
165 error("creating epoll");
166 if (add_poll(sigs, &sigs) < 0)
167 error("adding signal epoll");
170 for (i = 1; i < argc; i++) {
171 if (!(tty = malloc(sizeof(tty_t))))
172 error("allocating memory");
173 if (asprintf(&tty->path, "/dev/%s", argv[i]) < 0)
174 error("allocating path name");
175 if (start_tty(tty) < 0)
176 error("starting tty '%s'", tty->path);
184 struct epoll_event event;
186 count = epoll_wait(epoll, &event, 1, -1);
191 if (event.data.ptr == &sigs)
194 read_tty(event.data.ptr);