diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2015-12-30 13:15:53 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2015-12-30 13:15:53 +0000 |
commit | f73e3758610c84857f0590e7695e823a0e4103bc (patch) | |
tree | 8279aff56fd875d75d1c20fca9cea4d3c1984f5a /regress/usr.sbin | |
parent | 40c872ba8b50d97cd89d6e637a95cf1895ccbdce (diff) |
Test logging to console by redirecting the system's console into a
file. All subtests get an additional /dev/console entry in
syslog.conf, then check that messages appear in the console file.
Add a test that stops syslogd, calls sendsyslog2() with LOG_CONS
and checks that the message appears in the console file.
Diffstat (limited to 'regress/usr.sbin')
-rw-r--r-- | regress/usr.sbin/syslogd/README | 9 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/Syslogd.pm | 50 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-default.pl | 2 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-fdexhaustion-config.pl | 10 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-fdexhaustion-sighup.pl | 12 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-fdexhaustion-tcp.pl | 10 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-sendsyslog-console.pl | 35 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-sendsyslog-dropped.pl | 4 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-sendsyslog-native.pl | 2 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-sigterm.pl | 28 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-ttymsg-delay.pl | 6 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/args-ttymsg-wall.pl | 6 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/funcs.pl | 18 | ||||
-rw-r--r-- | regress/usr.sbin/syslogd/ttylog.c | 96 |
14 files changed, 185 insertions, 103 deletions
diff --git a/regress/usr.sbin/syslogd/README b/regress/usr.sbin/syslogd/README index ca269024259..0f39a4e0fd5 100644 --- a/regress/usr.sbin/syslogd/README +++ b/regress/usr.sbin/syslogd/README @@ -7,10 +7,11 @@ to syslogd. From there UDP transport is used to reach the server. All processes write log files where the message has to show up. The test arguments are kept in the args-*.pl files. The content of a log file, the data sent to a pipe process and what -the server received are checked. Logging to a user's tty is tested -with a fake login. The invocation of the sendsyslog(2) syscall is -checked with ktrace, the open file descriptors of syslogd are checked -with fstat. +the server received are checked. Logging to /dev/console is tested +with console redirection. Logging to a user's tty is tested with +a fake login. The invocation of the sendsyslog(2) syscall is checked +with ktrace, the open file descriptors of syslogd are checked with +fstat. When invoked with "make libevent", all tests are executed three times. They pass the EVENT_NO... environment variables over sudo into syslogd. This way the select(2) and poll(2) and kqueue(2) diff --git a/regress/usr.sbin/syslogd/Syslogd.pm b/regress/usr.sbin/syslogd/Syslogd.pm index 54e389b3e79..14be3488b76 100644 --- a/regress/usr.sbin/syslogd/Syslogd.pm +++ b/regress/usr.sbin/syslogd/Syslogd.pm @@ -1,4 +1,4 @@ -# $OpenBSD: Syslogd.pm,v 1.16 2015/10/19 20:16:09 bluhm Exp $ +# $OpenBSD: Syslogd.pm,v 1.17 2015/12/30 13:15:52 bluhm Exp $ # Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org> # Copyright (c) 2014 Florian Riehm <mail@friehm.de> @@ -42,7 +42,8 @@ sub new { $args{conffile} ||= "syslogd.conf"; $args{outfile} ||= "file.log"; $args{outpipe} ||= "pipe.log"; - $args{outtty} ||= "tty.log"; + $args{outconsole} ||= "console.log"; + $args{outuser} ||= "user.log"; if ($args{memory}) { $args{memory} = {} unless ref $args{memory}; $args{memory}{name} ||= "memory"; @@ -68,6 +69,7 @@ sub new { or die ref($self), " create conf file $self->{conffile} failed: $!"; print $fh "*.*\t$self->{outfile}\n"; print $fh "*.*\t|dd of=$self->{outpipe}\n"; + print $fh "*.*\t/dev/console\n"; print $fh "*.*\tsyslogd-regress\n"; my $memory = $self->{memory}; print $fh "*.*\t:$memory->{size}:$memory->{name}\n" if $memory; @@ -87,6 +89,7 @@ sub new { sub create_out { my $self = shift; + my @sudo = $ENV{SUDO} ? $ENV{SUDO} : (); open(my $fh, '>', $self->{outfile}) or die ref($self), " create log file $self->{outfile} failed: $!"; @@ -98,16 +101,20 @@ sub create_out { chmod(0666, $self->{outpipe}) or die ref($self), " chmod pipe file $self->{outpipe} failed: $!"; - unlink($self->{outtty}); - open($fh, '>', $self->{outtty}) - or die ref($self), " create tty file $self->{outtty} failed: $!"; - close $fh; - my @sudo = $ENV{SUDO} ? $ENV{SUDO} : (); - my @cmd = (@sudo, "./ttylog", "syslogd-regress", $self->{outtty}); - open($fh, '|-', @cmd) - or die ref($self), " pipe to ttylog $self->{outfile} failed: $!"; - # remember until object is destroyed, perl autoclose will send EOF - $self->{fhtty} = $fh; + foreach my $dev (qw(console user)) { + my $file = $self->{"out$dev"}; + unlink($file); + open($fh, '>', $file) + or die ref($self), " create $dev file $file failed: $!"; + close $fh; + my $user = $dev eq "console" ? + "/dev/console" : "syslogd-regress"; + my @cmd = (@sudo, "./ttylog", $user, $file); + open(my $ctl, '|-', @cmd) + or die ref($self), " pipe to @cmd failed: $!"; + # remember until object is destroyed, autoclose will send EOF + $self->{"ctl$dev"} = $ctl; + } return $self; } @@ -171,14 +178,17 @@ sub up { sleep .1; } - while ($self->{fhtty}) { - open(my $fh, '<', $self->{outtty}) or die ref($self), - " open $self->{outtty} for reading failed: $!"; - last if grep { /ttylog: started/ } <$fh>; - time() < $end - or croak ref($self), " no 'started' in $self->{outtty} ". - "after $timeout seconds"; - sleep .1; + foreach my $dev (qw(console user)) { + my $file = $self->{"out$dev"}; + while ($self->{"ctl$dev"}) { + open(my $fh, '<', $file) or die ref($self), + " open $file for reading failed: $!"; + last if grep { /ttylog: started/ } <$fh>; + time() < $end + or croak ref($self), " no 'started' in $file ". + "after $timeout seconds"; + sleep .1; + } } return $self; diff --git a/regress/usr.sbin/syslogd/args-default.pl b/regress/usr.sbin/syslogd/args-default.pl index 5341cda925d..4f20a5ae347 100644 --- a/regress/usr.sbin/syslogd/args-default.pl +++ b/regress/usr.sbin/syslogd/args-default.pl @@ -3,7 +3,7 @@ # The syslogd writes it into a file and through a pipe and to tty. # The syslogd passes it via UDP to the loghost. # The server receives the message on its UDP socket. -# Find the message in client, file, pipe, tty, syslogd, server log. +# Find the message in client, file, pipe, console, user, syslogd, server log. use strict; use warnings; diff --git a/regress/usr.sbin/syslogd/args-fdexhaustion-config.pl b/regress/usr.sbin/syslogd/args-fdexhaustion-config.pl index 322d671dcb4..dfeb97ea310 100644 --- a/regress/usr.sbin/syslogd/args-fdexhaustion-config.pl +++ b/regress/usr.sbin/syslogd/args-fdexhaustion-config.pl @@ -17,15 +17,15 @@ our %args = ( RLIMIT_NOFILE => 30, }, loggrep => { - qr/syslogd: receive_fd: recvmsg: Message too long/ => 4, + qr/syslogd: receive_fd: recvmsg: Message too long/ => 5, # One file is opened by test default config, 20 by multifile. - qr/X FILE:/ => 1+16, - qr/X UNUSED:/ => 4, + qr/X FILE:/ => 1+15, + qr/X UNUSED:/ => 5, }, }, multifile => [ - (map { { loggrep => get_testgrep() } } 0..15), - (map { { loggrep => { qr/./s => 0 } } } 16..19), + (map { { loggrep => get_testgrep() } } 0..14), + (map { { loggrep => { qr/./s => 0 } } } 15..19), ], ); diff --git a/regress/usr.sbin/syslogd/args-fdexhaustion-sighup.pl b/regress/usr.sbin/syslogd/args-fdexhaustion-sighup.pl index d0d56a82c1b..b9ae77e3c7a 100644 --- a/regress/usr.sbin/syslogd/args-fdexhaustion-sighup.pl +++ b/regress/usr.sbin/syslogd/args-fdexhaustion-sighup.pl @@ -30,8 +30,8 @@ our %args = ( qr/syslogd: receive_fd: recvmsg: Message too long/ => '>='.(4+2*3), # During first initialization the lockpipe is open. When # SIGHUP happens it is closed and one more file can be opened. - qr/X FILE:/ => 1+16+1+17, - qr/X UNUSED:/ => 4+3, + qr/X FILE:/ => 1+15+1+16, + qr/X UNUSED:/ => 5+4, }, }, server => { @@ -49,15 +49,15 @@ our %args = ( }, }, multifile => [ - (map { { loggrep => get_testgrep() } } 0..16), - (map { { loggrep => { qr/./s => 0 } } } 17..19), + (map { { loggrep => get_testgrep() } } 0..15), + (map { { loggrep => { qr/./s => 0 } } } 16..19), ], - tty => { + user => { loggrep => { get_firstlog() => 1, get_testlog() => 0, } - } + }, ); 1; diff --git a/regress/usr.sbin/syslogd/args-fdexhaustion-tcp.pl b/regress/usr.sbin/syslogd/args-fdexhaustion-tcp.pl index 256e0302f9f..b35fed201de 100644 --- a/regress/usr.sbin/syslogd/args-fdexhaustion-tcp.pl +++ b/regress/usr.sbin/syslogd/args-fdexhaustion-tcp.pl @@ -25,10 +25,10 @@ our %args = ( RLIMIT_NOFILE => 30, }, loggrep => { - qr/syslogd: receive_fd: recvmsg: Message too long/ => 5, + qr/syslogd: receive_fd: recvmsg: Message too long/ => 6, # One file is opened by test default config, 20 by multifile. - qr/X FILE:/ => 1+15, - qr/X UNUSED:/ => 5, + qr/X FILE:/ => 1+14, + qr/X UNUSED:/ => 6, qr/Accepting tcp connection/ => 0, qr/Listen again/ => '>=1', }, @@ -37,8 +37,8 @@ our %args = ( loggrep => { get_testlog() => 0 }, }, multifile => [ - (map { { loggrep => qr/syslogd: accept deferred/ } } 0..14), - (map { { loggrep => { qr/./s => 0 } } } 15..19), + (map { { loggrep => qr/syslogd: accept deferred/ } } 0..13), + (map { { loggrep => { qr/./s => 0 } } } 14..19), ], file => { loggrep => qr/syslogd: accept deferred: Too many open files/, diff --git a/regress/usr.sbin/syslogd/args-sendsyslog-console.pl b/regress/usr.sbin/syslogd/args-sendsyslog-console.pl new file mode 100644 index 00000000000..4af091dbb41 --- /dev/null +++ b/regress/usr.sbin/syslogd/args-sendsyslog-console.pl @@ -0,0 +1,35 @@ +# The client kills syslogd. +# The client writes a message with sendsyslog2 LOG_CONS flag. +# Find the message in console log. +# Create a ktrace dump of the client and check for sendsyslog2. + +use strict; +use warnings; +use Errno ':POSIX'; +use Sys::Syslog 'LOG_CONS'; + +my $errno = ENOTCONN; + +our %args = ( + client => { + func => sub { + my $self = shift; + ${$self->{syslogd}}->kill_syslogd('TERM'); + ${$self->{syslogd}}->down(); + sendsyslog2(get_testlog(), LOG_CONS) + and die ref($self), " sendsyslog2 succeeded"; + }, + ktrace => { + qr/CALL sendsyslog2\(/ => 1, + qr/RET sendsyslog2 -1 errno $errno / => 1, + }, + loggrep => {}, + }, + syslogd => { loggrep => {} }, + server => { noserver => 1 }, + file => { nocheck => 1 }, + pipe => { nocheck => 1 }, + user => { nocheck => 1 }, +); + +1; diff --git a/regress/usr.sbin/syslogd/args-sendsyslog-dropped.pl b/regress/usr.sbin/syslogd/args-sendsyslog-dropped.pl index 754bad0bd88..cf5c0d669a4 100644 --- a/regress/usr.sbin/syslogd/args-sendsyslog-dropped.pl +++ b/regress/usr.sbin/syslogd/args-sendsyslog-dropped.pl @@ -22,8 +22,8 @@ our %args = ( or die "syslogd started not in syslogd.log"; })}, ktrace => { - qr/CALL sendsyslog/ => '>=2', - qr/RET sendsyslog -1 errno $errno / => '>=1', + qr/CALL sendsyslog2\(/ => '>=2', + qr/RET sendsyslog2 -1 errno $errno / => '>=1', }, }, syslogd => { diff --git a/regress/usr.sbin/syslogd/args-sendsyslog-native.pl b/regress/usr.sbin/syslogd/args-sendsyslog-native.pl index 0c00ea9c76b..5f45317d689 100644 --- a/regress/usr.sbin/syslogd/args-sendsyslog-native.pl +++ b/regress/usr.sbin/syslogd/args-sendsyslog-native.pl @@ -12,7 +12,7 @@ use warnings; our %args = ( client => { ktrace => { - qr/CALL sendsyslog2/ => 2, + qr/CALL sendsyslog2\(/ => 2, qr/GIO fd -1 wrote \d+ bytes/ => 2, qr/RET sendsyslog2 0/ => 2, }, diff --git a/regress/usr.sbin/syslogd/args-sigterm.pl b/regress/usr.sbin/syslogd/args-sigterm.pl index ac041486d5a..d97704c6820 100644 --- a/regress/usr.sbin/syslogd/args-sigterm.pl +++ b/regress/usr.sbin/syslogd/args-sigterm.pl @@ -10,12 +10,12 @@ use warnings; our %args = ( client => { - func => sub { write_between2logs(shift, sub { + func => sub { my $self = shift; - ${$self->{server}}->loggrep("Signal", 8) - or die ref($self), " no 'Signal' between logs"; - })}, - loggrep => { get_between2loggrep() }, + write_message($self, get_testlog()); + ${$self->{server}}->loggrep("syslogd: exiting", 8) + or die ref($self), " no 'syslogd: exiting' server log"; + }, }, syslogd => { ktrace => { @@ -25,24 +25,14 @@ our %args = ( loggrep => qr/\[unpriv\] syslogd child about to exit/, }, server => { - func => sub { read_between2logs(shift, sub { + func => sub { my $self = shift; + read_message($self, get_testgrep()); ${$self->{syslogd}}->kill_syslogd('TERM'); - my $pattern = "syslogd: exiting on signal 15"; - ${$self->{syslogd}}->loggrep("syslogd: exiting on signal 15", 5) - or die ref($self), - " no 'syslogd: exiting on signal 15' between logs"; - print STDERR "Signal\n"; - })}, - down => qr/syslogd: exiting on signal 15/, - loggrep => { - (get_between2loggrep())[0] => 1, - (get_between2loggrep())[2] => 0, + read_message($self, qr/syslogd: exiting/); }, + down => qr/syslogd: exiting on signal 15/, }, - file => { loggrep => (get_between2loggrep())[0] }, - pipe => { loggrep => (get_between2loggrep())[0] }, - tty => { loggrep => (get_between2loggrep())[0] }, ); 1; diff --git a/regress/usr.sbin/syslogd/args-ttymsg-delay.pl b/regress/usr.sbin/syslogd/args-ttymsg-delay.pl index f06134747b9..d16c2bef939 100644 --- a/regress/usr.sbin/syslogd/args-ttymsg-delay.pl +++ b/regress/usr.sbin/syslogd/args-ttymsg-delay.pl @@ -2,8 +2,8 @@ # The syslogd writes it into a file and through a pipe and to tty. # The syslogd passes it via UDP to the loghost. # The server receives the message on its UDP socket. -# Find the message in client, file, pipe, tty, syslogd, server log. -# Check that syslogd has logged that the tty blocked. +# Find the message in client, file, pipe, user, syslogd, server log. +# Check that syslogd has logged that the user's tty blocked. use strict; use warnings; @@ -22,7 +22,7 @@ our %args = ( qr/ttymsg delayed write/ => '>=1', }, }, - tty => { + user => { loggrep => { qr/ 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.* [12]$/ => 2, get_testgrep() => 1, diff --git a/regress/usr.sbin/syslogd/args-ttymsg-wall.pl b/regress/usr.sbin/syslogd/args-ttymsg-wall.pl index 80b0a235c61..bc2601c6d7b 100644 --- a/regress/usr.sbin/syslogd/args-ttymsg-wall.pl +++ b/regress/usr.sbin/syslogd/args-ttymsg-wall.pl @@ -4,8 +4,8 @@ # The special message also goes to all users with wall *. # The syslogd passes it via UDP to the loghost. # The server receives the message on its UDP socket. -# Find the message in client, file, pipe, tty, syslogd, server log. -# Check that the special message is in the tty log twice. +# Find the message in client, file, pipe, console, user, syslogd, server log. +# Check that the special message is in the user's tty log twice. use strict; use warnings; @@ -22,7 +22,7 @@ our %args = ( syslogd => { conf => "local5.err\t*", }, - tty => { + user => { loggrep => { qr/Message from syslogd/ => 1, qr/syslogd-regress.* test message to all users/ => 2, diff --git a/regress/usr.sbin/syslogd/funcs.pl b/regress/usr.sbin/syslogd/funcs.pl index 4cf196db13e..54f137c350b 100644 --- a/regress/usr.sbin/syslogd/funcs.pl +++ b/regress/usr.sbin/syslogd/funcs.pl @@ -1,4 +1,4 @@ -# $OpenBSD: funcs.pl,v 1.28 2015/12/04 13:49:42 bluhm Exp $ +# $OpenBSD: funcs.pl,v 1.29 2015/12/30 13:15:52 bluhm Exp $ # Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org> # @@ -363,14 +363,20 @@ sub check_out { unless ($args{pipe}{nocheck}) { $r->loggrep("bytes transferred", 1) or sleep 1; } - unless ($args{tty}{nocheck}) { - open(my $fh, '<', $r->{outtty}) - or die "Open file $r->{outtty} for reading failed: $!"; - grep { qr/^logout/ } <$fh> or sleep 1; + foreach my $dev (qw(console user)) { + $args{$dev}{nocheck} ||= $args{tty}{nocheck}; + $args{$dev}{loggrep} ||= $args{tty}{loggrep}; + next if $args{$dev}{nocheck}; + my $ctl = $r->{"ctl$dev"}; + close($ctl); + my $file = $r->{"out$dev"}; + open(my $fh, '<', $file) + or die "Open file $file for reading failed: $!"; + grep { /^logout/ or /^console .* off/ } <$fh> or sleep 1; close($fh); } - foreach my $name (qw(file pipe tty)) { + foreach my $name (qw(file pipe console user)) { next if $args{$name}{nocheck}; my $file = $r->{"out$name"} or die; my $pattern = $args{$name}{loggrep} || get_testgrep(); diff --git a/regress/usr.sbin/syslogd/ttylog.c b/regress/usr.sbin/syslogd/ttylog.c index 733464893de..1ac14f709f8 100644 --- a/regress/usr.sbin/syslogd/ttylog.c +++ b/regress/usr.sbin/syslogd/ttylog.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ttylog.c,v 1.4 2015/12/04 13:49:42 bluhm Exp $ */ +/* $OpenBSD: ttylog.c,v 1.5 2015/12/30 13:15:52 bluhm Exp $ */ /* * Copyright (c) 2015 Alexander Bluhm <bluhm@openbsd.org> @@ -33,33 +33,39 @@ #include <utmp.h> __dead void usage(void); +void redirect(void); +void restore(void); void timeout(int); void terminate(int); void iostdin(int); FILE *lg; -char *tty; +char *console, *username, *tty; +int sfd; __dead void usage() { - fprintf(stderr, "usage: %s username logfile\n", getprogname()); + fprintf(stderr, "usage: %s /dev/console|username logfile\n", + getprogname()); exit(2); } int main(int argc, char *argv[]) { - char buf[8192], ptyname[16], *username, *logfile; - struct utmp utmp; + char buf[8192], ptyname[16], *logfile; struct sigaction act; sigset_t set; - int mfd, sfd; ssize_t n; + int mfd; if (argc != 3) usage(); - username = argv[1]; + if (strcmp(argv[1], "/dev/console") == 0) + console = argv[1]; + else + username = argv[1]; logfile = argv[2]; sigemptyset(&set); @@ -93,12 +99,7 @@ main(int argc, char *argv[]) if (dup2(sfd, 1) == -1) err(1, "dup2 stdout"); - memset(&utmp, 0, sizeof(utmp)); - strlcpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); - strlcpy(utmp.ut_name, username, sizeof(utmp.ut_name)); - time(&utmp.ut_time); - login(&utmp); - fprintf(lg, "login %s %s\n", username, tty); + redirect(); act.sa_handler = iostdin; if (sigaction(SIGIO, &act, NULL) == -1) @@ -139,21 +140,66 @@ main(int argc, char *argv[]) err(1, "read %s", ptyname); fprintf(lg, "EOF %s\n", ptyname); - if (logout(tty) == 0) - errx(1, "logout %s", tty); - fprintf(lg, "logout %s\n", tty); + restore(); errx(3, "EOF"); } void -timeout(int sig) +redirect(void) { - fprintf(lg, "signal timeout %d\n", sig); - if (tty) { - logout(tty); + struct utmp utmp; + int fd, on; + + if (console) { + /* first remove any existing console redirection */ + on = 0; + if ((fd = open("/dev/console", O_WRONLY)) == -1) + err(1, "open /dev/console"); + if (ioctl(fd, TIOCCONS, &on) == -1) + err(1, "ioctl TIOCCONS"); + close(fd); + /* then redirect console to our pseudo tty */ + on = 1; + if (ioctl(sfd, TIOCCONS, &on) == -1) + err(1, "ioctl TIOCCONS on"); + fprintf(lg, "console %s on %s\n", console, tty); + } + if (username) { + memset(&utmp, 0, sizeof(utmp)); + strlcpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + strlcpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + time(&utmp.ut_time); + login(&utmp); + fprintf(lg, "login %s %s\n", username, tty); + } +} + +void +restore(void) +{ + int on; + + if (tty == NULL) + return; + if (console) { + on = 0; + if (ioctl(sfd, TIOCCONS, &on) == -1) + err(1, "ioctl TIOCCONS off"); + fprintf(lg, "console %s off\n", tty); + } + if (username) { + if (logout(tty) == 0) + errx(1, "logout %s", tty); fprintf(lg, "logout %s\n", tty); } +} + +void +timeout(int sig) +{ + fprintf(lg, "signal timeout %d\n", sig); + restore(); errx(3, "timeout"); } @@ -161,10 +207,7 @@ void terminate(int sig) { fprintf(lg, "signal terminate %d\n", sig); - if (tty) { - logout(tty); - fprintf(lg, "logout %s\n", tty); - } + restore(); errx(3, "terminate"); } @@ -177,10 +220,7 @@ iostdin(int sig) fprintf(lg, "signal iostdin %d\n", sig); if ((n = read(0, buf, sizeof(buf))) < 0) err(1, "read stdin"); - if (tty) { - logout(tty); - fprintf(lg, "logout %s\n", tty); - } + restore(); if (n > 0) errx(3, "read stdin %zd bytes", n); exit(0); |