From f8168ea75d63c16cd9bf60d97a1a6bdfae987a82 Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Fri, 15 Dec 2000 20:29:16 +0000 Subject: [PATCH] Author: Kev Log message: Finish the design of the features subsystem and fix some logging bogosity. Last thing to do with features: Make compile-time constants go away. Testing: Brute-force the logging stuff. This change destabilizes that stuff a bit. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@341 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 39 +++++ include/ircd_features.h | 14 ++ include/ircd_log.h | 6 +- include/numeric.h | 7 +- include/s_stats.h | 1 - ircd/Makefile.in | 22 +-- ircd/ircd_features.c | 356 ++++++++++++++++++++++++++++++++++++---- ircd/ircd_log.c | 113 ++++++++++--- ircd/m_stats.c | 7 +- ircd/s_conf.c | 3 + ircd/s_debug.c | 2 +- ircd/s_err.c | 8 +- ircd/s_stats.c | 9 - 13 files changed, 502 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index 644973f..b89e437 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,44 @@ 2000-12-15 Kevin L. Mitchell + * ircd/Makefile.in: run make depend... + + * ircd/s_stats.c: get rid of report_feature_list() + + * ircd/s_err.c: add the 'bad value' error message, shift error + messages over somewhat + + * ircd/s_debug.c (debug_init): call log_debug_init with the + use_tty flag + + * ircd/s_conf.c (read_configuration_file): unmark features before + reading the config file, then reset unmarked features after + reading the config file + + * ircd/m_stats.c: use feature_report() instead of + report_feature_list() + + * ircd/ircd_log.c: fix log_debug_file (bogus assertion); add + special 'mark' flags and use them; add the stuff needed by the + features API + + * ircd/ircd_features.c: rework the features API and add gobs of + comments to try to explain what some of these complex functions + are actually doing + + * include/s_stats.h: get rid of report_feature_list(); use + feature_report() instead + + * include/numeric.h: added a new error message and shifted old + values over some--this is, after all, an alpha + + * include/ircd_log.h: log_debug_init now takes an integer to tell + it if it should be using the tty; added a couple of functions + required by the features API + + * include/ircd_features.h: add an enum and some more functions to + flesh out the feature API--it should now be possible to put all + those compile-time constants in the config file! + * ircd/send.c: got the direction of the assert incorrect... * ircd/send.c: implement the efficiency of flush_connections by diff --git a/include/ircd_features.h b/include/ircd_features.h index c683721..e76140e 100644 --- a/include/ircd_features.h +++ b/include/ircd_features.h @@ -23,6 +23,11 @@ struct Client; +enum Feature { + FEAT_LOG, + FEAT_LAST_F +}; + extern int feature_set(struct Client* from, const char* const* fields, int count); extern int feature_reset(struct Client* from, const char* const* fields, @@ -30,4 +35,13 @@ extern int feature_reset(struct Client* from, const char* const* fields, extern int feature_get(struct Client* from, const char* const* fields, int count); +extern void feature_unmark(void); +extern void feature_mark(void); + +extern void feature_report(struct Client* to); + +extern int feature_int(enum Feature feat); +extern int feature_bool(enum Feature feat); +extern const char *feature_str(enum Feature feat); + #endif /* INCLUDED_features_h */ diff --git a/include/ircd_log.h b/include/ircd_log.h index e16b087..9c6b3b2 100644 --- a/include/ircd_log.h +++ b/include/ircd_log.h @@ -50,7 +50,7 @@ enum LogSys { LS_LAST_SYSTEM }; -extern void log_debug_init(char *file); +extern void log_debug_init(int usetty); extern void log_init(const char *process_name); extern void log_reopen(void); extern void log_close(void); @@ -88,6 +88,8 @@ 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); +extern void log_feature_unmark(void); +extern void log_feature_mark(int flag); +extern void log_feature_report(struct Client *to, int flag); #endif /* INCLUDED_ircd_log_h */ diff --git a/include/numeric.h b/include/numeric.h index 48c26a4..ecdc6c0 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -355,9 +355,10 @@ extern const struct Numeric* get_error_numeric(int err); /* 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_BADFEATVALUE 494 /* Undernet extension - features */ +#define ERR_BADLOGTYPE 495 /* Undernet extension - features */ +#define ERR_BADLOGSYS 496 /* Undernet extension - features */ +#define ERR_BADLOGVALUE 497 /* Undernet extension - features */ #define ERR_ISOPERLCHAN 498 /* Undernet extension */ diff --git a/include/s_stats.h b/include/s_stats.h index ecd5766..49dfe01 100644 --- a/include/s_stats.h +++ b/include/s_stats.h @@ -35,6 +35,5 @@ 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 2ec314b..b2f7a64 100644 --- a/ircd/Makefile.in +++ b/ircd/Makefile.in @@ -384,7 +384,8 @@ ircd_log.o: ircd_log.c ../include/ircd_log.h ../include/client.h \ ../include/ircd_snprintf.h ../include/ircd_string.h \ ../include/ircd_chattr.h ../include/ircd.h ../include/struct.h \ ../include/numeric.h ../include/s_debug.h ../include/send.h -ircd_osdep.o: ircd_osdep.c ../include/ircd_osdep.h +ircd_osdep.o: ircd_osdep.c ../include/ircd_osdep.h ../include/msgq.h \ + ../include/ircd_defs.h ircd_relay.o: ircd_relay.c ../include/ircd_relay.h \ ../include/channel.h ../config/config.h ../config/setup.h \ ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \ @@ -582,7 +583,7 @@ m_join.o: m_join.c ../include/channel.h ../config/config.h \ ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \ ../include/ircd_string.h ../include/msg.h ../include/numeric.h \ ../include/numnicks.h ../include/s_debug.h ../include/s_user.h \ - ../include/send.h ../include/handlers.h + ../include/send.h m_jupe.o: m_jupe.c ../include/client.h ../include/ircd_defs.h \ ../config/config.h ../config/setup.h ../include/dbuf.h \ ../include/msgq.h ../include/ircd_handler.h ../include/jupe.h \ @@ -810,12 +811,13 @@ m_stats.o: m_stats.c ../include/s_stats.h ../include/channel.h \ ../include/msgq.h ../include/ircd_handler.h ../include/gline.h \ ../include/hash.h ../include/ircd.h ../include/struct.h \ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_chattr.h \ - ../include/ircd_reply.h ../include/ircd_string.h ../include/list.h \ - ../include/listener.h ../include/match.h ../include/motd.h \ - ../include/msg.h ../include/numeric.h ../include/numnicks.h \ - ../include/opercmds.h ../include/s_bsd.h ../include/s_conf.h \ - ../include/s_debug.h ../include/s_misc.h ../include/s_serv.h \ - ../include/s_user.h ../include/send.h ../include/userload.h + ../include/ircd_features.h ../include/ircd_reply.h \ + ../include/ircd_string.h ../include/list.h ../include/listener.h \ + ../include/match.h ../include/motd.h ../include/msg.h \ + ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \ + ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \ + ../include/s_misc.h ../include/s_serv.h ../include/s_user.h \ + ../include/send.h ../include/userload.h m_time.o: m_time.c ../include/client.h ../include/ircd_defs.h \ ../config/config.h ../config/setup.h ../include/dbuf.h \ ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \ @@ -919,7 +921,7 @@ motd.o: motd.c ../include/motd.h ../include/class.h \ ../include/s_debug.h ../include/s_user.h ../include/send.h msgq.o: msgq.c ../include/msgq.h ../include/ircd_defs.h \ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_snprintf.h \ - ../config/config.h ../config/setup.h + ../config/config.h ../config/setup.h ../include/s_debug.h numnicks.o: numnicks.c ../include/numnicks.h ../include/client.h \ ../include/ircd_defs.h ../config/config.h ../config/setup.h \ ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \ @@ -1044,7 +1046,7 @@ s_serv.o: s_serv.c ../include/s_serv.h ../include/IPcheck.h \ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_reply.h \ ../include/ircd_string.h ../include/ircd_chattr.h \ ../include/ircd_snprintf.h ../include/ircd_xopen.h ../include/jupe.h \ - ../include/list.h ../include/msg.h ../include/match.h \ + ../include/list.h ../include/match.h ../include/msg.h \ ../include/numeric.h ../include/numnicks.h ../include/parse.h \ ../include/querycmds.h ../include/s_bsd.h ../include/s_conf.h \ ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \ diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c index 25d17c0..2ac6398 100644 --- a/ircd/ircd_features.c +++ b/ircd/ircd_features.c @@ -39,8 +39,10 @@ #include "sys.h" /* FALSE bleah */ #include +#include #include +/* List of log output types that can be set */ static struct LogTypes { char *type; int (*set)(const char *, const char *); @@ -53,6 +55,7 @@ static struct LogTypes { { 0, 0, 0 } }; +/* Look up a struct LogType given the type string */ static struct LogTypes * feature_log_desc(struct Client* from, const char *type) { @@ -65,7 +68,7 @@ feature_log_desc(struct Client* from, const char *type) return &logTypes[i]; Debug((DEBUG_ERROR, "Unknown log feature type \"%s\"", type)); - if (from) + if (from) /* send an error; if from is NULL, called from conf parser */ send_reply(from, ERR_BADLOGTYPE, type); else log_write(LS_CONFIG, L_ERROR, 0, "Unknown log feature type \"%s\"", type); @@ -73,7 +76,8 @@ feature_log_desc(struct Client* from, const char *type) return 0; /* not found */ } -static void +/* Set the value of a log output type for a log subsystem */ +static int feature_log_set(struct Client* from, const char* const* fields, int count) { struct LogTypes *desc; @@ -83,14 +87,15 @@ feature_log_set(struct Client* from, const char* const* fields, int count) if (log_set_default(count < 1 ? 0 : fields[0])) { assert(count >= 1); /* should always accept default */ - if (from) + if (from) /* send an error */ send_reply(from, ERR_BADLOGVALUE, fields[0]); else log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"%s\" for default facility", fields[0]); - } + } else + return count < 1 ? -1 : 1; /* tell feature to set or clear mark */ } else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */ - if (from) + if (from) /* send an error */ send_reply(from, ERR_BADLOGSYS, fields[0]); else log_write(LS_CONFIG, L_ERROR, 0, @@ -99,7 +104,7 @@ feature_log_set(struct Client* from, const char* const* fields, int count) if ((*desc->set)(fields[0], count < 3 ? 0 : fields[2])) { assert(count >= 3); /* should always accept default */ - if (from) + if (from) /* send an error */ send_reply(from, ERR_BADLOGVALUE, fields[2]); else log_write(LS_CONFIG, L_ERROR, 0, @@ -107,33 +112,40 @@ feature_log_set(struct Client* from, const char* const* fields, int count) fields[2], desc->type, subsys); } } + + return 0; } -static void +/* reset a log type for a subsystem to its default value */ +static int feature_log_reset(struct Client* from, const char* const* fields, int count) { struct LogTypes *desc; char *subsys; - assert(0 != from); + assert(0 != from); /* Never called by the .conf parser */ - if (count < 1) /* reset default facility */ + if (count < 1) { /* reset default facility */ log_set_default(0); - else if (count < 2) + return -1; /* unmark this entry */ + } 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); + (*desc->set)(fields[0], 0); /* default should always be accepted */ + + return 0; } +/* report the value of a log setting */ static void feature_log_get(struct Client* from, const char* const* fields, int count) { struct LogTypes *desc; char *value, *subsys; - assert(0 != from); + assert(0 != from); /* never called by .conf parser */ if (count < 1) /* return default facility */ send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Log facility: %s", @@ -153,18 +165,60 @@ feature_log_get(struct Client* from, const char* const* fields, int count) } } -typedef void (*feature_call)(struct Client*, const char* const*, int); +/* sets a feature to the given value */ +typedef int (*feat_set_call)(struct Client*, const char* const*, int); +/* gets the value of a feature */ +typedef void (*feat_get_call)(struct Client*, const char* const*, int); +/* unmarks all sub-feature values prior to reading .conf */ +typedef void (*feat_unmark_call)(void); +/* resets to defaults all currently unmarked values */ +typedef void (*feat_mark_call)(int); +/* reports features as a /stats f list */ +typedef void (*feat_report_call)(struct Client*, int); + +#define FEAT_NONE 0x0000 /* no value */ +#define FEAT_INT 0x0001 /* set if entry contains an integer value */ +#define FEAT_BOOL 0x0002 /* set if entry contains a boolean value */ +#define FEAT_STR 0x0003 /* set if entry contains a string value */ +#define FEAT_MASK 0x000f /* possible value types */ + +#define FEAT_MARK 0x0010 /* set if entry has been changed */ +#define FEAT_NULL 0x0020 /* NULL string is permitted */ +#define FEAT_CASE 0x0040 /* string is case-sensitive */ + +#define FEAT_OPER 0x0100 /* set to display only to opers */ +#define FEAT_MYOPER 0x0200 /* set to display only to local opers */ 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 */ + enum Feature feat; /* feature identifier */ + char* type; /* string describing type */ + unsigned int flags; /* flags for feature */ + int v_int; /* integer value */ + int def_int; /* default value */ + char* v_str; /* string value */ + char* def_str; /* default value */ + feat_set_call set; /* set feature values */ + feat_set_call reset; /* reset feature values to defaults */ + feat_get_call get; /* get feature values */ + feat_unmark_call unmark; /* unmark all feature change values */ + feat_mark_call mark; /* reset to defaults all unchanged features */ + feat_report_call report; /* report feature values */ } features[] = { - { "LOG", feature_log_set, feature_log_reset, feature_log_get }, - { 0, 0, 0, 0 } +#define F(type, flags, v_int, v_str, set, reset, get, unmark, mark, report) \ + { FEAT_##type, #type, (flags), \ + 0, (v_int), 0, (v_str), \ + (set), (reset), (get), \ + (unmark), (mark), \ + (report) } + + F(LOG, FEAT_NONE | FEAT_MYOPER, 0, 0, + feature_log_set, feature_log_reset, feature_log_get, + log_feature_unmark, log_feature_mark, log_feature_report), + + { FEAT_LAST_F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; +/* Given a feature's identifier, look up the feature descriptor */ static struct FeatureDesc * feature_desc(struct Client* from, const char *feature) { @@ -177,7 +231,7 @@ feature_desc(struct Client* from, const char *feature) return &features[i]; Debug((DEBUG_ERROR, "Unknown feature \"%s\"", feature)); - if (from) + if (from) /* report an error */ send_reply(from, ERR_NOFEATURE, feature); else log_write(LS_CONFIG, L_ERROR, 0, "Unknown feature \"%s\"", feature); @@ -185,37 +239,145 @@ feature_desc(struct Client* from, const char *feature) return 0; /* not found */ } +/* Given a feature vector string, set the value of a feature */ int feature_set(struct Client* from, const char* const* fields, int count) { + int i; struct FeatureDesc *feat; if (count < 1) { - if (from) + if (from) /* report an error in the number of arguments */ 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); + } else if ((feat = feature_desc(from, fields[0]))) { /* find feature */ + if (feat->set && (i = (*feat->set)(from, fields + 1, count - 1))) { + if (i > 0) /* call the set callback and do marking */ + feat->flags |= FEAT_MARK; + else /* i < 0 */ + feat->flags &= ~FEAT_MARK; + } else /* Ok, it's a value we can fiddle with */ + switch (feat->flags & FEAT_MASK) { + case FEAT_INT: /* an integer value */ + if (count < 2) { /* reset value */ + feat->v_int = feat->def_int; + feat->flags &= ~FEAT_MARK; + } else { /* ok, figure out the value and whether to mark it */ + feat->v_int = atoi(fields[1]); + if (feat->v_int == feat->def_int) + feat->flags &= ~FEAT_MARK; + else + feat->flags |= FEAT_MARK; + } + break; + + case FEAT_BOOL: /* it's a boolean value--true or false */ + if (count < 2) { /* reset value */ + feat->v_int = feat->def_int; + feat->flags &= ~FEAT_MARK; + } else { /* figure out the value and whether to mark it */ + if (!ircd_strncmp(fields[1], "TRUE", strlen(fields[1]))) + feat->v_int = 1; + else if (!ircd_strncmp(fields[1], "YES", strlen(fields[1]))) + feat->v_int = 1; + else if (!ircd_strncmp(fields[1], "FALSE", strlen(fields[1]))) + feat->v_int = 0; + else if (!ircd_strncmp(fields[1], "NO", strlen(fields[1]))) + feat->v_int = 0; + else if (from) /* report an error... */ + return send_reply(from, ERR_BADFEATVALUE, fields[1], feat->type); + else { + log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"%s\" for feature %s", + fields[1], feat->type); + return 0; + } + + if (feat->v_int == feat->def_int) /* figure out whether to mark it */ + feat->flags &= ~FEAT_MARK; + else + feat->flags |= FEAT_MARK; + } + break; + + case FEAT_STR: /* it's a string value */ + if (count < 2 || + !(feat->flags & FEAT_CASE ? strcmp(fields[1], feat->def_str) : + ircd_strcmp(fields[1], feat->def_str))) { /* reset to default */ + if (feat->v_str && feat->v_str != feat->def_str) + MyFree(feat->v_str); /* free old value */ + feat->v_str = feat->def_str; /* very special... */ + + feat->flags &= ~FEAT_MARK; /* unmark it */ + } else { + if (!*fields[1]) { /* empty string translates to NULL */ + if (feat->flags & FEAT_NULL) { /* permitted? */ + if (feat->v_str && feat->v_str != feat->def_str) + MyFree(feat->v_str); /* free old value */ + feat->v_str = 0; /* set it to NULL */ + } else if (from) /* hmmm...not permitted; report error */ + return send_reply(from, ERR_BADFEATVALUE, "NULL", feat->type); + else { + log_write(LS_CONFIG, L_ERROR, 0, + "Bad value \"NULL\" for feature %s", feat->type); + return 0; + } + } else if ((feat->flags & FEAT_CASE ? + strcmp(fields[1], feat->v_str) : + ircd_strcmp(fields[1], feat->v_str))) { /* new value */ + if (feat->v_str && feat->v_str != feat->def_str) + MyFree(feat->v_str); /* free old value */ + DupString(feat->v_str, fields[1]); /* store new value */ + } + + feat->flags |= FEAT_MARK; /* mark it as having been touched */ + } + break; + } + } return 0; } +/* reset a feature to its default values */ int feature_reset(struct Client* from, const char* const* fields, int count) { + int i; struct FeatureDesc *feat; assert(0 != from); - if (count < 1) + if (count < 1) /* check arguments */ need_more_params(from, "RESET"); - else if ((feat = feature_desc(from, fields[0]))) - (*feat->reset)(from, fields + 1, count - 1); + else if ((feat = feature_desc(from, fields[0]))) { /* get descriptor */ + if (feat->reset && (i = (*feat->reset)(from, fields + 1, count - 1))) { + if (i > 0) /* call reset callback and parse mark return */ + feat->flags |= FEAT_MARK; + else /* i < 0 */ + feat->flags &= ~FEAT_MARK; + } else { /* oh, it's something we own... */ + switch (feat->flags & FEAT_MASK) { + case FEAT_INT: /* Integer... */ + case FEAT_BOOL: /* Boolean... */ + feat->v_int = feat->def_int; /* set the default */ + break; + + case FEAT_STR: /* string! */ + if (feat->v_str && feat->v_str != feat->def_str) + MyFree(feat->v_str); /* free old value */ + feat->v_str = feat->def_str; /* set it to default */ + break; + } + + feat->flags &= ~FEAT_MARK; /* unmark it */ + } + } return 0; } +/* Gets the value of a specific feature and reports it to the user */ int feature_get(struct Client* from, const char* const* fields, int count) { @@ -223,10 +385,146 @@ feature_get(struct Client* from, const char* const* fields, int count) assert(0 != from); - if (count < 1) + if (count < 1) /* check parameters */ need_more_params(from, "GET"); - else if ((feat = feature_desc(from, fields[0]))) - (*feat->get)(from, fields + 1, count - 1); + else if ((feat = feature_desc(from, fields[0]))) { + if ((feat->flags & FEAT_MYOPER && !MyOper(from)) || + (feat->flags & FEAT_OPER && !IsAnOper(from))) /* check privs */ + return send_reply(from, ERR_NOPRIVILEGES); + + if (feat->get) /* if there's a callback, use it */ + (*feat->get)(from, fields + 1, count - 1); + else /* something we own */ + switch (feat->flags & FEAT_MASK) { + case FEAT_INT: /* integer, report integer value */ + send_reply(from, SND_EXPLICIT | RPL_FEATURE, + ":Integer value of %s: %d", feat->type, feat->v_int); + break; + + case FEAT_BOOL: /* boolean, report boolean value */ + send_reply(from, SND_EXPLICIT | RPL_FEATURE, + ":Boolean value of %s: %s", feat->type, + feat->v_int ? "TRUE" : "FALSE"); + break; + + case FEAT_STR: /* string, report string value */ + if (feat->v_str) /* deal with null case */ + send_reply(from, SND_EXPLICIT | RPL_FEATURE, + ":String value of %s: %s", feat->type, feat->v_str); + else + send_reply(from, SND_EXPLICIT | RPL_FEATURE, + ":String value for %s not set", feat->type); + break; + } + } return 0; } + +/* called before reading the .conf to clear all marks */ +void +feature_unmark(void) +{ + int i; + + for (i = 0; features[i].type; i++) { + features[i].flags &= ~FEAT_MARK; /* clear the marks... */ + if (features[i].unmark) /* call the unmark callback if necessary */ + (*features[i].unmark)(); + } +} + +/* Called after reading the .conf to reset unmodified values to defaults */ +void +feature_mark(void) +{ + int i; + + for (i = 0; features[i].type; i++) { + if (!(features[i].flags & FEAT_MARK)) { /* not changed? */ + switch (features[i].flags & FEAT_MASK) { + case FEAT_INT: /* Integers or Booleans... */ + case FEAT_BOOL: + features[i].v_int = features[i].def_int; + break; + + case FEAT_STR: /* strings... */ + if (features[i].v_str && features[i].v_str != features[i].def_str) + MyFree(features[i].v_str); /* free old value */ + features[i].v_str = features[i].def_str; + break; + } + } + + if (features[i].mark) /* call the mark callback if necessary */ + (*features[i].mark)(features[i].flags & FEAT_MARK ? 1 : 0); + } +} + +/* report all F-lines */ +void +feature_report(struct Client* to) +{ + int i; + + for (i = 0; features[i].type; i++) { + if ((features[i].flags & FEAT_MYOPER && !MyOper(to)) || + (features[i].flags & FEAT_OPER && !IsAnOper(to))) + continue; /* skip this one */ + + if (features[i].report) /* let the callback handle this */ + (*features[i].report)(to, features[i].flags & FEAT_MARK ? 1 : 0); + else if (features[i].flags & FEAT_MARK) { /* it's been changed */ + switch (features[i].flags & FEAT_MASK) { + case FEAT_INT: /* Report an F-line with integer values */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s %d", + features[i].type, features[i].v_int); + break; + + case FEAT_BOOL: /* Report an F-line with boolean values */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s %s", + features[i].type, features[i].v_int ? "TRUE" : "FALSE"); + break; + + case FEAT_STR: /* Report an F-line with string values */ + if (features[i].v_str) + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s %s", + features[i].type, features[i].v_str); + else /* Actually, F: would reset it; you want F:: */ + send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F %s", + features[i].type); + break; + } + } + } +} + +/* return a feature's integer value */ +int +feature_int(enum Feature feat) +{ + assert(features[feat].feat == feat); + assert((features[feat].flags & FEAT_MASK) == FEAT_INT); + + return features[feat].v_int; +} + +/* return a feature's boolean value */ +int +feature_bool(enum Feature feat) +{ + assert(features[feat].feat == feat); + assert((features[feat].flags & FEAT_MASK) == FEAT_BOOL); + + return features[feat].v_int; +} + +/* return a feature's string value */ +const char * +feature_str(enum Feature feat) +{ + assert(features[feat].feat == feat); + assert((features[feat].flags & FEAT_MASK) == FEAT_STR); + + return features[feat].v_str; +} diff --git a/ircd/ircd_log.c b/ircd/ircd_log.c index 37422bd..ccd1843 100644 --- a/ircd/ircd_log.c +++ b/ircd/ircd_log.c @@ -124,18 +124,24 @@ static struct { { 0, 0 } }; +#define LOG_MARK_FILE 0x0001 /* file has been changed */ +#define LOG_MARK_FACILITY 0x0002 /* facility has been changed */ +#define LOG_MARK_SNOMASK 0x0004 /* snomask has been changed */ +#define LOG_MARK_LEVEL 0x0008 /* level has been changed */ + /* Descriptions of all logging subsystems */ static struct LogDesc { enum LogSys subsys; /* number for subsystem */ char *name; /* subsystem name */ struct LogFile *file; /* file descriptor for subsystem */ + unsigned int mark; /* subsystem has been changed */ int def_fac; /* default facility */ unsigned int def_sno; /* default snomask */ int facility; /* -1 means don't use syslog */ unsigned int snomask; /* 0 means no server message */ enum LogLevel level; /* logging level */ } logDesc[] = { -#define S(sys, p, sn) { LS_ ## sys, #sys, 0, (p), (sn), (p), (sn), L_DEFAULT } +#define S(sys, p, sn) { LS_##sys, #sys, 0, 0, (p), (sn), (p), (sn), L_DEFAULT } S(SYSTEM, -1, 0), S(CONFIG, 0, SNO_OLDSNO), S(OPERMODE, -1, SNO_HACK4), @@ -221,7 +227,7 @@ log_debug_reopen(void) /* initialize debugging log */ void -log_debug_init(char *file) +log_debug_init(int usetty) { logInfo.dbfile = MyMalloc(sizeof(struct LogFile)); @@ -230,10 +236,10 @@ log_debug_init(char *file) logInfo.dbfile->fd = -1; logInfo.dbfile->ref = 1; - if (file) /* store pathname to use */ - DupString(logInfo.dbfile->file, file); - else + if (usetty) /* store pathname to use */ logInfo.dbfile->file = 0; + else + DupString(logInfo.dbfile->file, LOGFILE); log_debug_reopen(); /* open the debug log */ @@ -247,7 +253,8 @@ static int log_debug_file(const char *file) { #ifdef DEBUGMODE - assert(0 != file); + if (!file) + file = LOGFILE; /* If we weren't started with debugging enabled, or if we're using * the terminal, don't do anything at all. @@ -621,10 +628,14 @@ log_set_file(const char *subsys, const char *filename) if (desc->file && filename && !strcmp(desc->file->file, filename)) return 0; + if (filename) + desc->mark |= LOG_MARK_FILE; /* mark that file has been changed */ + else + desc->mark &= ~LOG_MARK_FILE; /* file has been reset to defaults */ + /* debug log is special, since it has to be opened on fd 2 */ - if (desc->subsys == LS_DEBUG) { + if (desc->subsys == LS_DEBUG) return log_debug_file(filename); - } if (desc->file) /* destroy previous entry... */ log_file_destroy(desc->file); @@ -660,11 +671,16 @@ log_set_facility(const char *subsys, const char *facility) return 2; /* set syslog facility */ - if (EmptyString(facility)) + if (EmptyString(facility)) { desc->facility = desc->def_fac; - else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND) + desc->mark &= ~LOG_MARK_FACILITY; + } else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND) { desc->facility = fac; - else + if (fac == desc->def_fac) + desc->mark &= ~LOG_MARK_FACILITY; + else + desc->mark |= LOG_MARK_FACILITY; + } else return 1; return 0; @@ -696,11 +712,16 @@ log_set_snomask(const char *subsys, const char *snomask) return 2; /* set snomask value */ - if (EmptyString(snomask)) + if (EmptyString(snomask)) { desc->snomask = desc->def_sno; - else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND) + desc->mark &= ~LOG_MARK_SNOMASK; + } else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND) { desc->snomask = sno; - else + if (sno == desc->def_sno) + desc->mark &= ~LOG_MARK_SNOMASK; + else + desc->mark |= LOG_MARK_SNOMASK; + } else return 1; return 0; @@ -732,11 +753,16 @@ log_set_level(const char *subsys, const char *level) return 2; /* set logging level */ - if (EmptyString(level)) + if (EmptyString(level)) { desc->level = L_DEFAULT; - else if ((lev = log_lev_find(level)) != L_LAST_LEVEL) + desc->mark &= ~LOG_MARK_LEVEL; + } else if ((lev = log_lev_find(level)) != L_LAST_LEVEL) { desc->level = lev; - else + if (lev == L_DEFAULT) + desc->mark &= ~LOG_MARK_LEVEL; + else + desc->mark |= LOG_MARK_LEVEL; + } else return 1; return 0; @@ -788,31 +814,72 @@ log_get_default(void) return log_fac_name(logInfo.facility); } +/* Clear the marks... */ +void +log_feature_unmark(void) +{ + int i; + + for (i = 0; i < LS_LAST_SYSTEM; i++) + logDesc[i].mark = 0; +} + +/* Reset unmarked fields to defaults... */ +void +log_feature_mark(int flag) +{ + int i; + + if (flag) + log_set_default(0); + + for (i = 0; i < LS_LAST_SYSTEM; i++) { + if (!(logDesc[i].mark & LOG_MARK_FILE)) { + if (logDesc[i].subsys == LS_DEBUG) + log_debug_file(0); /* debug is special */ + else { + if (logDesc[i].file) /* destroy previous entry... */ + log_file_destroy(logDesc[i].file); + logDesc[i].file = 0; + } + } + + if (!(logDesc[i].mark & LOG_MARK_FACILITY)) /* set default facility */ + logDesc[i].facility = logDesc[i].def_fac; + + if (!(logDesc[i].mark & LOG_MARK_SNOMASK)) /* set default snomask */ + logDesc[i].snomask = logDesc[i].def_sno; + + if (!(logDesc[i].mark & LOG_MARK_LEVEL)) /* set default level */ + logDesc[i].level = L_DEFAULT; + } +} + /* Report feature settings */ void -log_feature_report(struct Client *to) +log_feature_report(struct Client *to, int flag) { int i; for (i = 0; i < LS_LAST_SYSTEM; i++) { - if (logDesc[i].file && logDesc[i].file->file) /* report file */ + if (logDesc[i].mark & LOG_MARK_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 */ + if (logDesc[i].mark & LOG_MARK_FACILITY) /* 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 */ + if (logDesc[i].mark & LOG_MARK_SNOMASK) /* 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 */ + if (logDesc[i].mark & LOG_MARK_LEVEL) /* report log level */ send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s LEVEL %s", logDesc[i].name, log_lev_name(logDesc[i].level)); } - if (logInfo.facility != LOG_USER) /* report default facility */ + if (flag) /* report default facility */ send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s", log_fac_name(logInfo.facility)); } diff --git a/ircd/m_stats.c b/ircd/m_stats.c index 51a6c5f..73b9f3a 100644 --- a/ircd/m_stats.c +++ b/ircd/m_stats.c @@ -99,6 +99,7 @@ #include "ircd.h" #include "ircd_alloc.h" #include "ircd_chattr.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "list.h" @@ -272,7 +273,7 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) break; case 'F': case 'f': - report_feature_list(sptr); + feature_report(sptr); break; case 'I': case 'i': @@ -493,7 +494,7 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) break; case 'F': case 'f': - report_feature_list(sptr); + feature_report(sptr); break; case 'I': case 'i': @@ -712,7 +713,7 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) break; case 'F': case 'f': - report_feature_list(sptr); + feature_report(sptr); break; case 'I': case 'i': diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 24f2798..06beff8 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -944,6 +944,8 @@ int read_configuration_file(void) return 0; } + feature_unmark(); /* unmark all features for resetting later */ + while (fbgets(line, sizeof(line) - 1, file)) { if ('#' == *line || IsSpace(*line)) continue; @@ -1228,6 +1230,7 @@ int read_configuration_file(void) free_conf(aconf); fbclose(file); nextping = nextconnect = CurrentTime; + feature_mark(); /* reset unmarked features */ return 1; } diff --git a/ircd/s_debug.c b/ircd/s_debug.c index f1c7afd..32134b9 100644 --- a/ircd/s_debug.c +++ b/ircd/s_debug.c @@ -190,7 +190,7 @@ void debug_init(int use_tty) #ifdef DEBUGMODE if (debuglevel >= 0) { printf("isatty = %d ttyname = %s\n", isatty(2), ttyname(2)); - log_debug_init(use_tty ? 0 : LOGFILE); + log_debug_init(use_tty); } #endif } diff --git a/ircd/s_err.c b/ircd/s_err.c index 4daadd7..6a55b3d 100644 --- a/ircd/s_err.c +++ b/ircd/s_err.c @@ -1027,13 +1027,13 @@ static Numeric replyTable[] = { /* 493 */ { ERR_NOFEATURE, "%s :No such feature", "493" }, /* 494 */ - { ERR_BADLOGTYPE, "%s :No such log type", "494" }, + { ERR_BADFEATVALUE, "%s :Bad value for feature %s", "494" }, /* 495 */ - { ERR_BADLOGSYS, "%s :No such log subsystem", "495" }, + { ERR_BADLOGTYPE, "%s :No such log type", "495" }, /* 496 */ - { ERR_BADLOGVALUE, "%s :Bad value for log type", "496" }, + { ERR_BADLOGSYS, "%s :No such log subsystem", "496" }, /* 497 */ - { 0 }, + { ERR_BADLOGVALUE, "%s :Bad value for log type", "497" }, /* 498 */ { ERR_ISOPERLCHAN, "%s %s :Cannot kick or deop an IRC Operator on a local channel", "498" }, /* 499 */ diff --git a/ircd/s_stats.c b/ircd/s_stats.c index 68127b2..2a7ca4a 100644 --- a/ircd/s_stats.c +++ b/ircd/s_stats.c @@ -170,15 +170,6 @@ 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. -- 2.20.1