Subject: kern/5155: Kernel messages may be way too verbose for some apps.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <cgd@NetBSD.ORG>
List: netbsd-bugs
Date: 03/12/1998 13:40:17
>Number:         5155
>Category:       kern
>Synopsis:       Kernel messages may be way too verbose for some apps.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Thu Mar 12 13:50:02 1998
>Last-Modified:
>Originator:     Chris G. Demetriou
>Organization:
Kernel Hackers 'r' Us
>Release:        All versions of NetBSD, ever, up to and including today's.
>Environment:
System: NetBSD brick.int.demetriou.com 1.3E NetBSD 1.3E (BRICK) #39: Thu Mar 12 11:55:53 PST 1998 cgd@brick.int.demetriou.com:/usr/src/sys/arch/i386/compile/BRICK i386
But that's really irrelevant.


>Description:
	Kernel messages may be way too verbose for some applications.
	For some applications, NetBSD is used as an embedded operating
	system.  Users observing such systems boot don't need to know
	much, if anything, about what's going on, except in the case
	where something's failed and somebody needs to debug it.

	The same is true for messages from, for instance, /etc/rc.

	There are simple, inelegant ways to implement this.  An example
	of one is below.  It's not intended to be something that should
	be committed to the source tree, but instead should be looked
	at as an example of what i'm talking about.  (It has a lot of
	known problems, which aren't particularly easy to fix cleanly.
	However, it served its purpose, it's a concrete example of
	the minimum type of functionality i'm talking about, etc.)

	There are also more elegant ways to do something like this,
	e.g. assign a priority ("highest == always" > "error" >
	"informational" > "debugging") to all messages, and only
	print those messages which have a priority greater than or
	equal to the currently "enabled" level.  (Note that in all
	cases, the messages should go the to the message buffer.  Note
	also that, in my opinion at least, most kernel printfs
	should probably be logged with levels, whereas now they're
	not.)

	Examples of particular types of messages:

	Always:
		boot-time copyright notice announcements, and probably
	        some announcement that you're running NetBSD.

		post-shutdown messages (i.e. "hit any key to reboot")

	Error:
		panic (maybe this should be "always", but maybe not
		to avoid scaring naive users...  it'll be in msgbuf
		anyway, so if you had to dump the kernel you're fine.)

		serious device errors/driver problems (bad block,
		terminal on fire, etc.  maybe things like "device out
		of paper", though that's not really so serious.)

	Info:
		That autoconfiguration output we all know and love.

		Stuff about syncing disks on reboot.

		(Should still be kept to a minimum, e.g. no more verboes
		than what printf is normally used for now.)

	Debugging:
		"As verbose as you want to be."	

	Other useful features it'd be nice to have and/or notes that
	should be mentioned:

	* It'd be nice to be able to compile the system so that _none_ of
	  the printfs below a given level is included.  (Not necessarily
	  a good idea, but if you really need to squeeze for space you
	  should be able to do so.)

	* Debugging printfs should still be compiled in via driver/module
	  #defines, and made conditional on driver/module-specific flags.
	  Just because you've turned on debugging output to the console
	  doesn't mean you should get flooded, and don't forget that it's
	  going to the message buffer anyway.

	Note that I'm not suggesting that NetBSD ship with most messages
	disabled by default (at least on most systems), but it should
	be possible for people to configure their systems so that this
	is the default (and have the message-printing level be
	configurable via boot arguments or some similar/more permanent
	configuration mechanism).  I'd say that the default should
	probably be "all compiled in, info and higher go to the console."

>How-To-Repeat:
	Boot NetBSD.  Note that it spews much text.

>Fix:
	"See above."  Some diffs that show an example implementation
	of an inelegant way of doing something like this is below.
	(DO NOT SUGGEST THAT IT SHOULD BE COMMITTED, OR FLAME ME FOR
	IT!  8-)

Index: sys/kern/init_main.c
===================================================================
RCS file: /cvsroot/src/sys/kern/init_main.c,v
retrieving revision 1.118
diff -c -r1.118 init_main.c
*** init_main.c	1998/03/01 02:22:27	1.118
--- init_main.c	1998/03/12 19:48:07
***************
*** 139,144 ****
--- 139,147 ----
  extern char *syscallnames[];
  #endif
  
+ /* boot quietly */
+ static int quiet;
+ 
  struct emul emul_netbsd = {
  	"netbsd",
  	NULL,
***************
*** 190,196 ****
--- 193,207 ----
  	 * in case of early panic or other messages.
  	 */
  	consinit();
+ 	/*
+ 	 * Print the copyright message even if we're booting quietly.
+ 	 */
+ 	quiet = boothowto & RB_QUIET;
+ 	boothowto &= ~quiet;
  	printf(copyright);
+ 	if (quiet)
+ 	    printf("System Starting... ");
+ 	boothowto |= quiet;
  
  #if defined(UVM)
  	uvm_init();
***************
*** 354,359 ****
--- 365,371 ----
  	/* Mount the root file system. */
  	do {
  		domountroothook();
+ 		/* XXX quiet lossage */
  		if ((error = vfs_mountroot())) {
  			printf("cannot mount root, error = %d\n", error);
  			boothowto |= RB_ASKNAME;
***************
*** 393,398 ****
--- 405,419 ----
  	/* Initialize signal state for process 0. */
  	siginit(p);
  
+ 	/*
+ 	 * Now that all the "nerd junk" has been emitted, enable
+ 	 * kernel printfs if they were disabled by RB_QUIET.
+ 	 */
+ 	if (quiet) {
+ 	    boothowto &= ~RB_QUIET;
+ 	    printf(" \n");
+ 	}
+ 
  	/* Create process 1 (init(8)). */
  	if (fork1(p, 0, NULL, &p2))
  		panic("fork init");
***************
*** 455,461 ****
  	} */ args;
  	int options, i, error;
  	register_t retval[2];
! 	char flags[4], *flagsp;
  	char **pathp, *path, *ucp, **uap, *arg0, *arg1 = NULL;
  
  	/*
--- 476,482 ----
  	} */ args;
  	int options, i, error;
  	register_t retval[2];
! 	char flags[5], *flagsp;
  	char **pathp, *path, *ucp, **uap, *arg0, *arg1 = NULL;
  
  	/*
***************
*** 510,515 ****
--- 531,540 ----
  			options = 1;
  		}
  #endif
+ 		if (quiet) {
+ 			*flagsp++ = 'q';
+ 			options = 1;
+ 		}
  
  		/*
  		 * Move out the flags (arg 1), if necessary.
Index: sys/kern/subr_prf.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_prf.c,v
retrieving revision 1.48
diff -c -r1.48 subr_prf.c
*** subr_prf.c	1998/03/01 02:22:31	1.48
--- subr_prf.c	1998/03/12 19:48:07
***************
*** 155,160 ****
--- 155,164 ----
  	int bootopt;
  	va_list ap;
  
+ 	/*
+ 	 * Force kernel printfs on, regardless of quiet booting
+ 	 */
+ 	boothowto &= ~RB_QUIET;
  	bootopt = RB_AUTOBOOT | RB_DUMP;
  	if (panicstr)
  		bootopt |= RB_NOSYNC;
***************
*** 318,325 ****
  			}
  		}
  	}
! 	if ((flags & TOCONS) && constty == NULL && c != '\0')
! 		(*v_putc)(c);
  #ifdef DDB
  	if (flags & TODDB)
  		db_putchar(c);
--- 322,336 ----
  			}
  		}
  	}
! 	if ((flags & TOCONS) && constty == NULL && c != '\0') {
! 		if ((boothowto & RB_QUIET) == 0)
! 			(*v_putc)(c);
! 		else if (c == '\n') {
! 			(*v_putc)("|/-\\"[twiddlestate++]);
! 			(*v_putc)('\b');
! 			twiddlestate %= 4;
! 		}
! 	}
  #ifdef DDB
  	if (flags & TODDB)
  		db_putchar(c);
Index: sys/sys/reboot.h
===================================================================
RCS file: /cvsroot/src/sys/sys/reboot.h,v
retrieving revision 1.14
diff -c -r1.14 reboot.h
*** reboot.h	1998/03/01 02:24:14	1.14
--- reboot.h	1998/03/12 19:48:07
***************
*** 55,60 ****
--- 55,61 ----
  #define	RB_DUMP		0x100	/* dump kernel memory before reboot */
  #define	RB_MINIROOT	0x200	/* mini-root present in memory at boot time */
  #define RB_STRING	0x400	/* use provided bootstr */
+ #define RB_QUIET	0x800	/* boot quietly (twiddle) */
  
  /*
   * Constants for converting boot-style device number to type,
Index: sbin/init/init.c
===================================================================
RCS file: /src/kona.cvs/netbsd/sbin/init/init.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -c -r1.1.1.2 -r1.2
*** 1.1.1.2	1997/12/09 01:26:04
--- 1.2	1997/12/24 00:02:30
***************
*** 168,173 ****
--- 168,176 ----
  int getsecuritylevel __P((void));
  int setupargv __P((session_t *, struct ttyent *));
  int clang;
+ #ifndef LETS_GET_SMALL
+ int quiet;
+ #endif
  
  void clear_session_logs __P((session_t *));
  
***************
*** 237,243 ****
  	 * This code assumes that we always get arguments through flags,
  	 * never through bits set in some random machine register.
  	 */
! 	while ((c = getopt(argc, argv, "sf")) != -1)
  		switch (c) {
  		case 's':
  			requested_transition = single_user;
--- 240,246 ----
  	 * This code assumes that we always get arguments through flags,
  	 * never through bits set in some random machine register.
  	 */
! 	while ((c = getopt(argc, argv, "sfq")) != -1)
  		switch (c) {
  		case 's':
  			requested_transition = single_user;
***************
*** 245,252 ****
  		case 'f':
  			runcom_mode = FASTBOOT;
  			break;
  		default:
! 			warning("unrecognized flag '-%c'", c);
  			break;
  		}
  
--- 248,258 ----
  		case 'f':
  			runcom_mode = FASTBOOT;
  			break;
+ 		case 'q':
+ 			quiet = 1;
+ 			break;
  		default:
! 			warning("unrecognized flag '-%c'", optopt);
  			break;
  		}
  
***************
*** 531,538 ****
  transition(s)
  	state_t s;
  {
! 	for (;;)
  		s = (state_t) (*s)();
  }
  
  /*
--- 537,548 ----
  transition(s)
  	state_t s;
  {
! 	for (;;) {
  		s = (state_t) (*s)();
+ #ifndef LETS_GET_SMALL
+ 		quiet = 0;
+ #endif
+ 	}
  }
  
  /*
***************
*** 729,735 ****
  {
  	pid_t pid, wpid;
  	int status;
! 	char *argv[4];
  	struct sigaction sa;
  
  	if ((pid = fork()) == 0) {
--- 739,745 ----
  {
  	pid_t pid, wpid;
  	int status;
! 	char *argv[5], **ap;
  	struct sigaction sa;
  
  	if ((pid = fork()) == 0) {
***************
*** 741,750 ****
  
  		setctty(_PATH_CONSOLE);
  
! 		argv[0] = "sh";
! 		argv[1] = _PATH_RUNCOM;
! 		argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0;
! 		argv[3] = 0;
  
  		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
  
--- 751,764 ----
  
  		setctty(_PATH_CONSOLE);
  
! 		ap = argv;
! 		*ap++ = "sh";				/* 1 */
! 		*ap++ = _PATH_RUNCOM;			/* 2 */
! 		if (quiet)
! 			*ap++ = "-q";			/* 3 */
! 		if (runcom_mode == AUTOBOOT)
! 			*ap++ = "autoboot";		/* 4 */
! 		*ap++ = 0;				/* 5 */
  
  		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
  
Index: etc/rc
*** etc/rc	Thu Jan 15 17:44:56 1998
--- etc/rc	Fri Feb  6 15:37:00 1998
***************
*** 16,21 ****
--- 16,29 ----
  export HOME=/
  export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin
  
+ # XXX check rc.conf variable?
+ if [ "$1x" = -qx ]
+ then
+ 	shift
+ 	exec > /dev/null
+ 	echo Starting OS Utilities 1>&2
+ fi
+ 
  # Configure ccd devices.
  if [ -f /etc/ccd.conf ]; then
  	ccdconfig -C
***************
*** 37,53 ****
  		exit 1
  		;;
  	4)
! 		echo "Rebooting..."
  		reboot
! 		echo "Reboot failed; help!"
  		exit 1
  		;;
  	8)
! 		echo "Automatic file system check failed; help!"
  		exit 1
  		;;
  	12)
! 		echo "Boot interrupted."
  		exit 1
  		;;
  	130)
--- 45,61 ----
  		exit 1
  		;;
  	4)
! 		echo "Rebooting..." 1>&2
  		reboot
! 		echo "Reboot failed; help!" 1>&2
  		exit 1
  		;;
  	8)
! 		echo "Automatic file system check failed; help!" 1>&2
  		exit 1
  		;;
  	12)
! 		echo "Boot interrupted." 1>&2
  		exit 1
  		;;
  	130)
***************
*** 55,67 ****
  		exit 1
  		;;
  	*)
! 		echo "Unknown error; help!"
  		exit 1
  		;;
  	esac
  fi
  
! trap "echo 'Boot interrupted.'; exit 1" 3
  
  umount -a >/dev/null 2>&1
  mount /
--- 63,75 ----
  		exit 1
  		;;
  	*)
! 		echo "Unknown error; help!" 1>&2
  		exit 1
  		;;
  	esac
  fi
  
! trap "echo 'Boot interrupted.' 1>&2; exit 1" 3
  
  umount -a >/dev/null 2>&1
  mount /
***************
*** 70,76 ****
  if [ -f /etc/rc.subr ]; then
  	. /etc/rc.subr
  else
! 	echo "Can't read /etc/rc.subr; aborting."
  	exit 1;
  fi
  
--- 78,84 ----
  if [ -f /etc/rc.subr ]; then
  	. /etc/rc.subr
  else
! 	echo "Can't read /etc/rc.subr; aborting." 1>&2
  	exit 1;
  fi
  
***************
*** 79,85 ****
  fi
  
  if [ "$rc_configured" != YES ]; then
! 	echo "/etc/rc.conf is not configured. Multiuser boot aborted."
  	exit 1
  fi
  
--- 87,93 ----
  fi
  
  if [ "$rc_configured" != YES ]; then
! 	echo "/etc/rc.conf is not configured. Multiuser boot aborted." 1>&2
  	exit 1
  fi
  
***************
*** 97,102 ****
--- 105,126 ----
  	fi
  fi
  
+ # If a network interface is already up and running, then we must have
+ # been booted over the network.  In this case, delay starting the
+ # DHCP client untill later.  If we can't mount /usr, then delay as well.
+ 
+ if checkyesno dhclient; then
+     dhcstarted=""
+     nets="`ifconfig -a`"
+     if ! expr "$nets" : '.*inet.*' >/dev/null 2>&1; then
+ 	mount /usr >/dev/null 2>&1
+ 	if [ -r /etc/dhclient.conf ] && [ -x /usr/sbin/dhclient ]; then
+ 		/usr/sbin/dhclient $dhclient_flags
+ 		dhcstarted=1
+ 	fi
+     fi
+ fi
+ 
  # set hostname, turn on network
  echo 'starting network'
  sh /etc/netstart
***************
*** 126,135 ****
  # Check for no swap, and warn about it unless that is desired.
  if [ "$no_swap" != YES ]; then
  	swapctl -s | grep 'no swap devices configured' > /dev/null && \
! 		echo "WARNING:  no swap space configured!"
  fi
  
  # clean up left-over files
  rm -f /etc/nologin
  rm -f /var/spool/lock/LCK.*
  rm -f /var/spool/uucp/STST/*
--- 150,162 ----
  # Check for no swap, and warn about it unless that is desired.
  if [ "$no_swap" != YES ]; then
  	swapctl -s | grep 'no swap devices configured' > /dev/null && \
! 		echo "WARNING:  no swap space configured!" 1>&2
  fi
  
  # clean up left-over files
+ if [ -f /etc/rc.var-setup ]; then	# set up /var
+ 	. /etc/rc.var-setup
+ fi
  rm -f /etc/nologin
  rm -f /var/spool/lock/LCK.*
  rm -f /var/spool/uucp/STST/*
***************
*** 145,150 ****
--- 172,185 ----
  	syslogd $syslogd_flags
  fi
  
+ # If we didn't start the DHCP client earlier, do it now.
+ if checkyesno dhclient; then
+     if [ ! "$dhcstarted" ] && [ -r /etc/dhclient.conf ] && \
+        [ -x /usr/sbin/dhclient ]; then
+ 	/usr/sbin/dhclient $dhclient_flags $dhclient_net_flags
+     fi
+ fi
+ 
  # Enable ipmon (only useful if ipfilter is running)
  # NOTE: requires the IPFILTER_LOG kernel option.
  if checkyesno ipmon; then
***************
*** 469,473 ****
  
  . /etc/rc.local
  
! date
  exit 0
--- 504,508 ----
  
  . /etc/rc.local
  
! date 1>&2
  exit 0
>Audit-Trail:
>Unformatted: