+2000-11-30 Kevin L. Mitchell <klmitch@mit.edu>
+
+ * 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 <klmitch@mit.edu>
* ircd/s_debug.c: rewrite debug_init() and vdebug() in terms of
# 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:<key>:<value>[:<value>[...]]
+#
+# Currently, the only defined value for <key> 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:<facility>
+# F:LOG:<subsystem>:<type>[:<value>]
+#
+# The first sets the default facility for ircu to log to to <facility>.
+# Valid <facility> 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 <type> 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 <value> is given, or if <value> is empty, the default
+# value for that type is set.
+#
+# Valid <value>'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 <value>'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 <value>'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 <doco-com@undernet.org>
#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)
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*[]);
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*[]);
--- /dev/null
+#ifndef INCLUDED_features_h
+#define INCLUDED_features_h
+/*
+ * IRC - Internet Relay Chat, include/features.h
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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 */
#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 */
#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
*/
#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
#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 */
#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
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 */
hash.c \
ircd.c \
ircd_alloc.c \
+ ircd_features.c \
ircd_log.c \
ircd_osdep.c \
ircd_relay.c \
m_die.c \
m_endburst.c \
m_error.c \
+ m_get.c \
m_gline.c \
m_help.c \
m_info.c \
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 \
--- /dev/null
+/*
+ * IRC - Internet Relay Chat, ircd/features.c
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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 <assert.h>
+#include <string.h>
+
+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;
+}
#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"
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
/* finds a subsystem given its name */
static struct LogDesc *
-log_find(char *subsys)
+log_find(const char *subsys)
{
int i;
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;
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;
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;
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... */
/* 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;
}
/* 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;
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));
}
--- /dev/null
+/*
+ * 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 <assert.h>
+
+/*
+ * 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);
+}
#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"
/*
* 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 */
-
--- /dev/null
+/*
+ * 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 <assert.h>
+
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 <assert.h>
+
+/*
+ * 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);
+}
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':
{
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':
{
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':
{
/* 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
#include "class.h"
#include "client.h"
#include "crule.h"
+#include "ircd_features.h"
#include "fileio.h"
#include "gline.h"
#include "hash.h"
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;
/* 237 */
{ 0 },
/* 238 */
- { 0 },
+ { RPL_STATSFLINE, "%c %s %s", "238" },
/* 239 */
{ 0 },
/* 240 */
/* 283 */
{ RPL_ENDOFJUPELIST, ":End of Jupe List", "283" },
/* 284 */
- { 0 },
+ { RPL_FEATURE, 0, "284" },
/* 285 */
{ 0 },
/* 286 */
/* 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 */
#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"
"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.",
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.
/* 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);