Handle hostnames with upper-case letters
[webmin.git] / syslog-ng / syslog-ng-lib.pl
1 # Functions for parsing the syslog-ng config file
2
3 BEGIN { push(@INC, ".."); };
4 use WebminCore;
5 &init_config();
6
7 @log_flags = ( "final", "fallback", "catchall" );
8
9 # get_syslog_ng_version()
10 # Returns the version number for syslog-ng, or undef
11 sub get_syslog_ng_version
12 {
13 local $out = &backquote_command("$config{'syslogng_cmd'} -V 2>&1 </dev/null",1);
14 return $out =~ /syslog-ng\s+([0-9\.]+)/ ? $1 : undef;
15 }
16
17 sub supports_sun_streams
18 {
19 return $gconfig{'os_type'} eq 'solaris';
20 }
21
22 # get_config()
23 # Parses the syslog-ng config file into an array ref of objects
24 sub get_config
25 {
26 if (!scalar(@get_config_cache)) {
27         # First read file into tokens
28         @get_config_cache = &read_config_file($config{'syslogng_conf'});
29         }
30 return \@get_config_cache;
31 }
32
33 # read_config_file(file)
34 # Parses a config file into structures
35 sub read_config_file
36 {
37 local ($file) = @_;
38 local (@rv, @tok, @ltok, @lnum);
39 &open_readfile(CONF, $file);
40 local $lnum = 0;
41 local $cmode;
42 while($line = <CONF>) {
43         # strip comments
44         $line =~ s/\r|\n//g;
45         $line =~ s/#.*$//g;             # Remove hash comment
46         $line =~ s/\/\/.*$//g if ($line !~ /".*\/\/.*"/);
47         $line =~ s/\/\*.*\*\///g;       # Remove multi-line comment
48         $line =~ s/^\s*@.*$//g;         # Remove @version line
49         while(1) {
50                 if (!$cmode && $line =~ /\/\*/) {
51                         # start of a C-style comment
52                         $cmode = 1;
53                         $line =~ s/\/\*.*$//g;
54                         }
55                 elsif ($cmode) {
56                         if ($line =~ /\*\//) {
57                                 # end of comment
58                                 $cmode = 0;
59                                 $line =~ s/^.*\*\///g;
60                                 }
61                         else { $line = ""; last; }
62                         }
63                 else { last; }
64                 }
65
66         # split line into tokens
67         undef(@ltok);
68         while(1) {
69                 if ($line =~ /^\s*\"([^"]*)"(.*)$/) {
70                         # " quoted string
71                         push(@ltok, $1); $line = $2;
72                         }
73                 elsif ($line =~ /^\s*\'([^']*)'(.*)$/) {
74                         # ' quoted string
75                         push(@ltok, $1); $line = $2;
76                         }
77                 elsif ($line =~ /^\s*([{};\(\),\.])(.*)$/) {
78                         # regular word
79                         push(@ltok, $1); $line = $2;
80                         }
81                 elsif ($line =~ /^\s*([0-9\[\]\-]+\.[0-9\[\]\-]+\.[0-9\[\]\-]+\.[0-9\[\]\-]+)(.*)$/) {
82                         # IP address regexp
83                         push(@ltok, $1); $line = $2;
84                         }
85                 elsif ($line =~ /^\s*(\d+\.\d+\.\d+\.\d+)(.*)$/) {
86                         # IP address
87                         push(@ltok, $1); $line = $2;
88                         }
89                 elsif ($line =~ /^\s*([^{};\(\) \t,\.]+)(.*)$/) {
90                         # meta-character
91                         push(@ltok, $1); $line = $2;
92                         }
93                 else { last; }
94                 }
95         foreach my $t (@ltok) {
96                 push(@tok, $t);
97                 push(@lnum, $lnum);
98                 }
99         $lnum++;
100         }
101
102 # parse tokens into data structures
103 local $i = 0;
104 local $j = 0;
105 while($i < @tok) {
106         local $str = &parse_struct(\@tok, \@lnum, \$i, $j++, $file);
107         if ($str) {
108                 push(@rv, $str);
109                 }
110         }
111 close(CONF);
112 return @rv;
113 }
114
115 # parse_struct(&tokens, &lines, &line_num, index, file)
116 # Reads from the given list of tokens, until one complete structure has been
117 # parsed. If this contains sub-structures, they are parsed too.
118 sub parse_struct
119 {
120 local (%str, $i, $j, $t, @vals, $str);
121 $i = ${$_[2]};
122 return undef if ($_[0]->[$i] eq ")");   # end of a parent expression
123 &error("Bad directive ",$_[0]->[$i]," at ",$_[1]->[$i])
124         if ($_[0]->[$i] !~ /^[a-z0-9_\-]+$/i);
125 $str{'name'} = lc($_[0]->[$i]);
126 $str{'line'} = $_[1]->[$i];
127 $str{'index'} = $_[3];
128 $str{'file'} = $_[4];
129 $i++;
130
131 if ($_[0]->[$i] eq "(") {
132         # A directive like: use_dns (no);
133         # or file("/dev/console" owner(root));
134         # Read the first value, and then sub-directives
135         $i++;   # skip (
136         local @vals;
137         if ($_[0]->[$i] ne ")" && $_[0]->[$i+1] ne "(") {
138                 push(@vals, $_[0]->[$i++]);
139                 }
140
141         # Parse extra , or .. separated values after (
142         local $cont = 0;
143         while(1) {
144                 if ($_[0]->[$i] eq ",") {
145                         push(@vals, $_[0]->[$i++]);
146                         $cont = 1;
147                         }
148                 elsif ($_[0]->[$i] eq "." && $_[0]->[$i+1] eq ".") {
149                         push(@vals, "..");
150                         if ($_[0]->[$i+2] eq ".") {
151                                 $i++;   # Three dots!
152                                 }
153                         $i += 2;
154                         $cont = 1;
155                         }
156                 elsif ($cont) {
157                         push(@vals, $_[0]->[$i++]);
158                         $cont = 0;
159                         }
160                 else {
161                         last;
162                         }
163                 }
164         $str{'value'} = $vals[0];
165         $str{'values'} = \@vals;
166         local (@mems, $j);
167         $j = 0;
168         while($_[0]->[$i] ne ")") {
169                 if (!defined($_[0]->[$i])) { ${$_[2]} = $i; return undef; }
170                 local $str = &parse_struct($_[0], $_[1], \$i, $j++, $_[4]);
171                 push(@mems, $str);
172                 $i--;   # sub-directives don't have a ; at the end
173                 }
174         $str{'type'} = 0;
175         $str{'members'} = \@mems;
176         $i++;           # skip the )
177         $i++;           # skip the ;
178         }
179 else {
180         # A directive with children, like:  foo bar { smeg(spod); };
181         # These may also form a boolean expression, like :
182         #   level(info) or level(debug);
183         # Or even :
184         #   (level(info) or level(debug)) and facility(local7);
185         while($_[0]->[$i] ne "{") {
186                 # Parse stuff before {
187                 push(@vals, $_[0]->[$i++]);
188                 }
189         $str{'values'} = \@vals;
190         $str{'value'} = $vals[0];
191         $i++;   # skip the {
192
193         # Parse the sub-structures
194         local(@mems, $j);
195         $str{'type'} = 1;
196         $j = 0;
197         while($_[0]->[$i] ne "}") {
198                 if (!defined($_[0]->[$i])) { ${$_[2]} = $i; return undef; }
199                 if ($_[0]->[$i] eq "(" || $_[0]->[$i] eq ")") {
200                         # Start of a sub-expression
201                         push(@mems, $_[0]->[$i++]);
202                         }
203                 elsif ($_[0]->[$i] eq "and" || $_[0]->[$i] eq "or" ||
204                        $_[0]->[$i] eq "not") {
205                         # A separator between directives
206                         push(@mems, $_[0]->[$i++]);
207                         }
208                 elsif ($_[0]->[$i] eq ";") {
209                         # Left-over ; , in an expression like level(foo));
210                         $i++;
211                         }
212                 else {
213                         # An actual directive
214                         local $str = &parse_struct($_[0], $_[1], \$i, $j++, $_[4]);
215                         push(@mems, $str);
216                         if ($_[0]->[$i-1] ne ";") {
217                                 # This wasn't the last directive
218                                 $i--;
219                                 $str{'partial'} = 1;
220                                 }
221                         }
222                 }
223         $str{'members'} = \@mems;
224         $i += 2;        # skip trailing } and ;
225         }
226 $str{'eline'} = $_[1]->[$i-1];  # ending line is the line number the trailing
227                                 # ; is on
228 ${$_[2]} = $i;
229 return \%str;
230 }
231
232 # save_directive(&config, &parent, name|&old, &new, no-write)
233 # Updates, creates or deletes a directive in the syslog-ng config
234 sub save_directive
235 {
236 local ($conf, $parent, $name, $value, $nowrite) = @_;
237 local $x;
238 local $new = !$value ? undef : ref($value) ? $value :
239                 { 'name' => $name,
240                   'values' => [ $value ],
241                   'type' => 0 };
242
243 # Read the config file and work out the lines used
244 local $lref;
245 $lref = &read_file_lines($config{'syslogng_conf'}) if (!$nowrite);
246 local ($mems, $memseline);
247 if ($parent) {
248         $mems = $parent->{'members'};
249         $memseline = $parent->{'eline'};
250         }
251 else {
252         $mems = $conf;
253         $memseline = 0;
254         foreach my $c (@$conf) {
255                 $memseline = $c->{'eline'} if ($c->{'eline'} > $memseline);
256                 }
257         }
258 local $old = !$name ? undef : ref($name) ? $name : scalar(&find($name, $mems));
259 local ($idx, $oldlen, $newlen, @lines);
260 if ($old) {
261         $idx = &indexof($old, @$mems);
262         $idx >= 0 || &error("Failed to find $old in array of ",scalar(@$mems));
263         $oldlen = $old->{'eline'} - $old->{'line'} + 1;
264         }
265 if ($new) {
266         @lines = &directive_lines($new);
267         $newlen = scalar(@lines);
268         }
269
270 if ($old && $new) {
271         # Update the directive
272         $new->{'line'} = $old->{'line'};
273         $new->{'eline'} = $new->{'line'}+$newlen-1;
274         if ($new != $old) {
275                 # Replace in config
276                 local $idx = &indexof($old, @$mems);
277                 $mems->[$idx] = $new;
278                 }
279         if (!$nowrite) {
280                 # Update it in the file
281                 &renumber($conf, $new->{'line'}, $newlen - $oldlen);
282                 splice(@$lref, $old->{'line'}, $oldlen, @lines);
283                 }
284         $mems[$idx] = $new;
285         }
286 elsif ($old && !$new) {
287         # Remove the directive
288         splice(@$mems, $idx, 1);
289         if (!$nowrite) {
290                 # Remove from the file
291                 &renumber($conf, $old->{'line'}, -$oldlen);
292                 splice(@$lref, $old->{'line'}, $oldlen);
293                 }
294         }
295 elsif (!$old && $new) {
296         # Add the directive
297         $new->{'line'} = $memseline+1;
298         $new->{'eline'} = $memseline+$newlen;
299         if (!$nowrite) {
300                 # Insert into the file
301                 &renumber($conf, $new->{'line'}, $newlen);
302                 splice(@$lref, $new->{'line'}, 0, @lines);
303                 }
304         push(@$mems, $new);
305         }
306 &flush_file_lines($config{'syslogng_conf'}) if (!$nowrite);
307 }
308
309 # save_multiple_directives(&conf, &parent, &oldlist, &newlist, no-write)
310 # A convenience function to update multiple directives at once
311 sub save_multiple_directives
312 {
313 local ($conf, $parent, $oldlist, $newlist, $nowrite) = @_;
314 for(my $i=0; $i<@$oldlist || $i<@$newlist; $i++) {
315         local $what = $oldlist->[$i] || $newlist->[$i];
316         &save_directive($conf, $parent, $oldlist->[$i], $newlist->[$i],
317                         $nowrite);
318         }
319 }
320
321 # renumber(&conf, line, offset)
322 # Changes the line numbers of all directives AFTER the given line
323 sub renumber
324 {
325 local ($conf, $line, $offset) = @_;
326 foreach my $c (@$conf) {
327         $c->{'line'} += $offset if ($c->{'line'} > $line);
328         $c->{'eline'} += $offset if ($c->{'eline'} > $line);
329         &renumber($c->{'members'}, $line, $offset) if ($c->{'members'});
330         }
331 }
332
333 # directive_lines(&dir)
334 # Returns an array of lines used by some directive, which may be a single
335 # value, or have sub-members
336 sub directive_lines
337 {
338 local ($dir) = @_;
339 local @rv;
340 if ($dir->{'type'} == 0) {
341         # A directive like use_dns(no); or file("/dev/console" owner(root));
342         local $line = $dir->{'name'}."(";
343         foreach my $v (@{$dir->{'values'}}) {
344                 $line .= &quoted_value($v)." ";
345                 }
346         $line =~ s/\s+$//;
347         foreach my $m (@{$dir->{'members'}}) {
348                 local ($mline) = &directive_lines($m);
349                 $mline =~ s/;$//;
350                 $line .= " ".$mline;
351                 }
352         $line .= ");";
353         push(@rv, $line);
354         }
355 elsif ($dir->{'type'} == 1) {
356         # A directive with children, like:  foo bar { smeg(spod); };
357         local $line = $dir->{'name'};
358         foreach my $v (@{$dir->{'values'}}) {
359                 $line .= " ".&quoted_value($v);
360                 }
361         $line .= " {";
362         push(@rv, $line);
363         local @w;
364         foreach my $m (@{$dir->{'members'}}) {
365                 if (ref($m)) {
366                         # An actual directive
367                         local @mlines = &directive_lines($m);
368                         push(@w, @mlines);
369                         }
370                 else {
371                         # A separator word
372                         if (@w) {
373                                 # Previous one doesn't need a ;
374                                 $w[$#w] =~ s/\s*;\s*$//;
375                                 }
376                         push(@w, $m);
377                         }
378                 }
379         if ($dir->{'name'} eq 'filter') {
380                 # All one one line
381                 local $line = join(" ", @w);
382                 $line .= ";" if ($line && $line !~ /\s*;\s*$/);
383                 push(@rv, "  ".$line);
384                 }
385         else {
386                 # Each directive is on its own line
387                 push(@rv, map { "  ".$_ } @w);
388                 }
389         push(@rv, "  };");
390         }
391 return @rv;
392 }
393
394 # quoted_value(string)
395 # Returns some string with quotes around it, if needed
396 sub quoted_value
397 {
398 local ($str) = @_;
399 return $str =~ /^[a-z\_][a-z0-9\_]*$/i ? $str :
400        $str =~ /^\d+\.\d+\.\d+\.\d+$/ ? $str :
401        $str =~ /^[0-9\[\]\-]+\.[0-9\[\]\-]+\.[0-9\[\]\-]+\.[0-9\[\]\-]+$/ ? $str :
402        $str eq "," || $str eq ".." ? $str :
403        $str =~ /^\d+$/ ? $str :
404        $str =~ /\"/ ? "'$str'" : "\"$str\"";
405 }
406
407 # find(name, &array)
408 sub find
409 {
410 local($c, @rv);
411 foreach $c (@{$_[1]}) {
412         if ($c->{'name'} eq $_[0]) {
413                 push(@rv, $c);
414                 }
415         }
416 return @rv ? wantarray ? @rv : $rv[0]
417            : wantarray ? () : undef;
418 }
419
420 # find_value(name, &array)
421 sub find_value
422 {
423 local(@v);
424 @v = &find($_[0], $_[1]);
425 if (!@v) { return undef; }
426 elsif (wantarray) { return map { $_->{'value'} } @v; }
427 else { return $v[0]->{'value'}; }
428 }
429
430 sub is_syslog_ng_running
431 {
432 if ($config{'pid_file'}) {
433         return &check_pid_file($config{'pid_file'});
434         }
435 else {
436         return &find_byname("syslog-ng");
437         }
438 }
439
440 # nice_destination_type(&dest)
441 # Returns a human-readable destination type
442 sub nice_destination_type
443 {
444 local ($d) = @_;
445 local $file = &find_value("file", $d->{'members'});
446 local $usertty = &find_value("usertty", $d->{'members'});
447 local $program = &find_value("program", $d->{'members'});
448 local $pipe = &find_value("pipe", $d->{'members'});
449 local $udp = &find_value("udp", $d->{'members'});
450 local $tcp = &find_value("tcp", $d->{'members'});
451 local $dgram = &find_value("unix-dgram", $d->{'members'});
452 local $stream = &find_value("unix-stream", $d->{'members'});
453 return $file ? ($text{'destinations_typef'}, 0) :
454        $usertty ? ($text{'destinations_typeu'}, 1) :
455        $program ? ($text{'destinations_typep'}, 2) :
456        $pipe ? ($text{'destinations_typei'}, 3) :
457        $udp ? ($text{'destinations_typed'}, 4) :
458        $tcp ? ($text{'destinations_typet'}, 5) :
459        $dgram ? ($text{'destinations_typeg'}, 6) :
460        $stream ? ($text{'destinations_types'}, 7) : (undef, -1);
461 }
462
463 # nice_destination_file(&dest)
464 # Returns a human-readable destination filename / hostname / etc
465 sub nice_destination_file
466 {
467 local ($d) = @_;
468 local $file = &find_value("file", $d->{'members'});
469 local $usertty = &find_value("usertty", $d->{'members'});
470 local $program = &find_value("program", $d->{'members'});
471 local $pipe = &find_value("pipe", $d->{'members'});
472 local $udp = &find_value("udp", $d->{'members'});
473 local $tcp = &find_value("tcp", $d->{'members'});
474 local $dgram = &find_value("unix-dgram", $d->{'members'});
475 local $stream = &find_value("unix-stream", $d->{'members'});
476 return $file ? "<tt>$file</tt>" :
477        $program ? "<tt>$program</tt>" :
478        $pipe ? "<tt>$pipe</tt>" :
479        $tcp ? &text('destinations_host', "<tt>$tcp</tt>") :
480        $udp ? &text('destinations_host', "<tt>$udp</tt>") :
481        $dgram ? "<tt>$dgram</tt>" :
482        $stream ? "<tt>$stream</tt>" :
483        $usertty eq "*" ? $text{'destinations_allusers'} :
484        $usertty ? &text('destinations_users', "<tt>$usertty</tt>") :
485                   undef;
486 }
487
488 sub nice_source_desc
489 {
490 local ($source) = @_;
491 local @rv;
492 local $internal = &find("internal", $source->{'members'});
493 if ($internal) {
494         push(@rv, $text{'sources_typei'});
495         }
496 foreach my $t ("unix-stream", "unix-dgram") {
497         local $unix = &find($t, $source->{'members'});
498         local $msg = $t eq "unix-stream" ? 'sources_types' : 'sources_typed';
499         if ($unix) {
500                 push(@rv, $text{$msg}." <tt>$unix->{'value'}</tt>");
501                 }
502         }
503 foreach my $t ('tcp', 'udp') {
504         local $net = &find($t, $source->{'members'});
505         local $msg = $t eq "tcp" ? 'sources_typet' : 'sources_typeu';
506         if ($net) {
507                 push(@rv, $text{$msg});
508                 }
509         }
510 local $file = &find("file", $source->{'members'});
511 if ($file) {
512         push(@rv, $text{'sources_typef'}." <tt>$file->{'value'}</tt>");
513         }
514 local $pipe = &find("pipe", $source->{'members'});
515 if ($pipe) {
516         push(@rv, $text{'sources_typep'}." <tt>$pipe->{'value'}</tt>");
517         }
518 local $sun_streams = &find("sun-streams", $source->{'members'});
519 if ($sun_streams) {
520         push(@rv, $text{'sources_typen'}." <tt>$sun_streams->{'value'}</tt>");
521         }
522 return join(", ", @rv);
523 }
524
525 # check_dependencies(type, name)
526 # Returns a list of log objects that use some named source, destination or
527 # filter.
528 sub check_dependencies
529 {
530 local ($type, $name) = @_;
531 local $conf = &get_config();
532 local @logs = &find("log", $conf);
533 local @rv;
534 foreach my $l (@logs) {
535         local @deps = &find($type, $l->{'members'});
536         foreach my $d (@deps) {
537                 if ($d->{'value'} eq $name) {
538                         push(@rv, $l);
539                         last;
540                         }
541                 }
542         }
543 return @rv;
544 }
545
546 # rename_dependencies(type, old, new)
547 # Updates any log objects that use the old named type to use the new
548 sub rename_dependencies
549 {
550 local ($type, $oldname, $newname) = @_;
551 #return if ($oldname eq $newname);
552 local $conf = &get_config();
553 local @logs = &find("log", $conf);
554 local @rv;
555 foreach my $l (@logs) {
556         local @deps = &find($type, $l->{'members'});
557         local $changed = 0;
558         foreach my $d (@deps) {
559                 if ($d->{'value'} eq $oldname) {
560                         $d->{'values'} = [ $newname ];
561                         #&save_directive($conf, $l, $d, $d, 1);
562                         $changed = 1;
563                         }
564                 }
565         if ($changed) {
566                 &save_directive($conf, undef, $l, $l, 0);
567                 }
568         }
569 }
570
571 # all_log_files(file)
572 # Given a filename, returns all rotated versions, ordered by oldest first
573 sub all_log_files
574 {
575 $_[0] =~ /^(.*)\/([^\/]+)$/;
576 local $dir = $1;
577 local $base = $2;
578 local ($f, @rv);
579 opendir(DIR, &translate_filename($dir));
580 foreach $f (readdir(DIR)) {
581         local $trans = &translate_filename("$dir/$f");
582         if ($f =~ /^\Q$base\E/ && -f $trans) {
583                 push(@rv, "$dir/$f");
584                 $mtime{"$dir/$f"} = [ stat($trans) ];
585                 }
586         }
587 closedir(DIR);
588 return sort { $mtime{$a}->[9] <=> $mtime{$b}->[9] } @rv;
589 }
590
591 # catter_command(file)
592 # Given a file that may be compressed, returns the command to output it in
593 # plain text, or undef if impossible
594 sub catter_command
595 {
596 local ($l) = @_;
597 local $q = quotemeta($l);
598 if ($l =~ /\.gz$/i) {
599         return &has_command("gunzip") ? "gunzip -c $q" : undef;
600         }
601 elsif ($l =~ /\.Z$/i) {
602         return &has_command("uncompress") ? "uncompress -c $q" : undef;
603         }
604 elsif ($l =~ /\.bz2$/i) {
605         return &has_command("bunzip2") ? "bunzip2 -c $q" : undef;
606         }
607 else {
608         return "cat $q";
609         }
610 }
611
612 # nice_filter_desc(&filter)
613 # Returns a human-readable description for a filter
614 sub nice_filter_desc
615 {
616 local ($filter) = @_;
617 local @rv;
618 foreach my $m (@{$filter->{'members'}}) {
619           if (ref($m)) {
620                   # A condition like level, facility or match
621                   local @v = @{$m->{'values'}};
622                   if ($m->{'name'} eq 'level') {
623                           if ($v[1] eq "..") {
624                                   push(@rv, &text('filters_priorities',
625                                                   $v[0], $v[2]));
626                                   }
627                           elsif (@v > 1) {
628                                   @v = grep { $_ ne "," } @v;
629                                   push(@rv, &text('filters_priorities2',
630                                                   scalar(@v)));
631                                   }
632                           else {
633                                   push(@rv, &text('filters_priority', $v[0]));
634                                   }
635                           }
636                   elsif ($m->{'name'} eq 'facility') {
637                           if (@v > 1) {
638                                   @v = grep { $_ ne "," } @v;
639                                   push(@rv, &text('filters_facilities',
640                                                   scalar(@v)));
641                                   }
642                           else {
643                                   push(@rv, &text('filters_facility', $v[0]));
644                                   }
645                           }
646                   elsif ($m->{'name'} eq 'match') {
647                           push(@rv, &text('filters_match', $v[0]));
648                           }
649                   elsif ($m->{'name'} eq 'program') {
650                           push(@rv, &text('filters_program', $v[0]));
651                           }
652                   elsif ($m->{'name'} eq 'host') {
653                           push(@rv, &text('filters_host', $v[0]));
654                           }
655                   elsif ($m->{'name'} eq 'netmask') {
656                           push(@rv, &text('filters_netmask', $v[0]));
657                           }
658                   else {
659                           # Unknown type??
660                           push(@rv, $m->{'name'}."(".join(",", @v).")");
661                           }
662                   }
663           else {
664                   # An and/or keyword
665                   push(@rv, $m);
666                   }
667           }
668 if (@rv > 7) {
669           @rv = ( @rv[0..7], "..." );
670           }
671 return join(" ", @rv);
672 }
673
674 # list_priorities()
675 # Returns a list of all priorities
676 sub list_priorities
677 {
678 return ( 'debug', 'info', 'notice', 'warning',
679          'err', 'crit', 'alert', 'emerg' );
680 }
681
682 sub list_facilities
683 {
684 return ('auth', 'authpriv', 'cron', 'daemon', 'kern', 'lpr', 'mail', 'mark', 'news', 'syslog', 'user', 'uucp', 'local0', 'local1', 'local2', 'local3', 'local4', 'local5', 'local6', 'local7');
685 }
686
687 # apply_configuration()
688 # Activate the current config with a HUP signal
689 sub apply_configuration
690 {
691 local $pid = &check_pid_file($config{'pid_file'});
692 if ($pid) {
693         &kill_logged('HUP', $pid);
694         return undef;
695         }
696 else {
697         return $text{'apply_egone'};
698         }
699 }
700
701 # signal_syslog()
702 # Tell the syslog server to re-open it's log files
703 sub signal_syslog
704 {
705 &apply_configuration();
706 }
707
708 # start_syslog_ng()
709 # Attempts to start the syslog server process, and returns undef on success
710 # or an error message on failure
711 sub start_syslog_ng
712 {
713 local $cmd = $config{'start_cmd'} ||
714              "$config{'syslogng_cmd'} -f ".quotemeta($config{'syslogng_conf'}).
715              " -p ".quotemeta($config{'pid_file'});
716 local $out = &backquote_logged("$cmd 2>&1 </dev/null");
717 return $? ? "<pre>$out</pre>" : undef;
718 }
719
720 # stop_syslog_ng()
721 # Attempts to stop the syslog server process, and returns undef on success
722 # or an error message on failure
723 sub stop_syslog_ng
724 {
725 if ($config{'stop_cmd'}) {
726         local $out = &backquote_logged("$config{'stop_cmd'} 2>&1 </dev/null");
727         return $? ? "<pre>$out</pre>" : undef;
728         }
729 else {
730         local $pid = &check_pid_file($config{'pid_file'});
731         if ($pid) {
732                 &kill_logged('TERM', $pid);
733                 return undef;
734                 }
735         else {
736                 return $text{'apply_egone'};
737                 }
738         }
739 }
740
741 # get_other_module_logs([module])
742 # Returns a list of logs supplied by other modules
743 sub get_other_module_logs
744 {
745 local ($mod) = @_;
746 local @rv;
747 local %done;
748 foreach my $minfo (&get_all_module_infos()) {
749         next if ($mod && $minfo->{'dir'} ne $mod);
750         next if (!$minfo->{'syslog'});
751         next if (!&foreign_installed($minfo->{'dir'}));
752         local $mdir = &module_root_directory($minfo->{'dir'});
753         next if (!-r "$mdir/syslog_logs.pl");
754         &foreign_require($minfo->{'dir'}, "syslog_logs.pl");
755         local $j = 0;
756         foreach my $l (&foreign_call($minfo->{'dir'}, "syslog_getlogs")) {
757                 local $fc = $l->{'file'} || $l->{'cmd'};
758                 next if ($done{$fc}++);
759                 $l->{'minfo'} = $minfo;
760                 $l->{'mod'} = $minfo->{'dir'};
761                 $l->{'mindex'} = $j++;
762                 push(@rv, $l);
763                 }
764         }
765 @rv = sort { $a->{'minfo'}->{'desc'} cmp $b->{'minfo'}->{'desc'} } @rv;
766 local $i = 0;
767 foreach my $l (@rv) {
768         $l->{'index'} = $i++;
769         }
770 return @rv;
771 }
772
773 1;
774