All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Dr. Werner Fink" <werner@suse.de>
To: util-linux@vger.kernel.org
Subject: Re: [util-linux] [PATCH 00/13] Initial import of sulogin
Date: Fri, 12 Oct 2012 16:07:57 +0200	[thread overview]
Message-ID: <20121012140757.GA10101@boole.suse.de> (raw)
In-Reply-To: <20121012132336.GC23945@x2.net.home>

[-- Attachment #1: Type: text/plain, Size: 1263 bytes --]

On Fri, Oct 12, 2012 at 03:23:36PM +0200, Karel Zak wrote:
> On Fri, Oct 12, 2012 at 02:53:09PM +0200, Dr. Werner Fink wrote:
> > On Tue, Feb 28, 2012 at 11:48:40AM -0500, Dave Reisner wrote:
> > > On Tue, Feb 28, 2012 at 11:45:08AM -0500, Dave Reisner wrote:
> > > > This is an initial stab at importing sulogin from sysvinit and making it a bit
> > > > more universal. I've removed the distro specific code and brought the rest of
> > > > it more in line with the style of the remainder of the repo. I've also added
> > > > internationalization and cleaned up the manpage.
> > > 
> > > Err, forgot... these patches live in a repo below on the 'sulogin'
> > > branch:
> > 
> > Question: Why the code for multi console support was not included?
> 
>  Time... (the patch is one huge rewrite, I'd like to split it to more
>  patches). I'm busy with some others things, so next week.

Yep, this missing feature is also known here ;)
Maybe the attached patch help as it only adds the /proc/consoles and
/sys/class/tty/ scanner into common lib and leave sulogin untouched.

The integration into sulogin.c could then be done later

   Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr

[-- Attachment #2: util-linux-consoles.patch --]
[-- Type: text/x-patch, Size: 13732 bytes --]

>From 308abe7d8d567adb22b48d242bcffe3d6e16aa68 Mon Sep 17 00:00:00 2001
From: Werner Fink <werner@suse.de>
Date: Fri, 12 Oct 2012 14:35:22 +0200
Subject: [PATCH] Add code to detect all system consoles

Signed-off-by: Werner Fink <werner@suse.de>
---
 include/Makemodule.am |    1 +
 include/consoles.h    |   48 +++++
 lib/Makemodule.am     |    1 +
 lib/consoles.c        |  507 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 557 insertions(+), 0 deletions(-)
 create mode 100644 include/consoles.h
 create mode 100644 lib/consoles.c

diff --git a/include/Makemodule.am b/include/Makemodule.am
index 9f9b78e..8905237 100644
--- a/include/Makemodule.am
+++ b/include/Makemodule.am
@@ -8,6 +8,7 @@ dist_noinst_HEADERS += \
 	include/canonicalize.h \
 	include/carefulputc.h \
 	include/closestream.h \
+	include/consoles.h \
 	include/cpuset.h \
 	include/crc32.h \
 	include/env.h \
diff --git a/include/consoles.h b/include/consoles.h
new file mode 100644
index 0000000..c669eb2
--- /dev/null
+++ b/include/consoles.h
@@ -0,0 +1,48 @@
+/*
+ * consoles.h	    Header file for routines to detect the system consoles
+ *
+ * Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * 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;
+	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 int detect_consoles(const char *, int);
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index 33a3eb8..e51bd27 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -27,6 +27,7 @@ libcommon_la_SOURCES = \
 
 if LINUX
 libcommon_la_SOURCES += \
+	lib/consoles.c
 	lib/linux_version.c \
 	lib/loopdev.c
 endif
diff --git a/lib/consoles.c b/lib/consoles.c
new file mode 100644
index 0000000..7b3be9b
--- /dev/null
+++ b/lib/consoles.c
@@ -0,0 +1,507 @@
+/*
+ * consoles.c	    Routines to detect the system consoles
+ *
+ * Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifdef __linux__
+#  include <sys/vt.h>
+#  include <sys/kd.h>
+#  include <linux/serial.h>
+#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__
+# endif
+# ifndef  restrict
+#  define restrict		__restrict__
+# endif
+#endif
+
+#define alignof(type)		((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+
+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 below
+ *  /sys/class/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 below
+ * /sys/class/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__ */
+
+/*
+ * Search below /dev for the characer device in
+ * the local `dev_t comparedev' variable.
+ */
+static dev_t comparedev;
+static
+#ifdef __GNUC__
+__attribute__((__nonnull__,__malloc__,__hot__))
+#endif
+char* scandev(DIR *dir)
+{
+	char *name = (char*)0;
+	struct dirent *dent;
+	int fd;
+
+	fd = dirfd(dir);
+	rewinddir(dir);
+	while ((dent = readdir(dir))) {
+		char path[PATH_MAX];
+		struct stat st;
+		if (fstatat(fd, dent->d_name, &st, 0) < 0)
+			continue;
+		if (!S_ISCHR(st.st_mode))
+			continue;
+		if (comparedev != st.st_rdev)
+			continue;
+		if ((size_t)snprintf(path, sizeof(path), "/dev/%s", dent->d_name) >= sizeof(path))
+			continue;
+		name = realpath(path, NULL);
+		break;
+	}
+	return name;
+}
+
+/*
+ * Default control characters for an unknown terminal line.
+ */
+static
+struct chardata initcp = {
+	CERASE,
+	CKILL,
+	CTRL('r'),
+	0
+};
+
+/*
+ * Allocate an aligned `struct console' memory area,
+ * initialize its default values, and append it to
+ * the global linked list.
+ */
+
+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;
+}
+
+/*
+ * Try to detect the real device(s) used for the system console
+ * /dev/console if but only if /dev/console is used.  On Linux
+ * this can be more than one device, e.g. a serial line as well
+ * as a virtual console as well as a simple printer.
+ *
+ * Returns 1 if stdout and stderr should be reconnected and 0
+ * otherwise.
+ */
+int detect_consoles(const char *device, int fallback)
+{
+	int fd, ret = 0;
+#ifdef __linux__
+	char *attrib, *cmdline;
+	FILE *fc;
+#endif
+	if (!device || *device == '\0')
+		fd = dup(fallback);
+	else {
+		fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
+		ret = 1;
+	}
+
+	if (fd >= 0) {
+		DIR *dir;
+		char *name;
+		struct stat st;
+#ifdef TIOCGDEV
+		unsigned int devnum;
+#endif
+
+		if (fstat(fd, &st) < 0) {
+			close(fd);
+			goto fallback;
+		}
+		comparedev = st.st_rdev;
+
+		if (ret && (fstat(fallback, &st) < 0 || comparedev != st.st_rdev))
+			dup2(fd, fallback);
+#ifdef __linux__
+		/*
+		 * Check if the device detection for Linux system console should be used.
+		 */
+		if (comparedev == makedev(TTYAUX_MAJOR, 0)) {	/* /dev/tty	*/
+			close(fd);
+			device = "/dev/tty";
+			goto fallback;
+		}
+		if (comparedev == makedev(TTYAUX_MAJOR, 1)) {	/* /dev/console */
+			close(fd);
+			goto console;
+		}
+		if (comparedev == makedev(TTYAUX_MAJOR, 2)) {	/* /dev/ptmx	*/
+			close(fd);
+			device = "/dev/tty";
+			goto fallback;
+		}
+		if (comparedev == makedev(TTY_MAJOR, 0)) {	/* /dev/tty0	*/
+			struct vt_stat vt;
+			if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
+				close(fd);
+				goto fallback;
+			}
+			comparedev = makedev(TTY_MAJOR, (int)vt.v_active);
+		}
+#endif
+#ifdef TIOCGDEV
+		if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
+			close(fd);
+			goto fallback;
+		}
+		comparedev = (dev_t)devnum;
+#endif
+		close(fd);
+		dir = opendir("/dev");
+		if (!dir)
+			goto fallback;
+		name = scandev(dir);
+		if (name)
+			consalloc(name);
+		closedir(dir);
+		if (!consoles)
+			goto fallback;
+		return ret;
+	}
+#ifdef __linux__
+console:
+	/*
+	 * Detection of devices used for Linux system consolei using
+	 * the /proc/consoles API with kernel 2.6.38 and higher.
+	 */
+	if ((fc = fopen("/proc/consoles", "re"))) {
+		char fbuf[16];
+		int maj, min;
+		DIR *dir;
+		dir = opendir("/dev");
+		if (!dir) {
+			fclose(fc);
+			goto fallback;
+		}
+		while ((fscanf(fc, "%*s %*s (%[^)]) %d:%d", &fbuf[0], &maj, &min) == 3)) {
+			char * name;
+
+			if (!strchr(fbuf, 'E'))
+				continue;
+			comparedev = makedev(maj, min);
+
+			name = scandev(dir);
+			if (!name)
+				continue;
+			consalloc(name);
+		}
+		closedir(dir);
+		fclose(fc);
+		return ret;
+	}
+	/*
+	 * Detection of devices used for Linux system console using
+	 * the sysfs /sys/class/tty/ API with kernel 2.6.37 and higher.
+	 */
+	if ((attrib = actattr("console"))) {
+		char *words = attrib, *token;
+		DIR *dir;
+
+		dir = opendir("/dev");
+		if (!dir) {
+			free(attrib);
+			goto fallback;
+		}
+		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);
+		free(attrib);
+		if (!consoles)
+			goto fallback;
+		return ret;
+
+	}
+	/*
+	 * Detection of devices used for Linux system console using
+	 * kernel parameter on the kernels command line.
+	 */
+	if ((cmdline = oneline("/proc/cmdline"))) {
+		char *words= cmdline, *token;
+		DIR *dir;
+
+		dir = opendir("/dev");
+		if (!dir) {
+			free(cmdline);
+			goto fallback;
+		}
+		while ((token = strsep(&words, " \t\r\n"))) {
+#ifdef TIOCGDEV
+			unsigned int devnum;
+#else
+			struct vt_stat vt;
+			struct stat st;
+#endif
+			char *colon, *name;
+
+			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);
+		free(cmdline);
+		/*
+		 * Detection of the device used for Linux system console using
+		 * the ioctl TIOCGDEV if available (e.g. official 2.6.38).
+		 */
+		if (!consoles) {
+#ifdef TIOCGDEV
+			unsigned int devnum;
+			const char *name;
+
+			if (!device || *device == '\0')
+				fd = dup(fallback);
+			else	fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
+
+			if (fd < 0)
+				goto fallback;
+
+			if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
+				close(fd);
+				goto fallback;
+			}
+			comparedev = (dev_t)devnum;
+			close(fd);
+
+			if (device && *device != '\0')
+				name = device;
+			else	name = ttyname(fallback);
+
+			if (!name)
+				name = "/dev/tty1";
+
+			consalloc(strdup(name));
+			if (consoles) {
+				if (!device || *device == '\0')
+					consoles->fd = fallback;
+				return ret;
+			}
+#endif
+			goto fallback;
+		}
+		return ret;
+	}
+#endif /* __linux __ */
+fallback:
+	if (fallback >= 0) {
+		const char *name;
+		
+		if (device && *device != '\0')
+			name = device;
+		else	name = ttyname(fallback);
+
+		if (!name)
+			name = "/dev/tty";
+
+		consalloc(strdup(name));
+		if (consoles)
+			consoles->fd = fallback;
+	}
+	return ret;
+}
-- 
1.7.7


  reply	other threads:[~2012-10-12 14:08 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
2012-02-28 16:45 ` [PATCH 01/13] fstab.5: fix misspelling of deprecated Dave Reisner
2012-02-28 16:45 ` [PATCH 02/13] sulogin: initial import from sysvinit Dave Reisner
2012-02-28 18:45   ` Davidlohr Bueso
2012-02-28 16:45 ` [PATCH 03/13] sulogin.8: refactor manpage Dave Reisner
2012-02-28 16:45 ` [PATCH 04/13] sulogin: whitespace fixes Dave Reisner
2012-02-28 16:45 ` [PATCH 05/13] sulogin: replace older signal() with sigaction() Dave Reisner
2012-02-28 16:45 ` [PATCH 06/13] sulogin: remove CHECK_{DES,MD5} defines Dave Reisner
2012-02-28 16:45 ` [PATCH 07/13] sulogin: remove USE_ONELINE and SANE_TIO defines Dave Reisner
2012-02-28 16:45 ` [PATCH 08/13] sulogin: use size_t for iterator to avoid cast Dave Reisner
2012-02-28 16:45 ` [PATCH 09/13] sulogin: get rid of calls to /bin/sash Dave Reisner
2012-02-28 16:45 ` [PATCH 10/13] sulogin: use pathnames.h for file locations Dave Reisner
2012-02-28 16:45 ` [PATCH 11/13] sulogin: header/include cleanup Dave Reisner
2012-02-28 16:45 ` [PATCH 12/13] sulogin: use a more standard usage output Dave Reisner
2012-02-28 16:45 ` [PATCH 13/13] sulogin: add i18n strings Dave Reisner
2012-02-28 16:48 ` [PATCH 00/13] Initial import of sulogin Dave Reisner
2012-10-12 12:53   ` [util-linux] " Dr. Werner Fink
2012-10-12 13:23     ` Karel Zak
2012-10-12 14:07       ` Dr. Werner Fink [this message]
2012-11-09  8:38         ` Karel Zak
2012-11-09  8:45           ` Karel Zak
2012-11-09 12:09         ` Karel Zak
2012-11-30 15:57           ` Dr. Werner Fink
2012-12-04 12:12             ` Dr. Werner Fink
2012-03-12 14:20 ` sulogin merged into util-linux (Re: [PATCH 00/13] Initial import of sulogin) Karel Zak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20121012140757.GA10101@boole.suse.de \
    --to=werner@suse.de \
    --cc=util-linux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.