1/* 2 * UNIX Syslog extension for Ruby 3 * Amos Gouaux, University of Texas at Dallas 4 * <amos+ruby@utdallas.edu> 5 * Documented by mathew <meta@pobox.com> 6 * 7 * $RoughId: syslog.c,v 1.21 2002/02/25 12:21:17 knu Exp $ 8 * $Id: syslog.c 44659 2014-01-19 16:28:53Z nagachika $ 9 */ 10 11#include "ruby/ruby.h" 12#include "ruby/util.h" 13#include <syslog.h> 14 15/* Syslog class */ 16static VALUE mSyslog; 17/* 18 * Module holding all Syslog constants. See Syslog::log and 19 * Syslog::open for constant descriptions. 20 */ 21static VALUE mSyslogConstants; 22/* Module holding Syslog option constants */ 23static VALUE mSyslogOption; 24/* Module holding Syslog facility constants */ 25static VALUE mSyslogFacility; 26/* Module holding Syslog level constants */ 27static VALUE mSyslogLevel; 28/* Module holding Syslog utility macros */ 29static VALUE mSyslogMacros; 30 31static const char *syslog_ident = NULL; 32static int syslog_options = -1, syslog_facility = -1, syslog_mask = -1; 33static int syslog_opened = 0; 34 35/* Package helper routines */ 36static void syslog_write(int pri, int argc, VALUE *argv) 37{ 38 VALUE str; 39 40 rb_secure(4); 41 if (argc < 1) { 42 rb_raise(rb_eArgError, "no log message supplied"); 43 } 44 45 if (!syslog_opened) { 46 rb_raise(rb_eRuntimeError, "must open syslog before write"); 47 } 48 49 str = rb_f_sprintf(argc, argv); 50 51 syslog(pri, "%s", RSTRING_PTR(str)); 52} 53 54/* Closes the syslog facility. 55 * Raises a runtime exception if it is not open. 56 */ 57static VALUE mSyslog_close(VALUE self) 58{ 59 rb_secure(4); 60 if (!syslog_opened) { 61 rb_raise(rb_eRuntimeError, "syslog not opened"); 62 } 63 64 closelog(); 65 66 xfree((void *)syslog_ident); 67 syslog_ident = NULL; 68 syslog_options = syslog_facility = syslog_mask = -1; 69 syslog_opened = 0; 70 71 return Qnil; 72} 73 74/* call-seq: 75 * open(ident, options, facility) => syslog 76 * 77 * :yields: syslog 78 * 79 * Open the syslog facility. 80 * Raises a runtime exception if it is already open. 81 * 82 * Can be called with or without a code block. If called with a block, the 83 * Syslog object created is passed to the block. 84 * 85 * If the syslog is already open, raises a RuntimeError. 86 * 87 * +ident+ is a String which identifies the calling program. 88 * 89 * +options+ is the logical OR of any of the following: 90 * 91 * LOG_CONS:: If there is an error while sending to the system logger, 92 * write directly to the console instead. 93 * 94 * LOG_NDELAY:: Open the connection now, rather than waiting for the first 95 * message to be written. 96 * 97 * LOG_NOWAIT:: Don't wait for any child processes created while logging 98 * messages. (Has no effect on Linux.) 99 * 100 * LOG_ODELAY:: Opposite of LOG_NDELAY; wait until a message is sent before 101 * opening the connection. (This is the default.) 102 * 103 * LOG_PERROR:: Print the message to stderr as well as sending it to syslog. 104 * (Not in POSIX.1-2001.) 105 * 106 * LOG_PID:: Include the current process ID with each message. 107 * 108 * +facility+ describes the type of program opening the syslog, and is 109 * the logical OR of any of the following which are defined for the host OS: 110 * 111 * LOG_AUTH:: Security or authorization. Deprecated, use LOG_AUTHPRIV 112 * instead. 113 * 114 * LOG_AUTHPRIV:: Security or authorization messages which should be kept 115 * private. 116 * 117 * LOG_CONSOLE:: System console message. 118 * 119 * LOG_CRON:: System task scheduler (cron or at). 120 * 121 * LOG_DAEMON:: A system daemon which has no facility value of its own. 122 * 123 * LOG_FTP:: An FTP server. 124 * 125 * LOG_KERN:: A kernel message (not sendable by user processes, so not of 126 * much use to Ruby, but listed here for completeness). 127 * 128 * LOG_LPR:: Line printer subsystem. 129 * 130 * LOG_MAIL:: Mail delivery or transport subsystem. 131 * 132 * LOG_NEWS:: Usenet news system. 133 * 134 * LOG_NTP:: Network Time Protocol server. 135 * 136 * LOG_SECURITY:: General security message. 137 * 138 * LOG_SYSLOG:: Messages generated internally by syslog. 139 * 140 * LOG_USER:: Generic user-level message. 141 * 142 * LOG_UUCP:: UUCP subsystem. 143 * 144 * LOG_LOCAL0 to LOG_LOCAL7:: Locally-defined facilities. 145 * 146 * Example: 147 * 148 * Syslog.open("webrick", Syslog::LOG_PID, 149 * Syslog::LOG_DAEMON | Syslog::LOG_LOCAL3) 150 * 151 */ 152static VALUE mSyslog_open(int argc, VALUE *argv, VALUE self) 153{ 154 VALUE ident, opt, fac; 155 156 if (syslog_opened) { 157 rb_raise(rb_eRuntimeError, "syslog already open"); 158 } 159 160 rb_scan_args(argc, argv, "03", &ident, &opt, &fac); 161 162 if (NIL_P(ident)) { 163 ident = rb_gv_get("$0"); 164 } 165 SafeStringValue(ident); 166 syslog_ident = strdup(RSTRING_PTR(ident)); 167 168 if (NIL_P(opt)) { 169 syslog_options = LOG_PID | LOG_CONS; 170 } else { 171 syslog_options = NUM2INT(opt); 172 } 173 174 if (NIL_P(fac)) { 175 syslog_facility = LOG_USER; 176 } else { 177 syslog_facility = NUM2INT(fac); 178 } 179 180 openlog(syslog_ident, syslog_options, syslog_facility); 181 182 syslog_opened = 1; 183 184 setlogmask(syslog_mask = setlogmask(0)); 185 186 /* be like File.new.open {...} */ 187 if (rb_block_given_p()) { 188 rb_ensure(rb_yield, self, mSyslog_close, self); 189 } 190 191 return self; 192} 193 194/* call-seq: 195 * reopen(ident, options, facility) => syslog 196 * 197 * :yields: syslog 198 * 199 * Closes and then reopens the syslog. 200 * 201 * Arguments are the same as for open(). 202 */ 203static VALUE mSyslog_reopen(int argc, VALUE *argv, VALUE self) 204{ 205 mSyslog_close(self); 206 207 return mSyslog_open(argc, argv, self); 208} 209 210/* call-seq: 211 * opened? 212 * 213 * Returns true if the syslog is open. 214 */ 215static VALUE mSyslog_isopen(VALUE self) 216{ 217 return syslog_opened ? Qtrue : Qfalse; 218} 219 220/* Returns the identity string used in the last call to open() 221 */ 222static VALUE mSyslog_ident(VALUE self) 223{ 224 return syslog_opened ? rb_str_new2(syslog_ident) : Qnil; 225} 226 227/* Returns the options bitmask used in the last call to open() 228 */ 229static VALUE mSyslog_options(VALUE self) 230{ 231 return syslog_opened ? INT2NUM(syslog_options) : Qnil; 232} 233 234/* Returns the facility number used in the last call to open() 235 */ 236static VALUE mSyslog_facility(VALUE self) 237{ 238 return syslog_opened ? INT2NUM(syslog_facility) : Qnil; 239} 240 241/* Returns the log priority mask in effect. The mask is not reset by opening 242 * or closing syslog. 243 */ 244static VALUE mSyslog_get_mask(VALUE self) 245{ 246 return syslog_opened ? INT2NUM(syslog_mask) : Qnil; 247} 248 249/* call-seq: 250 * mask=(priority_mask) 251 * 252 * Sets the log priority mask. A method LOG_UPTO is defined to make it easier 253 * to set mask values. Example: 254 * 255 * Syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_ERR) 256 * 257 * Alternatively, specific priorities can be selected and added together using 258 * binary OR. Example: 259 * 260 * Syslog.mask = Syslog::LOG_MASK(Syslog::LOG_ERR) | Syslog::LOG_MASK(Syslog::LOG_CRIT) 261 * 262 * The priority mask persists through calls to open() and close(). 263 */ 264static VALUE mSyslog_set_mask(VALUE self, VALUE mask) 265{ 266 rb_secure(4); 267 if (!syslog_opened) { 268 rb_raise(rb_eRuntimeError, "must open syslog before setting log mask"); 269 } 270 271 setlogmask(syslog_mask = NUM2INT(mask)); 272 273 return mask; 274} 275 276/* call-seq: 277 * log(priority, format_string, *format_args) 278 * 279 * Log a message with the specified priority. Example: 280 * 281 * Syslog.log(Syslog::LOG_CRIT, "Out of disk space") 282 * Syslog.log(Syslog::LOG_CRIT, "User %s logged in", ENV['USER']) 283 * 284 * The priority levels, in descending order, are: 285 * 286 * LOG_EMERG:: System is unusable 287 * LOG_ALERT:: Action needs to be taken immediately 288 * LOG_CRIT:: A critical condition has occurred 289 * LOG_ERR:: An error occurred 290 * LOG_WARNING:: Warning of a possible problem 291 * LOG_NOTICE:: A normal but significant condition occurred 292 * LOG_INFO:: Informational message 293 * LOG_DEBUG:: Debugging information 294 * 295 * Each priority level also has a shortcut method that logs with it's named priority. 296 * As an example, the two following statements would produce the same result: 297 * 298 * Syslog.log(Syslog::LOG_ALERT, "Out of memory") 299 * Syslog.alert("Out of memory") 300 * 301 * Format strings are as for printf/sprintf, except that in addition %m is 302 * replaced with the error message string that would be returned by 303 * strerror(errno). 304 * 305 */ 306static VALUE mSyslog_log(int argc, VALUE *argv, VALUE self) 307{ 308 VALUE pri; 309 310 if (argc < 2) { 311 rb_raise(rb_eArgError, "wrong number of arguments (%d for 2+)", argc); 312 } 313 314 argc--; 315 pri = *argv++; 316 317 if (!FIXNUM_P(pri)) { 318 rb_raise(rb_eTypeError, "type mismatch: %"PRIsVALUE" given", rb_obj_class(pri)); 319 } 320 321 syslog_write(FIX2INT(pri), argc, argv); 322 323 return self; 324} 325 326/* Returns an inspect() string summarizing the object state. 327 */ 328static VALUE mSyslog_inspect(VALUE self) 329{ 330 Check_Type(self, T_MODULE); 331 332 if (!syslog_opened) 333 return rb_sprintf("<#%"PRIsVALUE": opened=false>", self); 334 335 return rb_sprintf("<#%"PRIsVALUE": opened=true, ident=\"%s\", options=%d, facility=%d, mask=%d>", 336 self, 337 syslog_ident, 338 syslog_options, 339 syslog_facility, 340 syslog_mask); 341} 342 343/* Returns self, for backward compatibility. 344 */ 345static VALUE mSyslog_instance(VALUE self) 346{ 347 return self; 348} 349 350#define define_syslog_shortcut_method(pri, name) \ 351static VALUE mSyslog_##name(int argc, VALUE *argv, VALUE self) \ 352{ \ 353 syslog_write((pri), argc, argv); \ 354\ 355 return self; \ 356} 357 358#ifdef LOG_EMERG 359define_syslog_shortcut_method(LOG_EMERG, emerg) 360#endif 361#ifdef LOG_ALERT 362define_syslog_shortcut_method(LOG_ALERT, alert) 363#endif 364#ifdef LOG_CRIT 365define_syslog_shortcut_method(LOG_CRIT, crit) 366#endif 367#ifdef LOG_ERR 368define_syslog_shortcut_method(LOG_ERR, err) 369#endif 370#ifdef LOG_WARNING 371define_syslog_shortcut_method(LOG_WARNING, warning) 372#endif 373#ifdef LOG_NOTICE 374define_syslog_shortcut_method(LOG_NOTICE, notice) 375#endif 376#ifdef LOG_INFO 377define_syslog_shortcut_method(LOG_INFO, info) 378#endif 379#ifdef LOG_DEBUG 380define_syslog_shortcut_method(LOG_DEBUG, debug) 381#endif 382 383/* call-seq: 384 * LOG_MASK(priority_level) => priority_mask 385 * 386 * Generates a mask bit for a priority level. See #mask= 387 */ 388static VALUE mSyslogMacros_LOG_MASK(VALUE mod, VALUE pri) 389{ 390 return INT2FIX(LOG_MASK(NUM2INT(pri))); 391} 392 393/* call-seq: 394 * LOG_UPTO(priority_level) => priority_mask 395 * 396 * Generates a mask value for priority levels at or below the level specified. 397 * See #mask= 398 */ 399static VALUE mSyslogMacros_LOG_UPTO(VALUE mod, VALUE pri) 400{ 401 return INT2FIX(LOG_UPTO(NUM2INT(pri))); 402} 403 404static VALUE mSyslogMacros_included(VALUE mod, VALUE target) 405{ 406 rb_extend_object(target, mSyslogMacros); 407 return mod; 408} 409 410/* The syslog package provides a Ruby interface to the POSIX system logging 411 * facility. 412 * 413 * Syslog messages are typically passed to a central logging daemon. 414 * The daemon may filter them; route them into different files (usually 415 * found under /var/log); place them in SQL databases; forward 416 * them to centralized logging servers via TCP or UDP; or even alert the 417 * system administrator via email, pager or text message. 418 * 419 * Unlike application-level logging via Logger or Log4r, syslog is designed 420 * to allow secure tamper-proof logging. 421 * 422 * The syslog protocol is standardized in RFC 5424. 423 */ 424void Init_syslog() 425{ 426 mSyslog = rb_define_module("Syslog"); 427 428 mSyslogConstants = rb_define_module_under(mSyslog, "Constants"); 429 430 mSyslogOption = rb_define_module_under(mSyslog, "Option"); 431 mSyslogFacility = rb_define_module_under(mSyslog, "Facility"); 432 mSyslogLevel = rb_define_module_under(mSyslog, "Level"); 433 mSyslogMacros = rb_define_module_under(mSyslog, "Macros"); 434 435 rb_define_module_function(mSyslog, "open", mSyslog_open, -1); 436 rb_define_module_function(mSyslog, "reopen", mSyslog_reopen, -1); 437 rb_define_module_function(mSyslog, "open!", mSyslog_reopen, -1); 438 rb_define_module_function(mSyslog, "opened?", mSyslog_isopen, 0); 439 440 rb_define_module_function(mSyslog, "ident", mSyslog_ident, 0); 441 rb_define_module_function(mSyslog, "options", mSyslog_options, 0); 442 rb_define_module_function(mSyslog, "facility", mSyslog_facility, 0); 443 444 rb_define_module_function(mSyslog, "log", mSyslog_log, -1); 445 rb_define_module_function(mSyslog, "close", mSyslog_close, 0); 446 rb_define_module_function(mSyslog, "mask", mSyslog_get_mask, 0); 447 rb_define_module_function(mSyslog, "mask=", mSyslog_set_mask, 1); 448 449 rb_define_module_function(mSyslog, "inspect", mSyslog_inspect, 0); 450 rb_define_module_function(mSyslog, "instance", mSyslog_instance, 0); 451 452 /* Syslog options */ 453 454#define rb_define_syslog_option(c) \ 455 rb_define_const(mSyslogOption, #c, INT2NUM(c)) 456 457#ifdef LOG_PID 458 rb_define_syslog_option(LOG_PID); 459#endif 460#ifdef LOG_CONS 461 rb_define_syslog_option(LOG_CONS); 462#endif 463#ifdef LOG_ODELAY 464 rb_define_syslog_option(LOG_ODELAY); /* deprecated */ 465#endif 466#ifdef LOG_NDELAY 467 rb_define_syslog_option(LOG_NDELAY); 468#endif 469#ifdef LOG_NOWAIT 470 rb_define_syslog_option(LOG_NOWAIT); /* deprecated */ 471#endif 472#ifdef LOG_PERROR 473 rb_define_syslog_option(LOG_PERROR); 474#endif 475 476 /* Syslog facilities */ 477 478#define rb_define_syslog_facility(c) \ 479 rb_define_const(mSyslogFacility, #c, INT2NUM(c)) 480 481#ifdef LOG_AUTH 482 rb_define_syslog_facility(LOG_AUTH); 483#endif 484#ifdef LOG_AUTHPRIV 485 rb_define_syslog_facility(LOG_AUTHPRIV); 486#endif 487#ifdef LOG_CONSOLE 488 rb_define_syslog_facility(LOG_CONSOLE); 489#endif 490#ifdef LOG_CRON 491 rb_define_syslog_facility(LOG_CRON); 492#endif 493#ifdef LOG_DAEMON 494 rb_define_syslog_facility(LOG_DAEMON); 495#endif 496#ifdef LOG_FTP 497 rb_define_syslog_facility(LOG_FTP); 498#endif 499#ifdef LOG_KERN 500 rb_define_syslog_facility(LOG_KERN); 501#endif 502#ifdef LOG_LPR 503 rb_define_syslog_facility(LOG_LPR); 504#endif 505#ifdef LOG_MAIL 506 rb_define_syslog_facility(LOG_MAIL); 507#endif 508#ifdef LOG_NEWS 509 rb_define_syslog_facility(LOG_NEWS); 510#endif 511#ifdef LOG_NTP 512 rb_define_syslog_facility(LOG_NTP); 513#endif 514#ifdef LOG_SECURITY 515 rb_define_syslog_facility(LOG_SECURITY); 516#endif 517#ifdef LOG_SYSLOG 518 rb_define_syslog_facility(LOG_SYSLOG); 519#endif 520#ifdef LOG_USER 521 rb_define_syslog_facility(LOG_USER); 522#endif 523#ifdef LOG_UUCP 524 rb_define_syslog_facility(LOG_UUCP); 525#endif 526#ifdef LOG_LOCAL0 527 rb_define_syslog_facility(LOG_LOCAL0); 528#endif 529#ifdef LOG_LOCAL1 530 rb_define_syslog_facility(LOG_LOCAL1); 531#endif 532#ifdef LOG_LOCAL2 533 rb_define_syslog_facility(LOG_LOCAL2); 534#endif 535#ifdef LOG_LOCAL3 536 rb_define_syslog_facility(LOG_LOCAL3); 537#endif 538#ifdef LOG_LOCAL4 539 rb_define_syslog_facility(LOG_LOCAL4); 540#endif 541#ifdef LOG_LOCAL5 542 rb_define_syslog_facility(LOG_LOCAL5); 543#endif 544#ifdef LOG_LOCAL6 545 rb_define_syslog_facility(LOG_LOCAL6); 546#endif 547#ifdef LOG_LOCAL7 548 rb_define_syslog_facility(LOG_LOCAL7); 549#endif 550 551 /* Syslog levels and the shortcut methods */ 552 553#define rb_define_syslog_level(c, m) \ 554 rb_define_const(mSyslogLevel, #c, INT2NUM(c)); \ 555 rb_define_module_function(mSyslog, #m, mSyslog_##m, -1) 556 557#ifdef LOG_EMERG 558 rb_define_syslog_level(LOG_EMERG, emerg); 559#endif 560#ifdef LOG_ALERT 561 rb_define_syslog_level(LOG_ALERT, alert); 562#endif 563#ifdef LOG_CRIT 564 rb_define_syslog_level(LOG_CRIT, crit); 565#endif 566#ifdef LOG_ERR 567 rb_define_syslog_level(LOG_ERR, err); 568#endif 569#ifdef LOG_WARNING 570 rb_define_syslog_level(LOG_WARNING, warning); 571#endif 572#ifdef LOG_NOTICE 573 rb_define_syslog_level(LOG_NOTICE, notice); 574#endif 575#ifdef LOG_INFO 576 rb_define_syslog_level(LOG_INFO, info); 577#endif 578#ifdef LOG_DEBUG 579 rb_define_syslog_level(LOG_DEBUG, debug); 580#endif 581 582 /* Syslog macros */ 583 584 rb_define_method(mSyslogMacros, "LOG_MASK", mSyslogMacros_LOG_MASK, 1); 585 rb_define_method(mSyslogMacros, "LOG_UPTO", mSyslogMacros_LOG_UPTO, 1); 586 rb_define_singleton_method(mSyslogMacros, "included", mSyslogMacros_included, 1); 587 588 rb_include_module(mSyslogConstants, mSyslogOption); 589 rb_include_module(mSyslogConstants, mSyslogFacility); 590 rb_include_module(mSyslogConstants, mSyslogLevel); 591 rb_funcall(mSyslogConstants, rb_intern("include"), 1, mSyslogMacros); 592 593 rb_define_singleton_method(mSyslogConstants, "included", mSyslogMacros_included, 1); 594 rb_funcall(mSyslog, rb_intern("include"), 1, mSyslogConstants); 595} 596