diff options
Diffstat (limited to 'jabberd/progman.c')
-rw-r--r-- | jabberd/progman.c | 647 |
1 files changed, 0 insertions, 647 deletions
diff --git a/jabberd/progman.c b/jabberd/progman.c deleted file mode 100644 index 3dfe3ba..0000000 --- a/jabberd/progman.c +++ /dev/null @@ -1,647 +0,0 @@ -/* jabberd - a dispatcher program for jabber 2.x - Copyright (C) 2007 Sergey Poznyakoff - - 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ - -#include "jabberd.h" -#include <sys/stat.h> -#include <fcntl.h> - -#define TYPE_CORE 0 -#define TYPE_TRANSPORT 1 -#define TYPE_RETR 2 - -struct prog -{ - struct prog *next; /* Next program in the list */ - int type; - pid_t pid; /* PID */ - char *tag; /* Entry tag (for diagnostics purposes) */ - char **depend; - union - { - struct - { - int argc; - char **argv; /* Command line arguments */ - int retr[2]; - char *pidfile; /* Pidfile location */ - 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; -}; - - -#define IS_PROG(p) ((p)->type == TYPE_CORE || (p)->type == TYPE_TRANSPORT) - -static struct prog *proghead, *progtail; -static size_t prognum; - -static void prog_stop (struct prog *prog, int sig); - -void -link_prog (struct prog *pp, int prepend) -{ - if (prepend) - { - pp->next = proghead; - proghead = pp; - if (!progtail) - progtail = pp; - } - else - { - 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" }; - size_t taglen = strlen (master->tag) + 1 + strlen (retrstr[type]); - char *tag = emalloc (taglen + 1); - - strcpy (tag, master->tag); - strcat (tag, "/"); - strcat (tag, retrstr[type]); - - for (pp = proghead; pp; pp = pp->next) - if (pp->type == TYPE_RETR && pp->v.r.master == master - && strcmp (pp->tag, tag) == 0) - { - free (tag); - prog_stop (pp, SIGKILL); - break; - } - - if (!pp) - { - pp = emalloc (sizeof(*pp) + taglen + 1); - memset (pp, 0, sizeof(*pp)); - pp->type = TYPE_RETR; - pp->tag = (char *) (pp + 1); - strcpy (pp->tag, tag); - free (tag); - pp->v.r.master = master; - link_prog (pp, 1); - } - - pp->pid = pid; -} - -void -register_prog (int type, char *tag, char **argv, int retr[2], char **depv, - char *pidfile) -{ - struct prog *p, *newp; - char *pstr; - int i; - size_t size = 0; - int dep_all = 0; - int depc = 0; - - if (depv) - { - if (depv[0] && depv[1] == NULL) - { - if (strcmp (depv[0], "all") == 0) - { - dep_all = 1; - for (p = proghead; p; p = p->next) - if (p->type == TYPE_CORE) - { - depc++; - size += strlen (p->tag) + 1; - } - } - else if (strcmp (depv[0], "none") == 0) - depv = NULL; - } - - if (depc == 0) - for (depc = 0; depv[depc]; depc++) - ; - size += sizeof (depv[0]) * (depc + 1); - } - - for (i = 0; argv[i]; i++) - size += strlen (argv[i]); - size += i + sizeof (argv[0]) * (i + 1) + sizeof (*newp) - + (tag ? (strlen (tag) + 1) : 0); - if (pidfile) - size += strlen (pidfile) + 1; - - newp = emalloc (size); - memset (newp, 0, sizeof(*newp)); - newp->type = type; - newp->pid = 0; - newp->v.p.argc = i; - newp->v.p.argv = (char **) (newp + 1); - pstr = (char*) (newp->v.p.argv + i + 1); - - for (i = 0; argv[i]; i++) - { - strcpy (pstr, argv[i]); - newp->v.p.argv[i] = pstr; - pstr += strlen (pstr) + 1; - } - newp->v.p.argv[i] = NULL; - - if (tag) - { - newp->tag = strcpy (pstr, tag); - pstr += strlen (pstr) + 1; - } - else - newp->tag = newp->v.p.argv[0]; - - if (pidfile) - { - newp->v.p.pidfile = strcpy (pstr, pidfile); - pstr += strlen (pstr) + 1; - } - else - newp->v.p.pidfile = NULL; - - if (depv) - { - newp->depend = (char**) pstr; - pstr = (char*) (newp->depend + depc + 1); - if (dep_all) - { - depc = 0; - for (p = proghead; p; p = p->next) - if (p->type == TYPE_CORE) - { - newp->depend[depc++] = pstr; - strcpy (pstr, p->tag); - pstr += strlen (pstr) + 1; - } - } - else - { - for (depc = 0; depv[depc]; depc++) - { - newp->depend[depc] = pstr; - strcpy (pstr, p->tag); - pstr += strlen (pstr) + 1; - } - } - depv[depc] = NULL; - } - else - newp->depend = NULL; - - newp->v.p.retr[0] = retr[0]; - newp->v.p.retr[1] = retr[1]; - - link_prog (newp, 0); -} - -void -register_transport (char *tag, char **argv, int retr[2], char **depv, - char *pidfile) -{ - static char *std_dep[] = { "all", NULL }; - if (!depv) - depv = std_dep; - register_prog (TYPE_TRANSPORT, tag, argv, retr, depv, pidfile); -} - -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"; - retr[RETR_ERR] = LOG_DEBUG; - } - argv[argc] = NULL; - - register_prog (TYPE_CORE, NULL, argv, retr, NULL, NULL); -} - -static struct prog * -find_prog (pid_t pid) -{ - struct prog *prog; - - for (prog = proghead; prog; prog = prog->next) - if (prog->pid == pid) - break; - return prog; -} - -size_t -progman_running_count () -{ - size_t size = 0; - struct prog *prog; - - for (prog = proghead; prog; prog = prog->next) - if (prog->pid > 0) - size++; - 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; - time_t now; - int retr[2]; - - time (&now); - - if (prog->v.p.timestamp + TESTTIME > now) - prog->v.p.count++; - else - { - prog->v.p.count = 0; - prog->v.p.timestamp = now; - } - - if (prog->v.p.count > MAXSPAWN) - { - int old_alarm; - - logmsg(LOG_ERR, "%s is respawning too fast, disabled for %d minutes", - 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) - old_alarm = SLEEPTIME; - alarm (old_alarm); - return; - } - - logmsg (LOG_DEBUG, "starting %s", prog->tag); - - if (prog->v.p.pidfile) - { - if (unlink (prog->v.p.pidfile) && errno != ENOENT) - logmsg (LOG_ERR, "%s: cannot remove pidfile `%s': %s", - prog->tag, prog->v.p.pidfile, strerror (errno)); - } - - 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(prog->v.p.argv[0], prog->v.p.argv); - openlog (syslog_tag, LOG_PID, log_facility); - logmsg (LOG_CRIT, "cannot start `%s': %s", prog->tag, - strerror (errno)); - exit (1); - - case -1: - logmsg (LOG_CRIT, "cannot run `%s': fork failed: %s", - prog->tag, strerror (errno)); - break; - - default: - prog->pid = pid; - } -} - -void -progman_start () -{ - struct prog *prog; - - for (prog = proghead; prog; prog = prog->next) - if (IS_PROG (prog)) - prog_start (prog); -} - -void -progman_wake_disabled () -{ - struct prog *prog; - - for (prog = proghead; prog; prog = prog->next) - if (IS_PROG (prog) && prog->v.p.disabled) - { - prog->v.p.disabled = 0; - prog->v.p.count = 0; - prog->v.p.timestamp = 0; - prog_start (prog); - } -} - -static void -prog_stop (struct prog *prog, int sig) -{ - if (prog->pid > 0) - { - logmsg (LOG_DEBUG, "Stopping %s", - prog->tag, (unsigned long) prog->pid); - kill (prog->pid, sig); - } -} - -static void -prog_stop_recursive (struct prog *prog, int sig) -{ - if (!prog) - return; - prog_stop_recursive (prog->next, sig); - prog_stop (prog, sig); -} - -void -progman_stop () -{ - unsigned long i; - - prog_stop_recursive (proghead, SIGTERM); - for (i = 0; i < shutdown_timeout; i++) - { - progman_cleanup (1); - if (progman_running_count () == 0) - return; - sleep (1); - } - prog_stop_recursive (proghead, SIGKILL); -} - -static void -print_status (char *tag, pid_t pid, int status, int expect_term) -{ - if (WIFEXITED (status)) - { - if (WEXITSTATUS (status) == 0) - logmsg (LOG_DEBUG, - "%s (%lu) exited successfully", - tag, (unsigned long) pid); - else - logmsg (LOG_ERR, - "%s (%lu) failed with status %d", - tag, (unsigned long) pid, - WEXITSTATUS (status)); - } - else if (WIFSIGNALED (status)) - { - int prio; - - if (expect_term && WTERMSIG (status) == SIGTERM) - prio = LOG_DEBUG; - else - prio = LOG_ERR; - - logmsg(prio, - "%s (%lu) terminated on signal %d", - tag, (unsigned long) pid, - WTERMSIG (status)); - } - else if (WIFSTOPPED (status)) - logmsg(LOG_ERR, - "%s (%lu) stopped on signal %d", - tag, (unsigned long) pid, - WSTOPSIG (status)); -#ifdef WCOREDUMP - else if (WCOREDUMP (status)) - logmsg (LOG_ERR, - "%s (%lu) dumped core", - tag, (unsigned long) pid); -#endif - else - logmsg(LOG_ERR, - "%s (%lu) terminated with unrecognized status", - tag, (unsigned long) pid); -} - -void -prog_stop_dependent (struct prog *prog) -{ - struct prog *p; - - for (p = proghead; p; p = p->next) - if (p->depend) - { - int i; - for (i = 0; p->depend[i]; i++) - if (strcmp (prog->tag, p->depend[i]) == 0) - prog_stop (p, SIGTERM); - } -} - -void -progman_cleanup (int expect_term) -{ - pid_t pid; - int status; - while ((pid = waitpid (-1, &status, WNOHANG)) > 0) - { - struct prog *prog = find_prog (pid); - if (!prog) - { - logmsg (LOG_NOTICE, "unknown child %lu finished", - (unsigned long) pid); - continue; - } - print_status (prog->tag, prog->pid, status, expect_term); - prog->pid = 0; - if (IS_PROG (prog)) - { - prog_stop_dependent (prog); - if (!expect_term) - prog_start (prog); - } - } -} - -void -progman_stop_component (const char *name) -{ - struct prog *prog; - - logmsg (LOG_INFO, "stopping component `%s'", name); - for (prog = proghead; prog; prog = prog->next) - if (IS_PROG (prog) && strcmp (prog->tag, name) == 0) - { - if (prog->v.p.disabled) - logmsg (LOG_INFO, "stopping component `%s': component not started", - name); - else - prog_stop (prog, SIGTERM); - } -} - -void -progman_dump_stats (const char *filename) -{ - FILE *fp; - struct prog *prog; - char *s; - int rc; - - logmsg (LOG_INFO, "dumping statistics to `%s'", filename); - fp = fopen (filename, "w"); - if (!fp) - { - logmsg (LOG_ERR, "cannot open file `%s' for writing: %s", - filename, strerror (errno)); - return; - } - - for (prog = proghead; prog; prog = prog->next) - { - switch (prog->type) - { - case TYPE_CORE: - case TYPE_TRANSPORT: - fprintf (fp, "%s %s ", - prog->type == TYPE_CORE ? "core" : "transport", - prog->tag); - if (prog->pid) - fprintf (fp, "%lu", (unsigned long) prog->pid); - else if (prog->v.p.disabled) - { - char buf[48]; - time_t t = prog->v.p.timestamp + SLEEPTIME; - strftime (buf, sizeof buf, "%c", - localtime (&t)); - fprintf (fp, "[disabled; scheduled for %s]", buf); - } - else - fprintf (fp, "[not running]"); - if (rc = argcv_string (prog->v.p.argc, prog->v.p.argv, &s)) - { - logmsg (LOG_ERR, "cannot convert argument list: %s", - strerror (rc)); - } - else - { - fprintf (fp, " %s", s); - free (s); - } - fputc ('\n', fp); - break; - - case TYPE_RETR: - fprintf (fp, "retranslator %s %lu\n", prog->tag, - (unsigned long) prog->pid); - } - } - fclose (fp); -} |