diff options
Diffstat (limited to 'riemann.fmi.uni-sofia.bg/ngetty/ngetty-1.1/ngetty.c')
| -rw-r--r-- | riemann.fmi.uni-sofia.bg/ngetty/ngetty-1.1/ngetty.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/riemann.fmi.uni-sofia.bg/ngetty/ngetty-1.1/ngetty.c b/riemann.fmi.uni-sofia.bg/ngetty/ngetty-1.1/ngetty.c new file mode 100644 index 0000000..926e904 --- /dev/null +++ b/riemann.fmi.uni-sofia.bg/ngetty/ngetty-1.1/ngetty.c @@ -0,0 +1,278 @@ +/* + * ngetty.c - daemon for virtual console terminals + * + * Copyright 2007 Andre Oliveira + * Copyright 2007,2008 Nikola Vladov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Synopsis: ngetty tty... + * + * ngetty open()s the virtual console terminals specified as arguments and + * poll()s them for user input. Once input is available on one of the + * terminals, it fork()s and exec()s the ngetty-helper programs with that + * terminal set up as the controlling terminal. ngetty-helper make + * utmp/wtmp records, print /etc/issue, ask for user name and then + * exec()s login(1) program. When a ngetty session terminates, + * the sig_handler() restarts the corresponding terminal. + */ + +#include <unistd.h> +#include <fcntl.h> +#include <poll.h> +#include <alloca.h> +#include <errno.h> +#include <sys/wait.h> +#include "lib.h" +#include "sig_action.h" + +#ifdef NEED_HELPER_OPTION +static char *helper; +#else +#define helper NGETTY_HELPER +#endif + +struct tty_name { + char *tty; /* original ttyname */ + char tmp[23]; /* expanded ttyname; /dev/ttyX or /dev/vc/X */ + char st; +}; +typedef struct tty_name tty_name_; +typedef struct pollfd pollfd_; + +static tty_name_ *tty; + +/* Number of managed terminals (argc - 1). */ +static int npfd; + +/* + * Poll data for the terminals. + * When polling for input on a terminal, the fd field stores its + * file descriptor, as customary. After fork()ing, though, the parent + * process closes the terminal and stores the child's _negative_ pid + * in the fd field, so that poll() ignores that entry and + * main() knows every child's pid. + */ +static pollfd_ *pfd; + +static void nano_sleep(int n) { /* sleep n.5 secs */ + struct timespec ts = { n, 500111222 }; + nanosleep(&ts, 0); +} + +static void max_copy(char *out,const char *in) { + int len; + for (len=0; len<10; len++) { if (!(out[len]=in[len])) break; } + out[len] = 0; +} + +/* + * Exec NGETTY_HELPER. + */ +static void exechelper(int i, char *login) { + pollfd_ *xx = pfd + i; + int pid; + while ((pid=fork()) < 0) + nano_sleep(0); + + if (pid==0) { + tty_name_ *tt = tty + i; + char *a1 = (tt->tmp[0]) ? tt->tmp : tt->tty; + char *arg[4] = { helper, a1, login, 0 }; + +#ifndef NGETTY_SELFPIPE + if (xx->fd) +#endif + dup2(xx->fd, 0); + i = npfd + 8; + while (--i) close(i); + + execve(*arg, arg, environ); + nano_sleep(5); + _exit(127); + } + close(xx->fd); + xx->fd = -pid; +} + +/* + * Open virtual console terminal i. + * + * In case of failure, most likely because the device node does not exist, + * poll() will simply ignore this entry and users get a blank screen and + * locked keyboard on this console. That's enough error reporting. ;-) + * No need to add code to check all syscalls' return values. + * + * Linux does not implement revoke(); the *BSD do. + */ +void opentty(int k) { + tty_name_ *tt = tty + k; + char *path = tt->tty, *m = tt->tmp, st; + int fd; + + if (*path != '/') { + max_copy(m, "/dev/vc/"); + if ('0'<=*path && *path<='9') { + max_copy(m+8, path); + if (chown(m,0,0)) + { m[5]='t'; m[6]='t'; m[7]='y'; } + } else { + if (path[0]==0) { fd = -1; goto do_it; } + max_copy(m+5, path); + } + path = m; + } else + m[0] = 0; + + chown(path, 0, 0); + chmod(path, 0600); +#ifdef HAVE_REVOKE + revoke(path); +#endif + + fd = open(path, O_RDWR | O_NOCTTY); + if (fd > npfd + 4) _exit(100); + do_it: + pfd[k].fd = fd; + if (fd < 0) st = 0; + else { + st = tt->st ^ 1; + if (st) exechelper(k,0); + } + tt->st = st; +} + +#ifndef NGETTY_SELFPIPE +static int volatile poll_timeout; +#endif +/* + * SIG handler. + */ +static void sig_handler(int sig) { + if (sig == SIGTERM) { + int k; + again: + for (k = 0; k < npfd; k++) { + int pid = -pfd[k].fd; + if (pid > 1) kill(pid, sig); + } + nano_sleep(0); + if (sig == SIGKILL) _exit(0); + sig = SIGKILL; + goto again; + } +#ifdef NGETTY_SELFPIPE + write(1,"",1); +#else + poll_timeout = 1; +#endif +} + +static void set_handler() { + struct sigaction sa; + sigset_t *mask = &sa.sa_mask; + sigemptyset(mask); + sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; + sa.sa_handler = sig_handler; + sigaction(SIGTERM, &sa, 0); + sigaction(SIGCHLD, &sa, 0); +} + +#ifdef NGETTY_SORT +#include "sortpfd.h" +#define SORT_x_PFD k = sortpfd() +#define KK_selfpipe k+1 +#define KK k +#else +#define SORT_x_PFD +#define KK_selfpipe argc +#define KK npfd +#endif + +#ifdef NGETTY_SELFPIPE +#define DO_x_POLL poll(pfd-1, KK_selfpipe, -1) +#else +#define DO_x_POLL poll(pfd, KK, poll_timeout); poll_timeout = 512*1024 +#endif + +/* + * Synopsis: ngetty tty... + * + * Since each terminal's struct pollfd only takes up 8 bytes, just + * alloca()te the array on the stack, instead of using the bloated malloc(). + */ +int main(int argc, char **argv) { + int i,k; +#ifdef NGETTY_SELFPIPE + int pi[6]; +#endif + +#ifdef NEED_HELPER_OPTION + if ((helper=argv[1]) && helper[0] == '-' && helper[1] == 'H') { + argv++; argc--; helper += 2; + } else helper = NGETTY_HELPER; +#endif + + npfd = argc - 1; + tty = alloca(npfd * sizeof(tty_name_)); if (tty==0) _exit(111); + pfd = alloca(argc * sizeof(pollfd_)); if (pfd==0) _exit(111); + +#ifdef NGETTY_SELFPIPE + pfd->fd = 0; + pfd->events = POLLIN; + pfd++; +#endif + + for (k = 0; k < npfd; k++) { + tty[k].tty = *++argv; + tty[k].st = 0; + pfd[k].fd = -1; + pfd[k].events = POLLIN; + } + for (k = 0; k < 127; k++) close(k); + +#ifdef NGETTY_SELFPIPE + if (pipe(pi) || pi[0] != 0 || pi[1] != 1) _exit(111); + for (k=0; k<2; k++) + fcntl(k, F_SETFL, fcntl(k,F_GETFL,0) | O_NONBLOCK); +#endif + + set_handler(); + + again: + while ((i = waitpid(-1, NULL, WNOHANG)) > 1) + for (k = 0; k < npfd; k++) + if (pfd[k].fd == -i) + { pfd[k].fd = -1; break; } + + for (k = 0; k < npfd; k++) + if (pfd[k].fd == -1) opentty(k); + + SORT_x_PFD; + i = DO_x_POLL; + + if (i==-1) { + if (errno != EINTR) + sig_handler(SIGTERM); /* poll failed, what to do? */ + } else { + for (i = 0; i < KK; i++) + if (pfd[i].revents) + exechelper(i,"login"); + } + +#ifdef NGETTY_SELFPIPE + read(0, pi, sizeof pi); +#endif + goto again; + return 1; +} |
