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", 33)
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	    ${$self->{syslogd}}->loggrep(qr/write to file .* $errors/, 10)
48		or die ref($self), " write to file error not in syslogd log";
49	    close($big);
50	    # wait until syslogd has processed everything
51	    write_message($self, get_secondlog());
52	    ${$self->{server}}->loggrep(get_secondlog(), 8)
53		or die ref($self), " second log not in server log";
54	})},
55    },
56    syslogd => {
57	outfile => $fslog,
58	loggrep => {
59	    get_charlog() => 100,
60	},
61    },
62    server => {
63	func => sub {
64	    my $self = shift;
65	    read_log($self);
66	    ${$self->{syslogd}}->kill_syslogd('TERM');
67	    ${$self->{syslogd}}->loggrep("syslogd: exited", 5)
68		or die ref($self), " no 'syslogd: exited' in syslogd log";
69	    read_message($self, "exiting on signal 15");
70	},
71	loggrep => {
72	    get_firstlog() => 1,
73	    get_secondlog() => 1,
74	    get_testgrep() => 1,
75	    qr/syslogd\[\d+\]: start/ => 1,
76	    qr/syslogd\[\d+\]: restart/ => 0,
77	    qr/syslogd\[\d+\]: write to file "$fslog": /.
78		qr/No space left on device/ => '>=1',
79	    qr/bsd: .* on $fspath: file system full/ => '>=1',
80	    qr/syslogd\[\d+\]: dropped \d+ messages to file$/ => 1,
81	},
82    },
83    file => {
84	loggrep => {
85	    get_firstlog() => 1,
86	    get_testgrep() => 0,
87	    qr/syslogd\[\d+\]: write to file "$fslog": /.
88		qr/No space left on device/ => 0,
89	    qr/syslogd\[\d+\]: dropped \d+ messages to file$/ => 0,
90	},
91    },
92    pipe => { nocheck => 1 },
93    tty => { nocheck => 1 },
94);
95
961;
97