]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/ircd_log.c
Should be unsigned long for A
[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.2.1 2006/02/16 03:49:54 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), M(AUTH),
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 S(SETHOST, -1, SNO_OLDSNO),
168 #undef S
169 { LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
170 };
171
172 /** Describes a log file. */
173 struct LogFile {
174 struct LogFile *next; /**< next log file descriptor */
175 struct LogFile **prev_p; /**< what points to us */
176 int fd; /**< file's descriptor-- -1 if not open */
177 int ref; /**< how many things refer to us? */
178 char *file; /**< file name */
179 };
180
181 /** Modifiable static information. */
182 static struct {
183 struct LogFile *filelist; /**< list of log files */
184 struct LogFile *freelist; /**< list of free'd log files */
185 int facility; /**< default facility */
186 const char *procname; /**< process's name */
187 struct LogFile *dbfile; /**< debug file */
188 } logInfo = { 0, 0, LOG_USER, "ircd", 0 };
189
190 /** Helper routine to open a log file if needed.
191 * If the log file is already open, do nothing.
192 * @param[in,out] lf Log file to open.
193 */
194 static void
195 log_open(struct LogFile *lf)
196 {
197 /* only open the file if we haven't already */
198 if (lf && lf->fd < 0) {
199 lf->fd = open(lf->file, O_WRONLY | O_CREAT | O_APPEND,
200 S_IRUSR | S_IWUSR);
201 }
202 }
203
204 #ifdef DEBUGMODE
205
206 /** Reopen debug log file. */
207 static void
208 log_debug_reopen(void)
209 {
210 if (!logInfo.dbfile) /* no open debugging file */
211 return;
212
213 if (!logInfo.dbfile->file) { /* using terminal output */
214 logInfo.dbfile->fd = 2;
215 return;
216 }
217
218 /* Ok, it's a real file; close it if necessary and use log_open to open it */
219 if (logInfo.dbfile->fd >= 0) {
220 close(logInfo.dbfile->fd);
221 logInfo.dbfile->fd = -1; /* mark that it's closed for log_open */
222 }
223
224 log_open(logInfo.dbfile);
225
226 if (logInfo.dbfile->fd < 0) { /* try again with /dev/null */
227 if ((logInfo.dbfile->fd = open("/dev/null", O_WRONLY)) < 0)
228 exit(-1);
229 }
230
231 /* massage the file descriptor to be stderr */
232 if (logInfo.dbfile->fd != 2) {
233 int fd;
234 fd = dup2(logInfo.dbfile->fd, 2);
235 close(logInfo.dbfile->fd);
236 logInfo.dbfile->fd = fd;
237 }
238 }
239
240 /** initialize debugging log file.
241 * @param[in] usetty If non-zero, log to terminal instead of file.
242 */
243 void
244 log_debug_init(int usetty)
245 {
246 logInfo.dbfile = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
247
248 logInfo.dbfile->next = 0; /* initialize debugging filename */
249 logInfo.dbfile->prev_p = 0;
250 logInfo.dbfile->fd = -1;
251 logInfo.dbfile->ref = 1;
252
253 if (usetty) /* store pathname to use */
254 logInfo.dbfile->file = 0;
255 else
256 DupString(logInfo.dbfile->file, LOGFILE);
257
258 log_debug_reopen(); /* open the debug log */
259
260 logDesc[LS_DEBUG].file = logInfo.dbfile; /* remember where it went */
261 }
262
263 #endif /* DEBUGMODE */
264
265 /** Set the debug log file name.
266 * @param[in] file File name, or NULL to select the default.
267 * @return Zero if the file was reopened; non-zero if not debugging to file.
268 */
269 static int
270 log_debug_file(const char *file)
271 {
272 #ifdef DEBUGMODE
273 if (!file)
274 file = LOGFILE;
275
276 /* If we weren't started with debugging enabled, or if we're using
277 * the terminal, don't do anything at all.
278 */
279 if (!logInfo.dbfile || !logInfo.dbfile->file)
280 return 1;
281
282 MyFree(logInfo.dbfile->file); /* free old pathname */
283 DupString(logInfo.dbfile->file, file); /* store new pathname */
284
285 log_debug_reopen(); /* reopen the debug log */
286 #endif /* DEBUGMODE */
287 return 0;
288 }
289
290 /** Initialize logging subsystem.
291 * @param[in] process_name Process name to interactions with syslog.
292 */
293 void
294 log_init(const char *process_name)
295 {
296 /* store the process name; probably belongs in ircd.c, but oh well... */
297 if (!EmptyString(process_name))
298 logInfo.procname = process_name;
299
300 /* ok, open syslog; default facility: LOG_USER */
301 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
302 }
303
304 /** Reopen log files (so admins can do things like rotate log files). */
305 void
306 log_reopen(void)
307 {
308 log_close(); /* close everything...we reopen on demand */
309
310 #ifdef DEBUGMODE
311 log_debug_reopen(); /* reopen debugging log if necessary */
312 #endif /* DEBUGMODE */
313
314 /* reopen syslog, if needed; default facility: LOG_USER */
315 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
316 }
317
318 /** Close all log files. */
319 void
320 log_close(void)
321 {
322 struct LogFile *ptr;
323
324 closelog(); /* close syslog */
325
326 for (ptr = logInfo.filelist; ptr; ptr = ptr->next) {
327 if (ptr->fd >= 0)
328 close(ptr->fd); /* close all the files... */
329
330 ptr->fd = -1;
331 }
332
333 if (logInfo.dbfile && logInfo.dbfile->file) {
334 if (logInfo.dbfile->fd >= 0)
335 close(logInfo.dbfile->fd); /* close the debug log file */
336
337 logInfo.dbfile->fd = -1;
338 }
339 }
340
341 /** Write a logging entry.
342 * @param[in] subsys Target subsystem.
343 * @param[in] severity Severity of message.
344 * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
345 * @param[in] fmt Format string for message.
346 */
347 void
348 log_write(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
349 const char *fmt, ...)
350 {
351 va_list vl;
352
353 va_start(vl, fmt);
354 log_vwrite(subsys, severity, flags, fmt, vl);
355 va_end(vl);
356 }
357
358 /** Write a logging entry using a va_list.
359 * @param[in] subsys Target subsystem.
360 * @param[in] severity Severity of message.
361 * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
362 * @param[in] fmt Format string for message.
363 * @param[in] vl Variable-length argument list for message.
364 */
365 void
366 log_vwrite(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
367 const char *fmt, va_list vl)
368 {
369 struct VarData vd;
370 struct LogDesc *desc;
371 struct LevelData *ldata;
372 struct tm *tstamp;
373 struct iovec vector[3];
374 time_t curtime;
375 char buf[LOG_BUFSIZE];
376 /* 1234567890123456789012 3 */
377 /* [2000-11-28 16:11:20] \0 */
378 char timebuf[23];
379
380 /* check basic assumptions */
381 assert(-1 < (int)subsys);
382 assert((int)subsys < LS_LAST_SYSTEM);
383 assert(-1 < (int)severity);
384 assert((int)severity < L_LAST_LEVEL);
385 assert(0 == (flags & ~LOG_NOMASK));
386 assert(0 != fmt);
387
388 /* find the log data and the severity data */
389 desc = &logDesc[subsys];
390 ldata = &levelData[severity];
391
392 /* check the set of ordering assumptions */
393 assert(desc->subsys == subsys);
394 assert(ldata->level == severity);
395
396 /* check severity... */
397 if (severity > desc->level)
398 return;
399
400 /* figure out where all we need to log */
401 if (!(flags & LOG_NOFILELOG) && desc->file) {
402 log_open(desc->file);
403 if (desc->file->fd >= 0) /* don't log to file if we can't open the file */
404 flags |= LOG_DOFILELOG;
405 }
406
407 if (!(flags & LOG_NOSYSLOG) && desc->facility >= 0)
408 flags |= LOG_DOSYSLOG; /* will syslog */
409
410 if (!(flags & LOG_NOSNOTICE) && (desc->snomask != 0 || ldata->snomask != 0))
411 flags |= LOG_DOSNOTICE; /* will send a server notice */
412
413 /* short-circuit if there's nothing to do... */
414 if (!(flags & LOG_DOMASK))
415 return;
416
417 /* Build the basic log string */
418 vd.vd_format = fmt;
419 va_copy(vd.vd_args, vl);
420
421 /* save the length for writev */
422 /* Log format: "SYSTEM [SEVERITY]: log message" */
423 vector[1].iov_len =
424 ircd_snprintf(0, buf, sizeof(buf), "%s [%s]: %v", desc->name,
425 ldata->string, &vd);
426
427 /* if we have something to write to... */
428 if (flags & LOG_DOFILELOG) {
429 curtime = TStime();
430 tstamp = localtime(&curtime); /* build the timestamp */
431
432 vector[0].iov_len =
433 ircd_snprintf(0, timebuf, sizeof(timebuf), "[%d-%d-%d %d:%02d:%02d] ",
434 tstamp->tm_year + 1900, tstamp->tm_mon + 1,
435 tstamp->tm_mday, tstamp->tm_hour, tstamp->tm_min,
436 tstamp->tm_sec);
437
438 /* set up the remaining parts of the writev vector... */
439 vector[0].iov_base = timebuf;
440 vector[1].iov_base = buf;
441
442 vector[2].iov_base = (void*) "\n"; /* terminate lines with a \n */
443 vector[2].iov_len = 1;
444
445 /* write it out to the log file */
446 writev(desc->file->fd, vector, 3);
447 }
448
449 /* oh yeah, syslog it too... */
450 if (flags & LOG_DOSYSLOG)
451 syslog(ldata->syslog | desc->facility, "%s", buf);
452
453 /* can't forget server notices... */
454 if (flags & LOG_DOSNOTICE)
455 sendto_opmask_butone(0, ldata->snomask ? ldata->snomask : desc->snomask,
456 "%s", buf);
457 }
458
459 /** Log an appropriate message for kills.
460 * @param[in] victim %Client being killed.
461 * @param[in] killer %User or server doing the killing.
462 * @param[in] inpath Peer that sent us the KILL message.
463 * @param[in] path Kill path that sent to us by \a inpath.
464 * @param[in] msg Kill reason.
465 */
466 void
467 log_write_kill(const struct Client *victim, const struct Client *killer,
468 const char *inpath, const char *path, const char *msg)
469 {
470 if (MyUser(victim))
471 log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
472 "A local client %#C KILLED by %#C Path: %s!%s %s",
473 victim, killer, inpath, path, msg);
474 else
475 log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
476 "KILL from %C For %C Path: %s!%s %s", killer, victim, inpath,
477 path, msg);
478 }
479
480 /** Find a reference-counted LogFile by file name.
481 * @param[in] file Name of file.
482 * @return A log file descriptor with LogFile::ref at least 1.
483 */
484 static struct LogFile *
485 log_file_create(const char *file)
486 {
487 struct LogFile *tmp;
488
489 assert(0 != file);
490
491 /* if one already exists for that file, return it */
492 for (tmp = logInfo.filelist; tmp; tmp = tmp->next)
493 if (!strcmp(tmp->file, file)) {
494 tmp->ref++;
495 return tmp;
496 }
497
498 if (logInfo.freelist) { /* pop one off the free list */
499 tmp = logInfo.freelist;
500 logInfo.freelist = tmp->next;
501 } else /* allocate a new one */
502 tmp = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
503
504 tmp->fd = -1; /* initialize the structure */
505 tmp->ref = 1;
506 DupString(tmp->file, file);
507
508 tmp->next = logInfo.filelist; /* link it into the list... */
509 tmp->prev_p = &logInfo.filelist;
510 if (logInfo.filelist)
511 logInfo.filelist->prev_p = &tmp->next;
512 logInfo.filelist = tmp;
513
514 return tmp;
515 }
516
517 /** Dereference a log file.
518 * If the reference count is exactly one on entry to this function,
519 * the file is closed and its structure is freed.
520 * @param[in] lf Log file to dereference.
521 */
522 static void
523 log_file_destroy(struct LogFile *lf)
524 {
525 assert(0 != lf);
526
527 if (--lf->ref == 0) {
528 if (lf->next) /* clip it out of the list */
529 lf->next->prev_p = lf->prev_p;
530 *lf->prev_p = lf->next;
531
532 lf->prev_p = 0; /* we won't use it for the free list */
533 if (lf->fd >= 0)
534 close(lf->fd);
535 lf->fd = -1;
536 MyFree(lf->file); /* free the file name */
537
538 lf->next = logInfo.freelist; /* stack it onto the free list */
539 logInfo.freelist = lf;
540 }
541 }
542
543 /** Look up a log subsystem by name.
544 * @param[in] subsys Subsystem name.
545 * @return Pointer to the subsystem's LogDesc, or NULL if none exists.
546 */
547 static struct LogDesc *
548 log_find(const char *subsys)
549 {
550 int i;
551
552 assert(0 != subsys);
553
554 /* find the named subsystem */
555 for (i = 0; i < LS_LAST_SYSTEM; i++)
556 if (!ircd_strcmp(subsys, logDesc[i].name))
557 return &logDesc[i];
558
559 return 0; /* not found */
560 }
561
562 /** Return canonical version of log subsystem name.
563 * @param[in] subsys Subsystem name.
564 * @return A constant string containing the canonical name.
565 */
566 char *
567 log_canon(const char *subsys)
568 {
569 struct LogDesc *desc;
570
571 if (!(desc = log_find(subsys)))
572 return 0;
573
574 return desc->name;
575 }
576
577 /** Look up a log level by name.
578 * @param[in] level Log level name.
579 * @return LogLevel enumeration, or L_LAST_LEVEL if none exists.
580 */
581 static enum LogLevel
582 log_lev_find(const char *level)
583 {
584 int i;
585
586 assert(0 != level);
587
588 /* find the named level */
589 for (i = 0; levelData[i].string; i++)
590 if (!ircd_strcmp(level, levelData[i].string))
591 return levelData[i].level;
592
593 return L_LAST_LEVEL; /* not found */
594 }
595
596 /** Look up the canonical name for a log level.
597 * @param[in] lev
598 * @return A constant string containing the level's canonical name.
599 */
600 static char *
601 log_lev_name(enum LogLevel lev)
602 {
603 assert(-1 < (int)lev);
604 assert((int)lev < L_LAST_LEVEL);
605 assert(lev == levelData[lev].level);
606
607 return levelData[lev].string;
608 }
609
610 /** Look up a syslog facility by name.
611 * @param[in] facility Facility name.
612 * @return Syslog facility value, or LOG_NOTFOUND if none exists.
613 */
614 static int
615 log_fac_find(const char *facility)
616 {
617 int i;
618
619 assert(0 != facility);
620
621 /* find the named facility */
622 for (i = 0; facilities[i].name; i++)
623 if (!ircd_strcmp(facility, facilities[i].name))
624 return facilities[i].facility;
625
626 return LOG_NOTFOUND; /* not found */
627 }
628
629 /** Look up the name for a syslog facility.
630 * @param[in] fac Facility value.
631 * @return Canonical name for facility, or NULL if none exists.
632 */
633 static char *
634 log_fac_name(int fac)
635 {
636 int i;
637
638 /* find the facility */
639 for (i = 0; facilities[i].name; i++)
640 if (facilities[i].facility == fac)
641 return facilities[i].name;
642
643 return 0; /* not found; should never happen */
644 }
645
646 /** Look up a server notice mask by name.
647 * @param[in] maskname Name of server notice mask.
648 * @return Bitmask for server notices, or 0 if none exists.
649 */
650 static unsigned int
651 log_sno_find(const char *maskname)
652 {
653 int i;
654
655 assert(0 != maskname);
656
657 /* find the named snomask */
658 for (i = 0; masks[i].name; i++)
659 if (!ircd_strcmp(maskname, masks[i].name))
660 return masks[i].snomask;
661
662 return SNO_NOTFOUND; /* not found */
663 }
664
665 /** Look up the canonical name for a server notice mask.
666 * @param[in] sno Server notice mask.
667 * @return Canonical name for the mask, or NULL if none exists.
668 */
669 static char *
670 log_sno_name(unsigned int sno)
671 {
672 int i;
673
674 /* find the snomask */
675 for (i = 0; masks[i].name; i++)
676 if (masks[i].snomask == sno)
677 return masks[i].name;
678
679 return 0; /* not found; should never happen */
680 }
681
682 /** Set a log file for a particular subsystem.
683 * @param[in] subsys Subsystem name.
684 * @param[in] filename Log file to write to.
685 * @return Zero on success; non-zero on error.
686 */
687 int
688 log_set_file(const char *subsys, const char *filename)
689 {
690 struct LogDesc *desc;
691
692 /* find subsystem */
693 if (!(desc = log_find(subsys)))
694 return 2;
695
696 if (filename)
697 desc->mark |= LOG_MARK_FILE; /* mark that file has been changed */
698 else
699 desc->mark &= ~LOG_MARK_FILE; /* file has been reset to defaults */
700
701 /* no change, don't go to the trouble of destroying and recreating */
702 if (desc->file && desc->file->file && filename &&
703 !strcmp(desc->file->file, filename))
704 return 0;
705
706 /* debug log is special, since it has to be opened on fd 2 */
707 if (desc->subsys == LS_DEBUG)
708 return log_debug_file(filename);
709
710 if (desc->file) /* destroy previous entry... */
711 log_file_destroy(desc->file);
712
713 /* set the file to use */
714 desc->file = filename ? log_file_create(filename) : 0;
715
716 return 0;
717 }
718
719 /** Find the log file name for a subsystem.
720 * @param[in] subsys Subsystem name.
721 * @return Log file for the subsystem, or NULL if not being logged to a file.
722 */
723 char *
724 log_get_file(const char *subsys)
725 {
726 struct LogDesc *desc;
727
728 /* find subsystem */
729 if (!(desc = log_find(subsys)))
730 return 0;
731
732 return desc->file ? desc->file->file : 0;
733 }
734
735 /** Set the syslog facility for a particular subsystem.
736 * @param[in] subsys Subsystem name.
737 * @param[in] facility Facility name to log to.
738 * @return Zero on success; non-zero on error.
739 */
740 int
741 log_set_facility(const char *subsys, const char *facility)
742 {
743 struct LogDesc *desc;
744 int fac;
745
746 /* find subsystem */
747 if (!(desc = log_find(subsys)))
748 return 2;
749
750 /* set syslog facility */
751 if (EmptyString(facility)) {
752 desc->facility = desc->def_fac;
753 desc->mark &= ~LOG_MARK_FACILITY;
754 } else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND) {
755 desc->facility = fac;
756 if (fac == desc->def_fac)
757 desc->mark &= ~LOG_MARK_FACILITY;
758 else
759 desc->mark |= LOG_MARK_FACILITY;
760 } else
761 return 1;
762
763 return 0;
764 }
765
766 /** Find the facility name for a subsystem.
767 * @param[in] subsys Subsystem name.
768 * @return Facility name being used, or NULL if not being logged to syslog.
769 */
770 char *
771 log_get_facility(const char *subsys)
772 {
773 struct LogDesc *desc;
774
775 /* find subsystem */
776 if (!(desc = log_find(subsys)))
777 return 0;
778
779 /* find the facility's name */
780 return log_fac_name(desc->facility);
781 }
782
783 /** Set the server notice mask for a subsystem.
784 * @param[in] subsys Subsystem name.
785 * @param[in] snomask Server notice mask name.
786 * @return Zero on success; non-zero on error.
787 */
788 int
789 log_set_snomask(const char *subsys, const char *snomask)
790 {
791 struct LogDesc *desc;
792 unsigned int sno = SNO_DEFAULT;
793
794 /* find subsystem */
795 if (!(desc = log_find(subsys)))
796 return 2;
797
798 /* set snomask value */
799 if (EmptyString(snomask)) {
800 desc->snomask = desc->def_sno;
801 desc->mark &= ~LOG_MARK_SNOMASK;
802 } else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND) {
803 desc->snomask = sno;
804 if (sno == desc->def_sno)
805 desc->mark &= ~LOG_MARK_SNOMASK;
806 else
807 desc->mark |= LOG_MARK_SNOMASK;
808 } else
809 return 1;
810
811 return 0;
812 }
813
814 /** Find the server notice mask name for a subsystem.
815 * @param[in] subsys Subsystem name.
816 * @return Name of server notice mask being used, or NULL if none.
817 */
818 char *
819 log_get_snomask(const char *subsys)
820 {
821 struct LogDesc *desc;
822
823 /* find subsystem */
824 if (!(desc = log_find(subsys)))
825 return 0;
826
827 /* find the snomask value's name */
828 return log_sno_name(desc->snomask);
829 }
830
831 /** Set the verbosity level for a subsystem.
832 * @param[in] subsys Subsystem name.
833 * @param[in] level Minimum log level.
834 * @return Zero on success; non-zero on error.
835 */
836 int
837 log_set_level(const char *subsys, const char *level)
838 {
839 struct LogDesc *desc;
840 enum LogLevel lev;
841
842 /* find subsystem */
843 if (!(desc = log_find(subsys)))
844 return 2;
845
846 /* set logging level */
847 if (EmptyString(level)) {
848 desc->level = L_DEFAULT;
849 desc->mark &= ~LOG_MARK_LEVEL;
850 } else if ((lev = log_lev_find(level)) != L_LAST_LEVEL) {
851 desc->level = lev;
852 if (lev == L_DEFAULT)
853 desc->mark &= ~LOG_MARK_LEVEL;
854 else
855 desc->mark |= LOG_MARK_LEVEL;
856 } else
857 return 1;
858
859 return 0;
860 }
861
862 /** Find the verbosity level for a subsystem.
863 * @param[in] subsys Subsystem name.
864 * @return Minimum verbosity level being used, or NULL on error.
865 */
866 char *
867 log_get_level(const char *subsys)
868 {
869 struct LogDesc *desc;
870
871 /* find subsystem */
872 if (!(desc = log_find(subsys)))
873 return 0;
874
875 /* find the level's name */
876 return log_lev_name(desc->level);
877 }
878
879 /** Set the default syslog facility.
880 * @param[in] facility Syslog facility name.
881 * @return Zero on success, non-zero on error.
882 */
883 int
884 log_set_default(const char *facility)
885 {
886 int fac, oldfac;
887
888 oldfac = logInfo.facility;
889
890 if (EmptyString(facility))
891 logInfo.facility = LOG_USER;
892 else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND &&
893 fac != LOG_NONE && fac != LOG_DEFAULT)
894 logInfo.facility = fac;
895 else
896 return 1;
897
898 if (logInfo.facility != oldfac) {
899 closelog(); /* reopen syslog with new facility setting */
900 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
901 }
902
903 return 0;
904 }
905
906 /** Find the default syslog facility name.
907 * @return Canonical name of default syslog facility, or NULL if none.
908 */
909 char *
910 log_get_default(void)
911 {
912 /* find the facility's name */
913 return log_fac_name(logInfo.facility);
914 }
915
916 /** Clear all marks. */
917 void
918 log_feature_unmark(void)
919 {
920 int i;
921
922 for (i = 0; i < LS_LAST_SYSTEM; i++)
923 logDesc[i].mark = 0;
924 }
925
926 /** Reset unmodified fields in all log subsystems to their defaults.
927 * @param[in] flag If non-zero, clear default syslog facility.
928 */
929 int
930 log_feature_mark(int flag)
931 {
932 int i;
933
934 if (flag)
935 log_set_default(0);
936
937 for (i = 0; i < LS_LAST_SYSTEM; i++) {
938 if (!(logDesc[i].mark & LOG_MARK_FILE)) {
939 if (logDesc[i].subsys != LS_DEBUG) { /* debug is special */
940 if (logDesc[i].file) /* destroy previous entry... */
941 log_file_destroy(logDesc[i].file);
942 logDesc[i].file = 0;
943 }
944 }
945
946 if (!(logDesc[i].mark & LOG_MARK_FACILITY)) /* set default facility */
947 logDesc[i].facility = logDesc[i].def_fac;
948
949 if (!(logDesc[i].mark & LOG_MARK_SNOMASK)) /* set default snomask */
950 logDesc[i].snomask = logDesc[i].def_sno;
951
952 if (!(logDesc[i].mark & LOG_MARK_LEVEL)) /* set default level */
953 logDesc[i].level = L_DEFAULT;
954 }
955
956 return 0; /* we don't have a notify handler */
957 }
958
959 /** Feature list callback to report log settings.
960 * @param[in] to Client requesting list.
961 * @param[in] flag If non-zero, report default syslog facility.
962 */
963 void
964 log_feature_report(struct Client *to, int flag)
965 {
966 int i;
967
968 for (i = 0; i < LS_LAST_SYSTEM; i++)
969 {
970 if (logDesc[i].mark & LOG_MARK_FILE) /* report file */
971 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FILE %s",
972 logDesc[i].name, (logDesc[i].file && logDesc[i].file->file ?
973 logDesc[i].file->file : "(terminal)"));
974
975 if (logDesc[i].mark & LOG_MARK_FACILITY) /* report facility */
976 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FACILITY %s",
977 logDesc[i].name, log_fac_name(logDesc[i].facility));
978
979 if (logDesc[i].mark & LOG_MARK_SNOMASK) /* report snomask */
980 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s SNOMASK %s",
981 logDesc[i].name, log_sno_name(logDesc[i].snomask));
982
983 if (logDesc[i].mark & LOG_MARK_LEVEL) /* report log level */
984 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s LEVEL %s",
985 logDesc[i].name, log_lev_name(logDesc[i].level));
986 }
987
988 if (flag) /* report default facility */
989 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s",
990 log_fac_name(logInfo.facility));
991 }