Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Feb 2018 10:54:15 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r330054 - in head: include lib/libc/gen sbin/init
Message-ID:  <201802271054.w1RAsF0r098387@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Tue Feb 27 10:54:15 2018
New Revision: 330054
URL: https://svnweb.freebsd.org/changeset/base/330054

Log:
  Improve missing tty handling in init(8).  This removes a check that did
  nothing - it was checking for ENXIO, which, with devfs, is no longer
  returned - and was badly placed anyway, and replaces it with similar
  one that works, and is done just before starting getty, instead of being
  done when rereading ttys(5).
  
  From the practical point of view, this makes init(8) handle disappearing
  terminals (eg /dev/ttyU*) gracefully, without unneccessary getty restarts
  and resulting error messages.
  
  Reviewed by:	imp@
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D14307

Modified:
  head/include/ttyent.h
  head/lib/libc/gen/getttyent.3
  head/lib/libc/gen/getttyent.c
  head/sbin/init/init.c

Modified: head/include/ttyent.h
==============================================================================
--- head/include/ttyent.h	Tue Feb 27 04:41:14 2018	(r330053)
+++ head/include/ttyent.h	Tue Feb 27 10:54:15 2018	(r330054)
@@ -57,6 +57,8 @@ struct ttyent {
 #define	TTY_SECURE	0x02	/* allow uid of 0 to login */
 #define	TTY_DIALUP	0x04	/* is a dialup tty */
 #define	TTY_NETWORK	0x08	/* is a network tty */
+#define	TTY_IFEXISTS	0x10	/* configured as "onifexists" */
+#define	TTY_IFCONSOLE	0x20	/* configured as "onifconsole" */
 	int	ty_status;	/* status flags */
 	char 	*ty_window;	/* command to start up window manager */
 	char	*ty_comment;	/* comment field */

Modified: head/lib/libc/gen/getttyent.3
==============================================================================
--- head/lib/libc/gen/getttyent.3	Tue Feb 27 04:41:14 2018	(r330053)
+++ head/lib/libc/gen/getttyent.3	Tue Feb 27 10:54:15 2018	(r330054)
@@ -75,6 +75,8 @@ struct ttyent {
 #define	TTY_SECURE	0x02	/* allow uid of 0 to login */
 #define	TTY_DIALUP	0x04	/* is a dialup tty */
 #define	TTY_NETWORK	0x08	/* is a network tty */
+#define	TTY_IFEXISTS	0x10	/* configured as "onifexists" */
+#define	TTY_IFCONSOLE	0x20	/* configured as "onifconsole" */
 	int	ty_status;	/* status flags */
 	char	*ty_window;	/* command to start up window manager */
 	char	*ty_comment;	/* comment field */
@@ -115,6 +117,10 @@ Identifies a tty used for network connections.
 If this flag is set, then
 .Fn isnettty
 will return a non-zero value.
+.It Dv TTY_IFEXISTS
+Identifies a tty that does not neccessarily exist.
+.It Dv TTY_IFCONSOLE
+Identifies a tty that might be a system console.
 .El
 .It Fa ty_window
 The command to execute for a window system associated with the line.

Modified: head/lib/libc/gen/getttyent.c
==============================================================================
--- head/lib/libc/gen/getttyent.c	Tue Feb 27 04:41:14 2018	(r330053)
+++ head/lib/libc/gen/getttyent.c	Tue Feb 27 10:54:15 2018	(r330054)
@@ -75,11 +75,14 @@ auto_tty_status(const char *ty_name)
 {
 	size_t len;
 	char *buf, *cons, *nextcons;
+	int rv;
 
+	rv = TTY_IFCONSOLE;
+
 	/* Check if this is an enabled kernel console line */
 	buf = NULL;
 	if (sysctlbyname("kern.console", NULL, &len, NULL, 0) == -1)
-		return (0); /* Errors mean don't enable */
+		return (rv); /* Errors mean don't enable */
 	buf = malloc(len);
 	if (sysctlbyname("kern.console", buf, &len, NULL, 0) == -1)
 		goto done;
@@ -90,14 +93,14 @@ auto_tty_status(const char *ty_name)
 	nextcons = buf;
 	while ((cons = strsep(&nextcons, ",")) != NULL && strlen(cons) != 0) {
 		if (strcmp(cons, ty_name) == 0) {
-			free(buf);
-			return (TTY_ON);
+			rv |= TTY_ON;
+			break;
 		}
 	}
 
 done:
 	free(buf);
-	return (0);
+	return (rv);
 }
 
 static int
@@ -107,13 +110,13 @@ auto_exists_status(const char *ty_name)
 	char *dev;
 	int rv;
 
-	rv = 0;
+	rv = TTY_IFEXISTS;
 	if (*ty_name == '/')
 		asprintf(&dev, "%s", ty_name);
 	else
 		asprintf(&dev, "/dev/%s", ty_name);
 	if (dev != NULL && stat(dev, &sb) == 0)
-		rv = TTY_ON;
+		rv |= TTY_ON;
 	free(dev);
 	return (rv);
 }

Modified: head/sbin/init/init.c
==============================================================================
--- head/sbin/init/init.c	Tue Feb 27 04:41:14 2018	(r330053)
+++ head/sbin/init/init.c	Tue Feb 27 10:54:15 2018	(r330054)
@@ -156,6 +156,8 @@ typedef struct init_session {
 	int	se_flags;		/* status of session */
 #define	SE_SHUTDOWN	0x1		/* session won't be restarted */
 #define	SE_PRESENT	0x2		/* session is in /etc/ttys */
+#define	SE_IFEXISTS	0x4		/* session defined as "onifexists" */
+#define	SE_IFCONSOLE	0x8		/* session defined as "onifconsole" */
 	int	se_nspace;		/* spacing count */
 	char	*se_device;		/* filename of port */
 	char	*se_getty;		/* what to run on that port */
@@ -1262,7 +1264,6 @@ static session_t *
 new_session(session_t *sprev, struct ttyent *typ)
 {
 	session_t *sp;
-	int fd;
 
 	if ((typ->ty_status & TTY_ON) == 0 ||
 	    typ->ty_name == 0 ||
@@ -1273,21 +1274,15 @@ new_session(session_t *sprev, struct ttyent *typ)
 
 	sp->se_flags |= SE_PRESENT;
 
+	if ((typ->ty_status & TTY_IFEXISTS) != 0)
+		sp->se_flags |= SE_IFEXISTS;
+
+	if ((typ->ty_status & TTY_IFCONSOLE) != 0)
+		sp->se_flags |= SE_IFCONSOLE;
+
 	if (asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name) < 0)
 		err(1, "asprintf");
 
-	/*
-	 * Attempt to open the device, if we get "device not configured"
-	 * then don't add the device to the session list.
-	 */
-	if ((fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0)) < 0) {
-		if (errno == ENXIO) {
-			free_session(sp);
-			return (0);
-		}
-	} else
-		close(fd);
-
 	if (setupargv(sp, typ) == 0) {
 		free_session(sp);
 		return (0);
@@ -1507,6 +1502,30 @@ start_getty(session_t *sp)
 }
 
 /*
+ * Return 1 if the session is defined as "onifexists"
+ * or "onifconsole" and the device node does not exist.
+ */
+static int
+session_has_no_tty(session_t *sp)
+{
+	int fd;
+
+	if ((sp->se_flags & SE_IFEXISTS) == 0 &&
+	    (sp->se_flags & SE_IFCONSOLE) == 0)
+		return (0);
+
+	fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0);
+	if (fd < 0) {
+		if (errno == ENOENT)
+			return (1);
+		return (0);
+	}
+
+	close(fd);
+	return (0);
+}
+
+/*
  * Collect exit status for a child.
  * If an exiting login, start a new login running.
  */
@@ -1524,7 +1543,8 @@ collect_child(pid_t pid)
 	del_session(sp);
 	sp->se_process = 0;
 
-	if (sp->se_flags & SE_SHUTDOWN) {
+	if (sp->se_flags & SE_SHUTDOWN ||
+	    session_has_no_tty(sp)) {
 		if ((sprev = sp->se_prev) != NULL)
 			sprev->se_next = sp->se_next;
 		else
@@ -1610,6 +1630,8 @@ multi_user(void)
 
 	for (sp = sessions; sp; sp = sp->se_next) {
 		if (sp->se_process)
+			continue;
+		if (session_has_no_tty(sp))
 			continue;
 		if ((pid = start_getty(sp)) == -1) {
 			/* serious trouble */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802271054.w1RAsF0r098387>