*BSD News Article 43827


Return to BSD News archive

Newsgroups: comp.bugs.2bsd
Path: sserve!newshost.anu.edu.au!harbinger.cc.monash.edu.au!bunyip.cc.uq.oz.au!munnari.oz.au!news.ecn.uoknor.edu!paladin.american.edu!europa.chnt.gtegsc.com!wlbr!sms
From: sms@wlv.iipo.gtegsc.com (Steven M. Schultz)
Subject: new syslog(3) causes init(8) much grief (#238)
Sender: news@wlbr.iipo.gtegsc.com (System Administrator)
Organization: GTE Government Systems, Westlake Village
Message-ID: <D83DI7.8n6@wlbr.iipo.gtegsc.com>
X-Nntp-Posting-Host: wlv.iipo.gtegsc.com
Date: Fri, 5 May 1995 06:18:07 GMT
Lines: 319

Subject: new syslog(3) causes init(8) much grief (#238)
Index:	etc/init.c,lib/libc/gen/syslog.c 2.11BSD

Description:
	The new version of syslog() which incorporated several new features
	(vsyslog, improved timestamps, etc) causes two problem with init(8).

	1) init acquires a controlling terminal - bad.

	2) File descriptor 0 is no longer free because syslog() has used 
	   descriptor 0 for the socket for communicating with syslogd.
	   

Repeat-By:
	Relink and install 'init' with the syslog() function from update #233.

	DO NOT DO THIS IF YOU CAN NOT RLOGIN/TELNET from another computer to
	recover your system.  The console will be useless to you.  Other
	serial devices _may_ be ok.

Fix:
	Bug one not only caused 'init' to show up as running on "co" (the
	console) instead of "?" (a background process) but caused programs
	to inherit init's control terminal.  Bad news all around.

	This was caused by syslog()'s opening the console to write log
	messages.  The current version of the system allocates a controlling
	terminal on first open (same as 4.3BSD did).  Newer systems do not
	do this, instead requiring a process to ask for a controlling terminal.

	Until either a new TTY subsystem is ported OR until O_NOCTTY is
	implemented the solution to the first problem was to reinstate the
	'vfork' logic in syslog(3) and perform the open/write to the console
	in a child process.

	Bug two above totally broke the logic in 'init' which depended  on 
	'open' returning 0.   Previously init would do something like
	"open(/dev/console,...)" and _know_ that 0 would return - no check
	was made to see if that was the case.  So, file descriptor 0
	(which is now a socket to syslogd) would be dup'd on to 'stdout'
	and 'stderr'.  Naturally the single user 'sh' was unhappy in the
	extreme about this and the console promptly was useless - the
	system was unusable unless you had a network and could rlogin from
	another system!

	The fix was to properly check the return value from 'open' and dup2
	if necessary on to file descriptor 0.

	If you know the appropriate commands to compile individual libc.a
	modules you can substitute those commands for the 'make' in libc/gen
	below.

	To apply this fix:

	Save the following to a file (/tmp/238)

	patch -p0 < /tmp/238
	cd /usr/src/lib/libc/gen
	make
	ar r /lib/libc.a syslog.o
	cd profiled
	ar r /usr/lib/libc.a syslog.o
	cd ..
	make clean
	ranlib /lib/libc.a /usr/lib/libc.a
	cd /usr/src/etc
	make init
	cp -p /etc/init /etc/init.old
	install -m 755 init /etc/init

===============================cut here===================
*** /usr/src/etc/init.c.old	Tue Jan 17 21:50:15 1995
--- /usr/src/etc/init.c	Thu May  4 22:36:19 1995
***************
*** 5,11 ****
   */
  
  #if	defined(DOSCCS) && !defined(lint)
! static char sccsid[] = "@(#)init.c	5.6.1 (2.11BSD GTE) 1/17/95";
  #endif
  
  #include <sys/param.h>
--- 5,11 ----
   */
  
  #if	defined(DOSCCS) && !defined(lint)
! static char sccsid[] = "@(#)init.c	5.6.2 (2.11BSD GTE) 1995/05/04";
  #endif
  
  #include <sys/param.h>
***************
*** 19,24 ****
--- 19,25 ----
  #include <ttyent.h>
  #include <sys/syslog.h>
  #include <sys/stat.h>
+ #include <paths.h>
  
  #define	LINSIZ	sizeof(wtmp.ut_line)
  #define	CMDSIZ	200	/* max string length for getty or window command*/
***************
*** 27,38 ****
  #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
  #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
  
! char	shell[]	= "/bin/sh";
  char	minus[]	= "-";
  char	runc[]	= "/etc/rc";
! char	utmpf[]	= "/etc/utmp";
! char	wtmpf[]	= "/usr/adm/wtmp";
! char	ctty[]	= "/dev/console";
  
  struct utmp wtmp;
  struct	tab
--- 28,39 ----
  #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
  #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
  
! char	shell[]	= _PATH_BSHELL;
  char	minus[]	= "-";
  char	runc[]	= "/etc/rc";
! char	utmpf[]	= _PATH_UTMP;
! char	wtmpf[]	= _PATH_WTMP;
! char	ctty[]	= _PATH_CONSOLE;
  
  struct utmp wtmp;
  struct	tab
***************
*** 64,69 ****
--- 65,71 ----
  void	setsecuritylevel();
  int	getsecuritylevel();
  int	badsys();
+ extern	int errno;
  
  struct	sigvec rvec = { reset, sigmask(SIGHUP), 0 };
  
***************
*** 232,238 ****
  #ifdef KERN_SECURELVL
  	int name[2], curlevel;
  	size_t len;
- 	extern int errno;
  
  	name[0] = CTL_KERN;
  	name[1] = KERN_SECURELVL;
--- 234,239 ----
***************
*** 257,263 ****
  {
  #ifdef KERN_SECURELVL
  	int name[2], curlevel;
- 	extern int errno;
  
  	curlevel = getsecuritylevel();
  	if (newlevel == curlevel)
--- 258,263 ----
***************
*** 279,285 ****
  {
  	register pid;
  	register xpid;
! 	extern	errno;
  
  	/*
  	 * If the kernel is in secure mode, downgrade it to insecure mode.
--- 279,285 ----
  {
  	register pid;
  	register xpid;
! 	int	fd;
  
  	/*
  	 * If the kernel is in secure mode, downgrade it to insecure mode.
***************
*** 294,300 ****
  			signal(SIGHUP, SIG_DFL);
  			signal(SIGALRM, SIG_DFL);
  			signal(SIGTSTP, SIG_IGN);
! 			(void) open(ctty, O_RDWR);
  			dup2(0, 1);
  			dup2(0, 2);
  			execl(shell, minus, (char *)0);
--- 294,302 ----
  			signal(SIGHUP, SIG_DFL);
  			signal(SIGALRM, SIG_DFL);
  			signal(SIGTSTP, SIG_IGN);
! 			fd = open(ctty, O_RDWR, 0);
! 			if	(fd)
! 				dup2(fd, 0);
  			dup2(0, 1);
  			dup2(0, 2);
  			execl(shell, minus, (char *)0);
***************
*** 316,322 ****
  
  	pid = fork();
  	if (pid == 0) {
! 		(void) open("/", O_RDONLY);
  		dup2(0, 1);
  		dup2(0, 2);
  #ifdef pdp11
--- 318,326 ----
  
  	pid = fork();
  	if (pid == 0) {
! 		f = open("/", O_RDONLY);
! 		if	(f)
! 			dup2(f, 0);
  		dup2(0, 1);
  		dup2(0, 2);
  #ifdef pdp11
***************
*** 741,754 ****
  
  autoconfig()
  {
! 	int pid, status;
  	static char config[]= "/etc/autoconfig";
  
- 	syslog(LOG_NOTICE, "configure system\n");
  	if (!(pid = fork())) {
! 		open(ctty, O_RDWR, 0);
! 		dup(0);
! 		dup(0);
  		execl(config, "autoconfig", "-vc", 0);
  		syslog(LOG_ERR, "init: couldn't exec %s\n", config);
  		exit(AC_SETUP);
--- 745,760 ----
  
  autoconfig()
  {
! 	int pid, status, f;
  	static char config[]= "/etc/autoconfig";
  
  	if (!(pid = fork())) {
! 		syslog(LOG_NOTICE, "configure system\n");
! 		f = open(ctty, O_RDWR, 0);
! 		if	(f)
! 			dup2(f, 0);
! 		dup2(0, 1);
! 		dup2(0, 2);
  		execl(config, "autoconfig", "-vc", 0);
  		syslog(LOG_ERR, "init: couldn't exec %s\n", config);
  		exit(AC_SETUP);
*** /usr/src/lib/libc/gen/syslog.c.old	Sat Apr  1 22:56:02 1995
--- /usr/src/lib/libc/gen/syslog.c	Thu May  4 21:50:31 1995
***************
*** 32,38 ****
   */
  
  #if defined(LIBC_SCCS) && !defined(lint)
! static char sccsid[] = "@(#)syslog.c	8.4.1 (2.11BSD) 1995/04/01";
  #endif /* LIBC_SCCS and not lint */
  
  #include <sys/types.h>
--- 32,38 ----
   */
  
  #if defined(LIBC_SCCS) && !defined(lint)
! static char sccsid[] = "@(#)syslog.c	8.4.2 (2.11BSD) 1995/05/04";
  #endif /* LIBC_SCCS and not lint */
  
  #include <sys/types.h>
***************
*** 97,102 ****
--- 97,103 ----
  	time_t now;
  	int fd, saved_errno;
  	char *stdp, tbuf[640], fmt_cpy[512];
+ 	pid_t	pid;
  
  #define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
  	/* Check for invalid bits. */
***************
*** 176,189 ****
  	 * Output the message to the console; don't worry about blocking,
  	 * if console blocks everything will.  Make sure the error reported
  	 * is the one from the syslogd failure.
  	 */
! 	if (LogStat & LOG_CONS &&
! 	    (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) {
! 		(void)strcat(tbuf, "\r\n");
! 		cnt += 2;
! 		p = index(tbuf, '>') + 1;
! 		(void)write(fd, p, cnt - (p - tbuf));
! 		(void)close(fd);
  	}
  }
  
--- 177,204 ----
  	 * Output the message to the console; don't worry about blocking,
  	 * if console blocks everything will.  Make sure the error reported
  	 * is the one from the syslogd failure.
+ 	 *
+ 	 * 2.11BSD has to do a more complicated dance because we do not
+ 	 * want to acquire a controlling terminal (bad news for 'init'!).
+ 	 * Until either the tty driver is ported from 4.4 or O_NOCTTY
+ 	 * is implemented we have to fork and let the child do the open of
+ 	 * the console.
  	 */
! 	if (LogStat & LOG_CONS) {
! 		pid = vfork();
! 		if (pid == -1)
! 			return;
! 		if (pid == 0) {
! 	   		fd = open(_PATH_CONSOLE, O_WRONLY, 0);
! 			(void)strcat(tbuf, "\r\n");
! 			cnt += 2;
! 			p = index(tbuf, '>') + 1;
! 			(void)write(fd, p, cnt - (p - tbuf));
! 			(void)close(fd);
! 			_exit(0);
! 		}
! 		while (waitpid(pid, NULL, NULL) == -1 && (errno == EINTR))
! 			;
  	}
  }