Enhance src/consoles.c and src/consoles.h to reflect latest
authorDr. Werner Fink <werner@suse.de>
Thu, 31 Mar 2011 12:25:34 +0000 (12:25 +0000)
committerDr. Werner Fink <werner@suse.de>
Thu, 31 Mar 2011 12:25:34 +0000 (12:25 +0000)
linux kernel possiblities to detect the devices used for
the system console /dev/console

git-svn-id: svn://svn.sv.gnu.org/sysvinit/sysvinit/trunk@102 456724a4-4300-0410-8514-c89748c515a2

src/consoles.c
src/consoles.h

index 30d8a8fd072079ff2dedb07359751481cc71ef33..66888897c887d4f65cff337b51d63276b01002a4 100644 (file)
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifdef __linux__
+# ifndef TIOCGDEV
+#  include <sys/vt.h>
+#  include <sys/kd.h>
+#  include <linux/serial.h>
+# endif
+#endif
+#include <fcntl.h>
 #include <dirent.h>
+#include <unistd.h>
 #include "consoles.h"
 
+#ifdef __linux__
+# include <linux/major.h>
+#endif
+
 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
 # ifndef  typeof
 #  define typeof               __typeof__
 
 struct console *consoles;
 
+/*
+ * Read and allocate one line from file,
+ * the caller has to free the result
+ */
+static
+#ifdef __GNUC__
+__attribute__((__nonnull__))
+#endif
+char *oneline(const char *file)
+{
+       FILE *fp;
+       char *ret = (char*)0, *nl;
+       size_t len = 0;
+
+       if ((fp = fopen(file, "re")) == (FILE*)0)
+               goto err;
+       if (getline(&ret, &len, fp) < 0)
+               goto out;
+       if (len)
+               ret[len-1] = '\0';
+       if ((nl = strchr(ret, '\n')))
+               *nl = '\0';
+out:
+       fclose(fp);
+err:
+       return ret;
+}
+
+#ifdef __linux__
+/*
+ *  Read and determine active attribute for tty,
+ *  the caller has to free the result.
+ */
+static
+__attribute__((__malloc__))
+char *actattr(const char *tty)
+{
+       char *ret = (char*)0;
+       char *path;
+
+       if (!tty || *tty == '\0')
+               goto err;
+
+       if (asprintf(&path, "/sys/class/tty/%s/active", tty) < 0)
+               goto err;
+
+       if ((ret = oneline(path)) == (char*)0)
+               goto out;
+out:
+       free(path);
+err:
+       return ret;
+}
+
+/* Read and determine device attribute for tty */
+static
+dev_t devattr(const char *tty)
+{
+       unsigned int maj, min;
+       dev_t dev = 0;
+       char *path, *value;
+
+       if (!tty || *tty == '\0')
+               goto err;
+
+       if (asprintf(&path, "/sys/class/tty/%s/dev", tty) < 0)
+               goto err;
+
+       if ((value = oneline(path)) == (char*)0)
+               goto out;
+
+       if (sscanf(value, "%u:%u", &maj, &min) == 2)
+               dev = makedev(maj, min);
+       free(value);
+out:
+       free(path);
+err:
+       return dev;
+}
+#endif /* __linux__ */
+
 static dev_t comparedev;
-static char* scandev(DIR *dir)
+static
+#ifdef __GNUC__
+__attribute__((__nonnull__,__malloc__,__hot__))
+#endif
+char* scandev(DIR *dir)
 {
        char *name = (char*)0;
        struct dirent *dent;
@@ -69,41 +168,232 @@ static char* scandev(DIR *dir)
        return name;
 }
 
-void detect_consoles(void)
+static
+struct chardata initcp = {
+       CERASE,
+       CKILL,
+       CTRL('r'),
+       0
+};
+
+static int concount;           /* Counter for console IDs */
+
+static
+#ifdef __GNUC__
+__attribute__((__nonnull__,__hot__))
+#endif
+void consalloc(char * name)
+{
+       struct console *restrict tail;
+
+       if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0)
+               perror("memory allocation");
+
+       tail->next = (struct console*)0;
+       tail->tty = name;
+
+       tail->file = (FILE*)0;
+       tail->flags = 0;
+       tail->fd = -1;
+       tail->id = concount++;
+       tail->pid = 0;
+       memset(&tail->tio, 0, sizeof(tail->tio));
+       memcpy(&tail->cp, &initcp, sizeof(struct chardata));
+
+       if (!consoles)
+               consoles = tail;
+       else
+               consoles->next = tail;
+}
+
+void detect_consoles(const char *console, int fallback)
 {
+#ifdef __linux__
+       char *attrib, *cmdline;
        FILE *fc;
-       if ((fc = fopen("/proc/consoles", "r"))) {
+
+       if ((fc = fopen("/proc/consoles", "re"))) {
                char fbuf[16];
                int maj, min;
                DIR *dir;
                dir = opendir("/dev");
                if (!dir)
-                       goto out;
+                       goto out1;
                while ((fscanf(fc, "%*s %*s (%[^)]) %d:%d", &fbuf[0], &maj, &min) == 3)) {
-                       struct console *restrict tail;
                        char * name;
 
                        if (!strchr(fbuf, 'E'))
                                continue;
                        comparedev = makedev(maj, min);
+
                        name = scandev(dir);
+                       if (!name)
+                               continue;
+                       consalloc(name);
+               }
+               closedir(dir);
+out1:
+               fclose(fc);
+               return;
+       }
+
+       if ((attrib = actattr("console"))) {
+               char *words = attrib, *token;
+               DIR *dir;
+
+               dir = opendir("/dev");
+               if (!dir)
+                       goto out2;
+               while ((token = strsep(&words, " \t\r\n"))) {
+                       char * name;
+
+                       if (*token == '\0')
+                               continue;
+                       comparedev = devattr(token);
+                       if (comparedev == makedev(TTY_MAJOR, 0)) {
+                               char *tmp = actattr(token);
+                               if (!tmp)
+                                       continue;
+                               comparedev = devattr(tmp);
+                               free(tmp);
+                       }
 
+                       name = scandev(dir);
                        if (!name)
                                continue;
+                       consalloc(name);
+               }
+               closedir(dir);
+out2:
+               free(attrib);
+               return;
 
-                       if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0)
-                               perror("memory allocation");
+       }
 
-                       tail->next = (struct console*)0;
-                       tail->tty = name;
+       if ((cmdline = oneline("/proc/cmdline"))) {
+               char *words= cmdline, *token;
+               DIR *dir;
 
-                       if (!consoles)
-                               consoles = tail;
-                       else
-                               consoles->next = tail;
+               dir = opendir("/dev");
+               if (!dir)
+                       goto out3;
+               while ((token = strsep(&words, " \t\r\n"))) {
+#ifdef TIOCGDEV
+                       unsigned int devnum;
+#else
+                       struct vt_stat vt;
+                       struct stat st;
+#endif
+                       char *colon, *name;
+                       int fd;
+
+                       if (*token != 'c')
+                               continue;
+
+                       if (strncmp(token, "console=", 8) != 0)
+                               continue;
+                       token += 8;
+
+                       if (strcmp(token, "brl") == 0)
+                               token += 4;
+                       if ((colon = strchr(token, ',')))
+                               *colon = '\0';
+
+                       if (asprintf(&name, "/dev/%s", token) < 0)
+                               continue;
+
+                       if ((fd = open(name, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)) < 0) {
+                               free(name);
+                               continue;
+                       }
+                       free(name);
+#ifdef TIOCGDEV
+                       if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
+                               close(fd);
+                               continue;
+                       }
+                       comparedev = (dev_t)devnum;
+#else
+                       if (fstat(fd, &st) < 0) {
+                               close(fd);
+                               continue;
+                       }
+                       comparedev = st.st_rdev;
+                       if (comparedev == makedev(TTY_MAJOR, 0)) {
+                               if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
+                                       close(fd);
+                                       continue;
+                               }
+                               comparedev = makedev(TTY_MAJOR, (int)vt.v_active);
+                       }
+#endif
+                       close(fd);
+
+                       name = scandev(dir);
+                       if (!name)
+                               continue;
+                       consalloc(name);
                }
                closedir(dir);
-out:
-               fclose(fc);
+out3:
+               free(cmdline);
+               return;
+       }
+#endif /* __linux __ */
+       if (console && *console) {
+               int fd;
+               DIR *dir;
+               char *name;
+#ifdef TIOCGDEV
+               unsigned int devnum;
+#else
+# ifdef __linux__
+               struct vt_stat vt;
+# endif
+               struct stat st;
+#endif
+
+               if ((fd = open(console, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)) < 0)
+                       return;
+#ifdef TIOCGDEV
+               if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
+                       close(fd);
+                       return;
+               }
+               comparedev = (dev_t)devnum;
+#else
+               if (fstat(fd, &st) < 0) {
+                       close(fd);
+                       return;
+               }
+# ifdef __linux__
+               comparedev = st.st_rdev;
+               if (comparedev == makedev(TTY_MAJOR, 0)) {
+                       if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
+                               close(fd);
+                               return;
+                       }
+                       comparedev = makedev(TTY_MAJOR, (int)vt.v_active);
+               }
+# endif
+#endif
+               close(fd);
+               dir = opendir("/dev");
+               if (!dir)
+                       return;
+               name = scandev(dir);
+               if (name)
+                       consalloc(name);
+               closedir(dir);
+               return;
+       }
+
+       if (fallback >= 0) {
+               const char *name = ttyname(fallback);
+               if (!name)
+                       name = "/dev/console";
+               consalloc(strdup(name));
+               if (consoles)
+                       consoles->fd = fallback;
        }
 }
index 2bf8e126c1e2f908edaec6105b3e54ee06168f03..07526aa77b4cae7aeb32bb96702b41d8136c1d97 100644 (file)
  * Author: Werner Fink <werner@suse.de>
  */
 
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
 #include <termios.h>
 
+struct chardata {
+       uint8_t erase;
+       uint8_t kill;
+       uint8_t eol;
+       uint8_t parity;
+};
 struct console {
-       char * tty;
-       int tlock;
-       struct termios ltio, otio;
+       char *tty;
+       FILE *file;
+       uint32_t flags;
+       int fd, id;
+#define        CON_SERIAL      0x0001
+#define        CON_NOTTY       0x0002
+       pid_t pid;
+       struct chardata cp;
+       struct termios tio;
        struct console *next;
 };
 extern struct console *consoles;
-extern void detect_consoles(void);
+extern void detect_consoles(const char *console, int fallback);