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