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 --- 5,11 ---- */ #if defined(DOSCCS) && !defined(lint) ! static char sccsid[] = "@(#)init.c 5.6.2 (2.11BSD GTE) 1995/05/04"; #endif #include *************** *** 19,24 **** --- 19,25 ---- #include #include #include + #include #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 --- 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 *************** *** 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)) ! ; } }