]> git.ipfire.org Git - ipfire-3.x.git/commitdiff
Serial console: Initial commit.
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 10 Sep 2009 15:13:04 +0000 (17:13 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 14 Sep 2009 11:10:36 +0000 (13:10 +0200)
config/udev/10-console.rules
lfs/initscripts
src/initscripts/core/serial.conf [new file with mode: 0644]
src/initscripts/src/Makefile [new file with mode: 0644]
src/initscripts/src/console_check.c [new file with mode: 0644]
src/initscripts/src/securetty.c [new file with mode: 0644]
src/rootfiles/core/initscripts

index a3459ab098438892f644c0cd29e90709788a76b1..6e8c45876e1d6c498abf24070b6fe4071198359e 100644 (file)
@@ -1,2 +1,9 @@
 # Console initialization - keyboard, font, etc.
-KERNEL=="tty0",         RUN+="/lib/udev/console_init %k"
+KERNEL=="tty0",                RUN+="/lib/udev/console_init %k"
+
+# Check and set up serial and serial-like consoles if necessary
+KERNEL=="console",     RUN+="/lib/udev/console_check %k"
+KERNEL=="ttySG*",      RUN+="/lib/udev/console_check %k"
+KERNEL=="xvc*",                RUN+="/lib/udev/console_check %k"
+KERNEL=="hvsi*",       RUN+="/lib/udev/console_check %k"
+KERNEL=="hvc*",                RUN+="/lib/udev/console_check %k"
index f14083fd15f92d72e4562e248c414647370ee46b..dd90c555cd2e5ac43748c6591c8a25f84514bf70 100644 (file)
@@ -78,6 +78,11 @@ $(objects):
 
 $(OBJECT): $(objects)
        @$(PREBUILD)
+       cd $(DIR_APP)/src && make clean
+
+       cd $(DIR_APP)/src && make $(PARALLELISMFLAGS)
+       cd $(DIR_APP)/src && make install
+
        install -d -m 755 /etc/init
        install -d -m 755 /etc/sysconfig
 
@@ -92,4 +97,5 @@ $(OBJECT): $(objects)
 
        cp -vf $(DIR_CONFIG)/$(PKG_NAME)/sysctl.conf /etc
 
+       cd $(DIR_APP)/src && make clean
        @$(POSTBUILD)
diff --git a/src/initscripts/core/serial.conf b/src/initscripts/core/serial.conf
new file mode 100644 (file)
index 0000000..da1bd7e
--- /dev/null
@@ -0,0 +1,24 @@
+description             "Start a tty"
+author                  "IPFire Team"
+
+# Automatically start a configured serial console
+#
+# How this works:
+#
+# On boot, a udev helper examines /dev/console. If a serial console is the
+# primary console (last console on the commandline in grub),  the event
+# 'serial-console-available <port name> <speed>' is emitted, which
+# triggers this script.
+#
+# If your serial console is not the primary console, or you want a getty
+# on serial even if it's not the console, create your own event by copying
+# /etc/init/tty[2-6], and changing the getty line in that file.
+
+start on serial-console-available *
+stop on starting shutdown or starting reboot
+
+pre-start script
+       /sbin/securetty $1
+end script
+
+exec /sbin/agetty /dev/$1 $2 vt100-nav
diff --git a/src/initscripts/src/Makefile b/src/initscripts/src/Makefile
new file mode 100644 (file)
index 0000000..452f45f
--- /dev/null
@@ -0,0 +1,21 @@
+
+PROGS = console_check securetty
+
+CFLAGS += -D_GNU_SOURCE
+
+all: $(PROGS)
+
+clean:
+       rm -vf $(PROGS) *.o
+
+install:
+       -mkdir -pv $(DESTDIR)/lib/udev $(DESTDIR)/sbin
+       install -v -m 755 console_check $(DESTDIR)/lib/udev/
+       install -v -m 755 securetty $(DESTDIR)/sbin
+
+
+console_check: console_check.o
+       $(CC) $(LDFLAGS) -o $@ $<
+
+securetty: securetty.o
+       $(CC) $(LDFLAGS) -o $@ $<
diff --git a/src/initscripts/src/console_check.c b/src/initscripts/src/console_check.c
new file mode 100644 (file)
index 0000000..9ecbb03
--- /dev/null
@@ -0,0 +1,180 @@
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+struct speeds
+{
+       speed_t speed;
+       unsigned long value;
+};
+
+struct speeds speed_map[] =
+{
+       {B50, 50},
+       {B75, 75},
+       {B110, 110},
+        {B134, 134},
+        {B150, 150},
+        {B200, 200},
+        {B300, 300},
+        {B600, 600},
+        {B1200, 1200},
+        {B1800, 1800},
+        {B2400, 2400},
+        {B4800, 4800},
+        {B9600, 9600},
+        {B19200, 19200},
+        {B38400, 38400},
+#ifdef B57600
+       {B57600, 57600},
+#endif
+#ifdef B115200
+       {B115200, 115200},
+#endif
+#ifdef B230400
+       {B230400, 230400},
+#endif
+#ifdef B460800
+       {B460800, 460800},
+#endif
+       {0, 0}
+};
+
+int termcmp(struct termios *a, struct termios *b) {
+       if (a->c_iflag != b->c_iflag || a->c_oflag != b->c_oflag ||
+           a->c_cflag != b->c_cflag || a->c_lflag != b->c_lflag ||
+           cfgetispeed(a) != cfgetispeed(b) || cfgetospeed(a) != cfgetospeed(b))
+               return 1;
+       return memcmp(a->c_cc, b->c_cc, sizeof(a->c_cc));
+}       
+
+int get_serial_speed(int fd) {
+       struct termios mode;
+       
+       if (!tcgetattr(fd, &mode)) {
+               int i;
+               speed_t speed;
+               
+               speed = cfgetospeed(&mode);
+               for (i = 0; speed_map[i].value != 0; i++)
+                       if (speed_map[i].speed == speed)
+                               return speed_map[i].value;
+       }
+       return 0;
+}
+
+int compare_termios_to_console(char *dev, int *speed) {
+       struct termios cmode, mode;
+       int fd, cfd;
+
+       cfd = open ("/dev/console", O_RDONLY);
+       tcgetattr(cfd, &cmode);
+       close(cfd);
+
+       fd = open(dev, O_RDONLY|O_NONBLOCK);
+       tcgetattr(fd, &mode);
+
+       if (!termcmp(&cmode, &mode)) {
+               *speed = get_serial_speed(fd);
+               close(fd);
+               return 1;
+       }
+       close(fd);
+       return 0;
+}
+
+char *serial_tty_name(int type) {
+       switch (type) {
+               case PORT_8250...PORT_MAX_8250:
+                       return "ttyS";
+               case PORT_PMAC_ZILOG:
+                       return "ttyPZ";
+               case PORT_MPSC:
+                       return "ttyMM";
+               case PORT_CPM:
+                       return "ttyCPM";
+               case PORT_MPC52xx:
+                       return "ttyPSC";
+               default:
+                       return NULL;
+       }
+}
+
+char *check_serial_console(int *speed) {
+       int fd;
+       char *ret = NULL, *device;
+       char twelve = 12;
+       struct serial_struct si, si2;
+       char *tty_name;
+
+       memset(&si, 0, sizeof(si));
+       memset(&si2, 0, sizeof(si));
+
+       fd = open("/dev/console", O_RDWR);
+       if (ioctl (fd, TIOCLINUX, &twelve) >= 0)
+               goto out;
+
+       if (ioctl(fd, TIOCGSERIAL, &si) < 0)
+               goto out;
+       close(fd);
+
+       tty_name = serial_tty_name(si.type);
+       if (!tty_name)
+               goto out;
+
+       asprintf(&device, "%s%d", tty_name, si.line);
+       fd = open(device, O_RDWR|O_NONBLOCK);
+       if (fd == -1)
+               goto out;
+
+       if (ioctl(fd, TIOCGSERIAL, &si2) < 0)
+               goto out;
+
+       if (memcmp(&si,&si2, sizeof(si)))
+               goto out;
+
+       *speed = get_serial_speed(fd);
+       ret = device;
+out:
+       close(fd);
+       return ret;
+}
+
+int emit_console_event(char *dev, int speed) {
+       char *args[] = { "initctl", "emit", "--no-wait", "serial-console-available", NULL, NULL, NULL };
+       
+       args[4] = dev;
+       if (speed)
+               asprintf(&args[5],"%d",speed);
+       execv("/sbin/initctl", args);
+       return 1;       
+}
+
+int main(int argc, char **argv) {
+       char *device;
+       int speed;
+       
+       if (argc < 2) {
+               printf("usage: console_check <device>\n");
+               exit(1);
+       }
+       chdir("/dev");
+       device = argv[1];
+       if (!strcmp(device, "console")) {
+               device = check_serial_console(&speed);
+               if (device)
+                       return emit_console_event(device, speed);
+       } else if (compare_termios_to_console(device, &speed)) {
+               return emit_console_event(device, speed);
+       }
+       return 0;
+}
diff --git a/src/initscripts/src/securetty.c b/src/initscripts/src/securetty.c
new file mode 100644 (file)
index 0000000..f150507
--- /dev/null
@@ -0,0 +1,94 @@
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+void alarm_handler(int num) {
+        return;
+}
+
+int open_and_lock_securetty() {
+        int fd;
+        struct flock lock;
+        struct sigaction act, oldact;
+        
+        lock.l_type = F_WRLCK;
+        lock.l_whence = SEEK_SET;
+        lock.l_start = 0;
+        lock.l_len = 0;
+      
+        fd = open("/etc/securetty", O_RDWR);
+        if (fd == -1) {
+                syslog(LOG_ERR, "Couldn't open /etc/securetty: %s",strerror(errno));
+                return -1;
+        }
+        act.sa_handler = alarm_handler;
+        act.sa_flags = 0;
+        sigaction(SIGALRM, &act, &oldact);
+        alarm(2);
+        while (fcntl(fd, F_SETLKW, &lock) == -1) {
+                if (errno == EINTR) {
+                        syslog(LOG_ERR, "Couldn't lock /etc/securetty: Timeout exceeded");
+                } else {
+                        syslog(LOG_ERR, "Couldn't lock /etc/securetty: %s",strerror(errno));
+                }
+                return -1;
+        }
+        alarm(0);
+        sigaction(SIGALRM, &oldact, NULL);
+        return fd;
+}
+
+int rewrite_securetty(char *terminal) {
+        int fd;
+        char *buf, *pos;
+        struct stat sbuf;
+        
+        fd = open_and_lock_securetty();
+        if (fd == -1)
+                return 1;
+        if (fstat(fd, &sbuf) == -1) {
+                close(fd);
+                syslog(LOG_ERR, "Couldn't stat /etc/securetty: %s",strerror(errno));
+                return 1;
+        }
+        buf = malloc(sbuf.st_size + 1);
+        if (read(fd, buf, sbuf.st_size) != sbuf.st_size) {
+                close(fd);
+                syslog(LOG_ERR, "Couldn't read /etc/securetty: %s",strerror(errno));
+                return 1;
+        }
+        if (!strncmp(buf,terminal,strlen(terminal)) && buf[strlen(terminal)] == '\n')
+                goto out_ok;
+        if ((pos = strstr(buf, terminal))) {
+                if (pos[strlen(terminal)] == '\n' && *(pos-1) == '\n')
+                        goto out_ok;
+        }
+        if (lseek(fd, 0, SEEK_END) == -1) {
+                close(fd);
+                syslog(LOG_ERR, "Couldn't seek to end of /etc/securetty: %s",strerror(errno));
+                return 1;
+        }
+        write(fd, terminal, strlen(terminal));
+        write(fd, "\n", 1);
+out_ok:
+        close(fd);
+        return 0;
+}
+
+int main(int argc, char **argv) {
+        if (argc < 2 ) {
+                fprintf(stderr, "Usage: securetty <device>\n");
+                exit(1);
+        }
+        openlog("securetty", LOG_CONS, LOG_DAEMON);
+        return rewrite_securetty(argv[1]);
+}
index 5d89388737282b67b503788dd5a7dbd7a6380bf6..934350064d97856415ff219c85966ec7052b7396 100644 (file)
@@ -6,6 +6,7 @@ etc/init/load-modules.conf
 etc/init/loopback.conf
 etc/init/mount-kernel-filesystems.conf
 etc/init/mountfs.conf
+etc/init/serial.conf
 etc/init/shutdown.conf
 etc/init/swap.conf
 etc/init/sysctl.conf
@@ -24,3 +25,5 @@ etc/sysconfig/rc
 etc/sysconfig/rc.local
 etc/sysconfig/rc.site
 etc/sysctl.conf
+lib/udev/console_check
+sbin/securetty