Ruby  2.0.0p247(2013-06-27revision41674)
ext/syslog/syslog.c
Go to the documentation of this file.
00001 /*
00002  * UNIX Syslog extension for Ruby
00003  * Amos Gouaux, University of Texas at Dallas
00004  * <amos+ruby@utdallas.edu>
00005  * Documented by mathew <meta@pobox.com>
00006  *
00007  * $RoughId: syslog.c,v 1.21 2002/02/25 12:21:17 knu Exp $
00008  * $Id: syslog.c 35739 2012-05-21 07:18:49Z knu $
00009  */
00010 
00011 #include "ruby/ruby.h"
00012 #include "ruby/util.h"
00013 #include <syslog.h>
00014 
00015 /* Syslog class */
00016 static VALUE mSyslog;
00017 /*
00018  * Module holding all Syslog constants.  See Syslog::log and
00019  * Syslog::open for constant descriptions.
00020  */
00021 static VALUE mSyslogConstants;
00022 /* Module holding Syslog option constants */
00023 static VALUE mSyslogOption;
00024 /* Module holding Syslog facility constants */
00025 static VALUE mSyslogFacility;
00026 /* Module holding Syslog level constants */
00027 static VALUE mSyslogLevel;
00028 /* Module holding Syslog utility macros */
00029 static VALUE mSyslogMacros;
00030 
00031 static const char *syslog_ident = NULL;
00032 static int syslog_options = -1, syslog_facility = -1, syslog_mask = -1;
00033 static int syslog_opened = 0;
00034 
00035 /* Package helper routines */
00036 static void syslog_write(int pri, int argc, VALUE *argv)
00037 {
00038     VALUE str;
00039 
00040     rb_secure(4);
00041     if (argc < 1) {
00042         rb_raise(rb_eArgError, "no log message supplied");
00043     }
00044 
00045     if (!syslog_opened) {
00046         rb_raise(rb_eRuntimeError, "must open syslog before write");
00047     }
00048 
00049     str = rb_f_sprintf(argc, argv);
00050 
00051     syslog(pri, "%s", RSTRING_PTR(str));
00052 }
00053 
00054 /* Closes the syslog facility.
00055  * Raises a runtime exception if it is not open.
00056  */
00057 static VALUE mSyslog_close(VALUE self)
00058 {
00059     rb_secure(4);
00060     if (!syslog_opened) {
00061         rb_raise(rb_eRuntimeError, "syslog not opened");
00062     }
00063 
00064     closelog();
00065 
00066     xfree((void *)syslog_ident);
00067     syslog_ident = NULL;
00068     syslog_options = syslog_facility = syslog_mask = -1;
00069     syslog_opened = 0;
00070 
00071     return Qnil;
00072 }
00073 
00074 /* call-seq:
00075  *   open(ident, options, facility) => syslog
00076  *
00077  * :yields: syslog
00078  *
00079  * Open the syslog facility.
00080  * Raises a runtime exception if it is already open.
00081  *
00082  * Can be called with or without a code block. If called with a block, the
00083  * Syslog object created is passed to the block.
00084  *
00085  * If the syslog is already open, raises a RuntimeError.
00086  *
00087  * +ident+ is a String which identifies the calling program.
00088  *
00089  * +options+ is the logical OR of any of the following:
00090  *
00091  * LOG_CONS:: If there is an error while sending to the system logger,
00092  *            write directly to the console instead.
00093  *
00094  * LOG_NDELAY:: Open the connection now, rather than waiting for the first
00095  *              message to be written.
00096  *
00097  * LOG_NOWAIT:: Don't wait for any child processes created while logging
00098  *              messages. (Has no effect on Linux.)
00099  *
00100  * LOG_ODELAY:: Opposite of LOG_NDELAY; wait until a message is sent before
00101  *              opening the connection. (This is the default.)
00102  *
00103  * LOG_PERROR:: Print the message to stderr as well as sending it to syslog.
00104  *              (Not in POSIX.1-2001.)
00105  *
00106  * LOG_PID:: Include the current process ID with each message.
00107  *
00108  * +facility+ describes the type of program opening the syslog, and is
00109  * the logical OR of any of the following which are defined for the host OS:
00110  *
00111  * LOG_AUTH:: Security or authorization. Deprecated, use LOG_AUTHPRIV
00112  *            instead.
00113  *
00114  * LOG_AUTHPRIV:: Security or authorization messages which should be kept
00115  *                private.
00116  *
00117  * LOG_CONSOLE:: System console message.
00118  *
00119  * LOG_CRON:: System task scheduler (cron or at).
00120  *
00121  * LOG_DAEMON:: A system daemon which has no facility value of its own.
00122  *
00123  * LOG_FTP:: An FTP server.
00124  *
00125  * LOG_KERN:: A kernel message (not sendable by user processes, so not of
00126  *            much use to Ruby, but listed here for completeness).
00127  *
00128  * LOG_LPR:: Line printer subsystem.
00129  *
00130  * LOG_MAIL:: Mail delivery or transport subsystem.
00131  *
00132  * LOG_NEWS:: Usenet news system.
00133  *
00134  * LOG_NTP:: Network Time Protocol server.
00135  *
00136  * LOG_SECURITY:: General security message.
00137  *
00138  * LOG_SYSLOG:: Messages generated internally by syslog.
00139  *
00140  * LOG_USER:: Generic user-level message.
00141  *
00142  * LOG_UUCP:: UUCP subsystem.
00143  *
00144  * LOG_LOCAL0 to LOG_LOCAL7:: Locally-defined facilities.
00145  *
00146  * Example:
00147  *
00148  *  Syslog.open("webrick", Syslog::LOG_PID,
00149  *              Syslog::LOG_DAEMON | Syslog::LOG_LOCAL3)
00150  *
00151  */
00152 static VALUE mSyslog_open(int argc, VALUE *argv, VALUE self)
00153 {
00154     VALUE ident, opt, fac;
00155 
00156     if (syslog_opened) {
00157         rb_raise(rb_eRuntimeError, "syslog already open");
00158     }
00159 
00160     rb_scan_args(argc, argv, "03", &ident, &opt, &fac);
00161 
00162     if (NIL_P(ident)) {
00163         ident = rb_gv_get("$0");
00164     }
00165     SafeStringValue(ident);
00166     syslog_ident = strdup(RSTRING_PTR(ident));
00167 
00168     if (NIL_P(opt)) {
00169         syslog_options = LOG_PID | LOG_CONS;
00170     } else {
00171         syslog_options = NUM2INT(opt);
00172     }
00173 
00174     if (NIL_P(fac)) {
00175         syslog_facility = LOG_USER;
00176     } else {
00177         syslog_facility = NUM2INT(fac);
00178     }
00179 
00180     openlog(syslog_ident, syslog_options, syslog_facility);
00181 
00182     syslog_opened = 1;
00183 
00184     setlogmask(syslog_mask = setlogmask(0));
00185 
00186     /* be like File.new.open {...} */
00187     if (rb_block_given_p()) {
00188         rb_ensure(rb_yield, self, mSyslog_close, self);
00189     }
00190 
00191     return self;
00192 }
00193 
00194 /* call-seq:
00195  *   reopen(ident, options, facility) => syslog
00196  *
00197  * :yields: syslog
00198  *
00199  * Closes and then reopens the syslog.
00200  *
00201  * Arguments are the same as for open().
00202  */
00203 static VALUE mSyslog_reopen(int argc, VALUE *argv, VALUE self)
00204 {
00205     mSyslog_close(self);
00206 
00207     return mSyslog_open(argc, argv, self);
00208 }
00209 
00210 /* call-seq:
00211  *   opened?
00212  *
00213  * Returns true if the syslog is open.
00214  */
00215 static VALUE mSyslog_isopen(VALUE self)
00216 {
00217     return syslog_opened ? Qtrue : Qfalse;
00218 }
00219 
00220 /* Returns the identity string used in the last call to open()
00221  */
00222 static VALUE mSyslog_ident(VALUE self)
00223 {
00224     return syslog_opened ? rb_str_new2(syslog_ident) : Qnil;
00225 }
00226 
00227 /* Returns the options bitmask used in the last call to open()
00228  */
00229 static VALUE mSyslog_options(VALUE self)
00230 {
00231     return syslog_opened ? INT2NUM(syslog_options) : Qnil;
00232 }
00233 
00234 /* Returns the facility number used in the last call to open()
00235  */
00236 static VALUE mSyslog_facility(VALUE self)
00237 {
00238     return syslog_opened ? INT2NUM(syslog_facility) : Qnil;
00239 }
00240 
00241 /* Returns the log priority mask in effect. The mask is not reset by opening
00242  * or closing syslog.
00243  */
00244 static VALUE mSyslog_get_mask(VALUE self)
00245 {
00246     return syslog_opened ? INT2NUM(syslog_mask) : Qnil;
00247 }
00248 
00249 /* call-seq:
00250  *   mask=(priority_mask)
00251  *
00252  * Sets the log priority mask. A method LOG_UPTO is defined to make it easier
00253  * to set mask values. Example:
00254  *
00255  *   Syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_ERR)
00256  *
00257  * Alternatively, specific priorities can be selected and added together using
00258  * binary OR. Example:
00259  *
00260  *   Syslog.mask = Syslog::LOG_MASK(Syslog::LOG_ERR) | Syslog::LOG_MASK(Syslog::LOG_CRIT)
00261  *
00262  * The priority mask persists through calls to open() and close().
00263  */
00264 static VALUE mSyslog_set_mask(VALUE self, VALUE mask)
00265 {
00266     rb_secure(4);
00267     if (!syslog_opened) {
00268         rb_raise(rb_eRuntimeError, "must open syslog before setting log mask");
00269     }
00270 
00271     setlogmask(syslog_mask = NUM2INT(mask));
00272 
00273     return mask;
00274 }
00275 
00276 /* call-seq:
00277  *   log(priority, format_string, *format_args)
00278  *
00279  * Log a message with the specified priority. Example:
00280  *
00281  *   Syslog.log(Syslog::LOG_CRIT, "Out of disk space")
00282  *   Syslog.log(Syslog::LOG_CRIT, "User %s logged in", ENV['USER'])
00283  *
00284  * The priority levels, in descending order, are:
00285  *
00286  * LOG_EMERG::   System is unusable
00287  * LOG_ALERT::   Action needs to be taken immediately
00288  * LOG_CRIT::    A critical condition has occurred
00289  * LOG_ERR::     An error occurred
00290  * LOG_WARNING:: Warning of a possible problem
00291  * LOG_NOTICE::  A normal but significant condition occurred
00292  * LOG_INFO::    Informational message
00293  * LOG_DEBUG::   Debugging information
00294  *
00295  * Each priority level also has a shortcut method that logs with it's named priority.
00296  * As an example, the two following statements would produce the same result:
00297  *
00298  *   Syslog.log(Syslog::LOG_ALERT, "Out of memory")
00299  *   Syslog.alert("Out of memory")
00300  *
00301  * Format strings are as for printf/sprintf, except that in addition %m is
00302  * replaced with the error message string that would be returned by
00303  * strerror(errno).
00304  *
00305  */
00306 static VALUE mSyslog_log(int argc, VALUE *argv, VALUE self)
00307 {
00308     VALUE pri;
00309 
00310     if (argc < 2) {
00311         rb_raise(rb_eArgError, "wrong number of arguments (%d for 2+)", argc);
00312     }
00313 
00314     argc--;
00315     pri = *argv++;
00316 
00317     if (!FIXNUM_P(pri)) {
00318       rb_raise(rb_eTypeError, "type mismatch: %s given", rb_class2name(CLASS_OF(pri)));
00319     }
00320 
00321     syslog_write(FIX2INT(pri), argc, argv);
00322 
00323     return self;
00324 }
00325 
00326 /* Returns an inspect() string summarizing the object state.
00327  */
00328 static VALUE mSyslog_inspect(VALUE self)
00329 {
00330     Check_Type(self, T_MODULE);
00331 
00332     if (!syslog_opened)
00333         return rb_sprintf("<#%s: opened=false>", rb_class2name(self));
00334 
00335     return rb_sprintf("<#%s: opened=true, ident=\"%s\", options=%d, facility=%d, mask=%d>",
00336                       rb_class2name(self),
00337                       syslog_ident,
00338                       syslog_options,
00339                       syslog_facility,
00340                       syslog_mask);
00341 }
00342 
00343 /* Returns self, for backward compatibility.
00344  */
00345 static VALUE mSyslog_instance(VALUE self)
00346 {
00347     return self;
00348 }
00349 
00350 #define define_syslog_shortcut_method(pri, name) \
00351 static VALUE mSyslog_##name(int argc, VALUE *argv, VALUE self) \
00352 { \
00353     syslog_write((pri), argc, argv); \
00354 \
00355     return self; \
00356 }
00357 
00358 #ifdef LOG_EMERG
00359 define_syslog_shortcut_method(LOG_EMERG, emerg)
00360 #endif
00361 #ifdef LOG_ALERT
00362 define_syslog_shortcut_method(LOG_ALERT, alert)
00363 #endif
00364 #ifdef LOG_CRIT
00365 define_syslog_shortcut_method(LOG_CRIT, crit)
00366 #endif
00367 #ifdef LOG_ERR
00368 define_syslog_shortcut_method(LOG_ERR, err)
00369 #endif
00370 #ifdef LOG_WARNING
00371 define_syslog_shortcut_method(LOG_WARNING, warning)
00372 #endif
00373 #ifdef LOG_NOTICE
00374 define_syslog_shortcut_method(LOG_NOTICE, notice)
00375 #endif
00376 #ifdef LOG_INFO
00377 define_syslog_shortcut_method(LOG_INFO, info)
00378 #endif
00379 #ifdef LOG_DEBUG
00380 define_syslog_shortcut_method(LOG_DEBUG, debug)
00381 #endif
00382 
00383 /* call-seq:
00384  *   LOG_MASK(priority_level) => priority_mask
00385  *
00386  * Generates a mask bit for a priority level. See #mask=
00387  */
00388 static VALUE mSyslogMacros_LOG_MASK(VALUE mod, VALUE pri)
00389 {
00390     return INT2FIX(LOG_MASK(NUM2INT(pri)));
00391 }
00392 
00393 /* call-seq:
00394  *   LOG_UPTO(priority_level) => priority_mask
00395  *
00396  * Generates a mask value for priority levels at or below the level specified.
00397  * See #mask=
00398  */
00399 static VALUE mSyslogMacros_LOG_UPTO(VALUE mod, VALUE pri)
00400 {
00401     return INT2FIX(LOG_UPTO(NUM2INT(pri)));
00402 }
00403 
00404 static VALUE mSyslogMacros_included(VALUE mod, VALUE target)
00405 {
00406     rb_extend_object(target, mSyslogMacros);
00407     return mod;
00408 }
00409 
00410 /* The syslog package provides a Ruby interface to the POSIX system logging
00411  * facility.
00412  *
00413  * Syslog messages are typically passed to a central logging daemon.
00414  * The daemon may filter them; route them into different files (usually
00415  * found under /var/log); place them in SQL databases; forward
00416  * them to centralized logging servers via TCP or UDP; or even alert the
00417  * system administrator via email, pager or text message.
00418  *
00419  * Unlike application-level logging via Logger or Log4r, syslog is designed
00420  * to allow secure tamper-proof logging.
00421  *
00422  * The syslog protocol is standardized in RFC 5424.
00423  */
00424 void Init_syslog()
00425 {
00426     mSyslog = rb_define_module("Syslog");
00427 
00428     mSyslogConstants    = rb_define_module_under(mSyslog, "Constants");
00429 
00430     mSyslogOption       = rb_define_module_under(mSyslog, "Option");
00431     mSyslogFacility     = rb_define_module_under(mSyslog, "Facility");
00432     mSyslogLevel        = rb_define_module_under(mSyslog, "Level");
00433     mSyslogMacros       = rb_define_module_under(mSyslog, "Macros");
00434 
00435     rb_define_module_function(mSyslog, "open", mSyslog_open, -1);
00436     rb_define_module_function(mSyslog, "reopen", mSyslog_reopen, -1);
00437     rb_define_module_function(mSyslog, "open!", mSyslog_reopen, -1);
00438     rb_define_module_function(mSyslog, "opened?", mSyslog_isopen, 0);
00439 
00440     rb_define_module_function(mSyslog, "ident", mSyslog_ident, 0);
00441     rb_define_module_function(mSyslog, "options", mSyslog_options, 0);
00442     rb_define_module_function(mSyslog, "facility", mSyslog_facility, 0);
00443 
00444     rb_define_module_function(mSyslog, "log", mSyslog_log, -1);
00445     rb_define_module_function(mSyslog, "close", mSyslog_close, 0);
00446     rb_define_module_function(mSyslog, "mask", mSyslog_get_mask, 0);
00447     rb_define_module_function(mSyslog, "mask=", mSyslog_set_mask, 1);
00448 
00449     rb_define_module_function(mSyslog, "inspect", mSyslog_inspect, 0);
00450     rb_define_module_function(mSyslog, "instance", mSyslog_instance, 0);
00451 
00452     /* Syslog options */
00453 
00454 #define rb_define_syslog_option(c) \
00455     rb_define_const(mSyslogOption, #c, INT2NUM(c))
00456 
00457 #ifdef LOG_PID
00458     rb_define_syslog_option(LOG_PID);
00459 #endif
00460 #ifdef LOG_CONS
00461     rb_define_syslog_option(LOG_CONS);
00462 #endif
00463 #ifdef LOG_ODELAY
00464     rb_define_syslog_option(LOG_ODELAY); /* deprecated */
00465 #endif
00466 #ifdef LOG_NDELAY
00467     rb_define_syslog_option(LOG_NDELAY);
00468 #endif
00469 #ifdef LOG_NOWAIT
00470     rb_define_syslog_option(LOG_NOWAIT); /* deprecated */
00471 #endif
00472 #ifdef LOG_PERROR
00473     rb_define_syslog_option(LOG_PERROR);
00474 #endif
00475 
00476     /* Syslog facilities */
00477 
00478 #define rb_define_syslog_facility(c) \
00479     rb_define_const(mSyslogFacility, #c, INT2NUM(c))
00480 
00481 #ifdef LOG_AUTH
00482     rb_define_syslog_facility(LOG_AUTH);
00483 #endif
00484 #ifdef LOG_AUTHPRIV
00485     rb_define_syslog_facility(LOG_AUTHPRIV);
00486 #endif
00487 #ifdef LOG_CONSOLE
00488     rb_define_syslog_facility(LOG_CONSOLE);
00489 #endif
00490 #ifdef LOG_CRON
00491     rb_define_syslog_facility(LOG_CRON);
00492 #endif
00493 #ifdef LOG_DAEMON
00494     rb_define_syslog_facility(LOG_DAEMON);
00495 #endif
00496 #ifdef LOG_FTP
00497     rb_define_syslog_facility(LOG_FTP);
00498 #endif
00499 #ifdef LOG_KERN
00500     rb_define_syslog_facility(LOG_KERN);
00501 #endif
00502 #ifdef LOG_LPR
00503     rb_define_syslog_facility(LOG_LPR);
00504 #endif
00505 #ifdef LOG_MAIL
00506     rb_define_syslog_facility(LOG_MAIL);
00507 #endif
00508 #ifdef LOG_NEWS
00509     rb_define_syslog_facility(LOG_NEWS);
00510 #endif
00511 #ifdef LOG_NTP
00512    rb_define_syslog_facility(LOG_NTP);
00513 #endif
00514 #ifdef LOG_SECURITY
00515     rb_define_syslog_facility(LOG_SECURITY);
00516 #endif
00517 #ifdef LOG_SYSLOG
00518     rb_define_syslog_facility(LOG_SYSLOG);
00519 #endif
00520 #ifdef LOG_USER
00521     rb_define_syslog_facility(LOG_USER);
00522 #endif
00523 #ifdef LOG_UUCP
00524     rb_define_syslog_facility(LOG_UUCP);
00525 #endif
00526 #ifdef LOG_LOCAL0
00527     rb_define_syslog_facility(LOG_LOCAL0);
00528 #endif
00529 #ifdef LOG_LOCAL1
00530     rb_define_syslog_facility(LOG_LOCAL1);
00531 #endif
00532 #ifdef LOG_LOCAL2
00533     rb_define_syslog_facility(LOG_LOCAL2);
00534 #endif
00535 #ifdef LOG_LOCAL3
00536     rb_define_syslog_facility(LOG_LOCAL3);
00537 #endif
00538 #ifdef LOG_LOCAL4
00539     rb_define_syslog_facility(LOG_LOCAL4);
00540 #endif
00541 #ifdef LOG_LOCAL5
00542     rb_define_syslog_facility(LOG_LOCAL5);
00543 #endif
00544 #ifdef LOG_LOCAL6
00545     rb_define_syslog_facility(LOG_LOCAL6);
00546 #endif
00547 #ifdef LOG_LOCAL7
00548     rb_define_syslog_facility(LOG_LOCAL7);
00549 #endif
00550 
00551     /* Syslog levels and the shortcut methods */
00552 
00553 #define rb_define_syslog_level(c, m)                            \
00554     rb_define_const(mSyslogLevel, #c, INT2NUM(c));              \
00555     rb_define_module_function(mSyslog, #m, mSyslog_##m, -1)
00556 
00557 #ifdef LOG_EMERG
00558     rb_define_syslog_level(LOG_EMERG, emerg);
00559 #endif
00560 #ifdef LOG_ALERT
00561     rb_define_syslog_level(LOG_ALERT, alert);
00562 #endif
00563 #ifdef LOG_CRIT
00564     rb_define_syslog_level(LOG_CRIT, crit);
00565 #endif
00566 #ifdef LOG_ERR
00567     rb_define_syslog_level(LOG_ERR, err);
00568 #endif
00569 #ifdef LOG_WARNING
00570     rb_define_syslog_level(LOG_WARNING, warning);
00571 #endif
00572 #ifdef LOG_NOTICE
00573     rb_define_syslog_level(LOG_NOTICE, notice);
00574 #endif
00575 #ifdef LOG_INFO
00576     rb_define_syslog_level(LOG_INFO, info);
00577 #endif
00578 #ifdef LOG_DEBUG
00579     rb_define_syslog_level(LOG_DEBUG, debug);
00580 #endif
00581 
00582     /* Syslog macros */
00583 
00584     rb_define_method(mSyslogMacros, "LOG_MASK", mSyslogMacros_LOG_MASK, 1);
00585     rb_define_method(mSyslogMacros, "LOG_UPTO", mSyslogMacros_LOG_UPTO, 1);
00586     rb_define_singleton_method(mSyslogMacros, "included", mSyslogMacros_included, 1);
00587 
00588     rb_include_module(mSyslogConstants, mSyslogOption);
00589     rb_include_module(mSyslogConstants, mSyslogFacility);
00590     rb_include_module(mSyslogConstants, mSyslogLevel);
00591     rb_funcall(mSyslogConstants, rb_intern("include"), 1, mSyslogMacros);
00592 
00593     rb_define_singleton_method(mSyslogConstants, "included", mSyslogMacros_included, 1);
00594     rb_funcall(mSyslog, rb_intern("include"), 1, mSyslogConstants);
00595 }
00596