]> Pileus Git - mkinit/commitdiff
Add getty daemon
authorAndy Spencer <andy753421@gmail.com>
Sun, 4 Dec 2016 11:46:47 +0000 (11:46 +0000)
committerAndy Spencer <andy753421@gmail.com>
Sun, 4 Dec 2016 12:02:39 +0000 (12:02 +0000)
.gitignore
init.mk
mkfile
services.mk
src/gettyd.c [new file with mode: 0644]

index b08d8deee391a4c241ea17229f2e4669b41e480f..e9800f083049a6029667632d2987d3992fadd97a 100644 (file)
@@ -1,3 +1,4 @@
 *~
 *.o
+src/gettyd
 src/initctld
diff --git a/init.mk b/init.mk
index 244ea8dda2e50d8cb81f933cc4aa613d97e08741..3b5f459499fe4b72f7ce650aaab665376dda5735 100644 (file)
--- 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 f307ef50ce2377472d75124e6d56ba5970b63428..799b5014020bb175b00013d6140ac169106f3801 100644 (file)
--- 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
index a0f3fbf7bc2c1cfd7be696b7366289015324d5cd..3f69b57d1db4d948f5110db79fdc9bda18ca0478 100644 (file)
@@ -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 (file)
index 0000000..d87df72
--- /dev/null
@@ -0,0 +1,190 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/epoll.h>
+#include <sys/signalfd.h>
+
+/* 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 <tty> ...\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;
+}