1 /*
2 * logging.c - generic logging for snmp-agent
3 * * Contributed by Ragnar Kj�rstad, ucd@ragnark.vestdata.no 1999-06-26
4 */
5 /* Portions of this file are subject to the following copyright(s). See
6 * the Net-SNMP's COPYING file for more details and other copyrights
7 * that may apply:
8 */
9 /*
10 * Portions of this file are copyrighted by:
11 * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
12 * Use is subject to license terms specified in the COPYING file
13 * distributed with the Net-SNMP package.
14 *
15 * Portions of this file are copyrighted by:
16 * Copyright (c) 2016 VMware, Inc. All rights reserved.
17 * Use is subject to license terms specified in the COPYING file
18 * distributed with the Net-SNMP package.
19 */
20 /** @defgroup snmp_logging generic logging for net-snmp
21 * @ingroup library
22 *
23 * @{
24 */
25 #include <net-snmp/net-snmp-config.h>
26 #include <net-snmp/net-snmp-features.h>
27 #include <stdio.h>
28 #if HAVE_MALLOC_H
29 #include <malloc.h>
30 #endif
31 #if HAVE_STRING_H
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
36 #include <ctype.h>
37 #if HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #if HAVE_SYSLOG_H
45 #include <syslog.h>
46 #ifndef LOG_CONS /* Interesting Ultrix feature */
47 #include <sys/syslog.h>
48 #endif
49 #endif
50 #if TIME_WITH_SYS_TIME
51 # include <sys/time.h>
52 # include <time.h>
53 #else
54 # if HAVE_SYS_TIME_H
55 # include <sys/time.h>
56 # else
57 # include <time.h>
58 # endif
59 #endif
60 #if HAVE_NETINET_IN_H
61 #include <netinet/in.h>
62 #endif
63
64 #include <stdarg.h>
65
66 #if HAVE_UNISTD_H
67 #include <unistd.h>
68 #endif
69
70 #include <net-snmp/types.h>
71 #include <net-snmp/output_api.h>
72 #include <net-snmp/library/snmp_logging.h> /* For this file's "internal" definitions */
73 #include <net-snmp/config_api.h>
74 #include <net-snmp/utilities.h>
75
76 #include <net-snmp/library/callback.h>
77
78 #include "snmp_syslog.h"
79
80 #ifdef va_copy
81 #define NEED_VA_END_AFTER_VA_COPY
82 #else
83 #ifdef __vacopy
84 #define vacopy __vacopy
85 #define NEED_VA_END_AFTER_VA_COPY
86 #else
87 #define va_copy(dest, src) memcpy (&dest, &src, sizeof (va_list))
88 #endif
89 #endif
90 #ifndef HAVE_VSNPRINTF
91 #include "snprintf.h"
92 #endif
93
94 netsnmp_feature_child_of(logging_all, libnetsnmp);
95
96 netsnmp_feature_child_of(logging_outputs, logging_all);
97 netsnmp_feature_child_of(logging_file, logging_outputs);
98 netsnmp_feature_child_of(logging_stdio, logging_outputs);
99 netsnmp_feature_child_of(logging_syslog, logging_outputs);
100 netsnmp_feature_child_of(logging_external, logging_all);
101
102 netsnmp_feature_child_of(enable_stderrlog, logging_all);
103
104 netsnmp_feature_child_of(logging_enable_calllog, netsnmp_unused);
105 netsnmp_feature_child_of(logging_enable_loghandler, netsnmp_unused);
106
107 /* default to the file/stdio/syslog set */
108 netsnmp_feature_want(logging_outputs);
109
110 /*
111 * logh_head: A list of all log handlers, in increasing order of priority
112 * logh_priorities: 'Indexes' into this list, by priority
113 */
114 netsnmp_log_handler *logh_head = NULL;
115 netsnmp_log_handler *logh_priorities[LOG_DEBUG+1];
116 static int logh_enabled = 0;
117
118 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
119 static char syslogname[64] = DEFAULT_LOG_ID;
120 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
121
122 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
123 netsnmp_log_handler *
124 netsnmp_register_stdio_loghandler(int is_stdout, int priority, int priority_max,
125 const char *tok);
126 #endif
127 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
128 netsnmp_log_handler *
129 netsnmp_register_filelog_handler(const char* logfilename, int priority,
130 int priority_max, int dont_zero_log);
131 #endif
132
133 void
netsnmp_disable_this_loghandler(netsnmp_log_handler * logh)134 netsnmp_disable_this_loghandler(netsnmp_log_handler *logh)
135 {
136 if (!logh || (0 == logh->enabled))
137 return;
138 logh->enabled = 0;
139 --logh_enabled;
140 netsnmp_assert(logh_enabled >= 0);
141 }
142
143 void
netsnmp_enable_this_loghandler(netsnmp_log_handler * logh)144 netsnmp_enable_this_loghandler(netsnmp_log_handler *logh)
145 {
146 if (!logh || (0 != logh->enabled))
147 return;
148 logh->enabled = 1;
149 ++logh_enabled;
150 }
151
152 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
153 void
154 netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log);
155 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
156
157 void
parse_config_logOption(const char * token,char * cptr)158 parse_config_logOption(const char *token, char *cptr)
159 {
160 int my_argc = 0 ;
161 char **my_argv = NULL;
162
163 snmp_log_options( cptr, my_argc, my_argv );
164 }
165
166 void
init_snmp_logging(void)167 init_snmp_logging(void)
168 {
169 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "logTimestamp",
170 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_LOG_TIMESTAMP);
171 register_prenetsnmp_mib_handler("snmp", "logOption",
172 parse_config_logOption, NULL, "string");
173
174 }
175
176 void
shutdown_snmp_logging(void)177 shutdown_snmp_logging(void)
178 {
179 snmp_disable_log();
180 while(NULL != logh_head)
181 netsnmp_remove_loghandler( logh_head );
182 }
183
184 /* Set line buffering mode for a stream. */
185 void
netsnmp_set_line_buffering(FILE * stream)186 netsnmp_set_line_buffering(FILE *stream)
187 {
188 #if defined(WIN32)
189 /*
190 * According to MSDN, the Microsoft Visual Studio C runtime library does
191 * not support line buffering, so turn off buffering completely.
192 * See also http://msdn.microsoft.com/en-us/library/86cebhfs(VS.71).aspx.
193 */
194 setvbuf(stream, NULL, _IONBF, BUFSIZ);
195 #elif defined(HAVE_SETLINEBUF)
196 /* setlinefunction() is a function from the BSD Unix API. */
197 setlinebuf(stream);
198 #else
199 /* See also the C89 or C99 standard for more information about setvbuf(). */
200 setvbuf(stream, NULL, _IOLBF, BUFSIZ);
201 #endif
202 }
203
204 /*
205 * Decodes log priority.
206 * @param optarg - IN - priority to decode, "0" or "0-7"
207 * OUT - points to last character after the decoded priority
208 * @param pri_max - OUT - maximum priority (i.e. 0x7 from "0-7")
209 */
210 static int
decode_priority(char ** optarg,int * pri_max)211 decode_priority( char **optarg, int *pri_max )
212 {
213 int pri_low = LOG_DEBUG;
214
215 if (*optarg == NULL)
216 return -1;
217
218 switch (**optarg) {
219 case '0':
220 case '!':
221 pri_low = LOG_EMERG;
222 break;
223 case '1':
224 case 'a':
225 case 'A':
226 pri_low = LOG_ALERT;
227 break;
228 case '2':
229 case 'c':
230 case 'C':
231 pri_low = LOG_CRIT;
232 break;
233 case '3':
234 case 'e':
235 case 'E':
236 pri_low = LOG_ERR;
237 break;
238 case '4':
239 case 'w':
240 case 'W':
241 pri_low = LOG_WARNING;
242 break;
243 case '5':
244 case 'n':
245 case 'N':
246 pri_low = LOG_NOTICE;
247 break;
248 case '6':
249 case 'i':
250 case 'I':
251 pri_low = LOG_INFO;
252 break;
253 case '7':
254 case 'd':
255 case 'D':
256 pri_low = LOG_DEBUG;
257 break;
258 default:
259 fprintf(stderr, "invalid priority: %c\n",**optarg);
260 return -1;
261 }
262 *optarg = *optarg+1;
263
264 if (pri_max && **optarg=='-') {
265 *optarg = *optarg + 1; /* skip '-' */
266 *pri_max = decode_priority( optarg, NULL );
267 if (*pri_max == -1) return -1;
268 if (pri_low < *pri_max) {
269 int tmp = pri_low;
270 pri_low = *pri_max;
271 *pri_max = tmp;
272 }
273
274 }
275 return pri_low;
276 }
277
278 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
279 static int
decode_facility(char * optarg)280 decode_facility( char *optarg )
281 {
282 if (optarg == NULL)
283 return -1;
284
285 switch (*optarg) {
286 case 'd':
287 case 'D':
288 return LOG_DAEMON;
289 case 'u':
290 case 'U':
291 return LOG_USER;
292 case '0':
293 return LOG_LOCAL0;
294 case '1':
295 return LOG_LOCAL1;
296 case '2':
297 return LOG_LOCAL2;
298 case '3':
299 return LOG_LOCAL3;
300 case '4':
301 return LOG_LOCAL4;
302 case '5':
303 return LOG_LOCAL5;
304 case '6':
305 return LOG_LOCAL6;
306 case '7':
307 return LOG_LOCAL7;
308 default:
309 fprintf(stderr, "invalid syslog facility: %c\n",*optarg);
310 return -1;
311 }
312 }
313 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
314
315 int
snmp_log_options(char * optarg,int argc,char * const * argv)316 snmp_log_options(char *optarg, int argc, char *const *argv)
317 {
318 char *cp = optarg;
319 /*
320 * Hmmm... this doesn't seem to work.
321 * The main agent 'getopt' handling assumes
322 * that the -L option takes an argument,
323 * and objects if this is missing.
324 * Trying to differentiate between
325 * new-style "-Lx", and old-style "-L xx"
326 * is likely to be a major headache.
327 */
328 char missing_opt = 'e'; /* old -L is new -Le */
329 int priority = LOG_DEBUG;
330 int pri_max = LOG_EMERG;
331 int inc_optind = 0;
332 netsnmp_log_handler *logh;
333
334 DEBUGMSGT(("logging:options", "optarg: '%s', argc %d, argv '%s'\n",
335 optarg, argc, argv ? argv[0] : "NULL"));
336 optarg++;
337 if (!*cp)
338 cp = &missing_opt;
339
340 /*
341 * Support '... -Lx=value ....' syntax
342 */
343 if (*optarg == '=') {
344 optarg++;
345 }
346 /*
347 * and '.... "-Lx value" ....' (*with* the quotes)
348 */
349 while (*optarg && isspace((unsigned char)(*optarg))) {
350 optarg++;
351 }
352 /*
353 * Finally, handle ".... -Lx value ...." syntax
354 * (*without* surrounding quotes)
355 */
356 if ((!*optarg) && (NULL != argv)) {
357 /*
358 * We've run off the end of the argument
359 * so move on to the next.
360 * But we might not actually need it, so don't
361 * increment optind just yet!
362 */
363 optarg = argv[optind];
364 inc_optind = 1;
365 }
366
367 DEBUGMSGT(("logging:options", "*cp: '%c'\n", *cp));
368 switch (*cp) {
369
370 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
371 /*
372 * Log to Standard Error
373 */
374 case 'E':
375 priority = decode_priority( &optarg, &pri_max );
376 if (priority == -1) return -1;
377 if (inc_optind)
378 optind++;
379 /* Fallthrough */
380 case 'e':
381 logh = netsnmp_register_stdio_loghandler(0, priority, pri_max, "stderr");
382 break;
383
384 /*
385 * Log to Standard Output
386 */
387 case 'O':
388 priority = decode_priority( &optarg, &pri_max );
389 if (priority == -1) return -1;
390 if (inc_optind)
391 optind++;
392 /* Fallthrough */
393 case 'o':
394 logh = netsnmp_register_stdio_loghandler( 1, priority, pri_max, "stdout" );
395 break;
396 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
397
398 /*
399 * Log to a named file
400 */
401 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
402 case 'F':
403 priority = decode_priority( &optarg, &pri_max );
404 if (priority == -1) return -1;
405 while (*optarg == ' ') optarg++;
406 if (!*optarg && !argv) return -1;
407 else if (!*optarg) optarg = argv[++optind];
408 /* FALL THROUGH */
409 case 'f':
410 if (inc_optind)
411 optind++;
412 if (!optarg) {
413 fprintf(stderr, "Missing log file\n");
414 return -1;
415 }
416 DEBUGMSGTL(("logging:options", "%d-%d: '%s'\n", priority, pri_max, optarg));
417 logh = netsnmp_register_filelog_handler(optarg, priority, pri_max,
418 -1);
419 break;
420 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
421
422 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
423 /*
424 * Log to syslog
425 */
426 case 'S':
427 priority = decode_priority( &optarg, &pri_max );
428 if (priority == -1 || !argv) return -1;
429 if (!optarg[0]) {
430 /* The command line argument with priority does not contain log
431 * facility. The facility must be in next argument then. */
432 optind++;
433 if (optind < argc)
434 optarg = argv[optind];
435 }
436 /* Fallthrough */
437 case 's':
438 if (inc_optind)
439 optind++;
440 if (!optarg) {
441 fprintf(stderr, "Missing syslog facility\n");
442 return -1;
443 }
444 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG, priority);
445 if (logh) {
446 int facility = decode_facility(optarg);
447 if (facility == -1) {
448 netsnmp_remove_loghandler(logh);
449 return -1;
450 }
451 logh->pri_max = pri_max;
452 logh->token = strdup(snmp_log_syslogname(NULL));
453 logh->magic = (void *)(intptr_t)facility;
454 snmp_enable_syslog_ident(snmp_log_syslogname(NULL), facility);
455 }
456 break;
457 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
458
459 /*
460 * Don't log
461 */
462 case 'N':
463 priority = decode_priority( &optarg, &pri_max );
464 if (priority == -1) return -1;
465 if (inc_optind)
466 optind++;
467 /* Fallthrough */
468 case 'n':
469 /*
470 * disable all logs to clean them up (close files, etc),
471 * remove all log handlers, then register a null handler.
472 */
473 snmp_disable_log();
474 while(NULL != logh_head)
475 netsnmp_remove_loghandler( logh_head );
476 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, priority);
477 if (logh) {
478 logh->pri_max = pri_max;
479 }
480 break;
481
482 default:
483 fprintf(stderr, "Unknown logging option passed to -L: %c.\n", *cp);
484 return -1;
485 }
486 return 0;
487 }
488
489 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
490 char *
snmp_log_syslogname(const char * pstr)491 snmp_log_syslogname(const char *pstr)
492 {
493 if (pstr)
494 strlcpy (syslogname, pstr, sizeof(syslogname));
495
496 return syslogname;
497 }
498 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
499
500 void
snmp_log_options_usage(const char * lead,FILE * outf)501 snmp_log_options_usage(const char *lead, FILE * outf)
502 {
503 const char *pri1_msg = " for level 'pri' and above";
504 const char *pri2_msg = " for levels 'p1' to 'p2'";
505 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
506 fprintf(outf, "%se: log to standard error\n", lead);
507 fprintf(outf, "%so: log to standard output\n", lead);
508 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
509 fprintf(outf, "%sn: don't log at all\n", lead);
510 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
511 fprintf(outf, "%sf file: log to the specified file\n", lead);
512 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
513 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
514 fprintf(outf, "%ss facility: log to syslog (via the specified facility)\n", lead);
515 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
516 fprintf(outf, "\n%s(variants)\n", lead);
517 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
518 fprintf(outf, "%s[EON] pri: log to standard error, output or /dev/null%s\n", lead, pri1_msg);
519 fprintf(outf, "%s[EON] p1-p2: log to standard error, output or /dev/null%s\n", lead, pri2_msg);
520 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
521 fprintf(outf, "%s[FS] pri token: log to file/syslog%s\n", lead, pri1_msg);
522 fprintf(outf, "%s[FS] p1-p2 token: log to file/syslog%s\n", lead, pri2_msg);
523 }
524
525 /**
526 * Is logging done?
527 *
528 * @return Returns 0 if logging is off, 1 when it is done.
529 *
530 */
531 int
snmp_get_do_logging(void)532 snmp_get_do_logging(void)
533 {
534 return (logh_enabled > 0);
535 }
536
537
538 static char *
sprintf_stamp(time_t * now,char * sbuf)539 sprintf_stamp(time_t * now, char *sbuf)
540 {
541 time_t Now;
542 struct tm *tm;
543
544 if (now == NULL) {
545 now = &Now;
546 time(now);
547 }
548 tm = localtime(now);
549 sprintf(sbuf, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ",
550 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
551 tm->tm_hour, tm->tm_min, tm->tm_sec);
552 return sbuf;
553 }
554
555 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
556 void
snmp_disable_syslog_entry(netsnmp_log_handler * logh)557 snmp_disable_syslog_entry(netsnmp_log_handler *logh)
558 {
559 if (!logh || !logh->enabled || logh->type != NETSNMP_LOGHANDLER_SYSLOG)
560 return;
561
562 #ifdef WIN32
563 if (logh->magic) {
564 HANDLE eventlog_h = (HANDLE)logh->magic;
565 CloseEventLog(eventlog_h);
566 logh->magic = NULL;
567 }
568 #else
569 closelog();
570 logh->imagic = 0;
571 #endif
572
573 netsnmp_disable_this_loghandler(logh);
574 }
575
576 void
snmp_disable_syslog(void)577 snmp_disable_syslog(void)
578 {
579 netsnmp_log_handler *logh;
580
581 for (logh = logh_head; logh; logh = logh->next)
582 if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_SYSLOG)
583 snmp_disable_syslog_entry(logh);
584 }
585 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
586
587 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
588 void
snmp_disable_filelog_entry(netsnmp_log_handler * logh)589 snmp_disable_filelog_entry(netsnmp_log_handler *logh)
590 {
591 if (!logh /* || !logh->enabled */ || logh->type != NETSNMP_LOGHANDLER_FILE)
592 return;
593
594 if (logh->magic) {
595 fputs("\n", (FILE*)logh->magic); /* XXX - why? */
596 fclose((FILE*)logh->magic);
597 logh->magic = NULL;
598 }
599 netsnmp_disable_this_loghandler(logh);
600 }
601
602 void
snmp_disable_filelog(void)603 snmp_disable_filelog(void)
604 {
605 netsnmp_log_handler *logh;
606
607 for (logh = logh_head; logh; logh = logh->next)
608 if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_FILE)
609 snmp_disable_filelog_entry(logh);
610 }
611 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
612
613 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
614
615 netsnmp_log_handler *
netsnmp_register_stdio_loghandler(int is_stdout,int priority,int priority_max,const char * tok)616 netsnmp_register_stdio_loghandler(int is_stdout, int priority, int priority_max,
617 const char *tok)
618 {
619 netsnmp_log_handler *logh =
620 netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR, priority);
621 if (NULL == logh) {
622 return NULL;
623 }
624 if (is_stdout) {
625 netsnmp_set_line_buffering(stdout);
626 logh->imagic = 1; /* stdout, not stderr */
627 } else
628 netsnmp_set_line_buffering(stderr);
629
630 logh->pri_max = priority_max;
631 if (tok)
632 logh->token = strdup(tok);
633 return logh;
634 }
635
636 /*
637 * returns that status of stderr logging
638 *
639 * @retval 0 : stderr logging disabled
640 * @retval 1 : stderr logging enabled
641 */
642 int
snmp_stderrlog_status(void)643 snmp_stderrlog_status(void)
644 {
645 netsnmp_log_handler *logh;
646
647 for (logh = logh_head; logh; logh = logh->next)
648 if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
649 logh->type == NETSNMP_LOGHANDLER_STDERR)) {
650 return 1;
651 }
652
653 return 0;
654 }
655
656 void
snmp_disable_stderrlog(void)657 snmp_disable_stderrlog(void)
658 {
659 netsnmp_log_handler *logh;
660
661 for (logh = logh_head; logh; logh = logh->next)
662 if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
663 logh->type == NETSNMP_LOGHANDLER_STDERR)) {
664 netsnmp_disable_this_loghandler(logh);
665 }
666 }
667 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
668
669 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
670 void
snmp_disable_calllog(void)671 snmp_disable_calllog(void)
672 {
673 netsnmp_log_handler *logh;
674
675 for (logh = logh_head; logh; logh = logh->next)
676 if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
677 netsnmp_disable_this_loghandler(logh);
678 }
679 }
680 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
681
682 void
snmp_disable_log(void)683 snmp_disable_log(void)
684 {
685 netsnmp_log_handler *logh;
686
687 for (logh = logh_head; logh; logh = logh->next) {
688 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
689 if (logh->type == NETSNMP_LOGHANDLER_SYSLOG)
690 snmp_disable_syslog_entry(logh);
691 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
692 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
693 if (logh->type == NETSNMP_LOGHANDLER_FILE)
694 snmp_disable_filelog_entry(logh);
695 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
696 netsnmp_disable_this_loghandler(logh);
697 }
698 }
699
700 /*
701 * close and reopen all file based logs, to allow logfile
702 * rotation.
703 */
704 void
netsnmp_logging_restart(void)705 netsnmp_logging_restart(void)
706 {
707 netsnmp_log_handler *logh;
708 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
709 int doneone = 0;
710 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
711
712 for (logh = logh_head; logh; logh = logh->next) {
713 if (0 == logh->enabled)
714 continue;
715 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
716 if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
717 snmp_disable_syslog_entry(logh);
718 snmp_enable_syslog_ident(logh->token,(int)(intptr_t)logh->magic);
719 doneone = 1;
720 }
721 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
722 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
723 if (logh->type == NETSNMP_LOGHANDLER_FILE && !doneone) {
724 snmp_disable_filelog_entry(logh);
725 /** hmm, don't zero status isn't saved.. i think it's
726 * safer not to overwrite, in case a hup is just to
727 * re-read config files...
728 */
729 netsnmp_enable_filelog(logh, 1);
730 }
731 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
732 }
733 }
734
735 /* ================================================== */
736
737 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
738 void
snmp_enable_syslog(void)739 snmp_enable_syslog(void)
740 {
741 snmp_enable_syslog_ident(snmp_log_syslogname(NULL), LOG_DAEMON);
742 }
743
744 void
snmp_enable_syslog_ident(const char * ident,const int facility)745 snmp_enable_syslog_ident(const char *ident, const int facility)
746 {
747 netsnmp_log_handler *logh;
748 int found = 0;
749 int enable = 1;
750 #ifdef WIN32
751 HANDLE eventlog_h;
752 #else
753 void *eventlog_h = NULL;
754 #endif
755
756 snmp_disable_syslog(); /* only one syslog at a time */
757 #ifdef WIN32
758 eventlog_h = OpenEventLog(NULL, ident);
759 if (eventlog_h == NULL) {
760 /*
761 * Hmmm.....
762 * Maybe disable this handler, and log the error ?
763 */
764 fprintf(stderr, "Could not open event log for %s. Last error: %u\n",
765 ident, (unsigned int)GetLastError());
766 enable = 0;
767 }
768 #else
769 openlog(snmp_log_syslogname(ident), LOG_CONS | LOG_PID, facility);
770 #endif
771
772 for (logh = logh_head; logh; logh = logh->next)
773 if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) {
774 logh->magic = (void*)eventlog_h;
775 logh->imagic = enable; /* syslog open */
776 if (logh->enabled && (0 == enable))
777 netsnmp_disable_this_loghandler(logh);
778 else if ((0 == logh->enabled) && enable)
779 netsnmp_enable_this_loghandler(logh);
780 found = 1;
781 }
782
783 if (!found) {
784 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG,
785 LOG_DEBUG );
786 if (logh) {
787 logh->magic = (void*)eventlog_h;
788 logh->token = strdup(ident);
789 logh->imagic = enable; /* syslog open */
790 if (logh->enabled && (0 == enable))
791 netsnmp_disable_this_loghandler(logh);
792 else if ((0 == logh->enabled) && enable)
793 netsnmp_enable_this_loghandler(logh);
794 }
795 }
796 }
797 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
798
799 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
800 void
netsnmp_enable_filelog(netsnmp_log_handler * logh,int dont_zero_log)801 netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log)
802 {
803 FILE *logfile;
804
805 if (!logh)
806 return;
807
808 if (!logh->magic) {
809 logfile = fopen(logh->token, dont_zero_log ? "a" : "w");
810 if (!logfile) {
811 snmp_log_perror(logh->token);
812 return;
813 }
814 logh->magic = (void*)logfile;
815 netsnmp_set_line_buffering(logfile);
816 }
817 netsnmp_enable_this_loghandler(logh);
818 }
819
820 netsnmp_log_handler *
netsnmp_register_filelog_handler(const char * logfilename,int priority,int priority_max,int dont_zero_log)821 netsnmp_register_filelog_handler(const char* logfilename, int priority,
822 int priority_max, int dont_zero_log)
823 {
824 netsnmp_log_handler *logh =
825 netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE,
826 priority );
827 if (NULL == logh)
828 return NULL;
829 logh->pri_max = priority_max;
830 logh->token = strdup(logfilename);
831 if (-1 == dont_zero_log)
832 dont_zero_log = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
833 NETSNMP_DS_LIB_APPEND_LOGFILES);
834 netsnmp_enable_filelog(logh, dont_zero_log);
835 return logh;
836 }
837
838 void
snmp_enable_filelog(const char * logfilename,int dont_zero_log)839 snmp_enable_filelog(const char *logfilename, int dont_zero_log)
840 {
841 netsnmp_log_handler *logh;
842
843 /*
844 * don't disable ALL filelogs whenever a new one is enabled.
845 * this prevents '-Lf file' from working in snmpd, as the
846 * call to set up /var/log/snmpd.log will disable the previous
847 * log setup.
848 * snmp_disable_filelog();
849 */
850
851 if (logfilename) {
852 logh = netsnmp_find_loghandler( logfilename );
853 if (!logh)
854 logh = netsnmp_register_filelog_handler( logfilename, LOG_DEBUG,
855 0, dont_zero_log );
856 else
857 netsnmp_enable_filelog(logh, dont_zero_log);
858 } else {
859 for (logh = logh_head; logh; logh = logh->next)
860 if (logh->type == NETSNMP_LOGHANDLER_FILE)
861 netsnmp_enable_filelog(logh, dont_zero_log);
862 }
863 }
864 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
865
866
867 #ifndef NETSNMP_FEATURE_REMOVE_ENABLE_STDERRLOG
868 /* used in the perl modules and ip-mib/ipv4InterfaceTable/ipv4InterfaceTable_subagent.c */
869 void
snmp_enable_stderrlog(void)870 snmp_enable_stderrlog(void)
871 {
872 netsnmp_log_handler *logh;
873 int found = 0;
874
875 for (logh = logh_head; logh; logh = logh->next)
876 if (logh->type == NETSNMP_LOGHANDLER_STDOUT ||
877 logh->type == NETSNMP_LOGHANDLER_STDERR) {
878 netsnmp_enable_this_loghandler(logh);
879 found = 1;
880 }
881
882 if (!found) {
883 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR,
884 LOG_DEBUG );
885 if (logh)
886 logh->token = strdup("stderr");
887 }
888 }
889 #endif /* NETSNMP_FEATURE_REMOVE_ENABLE_STDERRLOG */
890
891 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG
892 void
snmp_enable_calllog(void)893 snmp_enable_calllog(void) /* XXX - or take a callback routine ??? */
894 {
895 netsnmp_log_handler *logh;
896 int found = 0;
897
898 for (logh = logh_head; logh; logh = logh->next)
899 if (logh->type == NETSNMP_LOGHANDLER_CALLBACK) {
900 netsnmp_enable_this_loghandler(logh);
901 found = 1;
902 }
903
904 if (!found) {
905 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_CALLBACK,
906 LOG_DEBUG );
907 if (logh)
908 logh->token = strdup("callback");
909 }
910 }
911 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_CALLLOG */
912
913
914 /* ==================================================== */
915
916
917 netsnmp_log_handler *
netsnmp_find_loghandler(const char * token)918 netsnmp_find_loghandler( const char *token )
919 {
920 netsnmp_log_handler *logh;
921 if (!token)
922 return NULL;
923
924 for (logh = logh_head; logh; logh = logh->next)
925 if (logh->token && !strcmp( token, logh->token ))
926 break;
927
928 return logh;
929 }
930
931 int
netsnmp_add_loghandler(netsnmp_log_handler * logh)932 netsnmp_add_loghandler( netsnmp_log_handler *logh )
933 {
934 int i;
935 netsnmp_log_handler *logh2;
936
937 if (!logh)
938 return 0;
939
940 /*
941 * Find the appropriate point for the new entry...
942 * (logh2 will point to the entry immediately following)
943 */
944 for (logh2 = logh_head; logh2; logh2 = logh2->next)
945 if ( logh2->priority >= logh->priority )
946 break;
947
948 /*
949 * ... and link it into the main list.
950 */
951 if (logh2) {
952 if (logh2->prev)
953 logh2->prev->next = logh;
954 else
955 logh_head = logh;
956 logh->next = logh2;
957 logh2->prev = logh;
958 } else if (logh_head ) {
959 /*
960 * If logh2 is NULL, we're tagging on to the end
961 */
962 for (logh2 = logh_head; logh2->next; logh2 = logh2->next)
963 ;
964 logh2->next = logh;
965 } else {
966 logh_head = logh;
967 }
968
969 /*
970 * Also tweak the relevant priority-'index' array.
971 */
972 for (i=LOG_EMERG; i<=logh->priority; i++)
973 if (!logh_priorities[i] ||
974 logh_priorities[i]->priority >= logh->priority)
975 logh_priorities[i] = logh;
976
977 return 1;
978 }
979
980 netsnmp_log_handler *
netsnmp_register_loghandler(int type,int priority)981 netsnmp_register_loghandler( int type, int priority )
982 {
983 netsnmp_log_handler *logh;
984
985 logh = SNMP_MALLOC_TYPEDEF(netsnmp_log_handler);
986 if (!logh)
987 return NULL;
988
989 DEBUGMSGT(("logging:register", "registering log type %d with pri %d\n",
990 type, priority));
991 if (priority > LOG_DEBUG) {
992 DEBUGMSGT(("logging:register", " limiting pri %d to %d\n", priority,
993 LOG_DEBUG));
994 priority = LOG_DEBUG;
995 }
996
997 logh->type = type;
998 switch ( type ) {
999 case NETSNMP_LOGHANDLER_STDOUT:
1000 logh->imagic = 1;
1001 logh->handler = log_handler_stdouterr;
1002 break;
1003 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1004 case NETSNMP_LOGHANDLER_STDERR:
1005 logh->handler = log_handler_stdouterr;
1006 break;
1007 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1008
1009 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1010 case NETSNMP_LOGHANDLER_FILE:
1011 logh->handler = log_handler_file;
1012 logh->imagic = 1;
1013 break;
1014 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1015 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1016 case NETSNMP_LOGHANDLER_SYSLOG:
1017 logh->handler = log_handler_syslog;
1018 break;
1019 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1020 case NETSNMP_LOGHANDLER_CALLBACK:
1021 logh->handler = log_handler_callback;
1022 break;
1023 case NETSNMP_LOGHANDLER_NONE:
1024 logh->handler = log_handler_null;
1025 break;
1026 default:
1027 free(logh);
1028 return NULL;
1029 }
1030 logh->priority = priority;
1031 netsnmp_enable_this_loghandler(logh);
1032 netsnmp_add_loghandler( logh );
1033 return logh;
1034 }
1035
1036
1037 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER
1038 int
netsnmp_enable_loghandler(const char * token)1039 netsnmp_enable_loghandler( const char *token )
1040 {
1041 netsnmp_log_handler *logh;
1042
1043 logh = netsnmp_find_loghandler( token );
1044 if (!logh)
1045 return 0;
1046 netsnmp_enable_this_loghandler(logh);
1047 return 1;
1048 }
1049
1050
1051 int
netsnmp_disable_loghandler(const char * token)1052 netsnmp_disable_loghandler( const char *token )
1053 {
1054 netsnmp_log_handler *logh;
1055
1056 logh = netsnmp_find_loghandler( token );
1057 if (!logh)
1058 return 0;
1059 netsnmp_disable_this_loghandler(logh);
1060 return 1;
1061 }
1062 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_ENABLE_LOGHANDLER */
1063
1064 int
netsnmp_remove_loghandler(netsnmp_log_handler * logh)1065 netsnmp_remove_loghandler( netsnmp_log_handler *logh )
1066 {
1067 int i;
1068 if (!logh)
1069 return 0;
1070
1071 if (logh->prev)
1072 logh->prev->next = logh->next;
1073 else
1074 logh_head = logh->next;
1075
1076 if (logh->next)
1077 logh->next->prev = logh->prev;
1078
1079 for (i=LOG_EMERG; i<=logh->priority; i++)
1080 if (logh == logh_priorities[i])
1081 logh_priorities[i] = logh->next;
1082 free(NETSNMP_REMOVE_CONST(char*, logh->token));
1083 SNMP_FREE(logh);
1084
1085 return 1;
1086 }
1087
1088 /* ==================================================== */
1089
1090 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1091 int
log_handler_stdouterr(netsnmp_log_handler * logh,int pri,const char * str)1092 log_handler_stdouterr( netsnmp_log_handler* logh, int pri, const char *str)
1093 {
1094 static int newline = 1; /* MTCRITICAL_RESOURCE */
1095 const char *newline_ptr;
1096 char sbuf[40];
1097
1098 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1099 NETSNMP_DS_LIB_LOG_TIMESTAMP) && newline) {
1100 sprintf_stamp(NULL, sbuf);
1101 } else {
1102 strcpy(sbuf, "");
1103 }
1104 /*
1105 * Remember whether or not the current line ends with a newline for the
1106 * next call of log_handler_stdouterr().
1107 */
1108 newline_ptr = strrchr(str, '\n');
1109 newline = newline_ptr && newline_ptr[1] == 0;
1110
1111 if (logh->imagic)
1112 printf( "%s%s", sbuf, str);
1113 else
1114 fprintf(stderr, "%s%s", sbuf, str);
1115
1116 return 1;
1117 }
1118 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1119
1120
1121 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1122 #ifdef WIN32
1123 int
log_handler_syslog(netsnmp_log_handler * logh,int pri,const char * str)1124 log_handler_syslog( netsnmp_log_handler* logh, int pri, const char *str)
1125 {
1126 WORD etype;
1127 LPCTSTR event_msg[2];
1128 HANDLE eventlog_h = logh->magic;
1129
1130 /*
1131 ** EVENT TYPES:
1132 **
1133 ** Information (EVENTLOG_INFORMATION_TYPE)
1134 ** Information events indicate infrequent but significant
1135 ** successful operations.
1136 ** Warning (EVENTLOG_WARNING_TYPE)
1137 ** Warning events indicate problems that are not immediately
1138 ** significant, but that may indicate conditions that could
1139 ** cause future problems. Resource consumption is a good
1140 ** candidate for a warning event.
1141 ** Error (EVENTLOG_ERROR_TYPE)
1142 ** Error events indicate significant problems that the user
1143 ** should know about. Error events usually indicate a loss of
1144 ** functionality or data.
1145 */
1146 switch (pri) {
1147 case LOG_EMERG:
1148 case LOG_ALERT:
1149 case LOG_CRIT:
1150 case LOG_ERR:
1151 etype = EVENTLOG_ERROR_TYPE;
1152 break;
1153 case LOG_WARNING:
1154 etype = EVENTLOG_WARNING_TYPE;
1155 break;
1156 case LOG_NOTICE:
1157 case LOG_INFO:
1158 case LOG_DEBUG:
1159 etype = EVENTLOG_INFORMATION_TYPE;
1160 break;
1161 default:
1162 etype = EVENTLOG_INFORMATION_TYPE;
1163 break;
1164 }
1165 event_msg[0] = str;
1166 event_msg[1] = NULL;
1167 /* NOTE: 4th parameter must match winservice.mc:MessageId value */
1168 if (!ReportEvent(eventlog_h, etype, 0, 100, NULL, 1, 0, event_msg, NULL)) {
1169 /*
1170 * Hmmm.....
1171 * Maybe disable this handler, and log the error ?
1172 */
1173 fprintf(stderr, "Could not report event. Last error: %u\n",
1174 (unsigned int)GetLastError());
1175 return 0;
1176 }
1177 return 1;
1178 }
1179 #else
1180 int
log_handler_syslog(netsnmp_log_handler * logh,int pri,const char * str)1181 log_handler_syslog( netsnmp_log_handler* logh, int pri, const char *str)
1182 {
1183 /*
1184 * XXX
1185 * We've got three items of information to work with:
1186 * Is the syslog currently open?
1187 * What ident string to use?
1188 * What facility to log to?
1189 *
1190 * We've got two "magic" locations (imagic & magic) plus the token
1191 */
1192 if (!(logh->imagic)) {
1193 const char *ident = logh->token;
1194 int facility = (int)(intptr_t)logh->magic;
1195 if (!ident)
1196 ident = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1197 NETSNMP_DS_LIB_APPTYPE);
1198 openlog(ident, LOG_CONS | LOG_PID, facility);
1199 logh->imagic = 1;
1200 }
1201 syslog( pri, "%s", str );
1202 return 1;
1203 }
1204 #endif /* !WIN32 */
1205 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1206
1207
1208 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
1209 int
log_handler_file(netsnmp_log_handler * logh,int pri,const char * str)1210 log_handler_file( netsnmp_log_handler* logh, int pri, const char *str)
1211 {
1212 FILE *fhandle;
1213 char sbuf[40];
1214 int len = strlen( str );
1215
1216 /*
1217 * We use imagic to save information about whether the next output
1218 * will start a new line, and thus might need a timestamp
1219 */
1220 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1221 NETSNMP_DS_LIB_LOG_TIMESTAMP) && logh->imagic) {
1222 sprintf_stamp(NULL, sbuf);
1223 } else {
1224 strcpy(sbuf, "");
1225 }
1226
1227 /*
1228 * If we haven't already opened the file, then do so.
1229 * Save the filehandle pointer for next time.
1230 *
1231 * Note that this should still work, even if the file
1232 * is closed in the meantime (e.g. a regular "cleanup" sweep)
1233 */
1234 fhandle = (FILE*)logh->magic;
1235 if (!logh->magic) {
1236 fhandle = fopen(logh->token, "a+");
1237 if (!fhandle)
1238 return 0;
1239 logh->magic = (void*)fhandle;
1240 }
1241 fprintf(fhandle, "%s%s", sbuf, str);
1242 fflush(fhandle);
1243 if (len > 0) {
1244 logh->imagic = str[len - 1] == '\n';
1245 } else {
1246 logh->imagic = 0;
1247 }
1248 return 1;
1249 }
1250 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
1251
1252 int
log_handler_callback(netsnmp_log_handler * logh,int pri,const char * str)1253 log_handler_callback(netsnmp_log_handler* logh, int pri, const char *str)
1254 {
1255 /*
1256 * XXX - perhaps replace 'snmp_call_callbacks' processing
1257 * with individual callback log_handlers ??
1258 */
1259 struct snmp_log_message slm;
1260 int dodebug = snmp_get_do_debugging();
1261
1262 slm.priority = pri;
1263 slm.msg = str;
1264 if (dodebug) /* turn off debugging inside the callbacks else will loop */
1265 snmp_set_do_debugging(0);
1266 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, &slm);
1267 if (dodebug)
1268 snmp_set_do_debugging(dodebug);
1269 return 1;
1270 }
1271
1272 int
log_handler_null(netsnmp_log_handler * logh,int pri,const char * str)1273 log_handler_null( netsnmp_log_handler* logh, int pri, const char *str)
1274 {
1275 /*
1276 * Dummy log handler - just throw away the error completely
1277 * You probably don't really want to do this!
1278 */
1279 return 1;
1280 }
1281
1282 void
snmp_log_string(int priority,const char * str)1283 snmp_log_string(int priority, const char *str)
1284 {
1285 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1286 static int stderr_enabled = 0;
1287 static netsnmp_log_handler lh = { 1, 0, 0, 0, "stderr",
1288 log_handler_stdouterr, 0, NULL, NULL,
1289 NULL };
1290 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1291 netsnmp_log_handler *logh;
1292
1293 /*
1294 * We've got to be able to log messages *somewhere*!
1295 * If you don't want stderr logging, then enable something else.
1296 */
1297 if (0 == logh_enabled) {
1298 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1299 if (!stderr_enabled) {
1300 ++stderr_enabled;
1301 netsnmp_set_line_buffering(stderr);
1302 }
1303 log_handler_stdouterr( &lh, priority, str );
1304 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1305
1306 return;
1307 }
1308 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
1309 else if (stderr_enabled) {
1310 stderr_enabled = 0;
1311 log_handler_stdouterr( &lh, LOG_INFO,
1312 "Log handling defined - disabling stderr\n" );
1313 }
1314 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
1315
1316
1317 /*
1318 * Start at the given priority, and work "upwards"....
1319 */
1320 if (priority > LOG_DEBUG)
1321 priority = LOG_DEBUG;
1322 logh = logh_priorities[priority];
1323 for ( ; logh; logh = logh->next ) {
1324 /*
1325 * ... but skipping any handlers with a "maximum priority"
1326 * that we have already exceeded. And don't forget to
1327 * ensure this logging is turned on (see snmp_disable_stderrlog
1328 * and its cohorts).
1329 */
1330 if (logh->enabled && (priority >= logh->pri_max))
1331 logh->handler( logh, priority, str );
1332 }
1333 }
1334
1335 /* ==================================================== */
1336
1337
1338 /**
1339 * This snmp logging function allows variable argument list given the
1340 * specified priority, format and a populated va_list structure.
1341 * The default logfile this function writes to is /var/log/snmpd.log.
1342 *
1343 * @param priority is an integer representing the type of message to be written
1344 * to the snmp log file. The types are errors, warning, and information.
1345 * - The error types are:
1346 * - LOG_EMERG system is unusable
1347 * - LOG_ALERT action must be taken immediately
1348 * - LOG_CRIT critical conditions
1349 * - LOG_ERR error conditions
1350 * - The warning type is:
1351 * - LOG_WARNING warning conditions
1352 * - The information types are:
1353 * - LOG_NOTICE normal but significant condition
1354 * - LOG_INFO informational
1355 * - LOG_DEBUG debug-level messages
1356 *
1357 * @param format is a pointer to a char representing the variable argument list
1358 * format used.
1359 *
1360 * @param ap is a va_list type used to traverse the list of arguments.
1361 *
1362 * @return Returns 0 on success, -1 when the code could not format the log-
1363 * string, -2 when dynamic memory could not be allocated if the length
1364 * of the log buffer is greater then 1024 bytes. For each of these
1365 * errors a LOG_ERR messgae is written to the logfile.
1366 *
1367 * @see snmp_log
1368 */
1369 int
snmp_vlog(int priority,const char * format,va_list ap)1370 snmp_vlog(int priority, const char *format, va_list ap)
1371 {
1372 char *buffer = NULL;
1373 int length;
1374
1375 length = vasprintf(&buffer, format, ap);
1376 if (length < 0) {
1377 snmp_log_string(LOG_ERR, "Could not format log-string\n");
1378 return -1;
1379 }
1380
1381 snmp_log_string(priority, buffer);
1382 free(buffer);
1383 return 0;
1384 }
1385
1386 /**
1387 * This snmp logging function allows variable argument list given the
1388 * specified format and priority. Calls the snmp_vlog function.
1389 * The default logfile this function writes to is /var/log/snmpd.log.
1390 *
1391 * @see snmp_vlog
1392 */
1393 int
snmp_log(int priority,const char * format,...)1394 snmp_log(int priority, const char *format, ...)
1395 {
1396 va_list ap;
1397 int ret;
1398 va_start(ap, format);
1399 ret = snmp_vlog(priority, format, ap);
1400 va_end(ap);
1401 return (ret);
1402 }
1403
1404 /*
1405 * log a critical error.
1406 */
1407 void
snmp_log_perror(const char * s)1408 snmp_log_perror(const char *s)
1409 {
1410 char *error = strerror(errno);
1411 if (s) {
1412 if (error)
1413 snmp_log(LOG_ERR, "%s: %s\n", s, error);
1414 else
1415 snmp_log(LOG_ERR, "%s: Error %d out-of-range\n", s, errno);
1416 } else {
1417 if (error)
1418 snmp_log(LOG_ERR, "%s\n", error);
1419 else
1420 snmp_log(LOG_ERR, "Error %d out-of-range\n", errno);
1421 }
1422 }
1423
1424 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL
1425 /* external access to logh_head variable */
1426 netsnmp_log_handler *
get_logh_head(void)1427 get_logh_head(void)
1428 {
1429 return logh_head;
1430 }
1431 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_EXTERNAL */
1432
1433 /** @} */
1434