aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-06-02 18:45:53 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-06-02 18:45:53 +0000
commit2c26c67fae94e783d5cc5ee634273b639aa405e5 (patch)
tree2a06b7393fa97e5ce6a4b5e166ae412de063f1ad
parent2a37423d019dbfdfd8c11072dd6abe624aa5c286 (diff)
downloadgsc-2c26c67fae94e783d5cc5ee634273b639aa405e5.tar.gz
gsc-2c26c67fae94e783d5cc5ee634273b639aa405e5.tar.bz2
Update
git-svn-id: file:///svnroot/gsc/trunk@250 d2de0444-eb31-0410-8365-af798a554d48
-rw-r--r--jabberd/Makefile.am2
-rw-r--r--jabberd/argcv.c439
-rw-r--r--jabberd/jabberd.h21
-rw-r--r--jabberd/main.c341
-rw-r--r--jabberd/progman.c292
5 files changed, 929 insertions, 166 deletions
diff --git a/jabberd/Makefile.am b/jabberd/Makefile.am
index 872b15c..b5667ba 100644
--- a/jabberd/Makefile.am
+++ b/jabberd/Makefile.am
@@ -1,3 +1,3 @@
bin_PROGRAMS = jabberd
-jabberd_SOURCES = main.c progman.c jabber.h
+jabberd_SOURCES = main.c progman.c jabber.h argcv.c
AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\" \ No newline at end of file
diff --git a/jabberd/argcv.c b/jabberd/argcv.c
new file mode 100644
index 0000000..dc3fbc0
--- /dev/null
+++ b/jabberd/argcv.c
@@ -0,0 +1,439 @@
+/* argcv.c - simple functions for parsing input based on whitespace
+ Copyright (C) 1999, 2000, 2001, 2003, 2004,
+ 2005, 2006 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+/*
+ * takes a string and splits it into several strings, breaking at ' '
+ * command is the string to split
+ * the number of strings is placed into argc
+ * the split strings are put into argv
+ * returns 0 on success, nonzero on failure
+ */
+
+#define isws(c) ((c)==' '||(c)=='\t'||(c)=='\n')
+#define isdelim(c,delim) (strchr(delim,(c))!=NULL)
+
+static int
+argcv_scan (int len, const char *command, const char *delim, const char* cmnt,
+ int *start, int *end, int *save)
+{
+ int i = 0;
+
+ for (;;)
+ {
+ i = *save;
+
+ if (i >= len)
+ return i + 1;
+
+ /* Skip initial whitespace */
+ while (i < len && isws (command[i]))
+ i++;
+ *start = i;
+
+ if (!isdelim (command[i], delim))
+ {
+ while (i < len)
+ {
+ if (command[i] == '\\')
+ {
+ if (++i == len)
+ break;
+ i++;
+ continue;
+ }
+
+ if (command[i] == '\'' || command[i] == '"')
+ {
+ int j;
+ for (j = i+1; j < len && command[j] != command[i]; j++)
+ if (command[j] == '\\')
+ j++;
+ if (j < len)
+ i = j+1;
+ else
+ i++;
+ }
+ else if (isws (command[i]) || isdelim (command[i], delim))
+ break;
+ else
+ i++; /* skip the escaped character */
+ }
+ i--;
+ }
+
+ *end = i;
+ *save = i + 1;
+
+ /* If we have a token, and it starts with a comment character, skip
+ to the newline and restart the token search. */
+ if (*save <= len)
+ {
+ if (strchr (cmnt, command[*start]) != NULL)
+ {
+ i = *save;
+ while (i < len && command[i] != '\n')
+ i++;
+
+ *save = i;
+ continue;
+ }
+ }
+ break;
+ }
+ return *save;
+}
+
+static char quote_transtab[] = "\\\\a\ab\bf\fn\nr\rt\t";
+
+int
+argcv_unquote_char (int c)
+{
+ char *p;
+
+ for (p = quote_transtab; *p; p += 2)
+ {
+ if (*p == c)
+ return p[1];
+ }
+ return c;
+}
+
+int
+argcv_quote_char (int c)
+{
+ char *p;
+
+ for (p = quote_transtab + sizeof(quote_transtab) - 2;
+ p > quote_transtab; p -= 2)
+ {
+ if (*p == c)
+ return p[-1];
+ }
+ return -1;
+}
+
+#define to_num(c) \
+ (isdigit(c) ? c - '0' : (isxdigit(c) ? toupper(c) - 'A' + 10 : 255 ))
+
+static int
+xtonum (int *pval, const char *src, int base, int cnt)
+{
+ int i, val;
+
+ for (i = 0, val = 0; i < cnt; i++, src++)
+ {
+ int n = *(unsigned char*)src;
+ if (n > 127 || (n = to_num(n)) >= base)
+ break;
+ val = val*base + n;
+ }
+ *pval = val;
+ return i;
+}
+
+size_t
+argcv_quoted_length (const char *str, int *quote)
+{
+ size_t len = 0;
+
+ *quote = 0;
+ for (; *str; str++)
+ {
+ if (*str == ' ')
+ {
+ len++;
+ *quote = 1;
+ }
+ else if (*str == '"')
+ {
+ len += 2;
+ *quote = 1;
+ }
+ else if (*str != '\t' && *str != '\\' && isprint (*str))
+ len++;
+ else if (argcv_quote_char (*str) != -1)
+ len += 2;
+ else
+ len += 4;
+ }
+ return len;
+}
+
+void
+argcv_unquote_copy (char *dst, const char *src, size_t n)
+{
+ int i = 0;
+ int c;
+ int expect_delim = 0;
+
+ while (i < n)
+ {
+ switch (src[i])
+ {
+ case '\'':
+ case '"':
+ if (!expect_delim)
+ {
+ const char *p;
+
+ for (p = src+i+1; *p && *p != src[i]; p++)
+ if (*p == '\\')
+ p++;
+ if (*p)
+ expect_delim = src[i++];
+ else
+ *dst++ = src[i++];
+ }
+ else if (expect_delim == src[i])
+ ++i;
+ else
+ *dst++ = src[i++];
+ break;
+
+ case '\\':
+ ++i;
+ if (src[i] == 'x' || src[i] == 'X')
+ {
+ if (n - i < 2)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ int off = xtonum(&c, src + i + 1, 16, 2);
+ if (off == 0)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ *dst++ = c;
+ i += off + 1;
+ }
+ }
+ }
+ else if ((unsigned char)src[i] < 128 && isdigit (src[i]))
+ {
+ if (n - i < 1)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ int off = xtonum (&c, src+i, 8, 3);
+ if (off == 0)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ *dst++ = c;
+ i += off;
+ }
+ }
+ }
+ else
+ *dst++ = argcv_unquote_char (src[i++]);
+ break;
+
+ default:
+ *dst++ = src[i++];
+ }
+ }
+ *dst = 0;
+}
+
+void
+argcv_quote_copy (char *dst, const char *src)
+{
+ for (; *src; src++)
+ {
+ if (*src == '"')
+ {
+ *dst++ = '\\';
+ *dst++ = *src;
+ }
+ else if (*src != '\t' && *src != '\\' && isprint(*src))
+ *dst++ = *src;
+ else
+ {
+ int c = argcv_quote_char (*src);
+ *dst++ = '\\';
+ if (c != -1)
+ *dst++ = c;
+ else
+ {
+ char tmp[4];
+ snprintf (tmp, sizeof tmp, "%03o", *(unsigned char*)src);
+ memcpy (dst, tmp, 3);
+ dst += 3;
+ }
+ }
+ }
+}
+
+int
+argcv_get_n (const char *command, int len, const char *delim, const char *cmnt,
+ int *argc, char ***argv)
+{
+ int i = 0;
+ int start, end, save;
+
+ *argv = NULL;
+
+ /* Count number of arguments */
+ *argc = 0;
+ save = 0;
+
+ if (!delim)
+ delim = "";
+ if (!cmnt)
+ cmnt = "";
+
+ while (argcv_scan (len, command, delim, cmnt, &start, &end, &save) <= len)
+ (*argc)++;
+
+ *argv = calloc ((*argc + 1), sizeof (char *));
+ if (*argv == NULL)
+ return ENOMEM;
+
+ i = 0;
+ save = 0;
+ for (i = 0; i < *argc; i++)
+ {
+ int n;
+ int unquote;
+
+ argcv_scan (len, command, delim, cmnt, &start, &end, &save);
+
+ if ((command[start] == '"' || command[end] == '\'')
+ && command[end] == command[start])
+ {
+ if (start < end)
+ {
+ start++;
+ end--;
+ }
+ unquote = 0;
+ }
+ else
+ unquote = 1;
+
+ n = end - start + 1;
+ (*argv)[i] = calloc (n+1, sizeof (char));
+ if ((*argv)[i] == NULL)
+ return ENOMEM;
+ if (unquote)
+ argcv_unquote_copy ((*argv)[i], &command[start], n);
+ else
+ memcpy ((*argv)[i], &command[start], n);
+ (*argv)[i][n] = 0;
+ }
+ (*argv)[i] = NULL;
+ return 0;
+}
+
+int
+argcv_get (const char *command, const char *delim, const char *cmnt,
+ int *argc, char ***argv)
+{
+ return argcv_get_n (command, strlen (command), delim, cmnt, argc, argv);
+}
+
+
+/*
+ * frees all elements of an argv array
+ * argc is the number of elements
+ * argv is the array
+ */
+int
+argcv_free (int argc, char **argv)
+{
+ while (--argc >= 0)
+ if (argv[argc])
+ free (argv[argc]);
+ free (argv);
+ return 0;
+}
+
+/* Take a argv an make string separated by ' '. */
+
+int
+argcv_string (int argc, char **argv, char **pstring)
+{
+ size_t i, j, len;
+ char *buffer;
+
+ /* No need. */
+ if (pstring == NULL)
+ return EINVAL;
+
+ buffer = malloc (1);
+ if (buffer == NULL)
+ return ENOMEM;
+ *buffer = '\0';
+
+ for (len = i = j = 0; i < argc; i++)
+ {
+ int quote;
+ int toklen;
+
+ toklen = argcv_quoted_length (argv[i], &quote);
+
+ len += toklen + 2;
+ if (quote)
+ len += 2;
+
+ buffer = realloc (buffer, len);
+ if (buffer == NULL)
+ return ENOMEM;
+
+ if (i != 0)
+ buffer[j++] = ' ';
+ if (quote)
+ buffer[j++] = '"';
+ argcv_quote_copy (buffer + j, argv[i]);
+ j += toklen;
+ if (quote)
+ buffer[j++] = '"';
+ }
+
+ for (; j > 0 && isspace (buffer[j-1]); j--)
+ ;
+ buffer[j] = 0;
+ if (pstring)
+ *pstring = buffer;
+ return 0;
+}
+
diff --git a/jabberd/jabberd.h b/jabberd/jabberd.h
index 2387132..388a307 100644
--- a/jabberd/jabberd.h
+++ b/jabberd/jabberd.h
@@ -41,11 +41,15 @@
# define getmaxfd() 256
#endif
+#define RETR_OUT 0
+#define RETR_ERR 1
+
#define TESTTIME 2*60
#define SLEEPTIME 5*60
#define MAXSPAWN 10
-void register_prog (char *cmd, char *cfg);
+void register_prog (char *tag, char **argv, int retr[2]);
+void register_jabber_process (char *cmd, char *cfg);
void logmsg(int prio, char *fmt, ...);
void signal_setup (RETSIGTYPE (*sf)(int));
@@ -59,3 +63,18 @@ void progman_wake_disabled (void);
extern int debug_level;
extern char *syslog_tag;
extern int log_facility;
+
+extern int argcv_get (const char *command, const char *delim,
+ const char* cmnt,
+ int *argc, char ***argv);
+extern int argcv_get_n (const char *command, int len,
+ const char *delim, const char *cmnt,
+ int *argc, char ***argv);
+
+extern int argcv_string (int argc, char **argv, char **string);
+extern int argcv_free (int argc, char **argv);
+extern int argcv_unquote_char (int c);
+extern int argcv_quote_char (int c);
+extern size_t argcv_quoted_length (const char *str, int *quote);
+extern void argcv_unquote_copy (char *dst, const char *src, size_t n);
+extern void argcv_quote_copy (char *dst, const char *src);
diff --git a/jabberd/main.c b/jabberd/main.c
index f195f72..f073e1e 100644
--- a/jabberd/main.c
+++ b/jabberd/main.c
@@ -145,24 +145,33 @@ usage ()
}
-/* Configuration file handling */
-
-typedef void (*cfg_fun) (unsigned line, char *kw, char *val);
+struct kw_int
+{
+ char *name;
+ int tok;
+};
-void
-cfg_syslog_tag (unsigned line, char *kw, char *val)
+int
+syslog_to_n (struct kw_int *kw, char *str, int *pint)
{
- syslog_tag = strdup (val);
+ int i;
+
+ if (strncasecmp (str, "LOG_", 4) == 0)
+ str += 4;
+
+ for (; kw->name; kw++)
+ if (strcasecmp (kw->name, str) == 0)
+ {
+ *pint = kw->tok;
+ return 0;
+ }
+ return 1;
}
-void
-cfg_syslog_facility (unsigned line, char *kw, char *val)
+int
+str_to_facility (char *str, int *pfacility)
{
- int i;
- static struct {
- char *name;
- int facility;
- } syslog_kw[] = {
+ static struct kw_int kw_facility[] = {
{ "USER", LOG_USER },
{ "DAEMON", LOG_DAEMON },
{ "AUTH", LOG_AUTH },
@@ -174,29 +183,141 @@ cfg_syslog_facility (unsigned line, char *kw, char *val)
{ "LOCAL5", LOG_LOCAL5 },
{ "LOCAL6", LOG_LOCAL6 },
{ "LOCAL7", LOG_LOCAL7 },
- { "MAIL", LOG_MAIL }
+ { "MAIL", LOG_MAIL },
+ { NULL }
};
+ return syslog_to_n (kw_facility, str, pfacility);
+}
- if (strncasecmp (val, "LOG_", 4) == 0)
- val += 4;
+int
+str_to_priority (char *str, int *pprio)
+{
+ static struct kw_int kw_prio[] = {
+ { "EMERG", LOG_EMERG },
+ { "ALERT", LOG_ALERT },
+ { "CRIT", LOG_CRIT },
+ { "ERR", LOG_ERR },
+ { "WARNING", LOG_WARNING },
+ { "NOTICE", LOG_NOTICE },
+ { "INFO", LOG_INFO },
+ { "DEBUG", LOG_DEBUG },
+ { NULL }
+ };
+ return syslog_to_n (kw_prio, str, pprio);
+}
- for (i = 0; i < sizeof (syslog_kw) / sizeof (syslog_kw[0]); i++)
- if (strcasecmp (syslog_kw[i].name, val) == 0)
- {
- log_facility = syslog_kw[i].facility;
- return;
- }
- logmsg (LOG_ERR, "%s:%u: Unknown facility `%s'", config_file, line, val);
+
+
+/* Configuration file handling */
+
+struct cfg_file
+{
+ FILE *fp;
+ unsigned line;
+ char *buf;
+ size_t size;
+};
+
+typedef void (*cfg_fun) (struct cfg_file *file, char *kw, char *val, void *data);
+
+struct kw_handler
+{
+ char *kw;
+ cfg_fun handler;
+};
+
+static cfg_fun
+find_cfg_fun (struct kw_handler *kwtab, char *kw)
+{
+ for (; kwtab->kw; kwtab++)
+ if (strcmp (kwtab->kw, kw) == 0)
+ return kwtab->handler;
+ return NULL;
+}
+
+void
+parse_block (struct cfg_file *file, void *data,
+ struct kw_handler *kwtab, const char *end)
+{
+ while (getline (&file->buf, &file->size, file->fp) > 0)
+ {
+ size_t len;
+ char *p, *kw, *val = NULL;
+ cfg_fun fun;
+
+ file->line++;
+ for (p = file->buf; *p && isspace (*p); p++)
+ ;
+ if (*p == '#' || *p == 0)
+ continue;
+
+ len = strlen (p);
+ if (p[len-1] == '\n')
+ p[--len] = 0;
+
+ for (;len > 0 && isspace (p[len-1]); len--)
+ ;
+
+ if (len > 0)
+ p[len] = 0;
+ else
+ continue;
+
+ kw = p;
+ for (; *p && !isspace (*p); p++)
+ ;
+
+ if (*p)
+ {
+ *p++ = 0;
+ for (; *p && isspace (*p); p++)
+ ;
+
+ val = p;
+ }
+
+ if (end && val == NULL && strcmp (kw, end) == 0)
+ break;
+
+ fun = find_cfg_fun (kwtab, kw);
+ if (fun)
+ fun (file, kw, val, data);
+ else
+ {
+#ifdef ALLOW_LEGACY_CONFIG
+ logmsg (LOG_WARNING, "%s:%u: legacy line", config_file, file->line);
+ register_jabber_process (kw, val);
+#else
+ logmsg (LOG_ERR, "%s:%u: unrecognized line", config_file, file->line);
+#endif
+ }
+ }
+}
+
+void
+cfg_syslog_tag (struct cfg_file *file, char *kw, char *val, void *unused)
+{
+ syslog_tag = strdup (val);
}
void
-cfg_user (unsigned line, char *kw, char *val)
+cfg_syslog_facility (struct cfg_file *file, char *kw, char *val, void *unused)
+{
+ if (str_to_facility (val, &log_facility))
+ logmsg (LOG_ERR, "%s:%u: Unknown facility `%s'",
+ config_file, file->line, val);
+}
+
+void
+cfg_user (struct cfg_file *file, char *kw, char *val, void *unused)
{
struct passwd *pwd = getpwnam (val);
if (!pwd)
- logmsg (LOG_ERR, "%s:%u: no such user `%s'", config_file, line, val);
+ logmsg (LOG_ERR, "%s:%u: no such user `%s'",
+ config_file, file->line, val);
else if (pwd->pw_uid == 0)
- logmsg (LOG_ERR, "%s:%u: user `%s' has zero UID", config_file, line, val);
+ logmsg (LOG_ERR, "%s:%u: user `%s' has zero UID", config_file,
+ file->line, val);
else
user = strdup (val);
}
@@ -210,7 +331,7 @@ struct group_list
static struct group_list *group_list;
void
-cfg_group (unsigned line, char *kw, char *val)
+cfg_group (struct cfg_file *file, char *kw, char *val, void *unused)
{
struct group *group = getgrnam (val);
if (group)
@@ -222,17 +343,17 @@ cfg_group (unsigned line, char *kw, char *val)
}
else
logmsg(LOG_ERR, "%s:%u: unknown group `%s'", config_file,
- line, val);
+ file->line, val);
}
void
-cfg_pidfile (unsigned line, char *kw, char *val)
+cfg_pidfile (struct cfg_file *file, char *kw, char *val, void *unused)
{
pidfile = strdup (val);
}
void
-cfg_prog (unsigned line, char *kw, char *val)
+cfg_prog (struct cfg_file *file, char *kw, char *val, void *unused)
{
char *prog = val;
char *p = val;
@@ -251,15 +372,84 @@ cfg_prog (unsigned line, char *kw, char *val)
else
val = 0;
- register_prog (prog, val);
+ register_jabber_process (prog, val);
}
-struct kw_handler
-{
- char *kw;
- cfg_fun handler;
+struct exec_rec {
+ char *tag;
+ char *command;
+ int facility;
+ int retr[2];
};
+static void
+cfg_exec_command (struct cfg_file *file, char *kw, char *val, void *data)
+{
+ struct exec_rec *prec = data;
+ prec->command = strdup (val);
+}
+
+void
+cfg_exec_facility (struct cfg_file *file, char *kw, char *val, void *data)
+{
+ struct exec_rec *prec = data;
+ if (str_to_facility (val, &prec->facility))
+ logmsg (LOG_ERR, "%s:%u: Unknown facility `%s'",
+ config_file, file->line, val);
+}
+
+void
+cfg_exec_stdout (struct cfg_file *file, char *kw, char *val, void *data)
+{
+ struct exec_rec *prec = data;
+ if (str_to_priority (val, &prec->retr[RETR_OUT]))
+ logmsg (LOG_ERR, "%s:%u: Unknown priority `%s'",
+ config_file, file->line, val);
+}
+
+void
+cfg_exec_stderr (struct cfg_file *file, char *kw, char *val, void *data)
+{
+ struct exec_rec *prec = data;
+ if (str_to_priority (val, &prec->retr[RETR_ERR]))
+ logmsg (LOG_ERR, "%s:%u: Unknown priority `%s'",
+ config_file, file->line, val);
+}
+
+void
+cfg_exec (struct cfg_file *file, char *kw, char *val, void *unused)
+{
+ int rc;
+ int argc;
+ char **argv;
+
+ struct exec_rec rec;
+ static struct kw_handler kwtab[] = {
+ { "command", cfg_exec_command },
+ { "stdout", cfg_exec_stdout },
+ { "stderr", cfg_exec_stderr },
+ { "facility", cfg_exec_facility },
+ { NULL }
+ };
+ memset (&rec, 0, sizeof rec);
+ rec.retr[RETR_OUT] = rec.retr[RETR_ERR] = -1;
+ if (val)
+ rec.tag = strdup (val);
+
+ parse_block (file, &rec, kwtab, "end");
+
+ if (rc = argcv_get (rec.command, NULL, NULL, &argc, &argv))
+ {
+ logmsg (LOG_ERR, "%s:%u: cannot split command line: %s",
+ config_file, file->line, strerror (rc));
+ return;
+ }
+ register_prog (rec.tag, argv, rec.retr);
+ free (rec.tag);
+ free (rec.command);
+ argcv_free (argc, argv);
+}
+
struct kw_handler kw_handler[] = {
{ "syslog-tag", cfg_syslog_tag },
{ "syslog-facility", cfg_syslog_facility },
@@ -267,82 +457,31 @@ struct kw_handler kw_handler[] = {
{ "group", cfg_group },
{ "pidfile", cfg_pidfile },
{ "prog", cfg_prog },
+ { "exec", cfg_exec },
{ NULL }
};
-cfg_fun
-find_cfg_fun (char *kw)
-{
- struct kw_handler *p;
- for (p = kw_handler; p->kw; p++)
- if (strcmp (p->kw, kw) == 0)
- return p->handler;
- return NULL;
-}
-
void
parse_config ()
{
- FILE *fp = fopen (config_file, "r");
- char *buf = NULL;
- size_t size = 0;
- unsigned line = 0;
+ struct cfg_file file;
- if (!fp)
+ file.fp = fopen (config_file, "r");
+ file.buf = NULL;
+ file.size = 0;
+ file.line = 0;
+
+ if (!file.fp)
{
logmsg (LOG_EMERG, "cannot open config file `%s': %s",
config_file, strerror (errno));
exit (1);
}
- while (getline (&buf, &size, fp) > 0)
- {
- size_t len;
- char *p, *kw, *val = NULL;
- cfg_fun fun;
-
- line++;
- for (p = buf; *p && isspace (*p); p++)
- ;
- if (*p == '#' || *p == 0)
- continue;
-
- len = strlen (p);
- if (p[len-1] == '\n')
- p[--len] = 0;
-
- for (;len > 0 && isspace (p[len-1]); len--)
- ;
+ parse_block (&file, NULL, kw_handler, NULL);
- if (len > 0)
- p[len] = 0;
- else
- continue;
-
- kw = p;
- for (; *p && !isspace (*p); p++)
- ;
-
- if (*p)
- {
- *p++ = 0;
- for (; *p && isspace (*p); p++)
- ;
-
- val = p;
- }
-
- fun = find_cfg_fun (kw);
- if (fun)
- fun(line, kw, val);
- else
- {
- logmsg(LOG_WARNING, "%s:%u: legacy line", config_file, line);
- register_prog (kw, val);
- }
- }
- free (buf);
- fclose (fp);
+ free (file.buf);
+ fclose (file.fp);
}
@@ -574,6 +713,12 @@ signal_setup (RETSIGTYPE (*sf)(int))
signal (SIGALRM, sf);
}
+void
+syslog_setup ()
+{
+ log_printer = syslog_printer;
+}
+
int
main(int argc, char **argv)
@@ -625,7 +770,7 @@ main(int argc, char **argv)
}
parse_config();
-
+
if (!log_to_stderr)
{
openlog (syslog_tag, LOG_PID, log_facility);
diff --git a/jabberd/progman.c b/jabberd/progman.c
index 274118a..a56c1d8 100644
--- a/jabberd/progman.c
+++ b/jabberd/progman.c
@@ -17,16 +17,34 @@
02110-1301 USA. */
#include "jabberd.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define TYPE_PROG 0
+#define TYPE_RETR 1
struct prog
{
- struct prog *next;
- pid_t pid;
- char *cmd;
- char *cfg;
- time_t timestamp;
- size_t count;
- int disabled;
+ struct prog *next; /* Next program in the list */
+ int type;
+ pid_t pid; /* PID */
+ char *tag; /* Entry tag (for diagnostics purposes) */
+ union
+ {
+ struct
+ {
+ char **argv; /* Command line arguments */
+ int retr[2];
+ time_t timestamp; /* Time of last startup */
+ size_t count; /* Number of failed starts since timestamp */
+ int disabled; /* 1 if this entry is disabled */
+ } p;
+
+ struct
+ {
+ struct prog *master;
+ } r;
+ } v;
};
@@ -34,28 +52,102 @@ static struct prog *proghead, *progtail;
static size_t prognum;
void
-register_prog (char *cmd, char *cfg)
+link_prog (struct prog *pp, int prepend)
{
- size_t cmdlen = strlen (cmd) + 1;
- size_t cfglen = cfg ? (strlen (cfg) + 1) : 0;
- struct prog *pp = emalloc (sizeof (*pp) + cmdlen + cfglen);
- memset(pp, 0, sizeof(*pp));
- pp->pid = 0;
- pp->cmd = (char *) (pp + 1);
- strcpy (pp->cmd, cmd);
- if (cfglen)
+ if (prepend)
{
- pp->cfg = (char *) (pp + 1) + cmdlen + 1;
- strcpy (pp->cfg, cfg);
+ pp->next = proghead;
+ proghead = pp;
+ if (!progtail)
+ progtail = pp;
}
else
- pp->cfg = NULL;
- pp->next = NULL;
- if (progtail)
- progtail->next = pp;
+ {
+ pp->next = NULL;
+ if (progtail)
+ progtail->next = pp;
+ else
+ proghead = pp;
+ progtail = pp;
+ }
+}
+
+void
+register_retr (int type, struct prog *master, pid_t pid)
+{
+ struct prog *pp;
+ static char *retrstr[2] = { "stdout", "stderr" };
+
+ pp = emalloc (sizeof(*pp) + strlen (master->tag) + 1 +
+ strlen (retrstr[type]) + 1);
+ memset (pp, 0, sizeof(*pp));
+ pp->type = TYPE_RETR;
+ pp->pid = pid;
+ pp->v.r.master = master;
+ pp->tag = (char *) (pp + 1);
+ strcpy (pp->tag, master->tag);
+ strcat (pp->tag, "/");
+ strcat (pp->tag, retrstr[type]);
+ link_prog (pp, 1);
+}
+
+void
+register_prog (char *tag, char **argv, int retr[2])
+{
+ struct prog *pp;
+ char *pstr;
+ int i;
+ size_t size = 0;
+
+ for (i = 0; argv[i]; i++)
+ size += strlen (argv[i]);
+ size += i + sizeof (argv[0]) * (i + 1) + sizeof (*pp)
+ + (tag ? (strlen (tag) + 1) : 0);
+
+ pp = emalloc (size);
+ memset (pp, 0, sizeof(*pp));
+ pp->type = TYPE_PROG;
+ pp->pid = 0;
+ pp->v.p.argv = (char **) (pp + 1);
+ pstr = (char*) (pp->v.p.argv + i + 1);
+
+ for (i = 0; argv[i]; i++)
+ {
+ strcpy (pstr, argv[i]);
+ pp->v.p.argv[i] = pstr;
+ pstr += strlen (pstr) + 1;
+ }
+ pp->v.p.argv[i] = NULL;
+
+ if (tag)
+ pp->tag = strcpy (pstr, tag);
else
- proghead = pp;
- progtail = pp;
+ pp->tag = pp->v.p.argv[0];
+
+ pp->v.p.retr[0] = retr[0];
+ pp->v.p.retr[1] = retr[1];
+
+ link_prog (pp, 0);
+}
+
+void
+register_jabber_process (char *cmd, char *cfg)
+{
+ int retr[2] = { -1, -1 };
+ char *argv[5];
+ int argc = 0;
+
+ argv[argc++] = cmd;
+ if (cfg)
+ {
+ argv[argc++] = "-c";
+ argv[argc++] = cfg;
+ }
+ if (debug_level > 2)
+ argv[argc++] = "-D";
+ argv[argc] = NULL;
+
+ register_prog (NULL, argv, retr);
}
static struct prog *
@@ -81,43 +173,82 @@ progman_running_count ()
return size;
}
+RETSIGTYPE
+retr_exit (int sig)
+{
+ exit (0);
+}
+
+int
+open_retranslator (struct prog *master, int type)
+{
+ int p[2];
+ FILE *fp;
+ char *buf = NULL;
+ size_t size = 0;
+ pid_t pid;
+
+ if (master->v.p.retr[type] == -1)
+ return -1;
+ pipe (p);
+ switch (pid = fork ())
+ {
+ case 0:
+ /* Retranslator process */
+
+ syslog_setup ();
+ signal_setup (retr_exit);
+
+ close (p[1]);
+ fp = fdopen (p[0], "r");
+ if (fp == NULL)
+ exit (1);
+
+ openlog (master->tag, LOG_PID, log_facility);
+
+ while (getline (&buf, &size, fp) > 0)
+ logmsg (master->v.p.retr[type], "%s", buf);
+ exit (0);
+
+ case -1:
+ logmsg (LOG_CRIT, "cannot run retranslator `%s': fork failed: %s",
+ master->tag, strerror (errno));
+ return -1;
+
+ default:
+ register_retr (type, master, pid);
+
+ close (p[0]);
+ return p[1];
+ }
+}
+
static void
prog_start (struct prog *prog)
{
int i;
pid_t pid;
- char *argv[5];
- int argc = 0;
time_t now;
+ int retr[2];
- argv[argc++] = prog->cmd;
- if (prog->cfg)
- {
- argv[argc++] = "-c";
- argv[argc++] = prog->cfg;
- }
- if (debug_level > 2)
- argv[argc++] = "-D";
- argv[argc] = NULL;
-
time (&now);
- if (prog->timestamp + TESTTIME > now)
- prog->count++;
+ if (prog->v.p.timestamp + TESTTIME > now)
+ prog->v.p.count++;
else
{
- prog->count = 0;
- prog->timestamp = now;
+ prog->v.p.count = 0;
+ prog->v.p.timestamp = now;
}
- if (prog->count > MAXSPAWN)
+ if (prog->v.p.count > MAXSPAWN)
{
int old_alarm;
logmsg(LOG_ERR, "%s is respawning too fast, disabled for %d minutes",
- prog->cmd, SLEEPTIME / 60);
- prog->timestamp = now;
- prog->disabled = 1;
+ prog->tag, SLEEPTIME / 60);
+ prog->v.p.timestamp = now;
+ prog->v.p.disabled = 1;
old_alarm = alarm (0);
if (old_alarm > SLEEPTIME || old_alarm <= 0)
@@ -126,27 +257,52 @@ prog_start (struct prog *prog)
return;
}
- logmsg (LOG_DEBUG, "starting %s", prog->cmd);
+ logmsg (LOG_DEBUG, "starting %s", prog->tag);
+
+ retr[RETR_OUT] = open_retranslator (prog, RETR_OUT);
+ retr[RETR_ERR] = open_retranslator (prog, RETR_ERR);
switch (pid = fork ())
{
/* The child branch. */
case 0:
+ if (retr[RETR_OUT] == -1)
+ {
+ close (1);
+ open ("/dev/null", O_RDWR);
+ }
+ else if (retr[RETR_OUT] != 1)
+ {
+ close (1);
+ dup2 (retr[RETR_OUT], 1);
+ }
+
+ if (retr[RETR_ERR] == -1)
+ {
+ close (2);
+ open ("/dev/null", O_RDWR);
+ }
+ else if (retr[RETR_ERR] != 1)
+ {
+ close (2);
+ dup2 (retr[RETR_ERR], 2);
+ }
+
/* Close unneded descripitors */
for (i = getmaxfd (); i > 2; i--)
close (i);
signal_setup (SIG_DFL);
- execvp(argv[0], argv);
+ execvp(prog->v.p.argv[0], prog->v.p.argv);
openlog (syslog_tag, LOG_PID, log_facility);
- logmsg (LOG_CRIT, "cannot start `%s': %s", prog->cmd,
+ logmsg (LOG_CRIT, "cannot start `%s': %s", prog->tag,
strerror (errno));
exit (1);
case -1:
- logmsg (LOG_CRIT, "cannot runt `%s': fork failed: %s",
- prog->cmd, strerror (errno));
+ logmsg (LOG_CRIT, "cannot run `%s': fork failed: %s",
+ prog->tag, strerror (errno));
break;
default:
@@ -160,7 +316,8 @@ progman_start ()
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
- prog_start (prog);
+ if (prog->type == TYPE_PROG)
+ prog_start (prog);
}
void
@@ -169,11 +326,11 @@ progman_wake_disabled ()
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
- if (prog->disabled)
+ if (prog->type == TYPE_PROG && prog->v.p.disabled)
{
- prog->disabled = 0;
- prog->count = 0;
- prog->timestamp = 0;
+ prog->v.p.disabled = 0;
+ prog->v.p.count = 0;
+ prog->v.p.timestamp = 0;
prog_start (prog);
}
}
@@ -187,7 +344,7 @@ prog_stop_recursive (struct prog *prog, int sig)
if (prog->pid > 0)
{
logmsg (LOG_DEBUG, "Stopping %s",
- prog->cmd, (unsigned long) prog->pid);
+ prog->tag, (unsigned long) prog->pid);
kill (prog->pid, sig);
}
}