From: Kevin L. Mitchell Date: Thu, 30 Nov 2000 22:20:24 +0000 (+0000) Subject: Author: Kev X-Git-Url: http://git.pk910.de/?a=commitdiff_plain;h=90db9ebe981002933d49e25522903359e24e6ee2;p=ircu2.10.12-pk.git Author: Kev Log message: Finished most of the logging system (except for conversions to log_write()) by implementing the feature system, composed of F-lines, to set features from the .conf, and the three new commands /set, /reset, and /get, to manipulate feature settings on the fly. Status: Stable, but expect bugs Testing needed: I'm too tired to try to figure out what sort of bugs might be hanging around. Beat on it for a while... git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@318 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- diff --git a/ChangeLog b/ChangeLog index 94ab0d0..5ab8c35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,60 @@ +2000-11-30 Kevin L. Mitchell + + * ircd/s_stats.c (report_feature_list): report features--only + local opers can see logging configuration, since it doesn't really + mean anything to users + + * ircd/s_err.c: add reply messages for new feature subsystem + + * ircd/s_conf.c: add F lines to .conf + + * ircd/parse.c: add the message descriptions for /set, /reset, and + /get + + * ircd/m_stats.c: add /stats f + + * ircd/m_set.c (mo_set): implement /set + + * ircd/m_reset.c (mo_reset): implement /reset + + * ircd/m_rehash.c: /rehash m now flushes MOTD cache, and /rehash l + reopens log files (for log file rotation) + + * ircd/m_get.c (mo_get): implement /get + + * ircd/ircd_log.c: use int instead of void return value; add + log_report_features() and log_canon(); fix a function that + disappears if DEBUGMODE not #define'd + + * ircd/ircd_features.c: functions to manipulate feature settings + either from the config file or with the new /set, /reset, and /get + commands + + * ircd/Makefile.in: add new .c files, run make depend + + * include/s_stats.h: declare report_feature_list() (/stats f + handler) + + * include/numeric.h: add RPL_STATSFLINE, RPL_FEATURE, + ERR_NOFEATURE, ERR_BADLOGTYPE, ERR_BADLOGSYS, and ERR_BADLOGVALUE + reply numerics + + * include/msg.h: add defines for SET, RESET, and GET + + * include/ircd_log.h: add a function to canonicalize subsystem + names; change some void return values to int + + * include/ircd_features.h: new features subsystem handles all the + manipulation of special features, like log files + + * include/handlers.h: declare new mo_{s,res,g}et message handlers + for fiddling with features run-time + + * include/client.h (SNO_DEFAULT): don't set SNO_DEBUG by default; + seemed like a good idea at the time... + + * doc/example.conf: document new F lines + 2000-11-29 Kevin L. Mitchell * ircd/s_debug.c: rewrite debug_init() and vdebug() in terms of diff --git a/doc/example.conf b/doc/example.conf index aa29ead..6fc165a 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -379,6 +379,66 @@ P:192.168.*:::6666 # with the IP address 168.8.21.107 #P:*:168.8.21.107:CH:7000 +# [F:lines] +# IRC servers have a large number of options and features. Most of these +# are set at compile time through the use of #define's--see "make config" +# for more details--but we are working to move many of these into the +# configuration file. Feature lines are the hook we're using for this. +# +# F::[:[...]] +# +# Currently, the only defined value for is "LOG," and it allows you +# to customize the settings of the logging architecture. You can set the +# default logging facility to, say, local7 (F:LOG:LOCAL7), or set a log +# file for one of the subsystems (F:LOG:GLINE:FILE:gline.log). More than +# one subsystem can log to the same file without danger of interleaving. +# +# The currently defined subsystems are SYSTEM, CONFIG, OPERMODE (used by +# /opmode and /clearmode), GLINE, JUPE, WHO (used by /whox), NETWORK +# (connects and disconnects), OPERKILL, SERVKILL, OPER, OPERLOG, USERLOG, +# RESOLVER, SOCKET, DEBUG, and OLDLOG. You can set log files for these +# subsystems to log to, or you can tell them to syslog their data, or +# even send server notices. You can do any of these in combination, but +# you can't log to more than one file. You can also set minimum log +# levels per subsystem, if you wish. +# +# The format for LOG Feature lines is as follows: +# +# F:LOG: +# F:LOG::[:] +# +# The first sets the default facility for ircu to log to to . +# Valid values are listed in the syslog(3) man page; just +# remove the "LOG_" prefix. +# +# The list of subsystems is given above. The valid values for are +# FILE, FACILITY, SNOMASK, and LEVEL, which respectively set the log file, +# the syslog facility, a server notice mask value, and the minimum log +# level. If no is given, or if is empty, the default +# value for that type is set. +# +# Valid 's for the FACILITY type are the normal syslog values (with +# the "LOG_" prefix removed) or the special values "NONE" (which specifies +# that syslogging should not be attempted) and "DEFAULT" (which specifies +# that the server-wide facility should be used); the default for all +# subsystems is "NONE." +# +# Valid 's for the SNOMASK type are OLDSNO, SERVKILL, OPERKILL, +# HACK2, HACK3, UNAUTH, TCPCOMMON, TOOMANY, HACK4, GLINE, NETWORK, +# IPMISMATCH, THROTTLE, OLDREALOP, and CONNEXIT, as well as the special +# values NONE, which specifies that no server notices should be sent, +# and DEBUG, which is only available if DEBUGMODE has been enabled. +# +# Valid 's for the LEVEL type are CRIT, ERR, WARNING, NOTICE, +# TRACE, INFO, and DEBUG. Note that logs with level CRIT always result +# in server notices to mask SNO_OLDSNO, and logs with level DEBUG always +# send server notices to mask SNO_DEBUG. +# +# A couple of things to note: log settings are not reset to defaults prior +# to a rehash; this means that if you delete F-lines and rehash, logs will +# continue going to the same place. Also, all subsystems are defaulted to +# minimum log level INFO (or DEBUG if DEBUGMODE is #define'd). + # # Well, you have now reached the end of this sample configuration file # If you have any questions, feel free to mail diff --git a/include/client.h b/include/client.h index 271e3d6..4253816 100644 --- a/include/client.h +++ b/include/client.h @@ -306,7 +306,7 @@ struct Client { #define SNO_USER (SNO_ALL & ~SNO_OPER) -#define SNO_DEFAULT ((SNO_NETWORK|SNO_OPERKILL|SNO_GLINE|SNO_DEBUG)&SNO_ALL) +#define SNO_DEFAULT (SNO_NETWORK|SNO_OPERKILL|SNO_GLINE) #define SNO_OPERDEFAULT (SNO_DEFAULT|SNO_HACK2|SNO_HACK4|SNO_THROTTLE|SNO_OLDSNO) #define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP) #define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH) diff --git a/include/handlers.h b/include/handlers.h index 9b991d5..4779db7 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -137,6 +137,7 @@ extern int mo_clearmode(struct Client*, struct Client*, int, char*[]); extern int mo_close(struct Client*, struct Client*, int, char*[]); extern int mo_connect(struct Client*, struct Client*, int, char*[]); extern int mo_die(struct Client*, struct Client*, int, char*[]); +extern int mo_get(struct Client*, struct Client*, int, char*[]); extern int mo_gline(struct Client*, struct Client*, int, char*[]); extern int mo_info(struct Client*, struct Client*, int, char*[]); extern int mo_jupe(struct Client*, struct Client*, int, char*[]); @@ -146,8 +147,10 @@ extern int mo_oper(struct Client*, struct Client*, int, char*[]); extern int mo_opmode(struct Client*, struct Client*, int, char*[]); extern int mo_privmsg(struct Client*, struct Client*, int, char*[]); extern int mo_rehash(struct Client*, struct Client*, int, char*[]); +extern int mo_reset(struct Client*, struct Client*, int, char*[]); extern int mo_restart(struct Client*, struct Client*, int, char*[]); extern int mo_rping(struct Client*, struct Client*, int, char*[]); +extern int mo_set(struct Client*, struct Client*, int, char*[]); extern int mo_settime(struct Client*, struct Client*, int, char*[]); extern int mo_squit(struct Client*, struct Client*, int, char*[]); extern int mo_stats(struct Client*, struct Client*, int, char*[]); diff --git a/include/ircd_features.h b/include/ircd_features.h new file mode 100644 index 0000000..c683721 --- /dev/null +++ b/include/ircd_features.h @@ -0,0 +1,33 @@ +#ifndef INCLUDED_features_h +#define INCLUDED_features_h +/* + * IRC - Internet Relay Chat, include/features.h + * Copyright (C) 2000 Kevin L. Mitchell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +struct Client; + +extern int feature_set(struct Client* from, const char* const* fields, + int count); +extern int feature_reset(struct Client* from, const char* const* fields, + int count); +extern int feature_get(struct Client* from, const char* const* fields, + int count); + +#endif /* INCLUDED_features_h */ diff --git a/include/ircd_log.h b/include/ircd_log.h index bd3468c..3673434 100644 --- a/include/ircd_log.h +++ b/include/ircd_log.h @@ -82,19 +82,23 @@ extern void log_write_kill(const struct Client *victim, #define LOG_NOMASK (LOG_NOSYSLOG | LOG_NOFILELOG | LOG_NOSNOTICE) -extern void log_set_file(char *subsys, char *filename); -extern char *log_get_file(char *subsys); +extern char *log_canon(const char *subsys); -extern void log_set_facility(char *subsys, char *facility); -extern char *log_get_facility(char *subsys); +extern int log_set_file(const char *subsys, const char *filename); +extern char *log_get_file(const char *subsys); -extern void log_set_snomask(char *subsys, char *facility); -extern char *log_get_snomask(char *subsys); +extern int log_set_facility(const char *subsys, const char *facility); +extern char *log_get_facility(const char *subsys); -extern void log_set_level(char *subsys, char *level); -extern char *log_get_level(char *subsys); +extern int log_set_snomask(const char *subsys, const char *facility); +extern char *log_get_snomask(const char *subsys); -extern void log_set_default(char *facility); +extern int log_set_level(const char *subsys, const char *level); +extern char *log_get_level(const char *subsys); + +extern int log_set_default(const char *facility); extern char *log_get_default(void); +extern void log_feature_report(struct Client *to); + #endif /* INCLUDED_ircd_log_h */ diff --git a/include/msg.h b/include/msg.h index df16388..0d4be46 100644 --- a/include/msg.h +++ b/include/msg.h @@ -325,6 +325,15 @@ struct Client; #define MSG_POST "POST" /* POST */ #define TOK_POST "POST" +#define MSG_SET "SET" /* SET */ +#define TOK_SET "SET" + +#define MSG_RESET "RESET" /* RESE */ +#define TOK_RESET "RESET" + +#define MSG_GET "GET" /* GET */ +#define TOK_GET "GET" + /* * Constants */ diff --git a/include/numeric.h b/include/numeric.h index 7cfda74..48c26a4 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -104,6 +104,7 @@ extern const struct Numeric* get_error_numeric(int err); #define RPL_SERVLIST 234 /* unused */ #define RPL_SERVLISTEND 235 /* unused */ +#define RPL_STATSFLINE 238 /* Undernet feature lines */ /* RPL_STATSIAUTH 239 IRCnet extension */ /* RPL_STATSVLINE 240 IRCnet extension */ #define RPL_STATSLLINE 241 @@ -155,7 +156,7 @@ extern const struct Numeric* get_error_numeric(int err); #define RPL_ENDOFGLIST 281 /* Undernet extension */ #define RPL_JUPELIST 282 /* Undernet extension - jupe -Kev */ #define RPL_ENDOFJUPELIST 283 /* Undernet extension - jupe -Kev */ - +#define RPL_FEATURE 284 /* Undernet extension - features */ /* RPL_CHANINFO_HANDLE 285 aircd */ /* RPL_CHANINFO_USERS 286 aircd */ /* RPL_CHANINFO_CHOPS 287 aircd */ @@ -353,6 +354,11 @@ extern const struct Numeric* get_error_numeric(int err); #define ERR_NOOPERHOST 491 /* ERR_NOSERVICEHOST 492 ? */ +#define ERR_NOFEATURE 493 /* Undernet extension - features */ +#define ERR_BADLOGTYPE 494 /* Undernet extension - features */ +#define ERR_BADLOGSYS 495 /* Undernet extension - features */ +#define ERR_BADLOGVALUE 496 /* Undernet extension - features */ + #define ERR_ISOPERLCHAN 498 /* Undernet extension */ #define ERR_UMODEUNKNOWNFLAG 501 diff --git a/include/s_stats.h b/include/s_stats.h index 49dfe01..ecd5766 100644 --- a/include/s_stats.h +++ b/include/s_stats.h @@ -35,5 +35,6 @@ extern int hunt_stats(struct Client* cptr, struct Client* sptr, int parc, char* extern void report_crule_list(struct Client* to, int mask); extern void report_motd_list(struct Client* to); extern void report_deny_list(struct Client* to); +extern void report_feature_list(struct Client* to); #endif /* INCLUDED_s_stats_h */ diff --git a/ircd/Makefile.in b/ircd/Makefile.in index 57bab57..16da513 100644 --- a/ircd/Makefile.in +++ b/ircd/Makefile.in @@ -76,6 +76,7 @@ SRC = \ hash.c \ ircd.c \ ircd_alloc.c \ + ircd_features.c \ ircd_log.c \ ircd_osdep.c \ ircd_relay.c \ @@ -101,6 +102,7 @@ SRC = \ m_die.c \ m_endburst.c \ m_error.c \ + m_get.c \ m_gline.c \ m_help.c \ m_info.c \ @@ -129,10 +131,12 @@ SRC = \ m_proto.c \ m_quit.c \ m_rehash.c \ + m_reset.c \ m_restart.c \ m_rping.c \ m_rpong.c \ m_server.c \ + m_set.c \ m_settime.c \ m_silence.c \ m_squit.c \ diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c new file mode 100644 index 0000000..aac26e1 --- /dev/null +++ b/ircd/ircd_features.c @@ -0,0 +1,232 @@ +/* + * IRC - Internet Relay Chat, ircd/features.c + * Copyright (C) 2000 Kevin L. Mitchell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +#include "features.h" +#include "client.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_alloc.h" +#include "ircd_log.h" +#include "ircd_reply.h" +#include "ircd_string.h" +#include "match.h" +#include "msg.h" +#include "numeric.h" +#include "numnicks.h" +#include "s_bsd.h" +#include "s_debug.h" +#include "s_misc.h" +#include "send.h" +#include "struct.h" +#include "support.h" +#include "sys.h" /* FALSE bleah */ + +#include +#include + +static struct LogTypes { + char *type; + int (*set)(const char *, const char *); + char *(*get)(const char *); +} logTypes[] = { + { "FILE", log_set_file, log_get_file }, + { "FACILITY", log_set_facility, log_get_facility }, + { "SNOMASK", log_set_snomask, log_get_snomask }, + { "LEVEL", log_set_level, log_get_level }, + { 0, 0, 0 } +}; + +static struct LogTypes * +feature_log_desc(struct Client* from, const char *type) +{ + int i; + + assert(0 != type); + + for (i = 0; logTypes[i].type; i++) /* find appropriate descriptor */ + if (!ircd_strcmp(type, logTypes[i].type)) + return &logTypes[i]; + + Debug((DEBUG_ERROR, "Unknown log feature type \"%s\"", type)); + if (from) + send_reply(from, ERR_BADLOGTYPE, type); + else + log_write(LS_CONFIG, L_ERROR, 0, "Unknown log feature type \"%s\"", type); + + return 0; /* not found */ +} + +static void +feature_log_set(struct Client* from, const char* const* fields, int count) +{ + struct LogTypes *desc; + char *subsys; + + if (count < 2) { /* set default facility */ + if (log_set_default(count < 1 ? 0 : fields[0])) { + assert(count >= 1); /* should always accept default */ + + if (from) + send_reply(from, ERR_BADLOGVALUE, fields[0]); + else + log_write(LS_CONFIG, L_ERROR, 0, + "Bad value \"%s\" for default facility", fields[0]); + } + } else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */ + if (from) + send_reply(from, ERR_BADLOGSYS, fields[0]); + else + log_write(LS_CONFIG, L_ERROR, 0, + "No such logging subsystem \"%s\"", fields[0]); + } else if ((desc = feature_log_desc(from, fields[1]))) { /* set value */ + if ((*desc->set)(fields[0], count < 3 ? 0 : fields[2])) { + assert(count >= 3); /* should always accept default */ + + if (from) + send_reply(from, ERR_BADLOGVALUE, fields[2]); + else + log_write(LS_CONFIG, L_ERROR, 0, + "Bad value \"%s\" for log type %s (subsystem %s)", + fields[2], desc->type, subsys); + } + } +} + +static void +feature_log_reset(struct Client* from, const char* const* fields, int count) +{ + struct LogTypes *desc; + char *subsys; + + assert(0 != from); + + if (count < 1) /* reset default facility */ + log_set_default(0); + else if (count < 2) + need_more_params(from, "RESET"); + else if (!(subsys = log_canon(fields[0]))) /* no such subsystem */ + send_reply(from, ERR_BADLOGSYS, fields[0]); + else if ((desc = feature_log_desc(from, fields[1]))) /* reset value */ + (*desc->set)(fields[0], 0); +} + +static void +feature_log_get(struct Client* from, const char* const* fields, int count) +{ + struct LogTypes *desc; + char *value, *subsys; + + assert(0 != from); + + if (count < 1) /* return default facility */ + send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Log facility: %s", + log_get_default()); + else if (count < 2) + need_more_params(from, "GET"); + else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */ + send_reply(from, ERR_BADLOGSYS, fields[0]); + } else if ((desc = feature_log_desc(from, fields[1]))) { + if ((value = (*desc->get)(fields[0]))) /* send along value */ + send_reply(from, SND_EXPLICIT | RPL_FEATURE, + ":Log %s for subsystem %s: %s", desc->type, subsys, + (*desc->get)(subsys)); + else + send_reply(from, SND_EXPLICIT | RPL_FEATURE, + ":No log %s is set for subsystem %s", desc->type, subsys); + } +} + +typedef void (*feature_call)(struct Client*, const char* const*, int); + +static struct FeatureDesc { + char *type; + feature_call set; /* set feature values */ + feature_call reset; /* reset feature values to defaults */ + feature_call get; /* get feature values */ +} features[] = { + { "LOG", feature_log_set, feature_log_reset, feature_log_get }, + { 0, 0, 0, 0 } +}; + +static struct FeatureDesc * +feature_desc(struct Client* from, const char *feature) +{ + int i; + + assert(0 != feature); + + for (i = 0; features[i].type; i++) /* find appropriate descriptor */ + if (!ircd_strcmp(feature, features[i].type)) + return &features[i]; + + Debug((DEBUG_ERROR, "Unknown feature \"%s\"", feature)); + if (from) + send_reply(from, ERR_NOFEATURE, feature); + else + log_write(LS_CONFIG, L_ERROR, 0, "Unknown feature \"%s\"", feature); + + return 0; /* not found */ +} + +int +feature_set(struct Client* from, const char* const* fields, int count) +{ + struct FeatureDesc *feat; + + if (count < 1) { + if (from) + need_more_params(from, "SET"); + else + log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line"); + } else if ((feat = feature_desc(from, fields[0]))) + (*feat->set)(from, fields + 1, count - 1); + + return 0; +} + +int +feature_reset(struct Client* from, const char* const* fields, int count) +{ + struct FeatureDesc *feat; + + assert(0 != from); + + if (count < 1) + need_more_params(from, "RESET"); + else if ((feat = feature_desc(from, fields[0]))) + (*feat->reset)(from, fields + 1, count - 1); + + return 0; +} + +int +feature_get(struct Client* from, const char* const* fields, int count) +{ + struct FeatureDesc *feat; + + assert(0 != from); + + if (count < 1) + need_more_params(from, "GET"); + else if ((feat = feature_desc(from, fields[0]))) + (*feat->get)(from, fields + 1, count - 1); + + return 0; +} diff --git a/ircd/ircd_log.c b/ircd/ircd_log.c index 8d2f251..b8669a4 100644 --- a/ircd/ircd_log.c +++ b/ircd/ircd_log.c @@ -26,9 +26,11 @@ #include "client.h" #include "config.h" #include "ircd_alloc.h" +#include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" #include "ircd.h" +#include "numeric.h" #include "s_debug.h" #include "send.h" #include "struct.h" @@ -248,25 +250,28 @@ log_debug_init(char *file) logDesc[LS_DEBUG].file = logInfo.dbfile; /* remember where it went */ } +#endif /* DEBUGMODE */ + /* set the debug log file */ -static void -log_debug_file(char *file) +static int +log_debug_file(const char *file) { +#ifdef DEBUGMODE assert(0 != file); /* If we weren't started with debugging enabled, or if we're using * the terminal, don't do anything at all. */ if (!logInfo.dbfile || !logInfo.dbfile->file) - return; + return 1; MyFree(logInfo.dbfile->file); /* free old pathname */ DupString(logInfo.dbfile->file, file); /* store new pathname */ log_debug_reopen(); /* reopen the debug log */ -} - #endif /* DEBUGMODE */ + return 0; +} /* called in place of open_log(), this stores the process name and prepares * for syslogging @@ -498,7 +503,7 @@ log_file_destroy(struct LogFile *lf) /* finds a subsystem given its name */ static struct LogDesc * -log_find(char *subsys) +log_find(const char *subsys) { int i; @@ -512,9 +517,21 @@ log_find(char *subsys) return 0; /* not found */ } +/* canonicalize subsystem names */ +char * +log_canon(const char *subsys) +{ + struct LogDesc *desc; + + if (!(desc = log_find(subsys))) + return 0; + + return desc->name; +} + /* find a level given its name */ static enum LogLevel -log_lev_find(char *level) +log_lev_find(const char *level) { int i; @@ -528,9 +545,20 @@ log_lev_find(char *level) return L_LAST_LEVEL; /* not found */ } +/* return a name for a level */ +static char * +log_lev_name(enum LogLevel lev) +{ + assert(-1 < (int)lev); + assert((int)lev < L_LAST_LEVEL); + assert(lev == levelData[lev].level); + + return levelData[lev].string; +} + /* find a facility given its name */ static int -log_fac_find(char *facility) +log_fac_find(const char *facility) { int i; @@ -544,9 +572,23 @@ log_fac_find(char *facility) return LOG_NOTFOUND; /* not found */ } +/* return a name for a facility */ +static char * +log_fac_name(int fac) +{ + int i; + + /* find the facility */ + for (i = 0; facilities[i].name; i++) + if (facilities[i].facility == fac) + return facilities[i].name; + + return 0; /* not found; should never happen */ +} + /* find a snomask value given its name */ static unsigned int -log_sno_find(char *maskname) +log_sno_find(const char *maskname) { int i; @@ -560,24 +602,37 @@ log_sno_find(char *maskname) return SNO_NOTFOUND; /* not found */ } +/* return a name for a snomask value */ +static char * +log_sno_name(unsigned int sno) +{ + int i; + + /* find the snomask */ + for (i = 0; masks[i].name; i++) + if (masks[i].snomask == sno) + return masks[i].name; + + return 0; /* not found; should never happen */ +} + /* set the log file for a subsystem */ -void -log_set_file(char *subsys, char *filename) +int +log_set_file(const char *subsys, const char *filename) { struct LogDesc *desc; /* find subsystem */ if (!(desc = log_find(subsys))) - return; + return 2; /* no change, don't go to the trouble of destroying and recreating */ if (filename && !strcmp(desc->file->file, filename)) - return; + return 0; /* debug log is special, since it has to be opened on fd 2 */ if (desc->subsys == LS_DEBUG) { - log_debug_file(filename); - return; + return log_debug_file(filename); } if (desc->file) /* destroy previous entry... */ @@ -585,11 +640,13 @@ log_set_file(char *subsys, char *filename) /* set the file to use */ desc->file = filename ? log_file_create(filename) : 0; + + return 0; } /* get the log file for a subsystem */ char * -log_get_file(char *subsys) +log_get_file(const char *subsys) { struct LogDesc *desc; @@ -601,119 +658,116 @@ log_get_file(char *subsys) } /* set the facility for a subsystem */ -void -log_set_facility(char *subsys, char *facility) +int +log_set_facility(const char *subsys, const char *facility) { struct LogDesc *desc; int fac; /* find subsystem */ if (!(desc = log_find(subsys))) - return; + return 2; /* set syslog facility */ if (EmptyString(facility)) desc->facility = desc->def_fac; else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND) desc->facility = fac; + else + return 1; + + return 0; } /* get the facility for a subsystem */ char * -log_get_facility(char *subsys) +log_get_facility(const char *subsys) { struct LogDesc *desc; - int i; /* find subsystem */ if (!(desc = log_find(subsys))) return 0; /* find the facility's name */ - for (i = 0; facilities[i].name; i++) - if (desc->facility == facilities[i].facility) - return facilities[i].name; /* found it... */ - - return 0; /* shouldn't ever happen */ + return log_fac_name(desc->facility); } /* set the snomask value for a subsystem */ -void -log_set_snomask(char *subsys, char *snomask) +int +log_set_snomask(const char *subsys, const char *snomask) { struct LogDesc *desc; - unsigned int sno; + unsigned int sno = SNO_DEFAULT; /* find subsystem */ if (!(desc = log_find(subsys))) - return; + return 2; /* set snomask value */ if (EmptyString(snomask)) desc->snomask = desc->def_sno; else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND) desc->snomask = sno; + else + return 1; + + return 0; } /* get the snomask value for a subsystem */ char * -log_get_snomask(char *subsys) +log_get_snomask(const char *subsys) { struct LogDesc *desc; - int i; /* find subsystem */ if (!(desc = log_find(subsys))) return 0; /* find the snomask value's name */ - for (i = 0; masks[i].name; i++) - if (desc->snomask == masks[i].snomask) - return masks[i].name; /* found it... */ - - return 0; /* shouldn't ever happen */ + return log_sno_name(desc->snomask); } /* set the level for a subsystem */ -void -log_set_level(char *subsys, char *level) +int +log_set_level(const char *subsys, const char *level) { struct LogDesc *desc; enum LogLevel lev; /* find subsystem */ if (!(desc = log_find(subsys))) - return; + return 2; /* set logging level */ if (EmptyString(level)) desc->level = L_DEFAULT; else if ((lev = log_lev_find(level)) != L_LAST_LEVEL) desc->level = lev; + else + return 1; + + return 0; } /* get the level for a subsystem */ char * -log_get_level(char *subsys) +log_get_level(const char *subsys) { struct LogDesc *desc; - int i; /* find subsystem */ if (!(desc = log_find(subsys))) return 0; /* find the level's name */ - for (i = 0; levelData[i].string; i++) - if (desc->level == levelData[i].level) - return levelData[i].string; /* found it... */ - - return 0; /* shouldn't ever happen */ + return log_lev_name(desc->level); } /* set the overall default syslog facility */ -void -log_set_default(char *facility) +int +log_set_default(const char *facility) { int fac, oldfac; @@ -724,23 +778,50 @@ log_set_default(char *facility) else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND && fac != LOG_NONE && fac != LOG_DEFAULT) logInfo.facility = fac; + else + return 1; if (logInfo.facility != oldfac) { closelog(); /* reopen syslog with new facility setting */ openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility); } + + return 0; } /* get the overall default syslog facility */ char * log_get_default(void) +{ + /* find the facility's name */ + return log_fac_name(logInfo.facility); +} + +/* Report feature settings */ +void +log_feature_report(struct Client *to) { int i; - /* find the facility's name */ - for (i = 0; facilities[i].name; i++) - if (logInfo.facility == facilities[i].facility) - return facilities[i].name; /* found it... */ + for (i = 0; i < LS_LAST_SYSTEM; i++) { + if (logDesc[i].file && logDesc[i].file->file) /* report file */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FILE %s", + logDesc[i].name, logDesc[i].file->file); + + if (logDesc[i].facility != logDesc[i].def_fac) /* report facility */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FACILITY %s", + logDesc[i].name, log_fac_name(logDesc[i].facility)); + + if (logDesc[i].snomask != logDesc[i].def_sno) /* report snomask */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s SNOMASK %s", + logDesc[i].name, log_sno_name(logDesc[i].snomask)); + + if (logDesc[i].level != L_DEFAULT) /* report log level */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s LEVEL %s", + logDesc[i].name, log_lev_name(logDesc[i].level)); + } - return 0; /* shouldn't ever happen */ + if (logInfo.facility != LOG_USER) /* report default facility */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s", + log_fac_name(logInfo.facility)); } diff --git a/ircd/m_get.c b/ircd/m_get.c new file mode 100644 index 0000000..3cdd6db --- /dev/null +++ b/ircd/m_get.c @@ -0,0 +1,108 @@ +/* + * IRC - Internet Relay Chat, ircd/m_get.c + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +/* + * m_functions execute protocol messages on this server: + * + * cptr is always NON-NULL, pointing to a *LOCAL* client + * structure (with an open socket connected!). This + * identifies the physical socket where the message + * originated (or which caused the m_function to be + * executed--some m_functions may call others...). + * + * sptr is the source of the message, defined by the + * prefix part of the message if present. If not + * or prefix not found, then sptr==cptr. + * + * (!IsServer(cptr)) => (cptr == sptr), because + * prefixes are taken *only* from servers... + * + * (IsServer(cptr)) + * (sptr == cptr) => the message didn't + * have the prefix. + * + * (sptr != cptr && IsServer(sptr) means + * the prefix specified servername. (?) + * + * (sptr != cptr && !IsServer(sptr) means + * that message originated from a remote + * user (not local). + * + * combining + * + * (!IsServer(sptr)) means that, sptr can safely + * taken as defining the target structure of the + * message in this server. + * + * *Always* true (if 'parse' and others are working correct): + * + * 1) sptr->from == cptr (note: cptr->from == cptr) + * + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr + * *cannot* be a local connection, unless it's + * actually cptr!). [MyConnect(x) should probably + * be defined as (x == x->from) --msa ] + * + * parc number of variable parameter strings (if zero, + * parv is allowed to be NULL) + * + * parv a NULL terminated list of parameter pointers, + * + * parv[0], sender (prefix string), if not present + * this points to an empty string. + * parv[1]...parv[parc-1] + * pointers to additional parameters + * parv[parc] == NULL, *always* + * + * note: it is guaranteed that parv[0]..parv[parc-1] are all + * non-NULL pointers. + */ +#if 0 +/* + * No need to include handlers.h here the signatures must match + * and we don't need to force a rebuild of all the handlers everytime + * we add a new one to the list. --Bleep + */ +#include "handlers.h" +#endif /* 0 */ +#include "client.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_features.h" +#include "ircd_reply.h" +#include "ircd_string.h" +#include "numeric.h" +#include "numnicks.h" +#include "send.h" + +#include + +/* + * mo_get - oper message handler + */ +int mo_get(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + return feature_get(sptr, (const char* const*)parv + 1, parc - 1); +} diff --git a/ircd/m_rehash.c b/ircd/m_rehash.c index de38a9c..01cfedc 100644 --- a/ircd/m_rehash.c +++ b/ircd/m_rehash.c @@ -92,6 +92,7 @@ #include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" +#include "motd.h" #include "numeric.h" #include "s_conf.h" #include "send.h" @@ -101,58 +102,47 @@ /* * mo_rehash - oper message handler * + * parv[1] = 'm' flushes the MOTD cache and returns + * parv[1] = 'l' reopens the log files and returns * parv[1] = 'q' to not rehash the resolver (optional) */ int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { #if defined(OPER_REHASH) || defined(LOCOP_REHASH) -#ifndef LOCOP_REHASH - if (!MyUser(sptr) || !IsOper(sptr)) -#else -#ifdef OPER_REHASH - if (!MyUser(sptr) || !IsAnOper(sptr)) -#else - if (!MyUser(sptr) || !IsLocOp(sptr)) -#endif -#endif - { - send_reply(sptr, ERR_NOPRIVILEGES); - return 0; + int flag = 0; + +# if !defined(OPER_REHASH) || !defined(LOCOP_REHASH) + if ( +# ifdef OPER_REHASH + !IsOper(sptr) +# else + !IsLocOp(sptr) +# endif + ) + return send_reply(sptr, ERR_NOPRIVILEGES); +# endif + + if (parc > 1) { /* special processing */ + if (*parv[1] == 'm') { + send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Flushing MOTD cache"); + motd_recache(); /* flush MOTD cache */ + return 0; + } else if (*parv[1] == 'l') { + send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files"); + log_reopen(); /* reopen log files */ + return 0; + } else if (*parv[1] == 'q') + flag = 2; } + send_reply(sptr, RPL_REHASHING, configfile); sendto_opmask_butone(0, SNO_OLDSNO, "%C is rehashing Server config file", sptr); + ircd_log(L_INFO, "REHASH From %s\n", get_client_name(sptr, HIDE_IP)); - return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0); + + return rehash(cptr, flag); #endif /* defined(OPER_REHASH) || defined(LOCOP_REHASH) */ return 0; } -#if 0 -#if defined(OPER_REHASH) || defined(LOCOP_REHASH) -/* - * m_rehash - */ -int m_rehash(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) -{ -#ifndef LOCOP_REHASH - if (!MyUser(sptr) || !IsOper(sptr)) -#else -#ifdef OPER_REHASH - if (!MyUser(sptr) || !IsAnOper(sptr)) -#else - if (!MyUser(sptr) || !IsLocOp(sptr)) -#endif -#endif - { - sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); /* XXX DEAD */ - return 0; - } - sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile); /* XXX DEAD */ - sendto_ops("%s is rehashing Server config file", parv[0]); /* XXX DEAD */ - ircd_log(L_INFO, "REHASH From %s\n", get_client_name(sptr, HIDE_IP)); - return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0); -} -#endif -#endif /* 0 */ - diff --git a/ircd/m_reset.c b/ircd/m_reset.c new file mode 100644 index 0000000..6a7981a --- /dev/null +++ b/ircd/m_reset.c @@ -0,0 +1,108 @@ +/* + * IRC - Internet Relay Chat, ircd/m_reset.c + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +/* + * m_functions execute protocol messages on this server: + * + * cptr is always NON-NULL, pointing to a *LOCAL* client + * structure (with an open socket connected!). This + * identifies the physical socket where the message + * originated (or which caused the m_function to be + * executed--some m_functions may call others...). + * + * sptr is the source of the message, defined by the + * prefix part of the message if present. If not + * or prefix not found, then sptr==cptr. + * + * (!IsServer(cptr)) => (cptr == sptr), because + * prefixes are taken *only* from servers... + * + * (IsServer(cptr)) + * (sptr == cptr) => the message didn't + * have the prefix. + * + * (sptr != cptr && IsServer(sptr) means + * the prefix specified servername. (?) + * + * (sptr != cptr && !IsServer(sptr) means + * that message originated from a remote + * user (not local). + * + * combining + * + * (!IsServer(sptr)) means that, sptr can safely + * taken as defining the target structure of the + * message in this server. + * + * *Always* true (if 'parse' and others are working correct): + * + * 1) sptr->from == cptr (note: cptr->from == cptr) + * + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr + * *cannot* be a local connection, unless it's + * actually cptr!). [MyConnect(x) should probably + * be defined as (x == x->from) --msa ] + * + * parc number of variable parameter strings (if zero, + * parv is allowed to be NULL) + * + * parv a NULL terminated list of parameter pointers, + * + * parv[0], sender (prefix string), if not present + * this points to an empty string. + * parv[1]...parv[parc-1] + * pointers to additional parameters + * parv[parc] == NULL, *always* + * + * note: it is guaranteed that parv[0]..parv[parc-1] are all + * non-NULL pointers. + */ +#if 0 +/* + * No need to include handlers.h here the signatures must match + * and we don't need to force a rebuild of all the handlers everytime + * we add a new one to the list. --Bleep + */ +#include "handlers.h" +#endif /* 0 */ +#include "client.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_features.h" +#include "ircd_reply.h" +#include "ircd_string.h" +#include "numeric.h" +#include "numnicks.h" +#include "send.h" + +#include + +/* + * mo_reset - oper message handler + */ +int mo_reset(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + return feature_reset(sptr, (const char* const*)parv + 1, parc - 1); +} diff --git a/ircd/m_set.c b/ircd/m_set.c new file mode 100644 index 0000000..76be0af --- /dev/null +++ b/ircd/m_set.c @@ -0,0 +1,108 @@ +/* + * IRC - Internet Relay Chat, ircd/m_set.c + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +/* + * m_functions execute protocol messages on this server: + * + * cptr is always NON-NULL, pointing to a *LOCAL* client + * structure (with an open socket connected!). This + * identifies the physical socket where the message + * originated (or which caused the m_function to be + * executed--some m_functions may call others...). + * + * sptr is the source of the message, defined by the + * prefix part of the message if present. If not + * or prefix not found, then sptr==cptr. + * + * (!IsServer(cptr)) => (cptr == sptr), because + * prefixes are taken *only* from servers... + * + * (IsServer(cptr)) + * (sptr == cptr) => the message didn't + * have the prefix. + * + * (sptr != cptr && IsServer(sptr) means + * the prefix specified servername. (?) + * + * (sptr != cptr && !IsServer(sptr) means + * that message originated from a remote + * user (not local). + * + * combining + * + * (!IsServer(sptr)) means that, sptr can safely + * taken as defining the target structure of the + * message in this server. + * + * *Always* true (if 'parse' and others are working correct): + * + * 1) sptr->from == cptr (note: cptr->from == cptr) + * + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr + * *cannot* be a local connection, unless it's + * actually cptr!). [MyConnect(x) should probably + * be defined as (x == x->from) --msa ] + * + * parc number of variable parameter strings (if zero, + * parv is allowed to be NULL) + * + * parv a NULL terminated list of parameter pointers, + * + * parv[0], sender (prefix string), if not present + * this points to an empty string. + * parv[1]...parv[parc-1] + * pointers to additional parameters + * parv[parc] == NULL, *always* + * + * note: it is guaranteed that parv[0]..parv[parc-1] are all + * non-NULL pointers. + */ +#if 0 +/* + * No need to include handlers.h here the signatures must match + * and we don't need to force a rebuild of all the handlers everytime + * we add a new one to the list. --Bleep + */ +#include "handlers.h" +#endif /* 0 */ +#include "client.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_features.h" +#include "ircd_reply.h" +#include "ircd_string.h" +#include "numeric.h" +#include "numnicks.h" +#include "send.h" + +#include + +/* + * mo_set - oper message handler + */ +int mo_set(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + return feature_set(sptr, (const char* const*)parv + 1, parc - 1); +} diff --git a/ircd/m_stats.c b/ircd/m_stats.c index de306a0..24f9cf0 100644 --- a/ircd/m_stats.c +++ b/ircd/m_stats.c @@ -270,6 +270,10 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (0 == report_klines(sptr, (parc == 4) ? parv[3] : 0, 0)) return 0; break; + case 'F': + case 'f': + report_feature_list(sptr); + break; case 'I': case 'i': { @@ -501,6 +505,10 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, !IsOper(sptr))) return 0; break; + case 'F': + case 'f': + report_feature_list(sptr); + break; case 'I': case 'i': { @@ -730,6 +738,10 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, 0)) return 0; break; + case 'F': + case 'f': + report_feature_list(sptr); + break; case 'I': case 'i': { diff --git a/ircd/parse.c b/ircd/parse.c index 7fb9571..2b44a41 100644 --- a/ircd/parse.c +++ b/ircd/parse.c @@ -531,6 +531,27 @@ struct Message msgtab[] = { /* UNREG, CLIENT, SERVER, OPER, SERVICE */ { m_proto, m_proto, m_proto, m_proto, m_ignore } }, + { + MSG_SET, + TOK_SET, + 0, MAXPARA, MFLG_SLOW, 0, + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ + { m_unregistered, m_not_oper, m_ignore, mo_set, m_ignore } + }, + { + MSG_RESET, + TOK_RESET, + 0, MAXPARA, MFLG_SLOW, 0, + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ + { m_unregistered, m_not_oper, m_ignore, mo_reset, m_ignore } + }, + { + MSG_GET, + TOK_GET, + 0, MAXPARA, MFLG_SLOW, 0, + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ + { m_unregistered, m_not_oper, m_ignore, mo_get, m_ignore } + }, /* This command is an alias for QUIT during the unregistered part of * of the server. This is because someone jumping via a broken web * proxy will send a 'POST' as their first command - which we will diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 8a457c8..44d311b 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -25,6 +25,7 @@ #include "class.h" #include "client.h" #include "crule.h" +#include "ircd_features.h" #include "fileio.h" #include "gline.h" #include "hash.h" @@ -1064,6 +1065,11 @@ int read_configuration_file(void) conf_add_crule(field_vector, field_count, CRULE_AUTO); aconf->status = CONF_ILLEGAL; break; + case 'F': /* Feature line */ + case 'f': + feature_set(0, &field_vector[1], field_count - 1); + aconf->status = CONF_ILLEGAL; + break; case 'H': /* Hub server line */ case 'h': aconf->status = CONF_HUB; diff --git a/ircd/s_err.c b/ircd/s_err.c index a347352..4daadd7 100644 --- a/ircd/s_err.c +++ b/ircd/s_err.c @@ -511,7 +511,7 @@ static Numeric replyTable[] = { /* 237 */ { 0 }, /* 238 */ - { 0 }, + { RPL_STATSFLINE, "%c %s %s", "238" }, /* 239 */ { 0 }, /* 240 */ @@ -603,7 +603,7 @@ static Numeric replyTable[] = { /* 283 */ { RPL_ENDOFJUPELIST, ":End of Jupe List", "283" }, /* 284 */ - { 0 }, + { RPL_FEATURE, 0, "284" }, /* 285 */ { 0 }, /* 286 */ @@ -1025,13 +1025,13 @@ static Numeric replyTable[] = { /* 492 */ { 0 }, /* 493 */ - { 0 }, + { ERR_NOFEATURE, "%s :No such feature", "493" }, /* 494 */ - { 0 }, + { ERR_BADLOGTYPE, "%s :No such log type", "494" }, /* 495 */ - { 0 }, + { ERR_BADLOGSYS, "%s :No such log subsystem", "495" }, /* 496 */ - { 0 }, + { ERR_BADLOGVALUE, "%s :Bad value for log type", "496" }, /* 497 */ { 0 }, /* 498 */ diff --git a/ircd/s_stats.c b/ircd/s_stats.c index ba97f8a..68127b2 100644 --- a/ircd/s_stats.c +++ b/ircd/s_stats.c @@ -27,6 +27,7 @@ #include "client.h" #include "ircd.h" #include "ircd_chattr.h" +#include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" #include "listener.h" @@ -71,6 +72,7 @@ const char *statsinfo[] = { "g - Global bans (G-lines).", "k - Local bans (K-Lines).", "o - Operator information.", + "f - Feature settings.", "m - Message usage information.", "t - Local connection statistics (Total SND/RCV, etc).", "w - Userload statistics.", @@ -168,6 +170,15 @@ void report_deny_list(struct Client* to) p->hostmask, p->message, p->usermask); } +/* + * {CONF_FEATURE, RPL_STATSFLINE, 'F'}, + */ +void report_feature_list(struct Client* to) +{ + if (MyOper(to)) /* non-local opers don't need to know log config */ + log_feature_report(to); +} + /* m_stats is so obnoxiously full of special cases that the different * hunt_server() possiblites were becoming very messy. It now uses a * switch() so as to be easier to read and update as params change. @@ -184,6 +195,8 @@ int hunt_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[], /* open to all, standard # of params */ case 'U': case 'u': + case 'F': + case 'f': return hunt_server_cmd(sptr, CMD_STATS, cptr, 0, "%s :%C", 2, parc, parv);