]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/ircd_log.c
Initial import of 2.10.12.01
[irc/quakenet/snircd.git] / ircd / ircd_log.c
1 /************************************************************************
2 * IRC - Internet Relay Chat, src/ircd_log.c
3 * Copyright (C) 1999 Thomas Helvey (BleepSoft)
4 * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
5 *
6 * See file AUTHORS in IRC package for additional names of
7 * the programmers.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 /** @file
24 * @brief IRC logging implementation.
25 * @version $Id: ircd_log.c,v 1.22 2005/08/25 01:26:46 entrope Exp $
26 */
27 #include "config.h"
28
29 #include "ircd_log.h"
30 #include "client.h"
31 #include "ircd_alloc.h"
32 #include "ircd_reply.h"
33 #include "ircd_snprintf.h"
34 #include "ircd_string.h"
35 #include "ircd.h"
36 #include "numeric.h"
37 #include "s_debug.h"
38 #include "send.h"
39 #include "struct.h"
40
41 /* #include <assert.h> -- Now using assert in ircd_log.h */
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 #include <sys/uio.h>
51 #include <syslog.h>
52 #include <time.h>
53 #include <unistd.h>
54
55 int log_inassert = 0;
56
57 #define LOG_BUFSIZE 2048 /**< Maximum length for a log message. */
58
59 /** Select default log level cutoff. */
60 #ifdef DEBUGMODE
61 # define L_DEFAULT L_DEBUG
62 #else
63 # define L_DEFAULT L_INFO
64 #endif
65
66 #define LOG_DOSYSLOG 0x10 /**< Try to use syslog. */
67 #define LOG_DOFILELOG 0x20 /**< Try to log to a file. */
68 #define LOG_DOSNOTICE 0x40 /**< Try to notify operators via notice. */
69 /** Bitmask of valid delivery mechanisms. */
70 #define LOG_DOMASK (LOG_DOSYSLOG | LOG_DOFILELOG | LOG_DOSNOTICE)
71
72 /** Map severity levels to strings and syslog levels */
73 static struct LevelData {
74 enum LogLevel level; /**< Log level being described. */
75 char *string; /**< Textual name of level. */
76 int syslog; /**< Syslog priority for log level. */
77 unsigned int snomask; /**< Server notice mask; 0 means use default in LogDesc. */
78 } levelData[] = {
79 #define L(level, syslog, mask) { L_ ## level, #level, (syslog), (mask) }
80 L(CRIT, LOG_CRIT, SNO_OLDSNO),
81 L(ERROR, LOG_ERR, 0),
82 L(WARNING, LOG_WARNING, 0),
83 L(NOTICE, LOG_NOTICE, 0),
84 L(TRACE, LOG_INFO, 0),
85 L(INFO, LOG_INFO, 0),
86 L(DEBUG, LOG_INFO, SNO_DEBUG),
87 #undef L
88 { L_LAST_LEVEL, 0, 0, 0 }
89 };
90
91 /* Just in case some implementation of syslog has them... */
92 #undef LOG_NONE
93 #undef LOG_DEFAULT
94 #undef LOG_NOTFOUND
95
96 #define LOG_NONE -1 /**< don't syslog */
97 #define LOG_DEFAULT 0 /**< syslog to logInfo.facility */
98 #define LOG_NOTFOUND -2 /**< didn't find a facility corresponding to name */
99
100 /** Map names to syslog facilities. */
101 static struct {
102 char *name; /**< Textual name of facility. */
103 int facility; /**< Facility value for syslog(). */
104 } facilities[] = {
105 #define F(fac) { #fac, LOG_ ## fac }
106 F(NONE), F(DEFAULT), F(AUTH),
107 #ifdef LOG_AUTHPRIV
108 F(AUTHPRIV),
109 #endif
110 F(CRON), F(DAEMON), F(LOCAL0), F(LOCAL1), F(LOCAL2), F(LOCAL3),
111 F(LOCAL4), F(LOCAL5), F(LOCAL6), F(LOCAL7), F(LPR), F(MAIL),
112 F(NEWS), F(USER), F(UUCP),
113 #undef F
114 { 0, 0 }
115 };
116
117 #define SNO_NONE 0x00000000 /**< don't send server notices */
118 #define SNO_NOTFOUND 0xffffffff /**< didn't find a SNO_MASK value for name */
119
120 /** Map names to snomask values. */
121 static struct {
122 char *name; /**< Name of server notice bit. */
123 unsigned int snomask; /**< Bitmask corresponding to name. */
124 } masks[] = {
125 #define M(mask) { #mask, SNO_ ## mask }
126 M(NONE), M(OLDSNO), M(SERVKILL), M(OPERKILL), M(HACK2),
127 M(HACK3), M(UNAUTH), M(TCPCOMMON), M(TOOMANY), M(HACK4),
128 M(GLINE), M(NETWORK), M(IPMISMATCH), M(THROTTLE), M(OLDREALOP),
129 M(CONNEXIT), M(DEBUG),
130 #undef M
131 { 0, 0 }
132 };
133
134 #define LOG_MARK_FILE 0x0001 /**< file has been changed */
135 #define LOG_MARK_FACILITY 0x0002 /**< facility has been changed */
136 #define LOG_MARK_SNOMASK 0x0004 /**< snomask has been changed */
137 #define LOG_MARK_LEVEL 0x0008 /**< level has been changed */
138
139 /** Descriptions of all logging subsystems. */
140 static struct LogDesc {
141 enum LogSys subsys; /**< number for subsystem */
142 char *name; /**< subsystem name */
143 struct LogFile *file; /**< file descriptor for subsystem */
144 unsigned int mark; /**< subsystem has been changed */
145 int def_fac; /**< default facility */
146 unsigned int def_sno; /**< default snomask */
147 int facility; /**< -1 means don't use syslog */
148 unsigned int snomask; /**< 0 means no server message */
149 enum LogLevel level; /**< logging level */
150 } logDesc[] = {
151 #define S(sys, p, sn) { LS_##sys, #sys, 0, 0, (p), (sn), (p), (sn), L_DEFAULT }
152 S(SYSTEM, -1, 0),
153 S(CONFIG, 0, SNO_OLDSNO),
154 S(OPERMODE, -1, SNO_HACK4),
155 S(GLINE, -1, SNO_GLINE),
156 S(JUPE, -1, SNO_NETWORK),
157 S(WHO, -1, 0),
158 S(NETWORK, -1, SNO_NETWORK),
159 S(OPERKILL, -1, 0),
160 S(SERVKILL, -1, 0),
161 S(USER, -1, 0),
162 S(OPER, -1, SNO_OLDREALOP),
163 S(RESOLVER, -1, 0),
164 S(SOCKET, -1, 0),
165 S(IAUTH, -1, SNO_NETWORK),
166 S(DEBUG, -1, SNO_DEBUG),
167 #undef S
168 { LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
169 };
170
171 /** Describes a log file. */
172 struct LogFile {
173 struct LogFile *next; /**< next log file descriptor */
174 struct LogFile **prev_p; /**< what points to us */
175 int fd; /**< file's descriptor-- -1 if not open */
176 int ref; /**< how many things refer to us? */
177 char *file; /**< file name */
178 };
179
180 /** Modifiable static information. */
181 static struct {
182 struct LogFile *filelist; /**< list of log files */
183 struct LogFile *freelist; /**< list of free'd log files */
184 int facility; /**< default facility */
185 const char *procname; /**< process's name */
186 struct LogFile *dbfile; /**< debug file */
187 } logInfo = { 0, 0, LOG_USER, "ircd", 0 };
188
189 /** Helper routine to open a log file if needed.
190 * If the log file is already open, do nothing.
191 * @param[in,out] lf Log file to open.
192 */
193 static void
194 log_open(struct LogFile *lf)
195 {
196 /* only open the file if we haven't already */
197 if (lf && lf->fd < 0) {
198 lf->fd = open(lf->file, O_WRONLY | O_CREAT | O_APPEND,
199 S_IRUSR | S_IWUSR);
200 }
201 }
202
203 #ifdef DEBUGMODE
204
205 /** Reopen debug log file. */
206 static void
207 log_debug_reopen(void)
208 {
209 if (!logInfo.dbfile) /* no open debugging file */
210 return;
211
212 if (!logInfo.dbfile->file) { /* using terminal output */
213 logInfo.dbfile->fd = 2;
214 return;
215 }
216
217 /* Ok, it's a real file; close it if necessary and use log_open to open it */
218 if (logInfo.dbfile->fd >= 0) {
219 close(logInfo.dbfile->fd);
220 logInfo.dbfile->fd = -1; /* mark that it's closed for log_open */
221 }
222
223 log_open(logInfo.dbfile);
224
225 if (logInfo.dbfile->fd < 0) { /* try again with /dev/null */
226 if ((logInfo.dbfile->fd = open("/dev/null", O_WRONLY)) < 0)
227 exit(-1);
228 }
229
230 /* massage the file descriptor to be stderr */
231 if (logInfo.dbfile->fd != 2) {
232 int fd;
233 fd = dup2(logInfo.dbfile->fd, 2);
234 close(logInfo.dbfile->fd);
235 logInfo.dbfile->fd = fd;
236 }
237 }
238
239 /** initialize debugging log file.
240 * @param[in] usetty If non-zero, log to terminal instead of file.
241 */
242 void
243 log_debug_init(int usetty)
244 {
245 logInfo.dbfile = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
246
247 logInfo.dbfile->next = 0; /* initialize debugging filename */
248 logInfo.dbfile->prev_p = 0;
249 logInfo.dbfile->fd = -1;
250 logInfo.dbfile->ref = 1;
251
252 if (usetty) /* store pathname to use */
253 logInfo.dbfile->file = 0;
254 else
255 DupString(logInfo.dbfile->file, LOGFILE);
256
257 log_debug_reopen(); /* open the debug log */
258
259 logDesc[LS_DEBUG].file = logInfo.dbfile; /* remember where it went */
260 }
261
262 #endif /* DEBUGMODE */
263
264 /** Set the debug log file name.
265 * @param[in] file File name, or NULL to select the default.
266 * @return Zero if the file was reopened; non-zero if not debugging to file.
267 */
268 static int
269 log_debug_file(const char *file)
270 {
271 #ifdef DEBUGMODE
272 if (!file)
273 file = LOGFILE;
274
275 /* If we weren't started with debugging enabled, or if we're using
276 * the terminal, don't do anything at all.
277 */
278 if (!logInfo.dbfile || !logInfo.dbfile->file)
279 return 1;
280
281 MyFree(logInfo.dbfile->file); /* free old pathname */
282 DupString(logInfo.dbfile->file, file); /* store new pathname */
283
284 log_debug_reopen(); /* reopen the debug log */
285 #endif /* DEBUGMODE */
286 return 0;
287 }
288
289 /** Initialize logging subsystem.
290 * @param[in] process_name Process name to interactions with syslog.
291 */
292 void
293 log_init(const char *process_name)
294 {
295 /* store the process name; probably belongs in ircd.c, but oh well... */
296 if (!EmptyString(process_name))
297 logInfo.procname = process_name;
298
299 /* ok, open syslog; default facility: LOG_USER */
300 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
301 }
302
303 /** Reopen log files (so admins can do things like rotate log files). */
304 void
305 log_reopen(void)
306 {
307 log_close(); /* close everything...we reopen on demand */
308
309 #ifdef DEBUGMODE
310 log_debug_reopen(); /* reopen debugging log if necessary */
311 #endif /* DEBUGMODE */
312
313 /* reopen syslog, if needed; default facility: LOG_USER */
314 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
315 }
316
317 /** Close all log files. */
318 void
319 log_close(void)
320 {
321 struct LogFile *ptr;
322
323 closelog(); /* close syslog */
324
325 for (ptr = logInfo.filelist; ptr; ptr = ptr->next) {
326 if (ptr->fd >= 0)
327 close(ptr->fd); /* close all the files... */
328
329 ptr->fd = -1;
330 }
331
332 if (logInfo.dbfile && logInfo.dbfile->file) {
333 if (logInfo.dbfile->fd >= 0)
334 close(logInfo.dbfile->fd); /* close the debug log file */
335
336 logInfo.dbfile->fd = -1;
337 }
338 }
339
340 /** Write a logging entry.
341 * @param[in] subsys Target subsystem.
342 * @param[in] severity Severity of message.
343 * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
344 * @param[in] fmt Format string for message.
345 */
346 void
347 log_write(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
348 const char *fmt, ...)
349 {
350 va_list vl;
351
352 va_start(vl, fmt);
353 log_vwrite(subsys, severity, flags, fmt, vl);
354 va_end(vl);
355 }
356
357 /** Write a logging entry using a va_list.
358 * @param[in] subsys Target subsystem.
359 * @param[in] severity Severity of message.
360 * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
361 * @param[in] fmt Format string for message.
362 * @param[in] vl Variable-length argument list for message.
363 */
364 void
365 log_vwrite(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
366 const char *fmt, va_list vl)
367 {
368 struct VarData vd;
369 struct LogDesc *desc;
370 struct LevelData *ldata;
371 struct tm *tstamp;
372 struct iovec vector[3];
373 time_t curtime;
374 char buf[LOG_BUFSIZE];
375 /* 1234567890123456789012 3 */
376 /* [2000-11-28 16:11:20] \0 */
377 char timebuf[23];
378
379 /* check basic assumptions */
380 assert(-1 < (int)subsys);
381 assert((int)subsys < LS_LAST_SYSTEM);
382 assert(-1 < (int)severity);
383 assert((int)severity < L_LAST_LEVEL);
384 assert(0 == (flags & ~LOG_NOMASK));
385 assert(0 != fmt);
386
387 /* find the log data and the severity data */
388 desc = &logDesc[subsys];
389 ldata = &levelData[severity];
390
391 /* check the set of ordering assumptions */
392 assert(desc->subsys == subsys);
393 assert(ldata->level == severity);
394
395 /* check severity... */
396 if (severity > desc->level)
397 return;
398
399 /* figure out where all we need to log */
400 if (!(flags & LOG_NOFILELOG) && desc->file) {
401 log_open(desc->file);
402 if (desc->file->fd >= 0) /* don't log to file if we can't open the file */
403 flags |= LOG_DOFILELOG;
404 }
405
406 if (!(flags & LOG_NOSYSLOG) && desc->facility >= 0)
407 flags |= LOG_DOSYSLOG; /* will syslog */
408
409 if (!(flags & LOG_NOSNOTICE) && (desc->snomask != 0 || ldata->snomask != 0))
410 flags |= LOG_DOSNOTICE; /* will send a server notice */
411
412 /* short-circuit if there's nothing to do... */
413 if (!(flags & LOG_DOMASK))
414 return;
415
416 /* Build the basic log string */
417 vd.vd_format = fmt;
418 va_copy(vd.vd_args, vl);
419
420 /* save the length for writev */
421 /* Log format: "SYSTEM [SEVERITY]: log message" */
422 vector[1].iov_len =
423 ircd_snprintf(0, buf, sizeof(buf), "%s [%s]: %v", desc->name,
424 ldata->string, &vd);
425
426 /* if we have something to write to... */
427 if (flags & LOG_DOFILELOG) {
428 curtime = TStime();
429 tstamp = localtime(&curtime); /* build the timestamp */
430
431 vector[0].iov_len =
432 ircd_snprintf(0, timebuf, sizeof(timebuf), "[%d-%d-%d %d:%02d:%02d] ",
433 tstamp->tm_year + 1900, tstamp->tm_mon + 1,
434 tstamp->tm_mday, tstamp->tm_hour, tstamp->tm_min,
435 tstamp->tm_sec);
436
437 /* set up the remaining parts of the writev vector... */
438 vector[0].iov_base = timebuf;
439 vector[1].iov_base = buf;
440
441 vector[2].iov_base = (void*) "\n"; /* terminate lines with a \n */
442 vector[2].iov_len = 1;
443
444 /* write it out to the log file */
445 writev(desc->file->fd, vector, 3);
446 }
447
448 /* oh yeah, syslog it too... */
449 if (flags & LOG_DOSYSLOG)
450 syslog(ldata->syslog | desc->facility, "%s", buf);
451
452 /* can't forget server notices... */
453 if (flags & LOG_DOSNOTICE)
454 sendto_opmask_butone(0, ldata->snomask ? ldata->snomask : desc->snomask,
455 "%s", buf);
456 }
457
458 /** Log an appropriate message for kills.
459 * @param[in] victim %Client being killed.
460 * @param[in] killer %User or server doing the killing.
461 * @param[in] inpath Peer that sent us the KILL message.
462 * @param[in] path Kill path that sent to us by \a inpath.
463 * @param[in] msg Kill reason.
464 */
465 void
466 log_write_kill(const struct Client *victim, const struct Client *killer,
467 const char *inpath, const char *path, const char *msg)
468 {
469 if (MyUser(victim))
470 log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
471 "A local client %#C KILLED by %#C Path: %s!%s %s",
472 victim, killer, inpath, path, msg);
473 else
474 log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
475 "KILL from %C For %C Path: %s!%s %s", killer, victim, inpath,
476 path, msg);
477 }
478
479 /** Find a reference-counted LogFile by file name.
480 * @param[in] file Name of file.
481 * @return A log file descriptor with LogFile::ref at least 1.
482 */
483 static struct LogFile *
484 log_file_create(const char *file)
485 {
486 struct LogFile *tmp;
487
488 assert(0 != file);
489
490 /* if one already exists for that file, return it */
491 for (tmp = logInfo.filelist; tmp; tmp = tmp->next)
492 if (!strcmp(tmp->file, file)) {
493 tmp->ref++;
494 return tmp;
495 }
496
497 if (logInfo.freelist) { /* pop one off the free list */
498 tmp = logInfo.freelist;
499 logInfo.freelist = tmp->next;
500 } else /* allocate a new one */
501 tmp = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
502
503 tmp->fd = -1; /* initialize the structure */
504 tmp->ref = 1;
505 DupString(tmp->file, file);
506
507 tmp->next = logInfo.filelist; /* link it into the list... */
508 tmp->prev_p = &logInfo.filelist;
509 if (logInfo.filelist)
510 logInfo.filelist->prev_p = &tmp->next;
511 logInfo.filelist = tmp;
512
513 return tmp;
514 }
515
516 /** Dereference a log file.
517 * If the reference count is exactly one on entry to this function,
518 * the file is closed and its structure is freed.
519 * @param[in] lf Log file to dereference.
520 */
521 static void
522 log_file_destroy(struct LogFile *lf)
523 {
524 assert(0 != lf);
525
526 if (--lf->ref == 0) {
527 if (lf->next) /* clip it out of the list */
528 lf->next->prev_p = lf->prev_p;
529 *lf->prev_p = lf->next;
530
531 lf->prev_p = 0; /* we won't use it for the free list */
532 if (lf->fd >= 0)
533 close(lf->fd);
534 lf->fd = -1;
535 MyFree(lf->file); /* free the file name */
536
537 lf->next = logInfo.freelist; /* stack it onto the free list */
538 logInfo.freelist = lf;
539 }
540 }
541
542 /** Look up a log subsystem by name.
543 * @param[in] subsys Subsystem name.
544 * @return Pointer to the subsystem's LogDesc, or NULL if none exists.
545 */
546 static struct LogDesc *
547 log_find(const char *subsys)
548 {
549 int i;
550
551 assert(0 != subsys);
552
553 /* find the named subsystem */
554 for (i = 0; i < LS_LAST_SYSTEM; i++)
555 if (!ircd_strcmp(subsys, logDesc[i].name))
556 return &logDesc[i];
557
558 return 0; /* not found */
559 }
560
561 /** Return canonical version of log subsystem name.
562 * @param[in] subsys Subsystem name.
563 * @return A constant string containing the canonical name.
564 */
565 char *
566 log_canon(const char *subsys)
567 {
568 struct LogDesc *desc;
569
570 if (!(desc = log_find(subsys)))
571 return 0;
572
573 return desc->name;
574 }
575
576 /** Look up a log level by name.
577 * @param[in] level Log level name.
578 * @return LogLevel enumeration, or L_LAST_LEVEL if none exists.
579 */
580 static enum LogLevel
581 log_lev_find(const char *level)
582 {
583 int i;
584
585 assert(0 != level);
586
587 /* find the named level */
588 for (i = 0; levelData[i].string; i++)
589 if (!ircd_strcmp(level, levelData[i].string))
590 return levelData[i].level;
591
592 return L_LAST_LEVEL; /* not found */
593 }
594
595 /** Look up the canonical name for a log level.
596 * @param[in] lev
597 * @return A constant string containing the level's canonical name.
598 */
599 static char *
600 log_lev_name(enum LogLevel lev)
601 {
602 assert(-1 < (int)lev);
603 assert((int)lev < L_LAST_LEVEL);
604 assert(lev == levelData[lev].level);
605
606 return levelData[lev].string;
607 }
608
609 /** Look up a syslog facility by name.
610 * @param[in] facility Facility name.
611 * @return Syslog facility value, or LOG_NOTFOUND if none exists.
612 */
613 static int
614 log_fac_find(const char *facility)
615 {
616 int i;
617
618 assert(0 != facility);
619
620 /* find the named facility */
621 for (i = 0; facilities[i].name; i++)
622 if (!ircd_strcmp(facility, facilities[i].name))
623 return facilities[i].facility;
624
625 return LOG_NOTFOUND; /* not found */
626 }
627
628 /** Look up the name for a syslog facility.
629 * @param[in] fac Facility value.
630 * @return Canonical name for facility, or NULL if none exists.
631 */
632 static char *
633 log_fac_name(int fac)
634 {
635 int i;
636
637 /* find the facility */
638 for (i = 0; facilities[i].name; i++)
639 if (facilities[i].facility == fac)
640 return facilities[i].name;
641
642 return 0; /* not found; should never happen */
643 }
644
645 /** Look up a server notice mask by name.
646 * @param[in] maskname Name of server notice mask.
647 * @return Bitmask for server notices, or 0 if none exists.
648 */
649 static unsigned int
650 log_sno_find(const char *maskname)
651 {
652 int i;
653
654 assert(0 != maskname);
655
656 /* find the named snomask */
657 for (i = 0; masks[i].name; i++)
658 if (!ircd_strcmp(maskname, masks[i].name))
659 return masks[i].snomask;
660
661 return SNO_NOTFOUND; /* not found */
662 }
663
664 /** Look up the canonical name for a server notice mask.
665 * @param[in] sno Server notice mask.
666 * @return Canonical name for the mask, or NULL if none exists.
667 */
668 static char *
669 log_sno_name(unsigned int sno)
670 {
671 int i;
672
673 /* find the snomask */
674 for (i = 0; masks[i].name; i++)
675 if (masks[i].snomask == sno)
676 return masks[i].name;
677
678 return 0; /* not found; should never happen */
679 }
680
681 /** Set a log file for a particular subsystem.
682 * @param[in] subsys Subsystem name.
683 * @param[in] filename Log file to write to.
684 * @return Zero on success; non-zero on error.
685 */
686 int
687 log_set_file(const char *subsys, const char *filename)
688 {
689 struct LogDesc *desc;
690
691 /* find subsystem */
692 if (!(desc = log_find(subsys)))
693 return 2;
694
695 if (filename)
696 desc->mark |= LOG_MARK_FILE; /* mark that file has been changed */
697 else
698 desc->mark &= ~LOG_MARK_FILE; /* file has been reset to defaults */
699
700 /* no change, don't go to the trouble of destroying and recreating */
701 if (desc->file && desc->file->file && filename &&
702 !strcmp(desc->file->file, filename))
703 return 0;
704
705 /* debug log is special, since it has to be opened on fd 2 */
706 if (desc->subsys == LS_DEBUG)
707 return log_debug_file(filename);
708
709 if (desc->file) /* destroy previous entry... */
710 log_file_destroy(desc->file);
711
712 /* set the file to use */
713 desc->file = filename ? log_file_create(filename) : 0;
714
715 return 0;
716 }
717
718 /** Find the log file name for a subsystem.
719 * @param[in] subsys Subsystem name.
720 * @return Log file for the subsystem, or NULL if not being logged to a file.
721 */
722 char *
723 log_get_file(const char *subsys)
724 {
725 struct LogDesc *desc;
726
727 /* find subsystem */
728 if (!(desc = log_find(subsys)))
729 return 0;
730
731 return desc->file ? desc->file->file : 0;
732 }
733
734 /** Set the syslog facility for a particular subsystem.
735 * @param[in] subsys Subsystem name.
736 * @param[in] facility Facility name to log to.
737 * @return Zero on success; non-zero on error.
738 */
739 int
740 log_set_facility(const char *subsys, const char *facility)
741 {
742 struct LogDesc *desc;
743 int fac;
744
745 /* find subsystem */
746 if (!(desc = log_find(subsys)))
747 return 2;
748
749 /* set syslog facility */
750 if (EmptyString(facility)) {
751 desc->facility = desc->def_fac;
752 desc->mark &= ~LOG_MARK_FACILITY;
753 } else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND) {
754 desc->facility = fac;
755 if (fac == desc->def_fac)
756 desc->mark &= ~LOG_MARK_FACILITY;
757 else
758 desc->mark |= LOG_MARK_FACILITY;
759 } else
760 return 1;
761
762 return 0;
763 }
764
765 /** Find the facility name for a subsystem.
766 * @param[in] subsys Subsystem name.
767 * @return Facility name being used, or NULL if not being logged to syslog.
768 */
769 char *
770 log_get_facility(const char *subsys)
771 {
772 struct LogDesc *desc;
773
774 /* find subsystem */
775 if (!(desc = log_find(subsys)))
776 return 0;
777
778 /* find the facility's name */
779 return log_fac_name(desc->facility);
780 }
781
782 /** Set the server notice mask for a subsystem.
783 * @param[in] subsys Subsystem name.
784 * @param[in] snomask Server notice mask name.
785 * @return Zero on success; non-zero on error.
786 */
787 int
788 log_set_snomask(const char *subsys, const char *snomask)
789 {
790 struct LogDesc *desc;
791 unsigned int sno = SNO_DEFAULT;
792
793 /* find subsystem */
794 if (!(desc = log_find(subsys)))
795 return 2;
796
797 /* set snomask value */
798 if (EmptyString(snomask)) {
799 desc->snomask = desc->def_sno;
800 desc->mark &= ~LOG_MARK_SNOMASK;
801 } else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND) {
802 desc->snomask = sno;
803 if (sno == desc->def_sno)
804 desc->mark &= ~LOG_MARK_SNOMASK;
805 else
806 desc->mark |= LOG_MARK_SNOMASK;
807 } else
808 return 1;
809
810 return 0;
811 }
812
813 /** Find the server notice mask name for a subsystem.
814 * @param[in] subsys Subsystem name.
815 * @return Name of server notice mask being used, or NULL if none.
816 */
817 char *
818 log_get_snomask(const char *subsys)
819 {
820 struct LogDesc *desc;
821
822 /* find subsystem */
823 if (!(desc = log_find(subsys)))
824 return 0;
825
826 /* find the snomask value's name */
827 return log_sno_name(desc->snomask);
828 }
829
830 /** Set the verbosity level for a subsystem.
831 * @param[in] subsys Subsystem name.
832 * @param[in] level Minimum log level.
833 * @return Zero on success; non-zero on error.
834 */
835 int
836 log_set_level(const char *subsys, const char *level)
837 {
838 struct LogDesc *desc;
839 enum LogLevel lev;
840
841 /* find subsystem */
842 if (!(desc = log_find(subsys)))
843 return 2;
844
845 /* set logging level */
846 if (EmptyString(level)) {
847 desc->level = L_DEFAULT;
848 desc->mark &= ~LOG_MARK_LEVEL;
849 } else if ((lev = log_lev_find(level)) != L_LAST_LEVEL) {
850 desc->level = lev;
851 if (lev == L_DEFAULT)
852 desc->mark &= ~LOG_MARK_LEVEL;
853 else
854 desc->mark |= LOG_MARK_LEVEL;
855 } else
856 return 1;
857
858 return 0;
859 }
860
861 /** Find the verbosity level for a subsystem.
862 * @param[in] subsys Subsystem name.
863 * @return Minimum verbosity level being used, or NULL on error.
864 */
865 char *
866 log_get_level(const char *subsys)
867 {
868 struct LogDesc *desc;
869
870 /* find subsystem */
871 if (!(desc = log_find(subsys)))
872 return 0;
873
874 /* find the level's name */
875 return log_lev_name(desc->level);
876 }
877
878 /** Set the default syslog facility.
879 * @param[in] facility Syslog facility name.
880 * @return Zero on success, non-zero on error.
881 */
882 int
883 log_set_default(const char *facility)
884 {
885 int fac, oldfac;
886
887 oldfac = logInfo.facility;
888
889 if (EmptyString(facility))
890 logInfo.facility = LOG_USER;
891 else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND &&
892 fac != LOG_NONE && fac != LOG_DEFAULT)
893 logInfo.facility = fac;
894 else
895 return 1;
896
897 if (logInfo.facility != oldfac) {
898 closelog(); /* reopen syslog with new facility setting */
899 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
900 }
901
902 return 0;
903 }
904
905 /** Find the default syslog facility name.
906 * @return Canonical name of default syslog facility, or NULL if none.
907 */
908 char *
909 log_get_default(void)
910 {
911 /* find the facility's name */
912 return log_fac_name(logInfo.facility);
913 }
914
915 /** Clear all marks. */
916 void
917 log_feature_unmark(void)
918 {
919 int i;
920
921 for (i = 0; i < LS_LAST_SYSTEM; i++)
922 logDesc[i].mark = 0;
923 }
924
925 /** Reset unmodified fields in all log subsystems to their defaults.
926 * @param[in] flag If non-zero, clear default syslog facility.
927 */
928 int
929 log_feature_mark(int flag)
930 {
931 int i;
932
933 if (flag)
934 log_set_default(0);
935
936 for (i = 0; i < LS_LAST_SYSTEM; i++) {
937 if (!(logDesc[i].mark & LOG_MARK_FILE)) {
938 if (logDesc[i].subsys != LS_DEBUG) { /* debug is special */
939 if (logDesc[i].file) /* destroy previous entry... */
940 log_file_destroy(logDesc[i].file);
941 logDesc[i].file = 0;
942 }
943 }
944
945 if (!(logDesc[i].mark & LOG_MARK_FACILITY)) /* set default facility */
946 logDesc[i].facility = logDesc[i].def_fac;
947
948 if (!(logDesc[i].mark & LOG_MARK_SNOMASK)) /* set default snomask */
949 logDesc[i].snomask = logDesc[i].def_sno;
950
951 if (!(logDesc[i].mark & LOG_MARK_LEVEL)) /* set default level */
952 logDesc[i].level = L_DEFAULT;
953 }
954
955 return 0; /* we don't have a notify handler */
956 }
957
958 /** Feature list callback to report log settings.
959 * @param[in] to Client requesting list.
960 * @param[in] flag If non-zero, report default syslog facility.
961 */
962 void
963 log_feature_report(struct Client *to, int flag)
964 {
965 int i;
966
967 for (i = 0; i < LS_LAST_SYSTEM; i++)
968 {
969 if (logDesc[i].mark & LOG_MARK_FILE) /* report file */
970 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FILE %s",
971 logDesc[i].name, (logDesc[i].file && logDesc[i].file->file ?
972 logDesc[i].file->file : "(terminal)"));
973
974 if (logDesc[i].mark & LOG_MARK_FACILITY) /* report facility */
975 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FACILITY %s",
976 logDesc[i].name, log_fac_name(logDesc[i].facility));
977
978 if (logDesc[i].mark & LOG_MARK_SNOMASK) /* report snomask */
979 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s SNOMASK %s",
980 logDesc[i].name, log_sno_name(logDesc[i].snomask));
981
982 if (logDesc[i].mark & LOG_MARK_LEVEL) /* report log level */
983 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s LEVEL %s",
984 logDesc[i].name, log_lev_name(logDesc[i].level));
985 }
986
987 if (flag) /* report default facility */
988 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s",
989 log_fac_name(logInfo.facility));
990 }