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