home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Updates / Perl / Non-RPC / !Perl / lib / zip / Sys / Syslog.pm < prev   
Text File  |  1998-07-30  |  8KB  |  277 lines

  1. package Sys::Syslog;
  2. require 5.000;
  3. require Exporter;
  4. use Carp;
  5.  
  6. @ISA = qw(Exporter);
  7. @EXPORT = qw(openlog closelog setlogmask syslog);
  8. @EXPORT_OK = qw(setlogsock);
  9.  
  10. use Socket;
  11. use Sys::Hostname;
  12.  
  13. # adapted from syslog.pl
  14. #
  15. # Tom Christiansen <tchrist@convex.com>
  16. # modified to use sockets by Larry Wall <lwall@jpl-devvax.jpl.nasa.gov>
  17. # NOTE: openlog now takes three arguments, just like openlog(3)
  18. # Modified to add UNIX domain sockets by Sean Robinson <robinson_s@sc.maricopa.edu>
  19. #  with support from Tim Bunce <Tim.Bunce@ig.co.uk> and the perl5-porters mailing list
  20.  
  21. # Todo: enable connect to try all three types before failing (auto setlogsock)?
  22.  
  23. =head1 NAME
  24.  
  25. Sys::Syslog, openlog, closelog, setlogmask, syslog - Perl interface to the UNIX syslog(3) calls
  26.  
  27. =head1 SYNOPSIS
  28.  
  29.     use Sys::Syslog;                          # all except setlogsock, or:
  30.     use Sys::Syslog qw(:DEFAULT setlogsock);  # default set, plus setlogsock
  31.  
  32.     setlogsock $sock_type;
  33.     openlog $ident, $logopt, $facility;
  34.     syslog $priority, $format, @args;
  35.     $oldmask = setlogmask $mask_priority;
  36.     closelog;
  37.  
  38. =head1 DESCRIPTION
  39.  
  40. Sys::Syslog is an interface to the UNIX C<syslog(3)> program.
  41. Call C<syslog()> with a string priority and a list of C<printf()> args
  42. just like C<syslog(3)>.
  43.  
  44. Syslog provides the functions:
  45.  
  46. =over
  47.  
  48. =item openlog $ident, $logopt, $facility
  49.  
  50. I<$ident> is prepended to every message.
  51. I<$logopt> contains zero or more of the words I<pid>, I<ndelay>, I<cons>, I<nowait>.
  52. I<$facility> specifies the part of the system
  53.  
  54. =item syslog $priority, $format, @args
  55.  
  56. If I<$priority> permits, logs I<($format, @args)>
  57. printed as by C<printf(3V)>, with the addition that I<%m>
  58. is replaced with C<"$!"> (the latest error message).
  59.  
  60. =item setlogmask $mask_priority
  61.  
  62. Sets log mask I<$mask_priority> and returns the old mask.
  63.  
  64. =item setlogsock $sock_type (added in 5.004_02)
  65.  
  66. Sets the socket type to be used for the next call to
  67. C<openlog()> or C<syslog()> and returns TRUE on success,
  68. undef on failure.
  69.  
  70. A value of 'unix' will connect to the UNIX domain socket returned by
  71. C<_PATH_LOG> in F<syslog.ph>.  A value of 'inet' will connect to an
  72. INET socket returned by getservbyname().  Any other value croaks.
  73.  
  74. The default is for the INET socket to be used.
  75.  
  76. =item closelog
  77.  
  78. Closes the log file.
  79.  
  80. =back
  81.  
  82. Note that C<openlog> now takes three arguments, just like C<openlog(3)>.
  83.  
  84. =head1 EXAMPLES
  85.  
  86.     openlog($program, 'cons,pid', 'user');
  87.     syslog('info', 'this is another test');
  88.     syslog('mail|warning', 'this is a better test: %d', time);
  89.     closelog();
  90.  
  91.     syslog('debug', 'this is the last test');
  92.  
  93.     setlogsock('unix');
  94.     openlog("$program $$", 'ndelay', 'user');
  95.     syslog('notice', 'fooprogram: this is really done');
  96.  
  97.     setlogsock('inet');
  98.     $! = 55;
  99.     syslog('info', 'problem was %m'); # %m == $! in syslog(3)
  100.  
  101. =head1 DEPENDENCIES
  102.  
  103. B<Sys::Syslog> needs F<syslog.ph>, which can be created with C<h2ph>.
  104.  
  105. =head1 SEE ALSO
  106.  
  107. L<syslog(3)>
  108.  
  109. =head1 AUTHOR
  110.  
  111. Tom Christiansen E<lt>F<tchrist@perl.com>E<gt> and Larry Wall E<lt>F<larry@wall.org>E<gt>.
  112. UNIX domain sockets added by Sean Robinson E<lt>F<robinson_s@sc.maricopa.edu>E<gt>
  113. with support from Tim Bunce <Tim.Bunce@ig.co.uk> and the perl5-porters mailing list.
  114.  
  115. =cut
  116.  
  117. require 'syslog.ph';
  118.  
  119. $maskpri = &LOG_UPTO(&LOG_DEBUG);
  120.  
  121. sub openlog {
  122.     ($ident, $logopt, $facility) = @_;  # package vars
  123.     $lo_pid = $logopt =~ /\bpid\b/;
  124.     $lo_ndelay = $logopt =~ /\bndelay\b/;
  125.     $lo_cons = $logopt =~ /\bcons\b/;
  126.     $lo_nowait = $logopt =~ /\bnowait\b/;
  127.     &connect if $lo_ndelay;
  128.  
  129. sub closelog {
  130.     $facility = $ident = '';
  131.     &disconnect;
  132.  
  133. sub setlogmask {
  134.     local($oldmask) = $maskpri;
  135.     $maskpri = shift;
  136.     $oldmask;
  137. }
  138.  
  139. sub setlogsock {
  140.     local($setsock) = shift;
  141.     &disconnect if $connected;
  142.     if (lc($setsock) eq 'unix') {
  143.         if (defined &_PATH_LOG) {
  144.             $sock_type = 1;
  145.         } else {
  146.             return undef;
  147.         }
  148.     } elsif (lc($setsock) eq 'inet') {
  149.         if (getservbyname('syslog','udp')) {
  150.             undef($sock_type);
  151.         } else {
  152.             return undef;
  153.         }
  154.     } else {
  155.         croak "Invalid argument passed to setlogsock; must be 'unix' or 'inet'";
  156.     }
  157.     return 1;
  158. }
  159.  
  160. sub syslog {
  161.     local($priority) = shift;
  162.     local($mask) = shift;
  163.     local($message, $whoami);
  164.     local(@words, $num, $numpri, $numfac, $sum);
  165.     local($facility) = $facility;    # may need to change temporarily.
  166.  
  167.     croak "syslog: expected both priority and mask" unless $mask && $priority;
  168.  
  169.     @words = split(/\W+/, $priority, 2);# Allow "level" or "level|facility".
  170.     undef $numpri;
  171.     undef $numfac;
  172.     foreach (@words) {
  173.     $num = &xlate($_);        # Translate word to number.
  174.     if (/^kern$/ || $num < 0) {
  175.         croak "syslog: invalid level/facility: $_";
  176.     }
  177.     elsif ($num <= &LOG_PRIMASK) {
  178.         croak "syslog: too many levels given: $_" if defined($numpri);
  179.         $numpri = $num;
  180.         return 0 unless &LOG_MASK($numpri) & $maskpri;
  181.     }
  182.     else {
  183.         croak "syslog: too many facilities given: $_" if defined($numfac);
  184.         $facility = $_;
  185.         $numfac = $num;
  186.     }
  187.     }
  188.  
  189.     croak "syslog: level must be given" unless defined($numpri);
  190.  
  191.     if (!defined($numfac)) {    # Facility not specified in this call.
  192.     $facility = 'user' unless $facility;
  193.     $numfac = &xlate($facility);
  194.     }
  195.  
  196.     &connect unless $connected;
  197.  
  198.     $whoami = $ident;
  199.  
  200.     if (!$whoami && $mask =~ /^(\S.*?):\s?(.*)/) {
  201.     $whoami = $1;
  202.     $mask = $2;
  203.     } 
  204.  
  205.     unless ($whoami) {
  206.     ($whoami = getlogin) ||
  207.         ($whoami = getpwuid($<)) ||
  208.         ($whoami = 'syslog');
  209.     }
  210.  
  211.     $whoami .= "[$$]" if $lo_pid;
  212.  
  213.     $mask =~ s/%m/$!/g;
  214.     $mask .= "\n" unless $mask =~ /\n$/;
  215.     $message = sprintf ($mask, @_);
  216.  
  217.     $sum = $numpri + $numfac;
  218.     unless (send(SYSLOG,"<$sum>$whoami: $message\0",0)) {
  219.     if ($lo_cons) {
  220.         if ($pid = fork) {
  221.         unless ($lo_nowait) {
  222.             $died = waitpid($pid, 0);
  223.         }
  224.         }
  225.         else {
  226.         open(CONS,">/dev/console");
  227.         print CONS "<$facility.$priority>$whoami: $message\r";
  228.         exit if defined $pid;        # if fork failed, we're parent
  229.         close CONS;
  230.         }
  231.     }
  232.     }
  233. }
  234.  
  235. sub xlate {
  236.     local($name) = @_;
  237.     $name = uc $name;
  238.     $name = "LOG_$name" unless $name =~ /^LOG_/;
  239.     $name = "Sys::Syslog::$name";
  240.     defined &$name ? &$name : -1;
  241. }
  242.  
  243. sub connect {
  244.     unless ($host) {
  245.     require Sys::Hostname;
  246.     my($host_uniq) = Sys::Hostname::hostname();
  247.     ($host) = $host_uniq =~ /([A-Za-z0-9_.-]+)/; # allow FQDN (inc _)
  248.     }
  249.     unless ( $sock_type ) {
  250.         my $udp = getprotobyname('udp');
  251.         my $syslog = getservbyname('syslog','udp');
  252.         my $this = sockaddr_in($syslog, INADDR_ANY);
  253.         my $that = sockaddr_in($syslog, inet_aton($host) || croak "Can't lookup $host");
  254.         socket(SYSLOG,AF_INET,SOCK_DGRAM,$udp)           || croak "socket: $!";
  255.         connect(SYSLOG,$that)                            || croak "connect: $!";
  256.     } else {
  257.         my $syslog = &_PATH_LOG                          || croak "_PATH_LOG not found in syslog.ph";
  258.         my $that = sockaddr_un($syslog)                  || croak "Can't locate $syslog";
  259.         socket(SYSLOG,AF_UNIX,SOCK_STREAM,0)             || croak "socket: $!";
  260.         if (!connect(SYSLOG,$that)) {
  261.             socket(SYSLOG,AF_UNIX,SOCK_DGRAM,0)          || croak "socket: $!";
  262.             connect(SYSLOG,$that) || croak "connect: $! (SOCK_DGRAM after trying SOCK_STREAM)";
  263.         }
  264.     }
  265.     local($old) = select(SYSLOG); $| = 1; select($old);
  266.     $connected = 1;
  267. }
  268.  
  269. sub disconnect {
  270.     close SYSLOG;
  271.     $connected = 0;
  272. }
  273.  
  274. 1;
  275.