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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7