1# Create a log file on a file system that can be easily filled.
2# The client writes messages to Sys::Syslog native method.
3# While writing messages, the client fills the log file system.
4# After the file system has been filled, send sigterm to syslogd.
5# The syslogd writes it into a file and through a pipe and to tty.
6# The syslogd passes it via UDP to the loghost.
7# The server receives the message on its UDP socket.
8# Find the message in client, file, pipe, console, user, syslogd, server log.
9# Check that syslogd error 'No space left on device' error is logged to server.
10# Check that kernel error 'file system full' error is logged.
11# Check that the final 'dropped messages to file' is logged by server.
12
13use strict;
14use warnings;
15use Errno ':POSIX';
16use File::Path qw(remove_tree);
17use Time::HiRes;
18
19my @errors = (ENOSPC);
20my $errors = "(". join("|", map { $! = $_ } @errors). ")";
21
22my $fspath = "/mnt/regress-syslogd";
23my $fslog = "$fspath/file.log";
24my $fsbig = "$fspath/big";
25
26remove_tree($fspath, { safe => 1, keep_root => 1 });
27open(my $log, '>', $fslog)
28    or die "Create $fslog failed: $!";
29
30our %args = (
31    client => {
32	func => sub { write_between2logs(shift, sub {
33	    my $self = shift;
34	    open(my $big, '>', $fsbig)
35		or die ref($self), " create $fsbig failed: $!";
36	    ${$self->{syslogd}}->loggrep(get_firstlog(), 5)
37		or die ref($self), " first log not in syslogd log";
38	    undef $!;
39	    for (my $i = 0; $i < 100000; $i++) {
40		syswrite($big, "regress syslogd file system full\n")
41		    or last;
42	    }
43	    $!{ENOSPC}
44		or die ref($self), " fill $fsbig failed: $!";
45	    # a single message still fits, write 4 KB logs to reach next block
46	    write_lines($self, 100, 70);
47	    write_lines($self, 9, 1);
48	    ${$self->{syslogd}}->loggrep(qr/write to file .* $errors/, 10)
49		or die ref($self), " write to file error not in syslogd log";
50	    close($big);
51	    # wait until syslogd has processed everything
52	    write_message($self, get_secondlog());
53	    ${$self->{server}}->loggrep(get_secondlog(), 8)
54		or die ref($self), " second log not in server log";
55	})},
56    },
57    syslogd => {
58	outfile => $fslog,
59	loggrep => {
60	    get_charlog() => 100,
61	},
62    },
63    server => {
64	func => sub {
65	    my $self = shift;
66	    read_log($self);
67	    ${$self->{syslogd}}->kill_syslogd('TERM');
68	    ${$self->{syslogd}}->loggrep("syslogd: exited", 5)
69		or die ref($self), " no 'syslogd: exited' in syslogd log";
70	    read_message($self, "exiting on signal 15");
71	},
72	loggrep => {
73	    get_firstlog() => 1,
74	    get_secondlog() => 1,
75	    get_testgrep() => 1,
76	    qr/syslogd\[\d+\]: start/ => 1,
77	    qr/syslogd\[\d+\]: restart/ => 0,
78	    qr/syslogd\[\d+\]: write to file "$fslog": /.
79		qr/No space left on device/ => '>=1',
80	    qr/bsd: .* on $fspath: file system full/ => '>=1',
81	    qr/syslogd\[\d+\]: dropped \d+ messages to file$/ => 1,
82	},
83    },
84    file => {
85	loggrep => {
86	    get_firstlog() => 1,
87	    get_testgrep() => 0,
88	    qr/syslogd\[\d+\]: write to file "$fslog": /.
89		qr/No space left on device/ => 0,
90	    qr/syslogd\[\d+\]: dropped \d+ messages to file$/ => 0,
91	},
92    },
93    pipe => { nocheck => 1 },
94    tty => { nocheck => 1 },
95);
96
971;
98