From: Andy Spencer Date: Sun, 4 Dec 2016 11:46:47 +0000 (+0000) Subject: Add getty daemon X-Git-Url: http://pileus.org/git/?p=mkinit;a=commitdiff_plain;h=5ade6c675ed74e6b9ebb77a5fff220061b612aa0 Add getty daemon --- diff --git a/.gitignore b/.gitignore index b08d8de..e9800f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *~ *.o +src/gettyd src/initctld diff --git a/init.mk b/init.mk index 244ea8d..3b5f459 100644 --- a/init.mk +++ b/init.mk @@ -13,7 +13,7 @@ apache2-opts = -DSSL -DPHP5 # single─bare─system─┬─desktop─> # └─server──> server = apache2 bitlbee cups denyhosts diod dovecot eth0 exim gitd jabberd mailman mysql ntpd spamd -desktop = alsa getty gpm keymap qingy wlan0 +desktop = alsa gettyd gpm keymap qingy wlan0 system = at cron hddtemp hwclock mdadm smartd sshd swap sysctl syslog bare = cpufreq fsclean hostname initctl localhost mdev modules mounts utmp diff --git a/mkfile b/mkfile index f307ef5..799b501 100644 --- a/mkfile +++ b/mkfile @@ -1,7 +1,10 @@ -# Copyright (C) 2009,2013 Andy Spencer +# Copyright (C) 2009,2013,2016 Andy Spencer # See COPYING for terms -all:V: src/initctld +all:V: src/gettyd src/initctld + +src/gettyd: src/gettyd.c + gcc -Wall -o $target $prereq src/initctld: src/initctld.c gcc -Wall -o $target $prereq @@ -11,6 +14,7 @@ install:V: all install -m 755 -D src/mkinit $DESTDIR/sbin/mkinit install -m 755 -D src/service $DESTDIR/lib/mkinit/bin/service install -m 755 -D src/respawn $DESTDIR/lib/mkinit/bin/respawn + install -m 755 -D src/gettyd $DESTDIR/lib/mkinit/bin/gettyd install -m 755 -D src/initctld $DESTDIR/lib/mkinit/bin/initctld install -m 644 -D init.mk $DESTDIR/etc/init.mk.example install -m 644 -D services.mk $DESTDIR/etc/services.mk.example diff --git a/services.mk b/services.mk index a0f3fbf..3f69b57 100644 --- a/services.mk +++ b/services.mk @@ -102,15 +102,21 @@ fsclean-start:VPservice -u: boot $P exec rm -rf /.old & service -U $target -# Spawn gettys for tty[23456] -getty-start:VEPservice -u: hostname-start utmp-start +# Spawn gettyd for tty[23456] +gettyd-start:VEPservice -u: hostname-start utmp-start + $P exec gettyd tty2 tty3 tty4 tty5 tty6 & + service -U $target +gettyd-stop_cmd=fuser -k /dev/tty2 /dev/tty3 /dev/tty4 /dev/tty5 /dev/tty6 + +# Spawn agettys for tty[23456] +agetty-start:VEPservice -u: hostname-start utmp-start $P respawn setsid agetty 38400 tty2 linux $P respawn setsid agetty 38400 tty3 linux $P respawn setsid agetty 38400 tty4 linux $P respawn setsid agetty 38400 tty5 linux $P respawn setsid agetty 38400 tty6 linux service -U $target -getty-stop_cmd=fuser -k /dev/tty2 /dev/tty3 /dev/tty4 /dev/tty5 /dev/tty6 +agetty-stop_cmd=fuser -k /dev/tty2 /dev/tty3 /dev/tty4 /dev/tty5 /dev/tty6 # Spawn qingys for tty[7] qingy-start:VEPservice -u: hostname-start utmp-start modules-start diff --git a/src/gettyd.c b/src/gettyd.c new file mode 100644 index 0000000..d87df72 --- /dev/null +++ b/src/gettyd.c @@ -0,0 +1,190 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* TTY data */ +typedef struct tty_t { + char *path; + int fd; + int pid; + struct tty_t *next; +} tty_t; + +/* Local Data */ +static int running; +static int epoll; +static int sigs; +static tty_t *ttys; + +/* Helper functions */ +void error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "Error "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": %s\n", strerror(errno)); + va_end(ap); + if (!running) + exit(1); +} + +int add_poll(int fd, void *ptr) +{ + struct epoll_event ctl = { + .events = EPOLLIN, + .data.ptr = ptr, + }; + return epoll_ctl(epoll, EPOLL_CTL_ADD, fd, &ctl); +} + +int del_poll(int fd) +{ + return epoll_ctl(epoll, EPOLL_CTL_DEL, fd, NULL); +} + +static int start_tty(tty_t *tty) +{ + const char *prompt = "[Press enter to login]"; + struct termios attr; + + tty->fd = open(tty->path, O_RDWR|O_NOCTTY|O_NONBLOCK|O_CLOEXEC, 0); + if (tty->fd < 0) + return tty->fd; + tcgetattr(tty->fd, &attr); + attr.c_lflag &= ~ECHO; + tcsetattr(tty->fd, TCSANOW, &attr); + write(tty->fd, "\033c", 2); + write(tty->fd, "\033[?1c", 5); + write(tty->fd, prompt, strlen(prompt)); + return add_poll(tty->fd, tty); +} + +static void read_tty(tty_t *tty) +{ + int flags; + char ch, login; + while (read(tty->fd, &ch, 1) == 1) + if (ch == '\n' || ch == '\r') + login = 1; + if (!login) + return; + if ((tty->pid = fork()) < 0) + return; + if (tty->pid == 0) { + if (putenv("TERM=linux")) + error("setting environment"); + if (setsid() < 0) + error("setting sid"); + if (write(tty->fd, "\033c", 2) < 0) + error("resetting tty"); + if ((flags = fcntl(tty->fd, F_GETFL)) < 0) + error("getting fd flags"); + if (fcntl(tty->fd, F_SETFL, flags&~O_NONBLOCK) < 0) + error("setting blocking flags"); + if (ioctl(tty->fd, TIOCSCTTY, 0) < 0) + error("setting ctty"); + if (dup2(tty->fd, 0) != 0) + error("setting stdin"); + if (dup2(tty->fd, 1) != 1) + error("setting stdout"); + if (dup2(tty->fd, 2) != 2) + error("setting stderr"); + if (execl("/bin/login", "login", NULL) < 0) + error("execing login program"); + } + del_poll(tty->fd); + close(tty->fd); +} + +void on_child(void) +{ + struct signalfd_siginfo info; + if (read(sigs, &info, sizeof(info)) != sizeof(info)) + return; + if (info.ssi_signo != SIGCHLD) + return; + + int status; + pid_t pid; + tty_t *tty; + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + for (tty = ttys; tty; tty = tty->next) { + if (pid == tty->pid) { + tty->pid = 0; + start_tty(tty); + } + } + } +} + +/* Main */ +int main(int argc, char **argv) +{ + int i, count; + tty_t *tty; + sigset_t mask; + + /* Check arguments */ + if (argc <= 1) { + printf("usage: gettyd ...\n"); + return 0; + } + + /* Setup */ + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGHUP); + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) + error("blocking signals"); + if ((sigs = signalfd(-1, &mask, SFD_CLOEXEC)) < 0) + error("creating signal fd"); + if ((epoll = epoll_create1(EPOLL_CLOEXEC)) < 0) + error("creating epoll"); + if (add_poll(sigs, &sigs) < 0) + error("adding signal epoll"); + + /* Open TTYs */ + for (i = 1; i < argc; i++) { + if (!(tty = malloc(sizeof(tty_t)))) + error("allocating memory"); + if (asprintf(&tty->path, "/dev/%s", argv[i]) < 0) + error("allocating path name"); + if (start_tty(tty) < 0) + error("starting tty '%s'", tty->path); + tty->next = ttys; + ttys = tty; + } + + /* Main loop */ + running = 1; + while (1) { + struct epoll_event event; + errno = 0; + count = epoll_wait(epoll, &event, 1, -1); + if (errno == EINTR) + continue; + if (count < 0) + continue; + if (event.data.ptr == &sigs) + on_child(); + else + read_tty(event.data.ptr); + } + + return 0; +}