home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl560.zip / ext / Sys / Syslog / Syslog.pm < prev    next >
Text File  |  2000-03-14  |  8KB  |  295 lines

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