diff --git a/Makefile b/Makefile index 812d9322..261a594e 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ EXEC = finit reboot HEADERS = plugin.h svc.h helpers.h queue.h DISTFILES = LICENSE README ChangeLog finit.conf services OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o -OBJS += strlcpy.o +OBJS += strlcpy.o tty.o SRCS = $(OBJS:.o=.c) DEPS = $(addprefix .,$(SRCS:.c=.d)) diff --git a/conf.c b/conf.c index a18ebf08..79ff7a2b 100644 --- a/conf.c +++ b/conf.c @@ -31,7 +31,6 @@ #define MATCH_CMD(l, c, x) \ (!strncmp(l, c, strlen(c)) && (x = (l) + strlen(c))) - static char *build_cmd(char *cmd, char *line, int len) { int l; @@ -135,6 +134,20 @@ void parse_finit_conf(char *file) svc_register(x, NULL); continue; } + + if (MATCH_CMD(line, "console ", x)) { + if (console) free(console); + console = build_cmd(NULL, x, CMD_SIZE); + continue; + } + + if (MATCH_CMD(line, "tty ", x)) { + char *tty = build_cmd(NULL, x, CMD_SIZE); + int baud = 115200; /* TODO: Read from config file. */ + + tty_add(tty, baud); + continue; + } } fclose(fp); } diff --git a/finit.c b/finit.c index 1db58aa2..c1dd02c6 100644 --- a/finit.c +++ b/finit.c @@ -35,14 +35,14 @@ #include "sig.h" #include "lite.h" -int debug = 0; -int verbose = 1; -char *sdown = NULL; -char *network = NULL; -char *username = NULL; -char *hostname = NULL; -char *rcsd = NULL; - +int debug = 0; +int verbose = 1; +char *sdown = NULL; +char *network = NULL; +char *username = NULL; +char *hostname = NULL; +char *rcsd = NULL; +char *console = NULL; static void parse_kernel_cmdline(void) { @@ -73,7 +73,7 @@ static int run_loop(void) return 0; } -int main(int UNUSED(args), char *argv[]) +int main(int UNUSED(args), char* UNUSED(argv[])) { /* * Initial setup of signals, ignore all until we're up. @@ -135,6 +135,7 @@ int main(int UNUSED(args), char *argv[]) #ifdef SYSROOT run(SYSROOT, "/", NULL, MS_MOVE, NULL); #endif + _d("Root FS up, calling hooks ..."); plugin_run_hooks(HOOK_ROOTFS_UP); @@ -193,9 +194,8 @@ int main(int UNUSED(args), char *argv[]) */ plugin_run_hooks(HOOK_SYSTEM_UP); - /* Start GETTY on console */ - _d("Starting getty on console ..."); - run_getty(GETTY, argv); + /* Start GETTY on console(s) */ + tty_start(); /* * Enter main loop to monior /dev/initctl and services diff --git a/finit.h b/finit.h index a1cf6416..525562e6 100644 --- a/finit.h +++ b/finit.h @@ -38,11 +38,11 @@ #if defined EMBEDDED_SYSTEM # define CONSOLE "/dev/console" # define MDEV "/sbin/mdev" -# define GETTY "/sbin/getty -L 115200 ttyS0 vt100" +# define GETTY "/sbin/getty -L 115200 %s vt100" #else /* Debian/Ubuntu based distributions */ # define RANDOMSEED "/var/lib/urandom/random-seed" # define CONSOLE "/dev/tty1" -# define GETTY "/sbin/getty -8 38400 tty1" +# define GETTY "/sbin/getty -8 38400 %s" # define REMOUNT_ROOTFS_RW # define RUNLEVEL 2 # define USE_UDEV @@ -62,15 +62,20 @@ #define USERNAME_SIZE 16 #define HOSTNAME_SIZE 32 -extern char *sdown; -extern char *network; -extern char *hostname; -extern char *username; -extern char *rcsd; +extern char *sdown; +extern char *network; +extern char *hostname; +extern char *username; +extern char *rcsd; +extern char *console; /* conf.c */ void parse_finit_conf(char *file); +/* tty.c */ +void tty_start(void); +int tty_add(char *tty, int baud); + #endif /* FINIT_H_ */ /** diff --git a/helpers.c b/helpers.c index 8a3c04b0..cc1024ac 100644 --- a/helpers.c +++ b/helpers.c @@ -250,21 +250,6 @@ char *pid_get_name(pid_t pid, char *name, size_t len) return name; } - -/** - * procname_set - Change process name, as seen in process listnings - * @name: New name of process - * @args: The process' argv[] vector. - */ -void procname_set(char *name, char *args[]) -{ - size_t len = strlen(args[0]) + 1; /* Include terminating '\0' */ - - prctl(PR_SET_NAME, name, 0, 0, 0); - memset(args[0], 0, len); - strlcpy(args[0], name, len); -} - /** * procname_kill - Send a signal to a process group by name. * @name: Name of process to send signal to. @@ -507,7 +492,7 @@ int run_interactive(char *cmd, char *fmt, ...) return status; } -pid_t run_getty(char *cmd, char *argv[]) +pid_t run_getty(char *cmd, int console) { pid_t pid = fork(); @@ -517,31 +502,32 @@ pid_t run_getty(char *cmd, char *argv[]) sigset_t nmask; struct sigaction sa; - /* Detach from initial controlling TTY */ - vhangup(); + if (console) { + /* Detach from initial controlling TTY */ + vhangup(); - close(2); - close(1); - close(0); + close(2); + close(1); + close(0); - /* Attach TTY to console */ - if (open(CONSOLE, O_RDWR) != 0) - exit(1); + /* Attach TTY to console */ + if (open(CONSOLE, O_RDWR) != 0) + exit(1); + dup2(0, STDIN_FILENO); + dup2(0, STDOUT_FILENO); + dup2(0, STDERR_FILENO); + + prctl(PR_SET_NAME, "console", 0, 0, 0); + } sigemptyset(&nmask); sigaddset(&nmask, SIGCHLD); sigprocmask(SIG_UNBLOCK, &nmask, NULL); /* Reset signal handlers that were set by the parent process */ - for (i = 1; i < NSIG; i++) + for (i = 1; i < NSIG; i++) DFLSIG(sa, i, 0); - dup2(0, STDIN_FILENO); - dup2(0, STDOUT_FILENO); - dup2(0, STDERR_FILENO); - - procname_set("console", argv); - while (!fexist(SYNC_SHUTDOWN)) { static const char msg[] = "\nPlease press Enter to activate this console. "; @@ -550,10 +536,11 @@ pid_t run_getty(char *cmd, char *argv[]) continue; } - i = write(STDERR_FILENO, msg, sizeof(msg) - 1); - while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') - continue; - + if (console) { + i = write(STDERR_FILENO, msg, sizeof(msg) - 1); + while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') + continue; + } if (fexist(SYNC_STOPPED)) continue; diff --git a/helpers.h b/helpers.h index 1d2e316c..4e9db2e5 100644 --- a/helpers.h +++ b/helpers.h @@ -88,7 +88,7 @@ void set_hostname (char *hostname); int run (char *cmd); int run_interactive (char *cmd, char *fmt, ...); -pid_t run_getty (char *cmd, char *argv[]); +pid_t run_getty (char *cmd, int console); int run_parts (char *dir, char *cmd); /* strlcpy.c */ diff --git a/tty.c b/tty.c new file mode 100644 index 00000000..08794f25 --- /dev/null +++ b/tty.c @@ -0,0 +1,138 @@ +/* TTY handling in finit + * + * Copyright (c) 2013 Mattias Walström + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include +#include +#include +#include + +#include "queue.h" +#include "finit.h" +#include "helpers.h" +#include "lite.h" + +typedef struct finit_tty_t { + char *name; + int baud; + + int pid; /* Runtime information*/ +} finit_tty_t; + +typedef struct node { + LIST_ENTRY(node) link; + finit_tty_t data; +} node_t; + + +/* We need to make room for the filename also, which is sent after inotify_event. */ +#define EVENT_SIZE ((sizeof(struct inotify_event) + FILENAME_MAX)) + +LIST_HEAD(, node) node_list = LIST_HEAD_INITIALIZER(); +int tty_add(char *tty, int baud) +{ + node_t *entry = malloc(sizeof(*entry)); + + if (!entry) + return errno = ENOMEM; + + entry->data.name = tty; + entry->data.baud = baud; + + LIST_INSERT_HEAD(&node_list, entry, link); + + return 0; +} + +static void tty_startstop_one(finit_tty_t *tty, uint32_t mask) +{ + char cmd[strlen(GETTY)+FILENAME_MAX]; + + if (mask & IN_CREATE) { + _d("Starting %s as %s", tty->name, (strcmp(tty->name, console) == 0) ? "console" : "TTY"); + snprintf(cmd, sizeof(cmd), GETTY, tty->name); + tty->pid = run_getty(cmd, strcmp(tty->name, console) == 0); + } + + /* Kill the spawned child, and recollect it. */ + if ((mask & IN_DELETE) && tty->pid) { + int status = 0; + _d("Stopping %s", tty->name); + kill(tty->pid, SIGKILL); + waitpid(tty->pid, &status, 0); + tty->pid = 0; + } +} + +void tty_start(void) +{ + int fd = -1; + node_t *entry; + + /* Start all TTYs that already exist in the system. */ + LIST_FOREACH(entry, &node_list, link) { + chdir("/dev"); + if (fexist (entry->data.name)) + tty_startstop_one(&entry->data, IN_CREATE); + } + + /* Start a inotify watcher to catch new TTYs that is discovered (USB for example) */ + if (!fork()) { + fd = inotify_init(); + + prctl(PR_SET_NAME, "tty_watcher", 0, 0, 0); + if (inotify_add_watch(fd, "/dev", IN_CREATE | IN_DELETE) < 0) { + fprintf(stderr, "Failed to add watcher, errno %s\n", strerror(errno)); + return; + } + + while (1) { + int len = 0;; + char buf[EVENT_SIZE]; + struct inotify_event *notified; + + while ((len = read(fd, buf, EVENT_SIZE))) { + if (len == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + } + notified = (struct inotify_event *) &buf[0]; + LIST_FOREACH(entry, &node_list, link) { + if (strcmp(notified->name, entry->data.name) == 0) { + tty_startstop_one(&entry->data, notified->mask); + } + } + } + } + exit(0); + } + +} + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */