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>
6 * See file AUTHORS in IRC package for additional names of
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)
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.
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.
24 * @brief IRC logging implementation.
31 #include "ircd_alloc.h"
32 #include "ircd_reply.h"
33 #include "ircd_snprintf.h"
34 #include "ircd_string.h"
41 /* #include <assert.h> -- Now using assert in ircd_log.h */
49 #include <sys/types.h>
57 #define LOG_BUFSIZE 2048 /**< Maximum length for a log message. */
59 /** Select default log level cutoff. */
61 # define L_DEFAULT L_DEBUG
63 # define L_DEFAULT L_INFO
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)
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. */
79 #define L(level, syslog, mask) { L_ ## level, #level, (syslog), (mask) }
80 L(CRIT, LOG_CRIT, SNO_OLDSNO),
82 L(WARNING, LOG_WARNING, 0),
83 L(NOTICE, LOG_NOTICE, 0),
84 L(TRACE, LOG_INFO, 0),
86 L(DEBUG, LOG_INFO, SNO_DEBUG),
88 { L_LAST_LEVEL, 0, 0, 0 }
91 /* Just in case some implementation of syslog has them... */
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 */
100 /** Map names to syslog facilities. */
102 char *name; /**< Textual name of facility. */
103 int facility; /**< Facility value for syslog(). */
105 #define F(fac) { #fac, LOG_ ## fac }
106 F(NONE), F(DEFAULT), F(AUTH),
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),
117 #define SNO_NONE 0x00000000 /**< don't send server notices */
118 #define SNO_NOTFOUND 0xffffffff /**< didn't find a SNO_MASK value for name */
120 /** Map names to snomask values. */
122 char *name; /**< Name of server notice bit. */
123 unsigned int snomask; /**< Bitmask corresponding to name. */
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),
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 */
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 */
151 #define S(sys, p, sn) { LS_##sys, #sys, 0, 0, (p), (sn), (p), (sn), L_DEFAULT }
153 S(CONFIG, 0, SNO_OLDSNO),
154 S(OPERMODE, -1, SNO_HACK4),
155 S(GLINE, -1, SNO_GLINE),
156 S(JUPE, -1, SNO_NETWORK),
158 S(NETWORK, -1, SNO_NETWORK),
162 S(OPER, -1, SNO_OLDREALOP),
165 S(IAUTH, -1, SNO_NETWORK),
166 S(DEBUG, -1, SNO_DEBUG),
168 { LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
171 /** Describes a log file. */
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 */
180 /** Modifiable static information. */
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 };
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.
194 log_open(struct LogFile *lf)
196 /* only open the file if we haven't already */
197 if (lf && lf->fd < 0) {
198 alarm(3); /* if NFS hangs, we hang only for 3 seconds */
199 lf->fd = open(lf->file, O_WRONLY | O_CREAT | O_APPEND,
207 /** Reopen debug log file. */
209 log_debug_reopen(void)
211 if (!logInfo.dbfile) /* no open debugging file */
214 if (!logInfo.dbfile->file) { /* using terminal output */
215 logInfo.dbfile->fd = 2;
219 /* Ok, it's a real file; close it if necessary and use log_open to open it */
220 if (logInfo.dbfile->fd >= 0) {
221 close(logInfo.dbfile->fd);
222 logInfo.dbfile->fd = -1; /* mark that it's closed for log_open */
225 log_open(logInfo.dbfile);
227 if (logInfo.dbfile->fd < 0) { /* try again with /dev/null */
228 if ((logInfo.dbfile->fd = open("/dev/null", O_WRONLY)) < 0)
232 /* massage the file descriptor to be stderr */
233 if (logInfo.dbfile->fd != 2) {
235 fd = dup2(logInfo.dbfile->fd, 2);
236 close(logInfo.dbfile->fd);
237 logInfo.dbfile->fd = fd;
241 /** initialize debugging log file.
242 * @param[in] usetty If non-zero, log to terminal instead of file.
245 log_debug_init(int usetty)
247 logInfo.dbfile = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
249 logInfo.dbfile->next = 0; /* initialize debugging filename */
250 logInfo.dbfile->prev_p = 0;
251 logInfo.dbfile->fd = -1;
252 logInfo.dbfile->ref = 1;
254 if (usetty) /* store pathname to use */
255 logInfo.dbfile->file = 0;
257 DupString(logInfo.dbfile->file, LOGFILE);
259 log_debug_reopen(); /* open the debug log */
261 logDesc[LS_DEBUG].file = logInfo.dbfile; /* remember where it went */
264 #endif /* DEBUGMODE */
266 /** Set the debug log file name.
267 * @param[in] file File name, or NULL to select the default.
268 * @return Zero if the file was reopened; non-zero if not debugging to file.
271 log_debug_file(const char *file)
277 /* If we weren't started with debugging enabled, or if we're using
278 * the terminal, don't do anything at all.
280 if (!logInfo.dbfile || !logInfo.dbfile->file)
283 MyFree(logInfo.dbfile->file); /* free old pathname */
284 DupString(logInfo.dbfile->file, file); /* store new pathname */
286 log_debug_reopen(); /* reopen the debug log */
287 #endif /* DEBUGMODE */
291 /** Initialize logging subsystem.
292 * @param[in] process_name Process name to interactions with syslog.
295 log_init(const char *process_name)
297 /* store the process name; probably belongs in ircd.c, but oh well... */
298 if (!EmptyString(process_name))
299 logInfo.procname = process_name;
301 /* ok, open syslog; default facility: LOG_USER */
302 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
305 /** Reopen log files (so admins can do things like rotate log files). */
309 log_close(); /* close everything...we reopen on demand */
312 log_debug_reopen(); /* reopen debugging log if necessary */
313 #endif /* DEBUGMODE */
315 /* reopen syslog, if needed; default facility: LOG_USER */
316 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
319 /** Close all log files. */
325 closelog(); /* close syslog */
327 for (ptr = logInfo.filelist; ptr; ptr = ptr->next) {
329 close(ptr->fd); /* close all the files... */
334 if (logInfo.dbfile && logInfo.dbfile->file) {
335 if (logInfo.dbfile->fd >= 0)
336 close(logInfo.dbfile->fd); /* close the debug log file */
338 logInfo.dbfile->fd = -1;
342 /** Write a logging entry.
343 * @param[in] subsys Target subsystem.
344 * @param[in] severity Severity of message.
345 * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
346 * @param[in] fmt Format string for message.
349 log_write(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
350 const char *fmt, ...)
355 log_vwrite(subsys, severity, flags, fmt, vl);
359 /** Write a logging entry using a va_list.
360 * @param[in] subsys Target subsystem.
361 * @param[in] severity Severity of message.
362 * @param[in] flags Combination of zero or more of LOG_NOSYSLOG, LOG_NOFILELOG, LOG_NOSNOTICE to suppress certain output.
363 * @param[in] fmt Format string for message.
364 * @param[in] vl Variable-length argument list for message.
367 log_vwrite(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
368 const char *fmt, va_list vl)
371 struct LogDesc *desc;
372 struct LevelData *ldata;
374 struct iovec vector[3];
376 char buf[LOG_BUFSIZE];
377 /* 1234567890123456789012 3 */
378 /* [2000-11-28 16:11:20] \0 */
381 /* check basic assumptions */
382 assert(-1 < (int)subsys);
383 assert((int)subsys < LS_LAST_SYSTEM);
384 assert(-1 < (int)severity);
385 assert((int)severity < L_LAST_LEVEL);
386 assert(0 == (flags & ~LOG_NOMASK));
389 /* find the log data and the severity data */
390 desc = &logDesc[subsys];
391 ldata = &levelData[severity];
393 /* check the set of ordering assumptions */
394 assert(desc->subsys == subsys);
395 assert(ldata->level == severity);
397 /* check severity... */
398 if (severity > desc->level)
401 /* figure out where all we need to log */
402 if (!(flags & LOG_NOFILELOG) && desc->file) {
403 log_open(desc->file);
404 if (desc->file->fd >= 0) /* don't log to file if we can't open the file */
405 flags |= LOG_DOFILELOG;
408 if (!(flags & LOG_NOSYSLOG) && desc->facility >= 0)
409 flags |= LOG_DOSYSLOG; /* will syslog */
411 if (!(flags & LOG_NOSNOTICE) && (desc->snomask != 0 || ldata->snomask != 0))
412 flags |= LOG_DOSNOTICE; /* will send a server notice */
414 /* short-circuit if there's nothing to do... */
415 if (!(flags & LOG_DOMASK))
418 /* Build the basic log string */
420 va_copy(vd.vd_args, vl);
422 /* save the length for writev */
423 /* Log format: "SYSTEM [SEVERITY]: log message" */
425 ircd_snprintf(0, buf, sizeof(buf), "%s [%s]: %v", desc->name,
428 /* if we have something to write to... */
429 if (flags & LOG_DOFILELOG) {
431 tstamp = localtime(&curtime); /* build the timestamp */
434 ircd_snprintf(0, timebuf, sizeof(timebuf), "[%d-%d-%d %d:%02d:%02d] ",
435 tstamp->tm_year + 1900, tstamp->tm_mon + 1,
436 tstamp->tm_mday, tstamp->tm_hour, tstamp->tm_min,
439 /* set up the remaining parts of the writev vector... */
440 vector[0].iov_base = timebuf;
441 vector[1].iov_base = buf;
443 vector[2].iov_base = (void*) "\n"; /* terminate lines with a \n */
444 vector[2].iov_len = 1;
446 /* write it out to the log file */
447 writev(desc->file->fd, vector, 3);
450 /* oh yeah, syslog it too... */
451 if (flags & LOG_DOSYSLOG)
452 syslog(ldata->syslog | desc->facility, "%s", buf);
454 /* can't forget server notices... */
455 if (flags & LOG_DOSNOTICE)
456 sendto_opmask_butone(0, ldata->snomask ? ldata->snomask : desc->snomask,
460 /** Log an appropriate message for kills.
461 * @param[in] victim %Client being killed.
462 * @param[in] killer %User or server doing the killing.
463 * @param[in] inpath Peer that sent us the KILL message.
464 * @param[in] path Kill path that sent to us by \a inpath.
465 * @param[in] msg Kill reason.
468 log_write_kill(const struct Client *victim, const struct Client *killer,
469 const char *inpath, const char *path, const char *msg)
472 log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
473 "A local client %#C KILLED by %#C Path: %s!%s %s",
474 victim, killer, inpath, path, msg);
476 log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0,
477 "KILL from %C For %C Path: %s!%s %s", killer, victim, inpath,
481 /** Find a reference-counted LogFile by file name.
482 * @param[in] file Name of file.
483 * @return A log file descriptor with LogFile::ref at least 1.
485 static struct LogFile *
486 log_file_create(const char *file)
492 /* if one already exists for that file, return it */
493 for (tmp = logInfo.filelist; tmp; tmp = tmp->next)
494 if (!strcmp(tmp->file, file)) {
499 if (logInfo.freelist) { /* pop one off the free list */
500 tmp = logInfo.freelist;
501 logInfo.freelist = tmp->next;
502 } else /* allocate a new one */
503 tmp = (struct LogFile*) MyMalloc(sizeof(struct LogFile));
505 tmp->fd = -1; /* initialize the structure */
507 DupString(tmp->file, file);
509 tmp->next = logInfo.filelist; /* link it into the list... */
510 tmp->prev_p = &logInfo.filelist;
511 if (logInfo.filelist)
512 logInfo.filelist->prev_p = &tmp->next;
513 logInfo.filelist = tmp;
518 /** Dereference a log file.
519 * If the reference count is exactly one on entry to this function,
520 * the file is closed and its structure is freed.
521 * @param[in] lf Log file to dereference.
524 log_file_destroy(struct LogFile *lf)
528 if (--lf->ref == 0) {
529 if (lf->next) /* clip it out of the list */
530 lf->next->prev_p = lf->prev_p;
531 *lf->prev_p = lf->next;
533 lf->prev_p = 0; /* we won't use it for the free list */
537 MyFree(lf->file); /* free the file name */
539 lf->next = logInfo.freelist; /* stack it onto the free list */
540 logInfo.freelist = lf;
544 /** Look up a log subsystem by name.
545 * @param[in] subsys Subsystem name.
546 * @return Pointer to the subsystem's LogDesc, or NULL if none exists.
548 static struct LogDesc *
549 log_find(const char *subsys)
555 /* find the named subsystem */
556 for (i = 0; i < LS_LAST_SYSTEM; i++)
557 if (!ircd_strcmp(subsys, logDesc[i].name))
560 return 0; /* not found */
563 /** Return canonical version of log subsystem name.
564 * @param[in] subsys Subsystem name.
565 * @return A constant string containing the canonical name.
568 log_canon(const char *subsys)
570 struct LogDesc *desc;
572 if (!(desc = log_find(subsys)))
578 /** Look up a log level by name.
579 * @param[in] level Log level name.
580 * @return LogLevel enumeration, or L_LAST_LEVEL if none exists.
583 log_lev_find(const char *level)
589 /* find the named level */
590 for (i = 0; levelData[i].string; i++)
591 if (!ircd_strcmp(level, levelData[i].string))
592 return levelData[i].level;
594 return L_LAST_LEVEL; /* not found */
597 /** Look up the canonical name for a log level.
599 * @return A constant string containing the level's canonical name.
602 log_lev_name(enum LogLevel lev)
604 assert(-1 < (int)lev);
605 assert((int)lev < L_LAST_LEVEL);
606 assert(lev == levelData[lev].level);
608 return levelData[lev].string;
611 /** Look up a syslog facility by name.
612 * @param[in] facility Facility name.
613 * @return Syslog facility value, or LOG_NOTFOUND if none exists.
616 log_fac_find(const char *facility)
620 assert(0 != facility);
622 /* find the named facility */
623 for (i = 0; facilities[i].name; i++)
624 if (!ircd_strcmp(facility, facilities[i].name))
625 return facilities[i].facility;
627 return LOG_NOTFOUND; /* not found */
630 /** Look up the name for a syslog facility.
631 * @param[in] fac Facility value.
632 * @return Canonical name for facility, or NULL if none exists.
635 log_fac_name(int fac)
639 /* find the facility */
640 for (i = 0; facilities[i].name; i++)
641 if (facilities[i].facility == fac)
642 return facilities[i].name;
644 return 0; /* not found; should never happen */
647 /** Look up a server notice mask by name.
648 * @param[in] maskname Name of server notice mask.
649 * @return Bitmask for server notices, or 0 if none exists.
652 log_sno_find(const char *maskname)
656 assert(0 != maskname);
658 /* find the named snomask */
659 for (i = 0; masks[i].name; i++)
660 if (!ircd_strcmp(maskname, masks[i].name))
661 return masks[i].snomask;
663 return SNO_NOTFOUND; /* not found */
666 /** Look up the canonical name for a server notice mask.
667 * @param[in] sno Server notice mask.
668 * @return Canonical name for the mask, or NULL if none exists.
671 log_sno_name(unsigned int sno)
675 /* find the snomask */
676 for (i = 0; masks[i].name; i++)
677 if (masks[i].snomask == sno)
678 return masks[i].name;
680 return 0; /* not found; should never happen */
683 /** Set a log file for a particular subsystem.
684 * @param[in] subsys Subsystem name.
685 * @param[in] filename Log file to write to.
686 * @return Zero on success; non-zero on error.
689 log_set_file(const char *subsys, const char *filename)
691 struct LogDesc *desc;
694 if (!(desc = log_find(subsys)))
698 desc->mark |= LOG_MARK_FILE; /* mark that file has been changed */
700 desc->mark &= ~LOG_MARK_FILE; /* file has been reset to defaults */
702 /* no change, don't go to the trouble of destroying and recreating */
703 if (desc->file && desc->file->file && filename &&
704 !strcmp(desc->file->file, filename))
707 /* debug log is special, since it has to be opened on fd 2 */
708 if (desc->subsys == LS_DEBUG)
709 return log_debug_file(filename);
711 if (desc->file) /* destroy previous entry... */
712 log_file_destroy(desc->file);
714 /* set the file to use */
715 desc->file = filename ? log_file_create(filename) : 0;
720 /** Find the log file name for a subsystem.
721 * @param[in] subsys Subsystem name.
722 * @return Log file for the subsystem, or NULL if not being logged to a file.
725 log_get_file(const char *subsys)
727 struct LogDesc *desc;
730 if (!(desc = log_find(subsys)))
733 return desc->file ? desc->file->file : 0;
736 /** Set the syslog facility for a particular subsystem.
737 * @param[in] subsys Subsystem name.
738 * @param[in] facility Facility name to log to.
739 * @return Zero on success; non-zero on error.
742 log_set_facility(const char *subsys, const char *facility)
744 struct LogDesc *desc;
748 if (!(desc = log_find(subsys)))
751 /* set syslog facility */
752 if (EmptyString(facility)) {
753 desc->facility = desc->def_fac;
754 desc->mark &= ~LOG_MARK_FACILITY;
755 } else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND) {
756 desc->facility = fac;
757 if (fac == desc->def_fac)
758 desc->mark &= ~LOG_MARK_FACILITY;
760 desc->mark |= LOG_MARK_FACILITY;
767 /** Find the facility name for a subsystem.
768 * @param[in] subsys Subsystem name.
769 * @return Facility name being used, or NULL if not being logged to syslog.
772 log_get_facility(const char *subsys)
774 struct LogDesc *desc;
777 if (!(desc = log_find(subsys)))
780 /* find the facility's name */
781 return log_fac_name(desc->facility);
784 /** Set the server notice mask for a subsystem.
785 * @param[in] subsys Subsystem name.
786 * @param[in] snomask Server notice mask name.
787 * @return Zero on success; non-zero on error.
790 log_set_snomask(const char *subsys, const char *snomask)
792 struct LogDesc *desc;
793 unsigned int sno = SNO_DEFAULT;
796 if (!(desc = log_find(subsys)))
799 /* set snomask value */
800 if (EmptyString(snomask)) {
801 desc->snomask = desc->def_sno;
802 desc->mark &= ~LOG_MARK_SNOMASK;
803 } else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND) {
805 if (sno == desc->def_sno)
806 desc->mark &= ~LOG_MARK_SNOMASK;
808 desc->mark |= LOG_MARK_SNOMASK;
815 /** Find the server notice mask name for a subsystem.
816 * @param[in] subsys Subsystem name.
817 * @return Name of server notice mask being used, or NULL if none.
820 log_get_snomask(const char *subsys)
822 struct LogDesc *desc;
825 if (!(desc = log_find(subsys)))
828 /* find the snomask value's name */
829 return log_sno_name(desc->snomask);
832 /** Set the verbosity level for a subsystem.
833 * @param[in] subsys Subsystem name.
834 * @param[in] level Minimum log level.
835 * @return Zero on success; non-zero on error.
838 log_set_level(const char *subsys, const char *level)
840 struct LogDesc *desc;
844 if (!(desc = log_find(subsys)))
847 /* set logging level */
848 if (EmptyString(level)) {
849 desc->level = L_DEFAULT;
850 desc->mark &= ~LOG_MARK_LEVEL;
851 } else if ((lev = log_lev_find(level)) != L_LAST_LEVEL) {
853 if (lev == L_DEFAULT)
854 desc->mark &= ~LOG_MARK_LEVEL;
856 desc->mark |= LOG_MARK_LEVEL;
863 /** Find the verbosity level for a subsystem.
864 * @param[in] subsys Subsystem name.
865 * @return Minimum verbosity level being used, or NULL on error.
868 log_get_level(const char *subsys)
870 struct LogDesc *desc;
873 if (!(desc = log_find(subsys)))
876 /* find the level's name */
877 return log_lev_name(desc->level);
880 /** Set the default syslog facility.
881 * @param[in] facility Syslog facility name.
882 * @return Zero on success, non-zero on error.
885 log_set_default(const char *facility)
889 oldfac = logInfo.facility;
891 if (EmptyString(facility))
892 logInfo.facility = LOG_USER;
893 else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND &&
894 fac != LOG_NONE && fac != LOG_DEFAULT)
895 logInfo.facility = fac;
899 if (logInfo.facility != oldfac) {
900 closelog(); /* reopen syslog with new facility setting */
901 openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
907 /** Find the default syslog facility name.
908 * @return Canonical name of default syslog facility, or NULL if none.
911 log_get_default(void)
913 /* find the facility's name */
914 return log_fac_name(logInfo.facility);
917 /** Clear all marks. */
919 log_feature_unmark(void)
923 for (i = 0; i < LS_LAST_SYSTEM; i++)
927 /** Reset unmodified fields in all log subsystems to their defaults.
928 * @param[in] flag If non-zero, clear default syslog facility.
931 log_feature_mark(int flag)
938 for (i = 0; i < LS_LAST_SYSTEM; i++) {
939 if (!(logDesc[i].mark & LOG_MARK_FILE)) {
940 if (logDesc[i].subsys != LS_DEBUG) { /* debug is special */
941 if (logDesc[i].file) /* destroy previous entry... */
942 log_file_destroy(logDesc[i].file);
947 if (!(logDesc[i].mark & LOG_MARK_FACILITY)) /* set default facility */
948 logDesc[i].facility = logDesc[i].def_fac;
950 if (!(logDesc[i].mark & LOG_MARK_SNOMASK)) /* set default snomask */
951 logDesc[i].snomask = logDesc[i].def_sno;
953 if (!(logDesc[i].mark & LOG_MARK_LEVEL)) /* set default level */
954 logDesc[i].level = L_DEFAULT;
957 return 0; /* we don't have a notify handler */
960 /** Feature list callback to report log settings.
961 * @param[in] to Client requesting list.
962 * @param[in] flag If non-zero, report default syslog facility.
965 log_feature_report(struct Client *to, int flag)
969 for (i = 0; i < LS_LAST_SYSTEM; i++)
971 if (logDesc[i].mark & LOG_MARK_FILE) /* report file */
972 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FILE %s",
973 logDesc[i].name, (logDesc[i].file && logDesc[i].file->file ?
974 logDesc[i].file->file : "(terminal)"));
976 if (logDesc[i].mark & LOG_MARK_FACILITY) /* report facility */
977 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FACILITY %s",
978 logDesc[i].name, log_fac_name(logDesc[i].facility));
980 if (logDesc[i].mark & LOG_MARK_SNOMASK) /* report snomask */
981 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s SNOMASK %s",
982 logDesc[i].name, log_sno_name(logDesc[i].snomask));
984 if (logDesc[i].mark & LOG_MARK_LEVEL) /* report log level */
985 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s LEVEL %s",
986 logDesc[i].name, log_lev_name(logDesc[i].level));
989 if (flag) /* report default facility */
990 send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s",
991 log_fac_name(logInfo.facility));