diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-06-04 12:35:54 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-06-04 12:35:54 +0000 |
commit | e7ffd40909f60b2230879e2767ad0a057198eb9f (patch) | |
tree | 4572199ebe2170e6abc97b77d4e1c4e496009079 /jabberd | |
parent | c4687307a4e3f4d08d5da97c0537fe0ce95960d1 (diff) | |
download | gsc-e7ffd40909f60b2230879e2767ad0a057198eb9f.tar.gz gsc-e7ffd40909f60b2230879e2767ad0a057198eb9f.tar.bz2 |
Implement long options, running instance control and component dependency checking
git-svn-id: file:///svnroot/gsc/trunk@254 d2de0444-eb31-0410-8365-af798a554d48
Diffstat (limited to 'jabberd')
-rw-r--r-- | jabberd/Makefile.am | 3 | ||||
-rw-r--r-- | jabberd/jabberd.h | 4 | ||||
-rw-r--r-- | jabberd/main.c | 412 | ||||
-rw-r--r-- | jabberd/progman.c | 228 |
4 files changed, 568 insertions, 79 deletions
diff --git a/jabberd/Makefile.am b/jabberd/Makefile.am index b5667ba..8fe9158 100644 --- a/jabberd/Makefile.am +++ b/jabberd/Makefile.am @@ -1,3 +1,4 @@ bin_PROGRAMS = jabberd jabberd_SOURCES = main.c progman.c jabber.h argcv.c -AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"
\ No newline at end of file +AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"\ + -DSTATEDIR=\"$(localstatedir)/jabberd\" diff --git a/jabberd/jabberd.h b/jabberd/jabberd.h index 6c9f480..336a023 100644 --- a/jabberd/jabberd.h +++ b/jabberd/jabberd.h @@ -48,7 +48,7 @@ #define SLEEPTIME 5*60 #define MAXSPAWN 10 -void register_prog (char *tag, char **argv, int retr[2]); +void register_trasport (char *tag, char **argv, int retr[2], char **depv); void register_jabber_process (char *cmd, char *cfg); void logmsg(int prio, char *fmt, ...); void signal_setup (RETSIGTYPE (*sf)(int)); @@ -59,6 +59,8 @@ void progman_start (void); void progman_stop (void); void progman_cleanup (int); void progman_wake_disabled (void); +void progman_stop_component (const char *); +void progman_dump_stats (const char *); extern int debug_level; extern char *syslog_tag; diff --git a/jabberd/main.c b/jabberd/main.c index e2a00ac..476abd8 100644 --- a/jabberd/main.c +++ b/jabberd/main.c @@ -28,7 +28,9 @@ char *syslog_tag = "jabberd"; int log_facility = LOG_LOCAL7; int x_argc; char **x_argv; -char *pidfile; +char *pidfile = STATEDIR "/jabberd.pid"; +char *ctlfile = STATEDIR "/.jabberd.ctl"; +char *statfile = STATEDIR "/.jabberd.stat"; unsigned long shutdown_timeout = 5; mode_t jabberd_umask = 037; @@ -131,17 +133,27 @@ version () void usage () { - printf ("usage: jabberd [-Dfehv][-c config][-p pidfile]\n"); + printf ("usage: jabberd [-Dfehv][-c config][-r tag [tag...]]\n"); printf ("jabberd -- A dispatcher program for jabber 2.x\n"); printf ("\n"); - printf ("Options:\n"); - printf (" -c FILE use this configuration file\n"); - printf (" -D increase debugging level\n"); - printf (" -f run in foreground mode (implies -e)\n"); - printf (" -e use standard error for diagnostics output\n"); - printf (" -h display this help list\n"); - printf (" -p FILE write master process ID to FILE\n"); - printf (" -v display program version\n"); + printf ("General-purpose options:\n"); + printf (" -c, --config-file=FILE use this configuration file\n"); + printf (" -D, --debug increase debugging level\n"); + printf (" -e, --stderr use standard error for diagnostics output\n"); + printf (" -f, --foreground run in foreground mode (implies -e)\n"); + printf (" --force start up even if another copy seems to be running\n"); + + printf ("\nControlling running instance:\n"); + printf (" --status display status information\n"); + printf (" --stop stop the running copy\n"); + printf (" --reload, --hup reload the running copy\n"); + printf (" -r, --restart tag [tag...] restart named components\n"); + + printf ("\nInformational options:\n"); + printf (" -h, --help display this help list\n"); + printf (" -v, --version display program version\n"); + + printf ("\n"); printf ("Report bugs to <%s>\n", PACKAGE_BUGREPORT); } @@ -356,6 +368,18 @@ cfg_pidfile (struct cfg_file *file, char *kw, char *val, void *unused) } void +cfg_ctlfile (struct cfg_file *file, char *kw, char *val, void *unused) +{ + ctlfile = strdup (val); +} + +void +cfg_statfile (struct cfg_file *file, char *kw, char *val, void *unused) +{ + ctlfile = strdup (val); +} + +void cfg_umask (struct cfg_file *file, char *kw, char *val, void *unused) { char *p; @@ -390,60 +414,76 @@ cfg_prog (struct cfg_file *file, char *kw, char *val, void *unused) register_jabber_process (prog, val); } -struct exec_rec { +struct transport_rec +{ char *tag; char *command; int facility; int retr[2]; + int depc; + char **depv; }; static void -cfg_exec_command (struct cfg_file *file, char *kw, char *val, void *data) +cfg_transport_command (struct cfg_file *file, char *kw, char *val, void *data) { - struct exec_rec *prec = data; + struct transport_rec *prec = data; prec->command = strdup (val); } void -cfg_exec_facility (struct cfg_file *file, char *kw, char *val, void *data) +cfg_transport_facility (struct cfg_file *file, char *kw, char *val, void *data) { - struct exec_rec *prec = data; + struct transport_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) +cfg_transport_stdout (struct cfg_file *file, char *kw, char *val, void *data) { - struct exec_rec *prec = data; + struct transport_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) +cfg_transport_stderr (struct cfg_file *file, char *kw, char *val, void *data) { - struct exec_rec *prec = data; + struct transport_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) +cfg_transport_depend (struct cfg_file *file, char *kw, char *val, void *data) +{ + struct transport_rec *prec = data; + int rc; + if (rc = argcv_get (val, NULL, NULL, &prec->depc, &prec->depv)) + { + logmsg (LOG_ERR, "%s:%u: cannot split dependency line: %s", + config_file, file->line, strerror (rc)); + } +} + +void +cfg_transport (struct cfg_file *file, char *kw, char *val, void *unused) { int rc; int argc; char **argv; - struct exec_rec rec; + struct transport_rec rec; static struct kw_handler kwtab[] = { - { "command", cfg_exec_command }, - { "stdout", cfg_exec_stdout }, - { "stderr", cfg_exec_stderr }, - { "facility", cfg_exec_facility }, + { "command", cfg_transport_command }, + { "stdout", cfg_transport_stdout }, + { "stderr", cfg_transport_stderr }, + { "facility", cfg_transport_facility }, + { "depend", cfg_transport_depend }, { NULL } }; memset (&rec, 0, sizeof rec); @@ -459,9 +499,10 @@ cfg_exec (struct cfg_file *file, char *kw, char *val, void *unused) config_file, file->line, strerror (rc)); return; } - register_prog (rec.tag, argv, rec.retr); + register_transport (rec.tag, argv, rec.retr, rec.depv); free (rec.tag); free (rec.command); + argcv_free (rec.depc, rec.depv); argcv_free (argc, argv); } @@ -482,9 +523,12 @@ struct kw_handler kw_handler[] = { { "user", cfg_user }, { "group", cfg_group }, { "pidfile", cfg_pidfile }, + { "ctlfile", cfg_ctlfile }, + { "statfile", cfg_statfile }, { "umask", cfg_umask }, { "prog", cfg_prog }, - { "exec", cfg_exec }, + { "transport", cfg_transport }, + { "exec", cfg_transport }, { "shutdown-timeout", cfg_shutdown_timeout }, { NULL } }; @@ -516,24 +560,59 @@ parse_config () void pidfile_write () { - if (pidfile) + FILE *fp = fopen (pidfile, "w"); + if (!fp) + { + logmsg (LOG_CRIT, "cannot open pidfile `%s' for writing: %s", + pidfile, strerror (errno)); + return; + } + fprintf (fp, "%lu\n", (unsigned long) getpid ()); + fclose (fp); +} + +pid_t +pidfile_read (int must_exist) +{ + int c; + pid_t n = 0; + FILE *fp = fopen (pidfile, "r"); + if (!fp) { - FILE *fp = fopen (pidfile, "w"); - if (!fp) + if (must_exist && errno != ENOENT) + logmsg (LOG_ERR, "cannot open pid file `%s': %s", + pidfile, + strerror (errno)); + return -1; + } + + while ((c = fgetc (fp)) != EOF) + { + if (isdigit (c)) + n = n * 10 + c - '0'; + else if (c == '\n') + break; + else { - logmsg (LOG_CRIT, "cannot open pidfile `%s' for writing: %s", - pidfile, strerror (errno)); - return; + logmsg (LOG_ERR, "unexpected character %#03o in pidfile `%s'", + c, pidfile); + return -1; } - fprintf (fp, "%lu\n", (unsigned long) getpid ()); - fclose (fp); } + fclose (fp); + if (kill (n, 0)) + { + logmsg (LOG_ERR, "Cannot signal master process %lu: %s", + (unsigned long) n, strerror (errno)); + return -1; + } + return n; } void pidfile_remove () { - if (pidfile && unlink (pidfile)) + if (unlink (pidfile)) logmsg (LOG_ERR, "cannot remove pidfile `%s': %s", pidfile, strerror (errno)); } @@ -547,7 +626,7 @@ switch_to_privs (uid_t uid, gid_t gid) gid_t *emptygidset; size_t size = 1, j = 1; struct group_list *gp; - + if (uid == 0) { logmsg(LOG_EMERG, "refusing to run as root"); @@ -688,9 +767,11 @@ priv_setup () } -#define ACTION_CONT 0 -#define ACTION_STOP 1 -#define ACTION_RESTART 2 +#define ACTION_CONT 0 +#define ACTION_STOP 1 +#define ACTION_RESTART 2 +#define ACTION_COMPRELOAD 3 +#define ACTION_DUMPSTATS 4 int action = ACTION_CONT; int children_cleanup = 0; @@ -726,6 +807,15 @@ sig_handler(int sig) case SIGALRM: got_alarm = 1; + break; + + case SIGUSR1: + action = ACTION_COMPRELOAD; + break; + + case SIGUSR2: + action = ACTION_DUMPSTATS; + break; } signal (sig, sig_handler); } @@ -739,6 +829,8 @@ signal_setup (RETSIGTYPE (*sf)(int)) signal (SIGINT, sf); signal (SIGHUP, sf); signal (SIGALRM, sf); + signal (SIGUSR1, sf); + signal (SIGUSR2, sf); } void @@ -748,13 +840,178 @@ syslog_setup () } + +void +stop_components () +{ + FILE *fp; + size_t size = 0; + char *buf = NULL; + + logmsg (LOG_INFO, "stopping components"); + + fp = fopen (ctlfile, "r"); + if (!fp) + { + logmsg (LOG_ERR, "cannot open control file `%s': %s", + ctlfile, strerror (errno)); + return; + } + if (unlink (ctlfile)) + { + logmsg (LOG_ERR, "cannot open control file `%s': %s", + ctlfile, strerror (errno)); + fclose (fp); + return; + } + + while (getline (&buf, &size, fp) > 0) + { + size_t len = strlen (buf); + if (len == 0) + continue; + if (buf[len-1] == '\n') + buf[len-1] = 0; + progman_stop_component (buf); + } + + free (buf); + fclose (fp); +} + +int +request_restart_components (char **argv) +{ + FILE *fp; + pid_t pid = pidfile_read (1); + + if (pid == -1) + return 1; + + fp = fopen (ctlfile, "w"); + if (!fp) + { + logmsg (LOG_ERR, "cannot open control file `%s': %s", + ctlfile, strerror (errno)); + return 1; + } + for (; *argv; argv++) + fprintf (fp, "%s\n", *argv); + fclose (fp); + + kill (pid, SIGUSR1); + return 0; +} + + +int +jabberd_reload () +{ + pid_t pid = pidfile_read (1); + + if (pid == -1) + { + logmsg (LOG_CRIT, "jabberd is not running"); + return 1; + } + + logmsg (LOG_INFO, "reloading jabberd at PID %lu", (unsigned long) pid); + return kill (pid, SIGHUP) ? 2 : 0; +} + +int +jabberd_status () +{ + FILE *fp; + pid_t pid = pidfile_read (0); + int i; + + if (pid == -1) + { + logmsg (LOG_INFO, "jabberd is not running"); + return 1; + } + + if (kill (pid, SIGUSR2)) + { + logmsg (LOG_INFO, + "jabberd is not running, but a pidfile is found (pid %lu)\n", + (unsigned long) pid); + return 1; + } + logmsg (LOG_INFO, "jabberd is running; PID %lu", + (unsigned long) pid); + + for (i = 0; i < access (statfile, R_OK); i++) + sleep (1); + + fp = fopen (statfile, "r"); + if (!fp) + logmsg (LOG_ERR, "cannot open statfile `%s': %s", + statfile, strerror (errno)); + else + { + char c; + + if (unlink (statfile)) + logmsg (LOG_ERR, "cannot unlink statfile `%s': %s", + statfile, strerror (errno)); + while ((c = fgetc (fp)) != EOF) + fputc (c, stdout); + fclose (fp); + } + return 0; +} + +int +jabberd_stop () +{ + pid_t pid = pidfile_read (1); + + if (pid == -1) + { + logmsg (LOG_CRIT, "jabberd is not running"); + return 1; + } + + logmsg (LOG_INFO, "stopping jabberd at PID %lu", (unsigned long) pid); + return kill (pid, SIGTERM) ? 2 : 0; +} + + +enum { + OPTION_RELOAD = 256, + OPTION_STATUS, + OPTION_STOP, + OPTION_FORCE +}; + +struct option options[] = { + { "config-file", required_argument, NULL, 'c' }, + { "debug", no_argument, NULL, 'D' }, + { "foreground", no_argument, NULL, 'f' }, + { "stderr", no_argument, NULL, 'e' }, + { "help", no_argument, NULL, 'h' }, + { "restart-module", no_argument, NULL, 'r' }, + { "reload", no_argument, NULL, OPTION_RELOAD }, + { "hup", no_argument, NULL, OPTION_RELOAD }, + { "status", no_argument, NULL, OPTION_STATUS }, + { "stop", no_argument, NULL, OPTION_STOP }, + { "version", no_argument, NULL, 'v' }, + { "force", no_argument, NULL, OPTION_FORCE }, + { NULL } +}; + int main(int argc, char **argv) { int c; - + int mode = 0; + pid_t pid; + int force = 0; + progname = argv[0]; - while ((c = getopt(argc, argv, "c:Dfehp:v")) != EOF) + while ((c = getopt_long (argc, argv, "c:Dfehrv", options, NULL)) != EOF) { switch (c) { @@ -777,13 +1034,21 @@ main(int argc, char **argv) usage (); exit (0); - case 'p': - pidfile = optarg; - break; - case 'v': version (); exit (0); + + case 'r': + case OPTION_RELOAD: + case OPTION_STATUS: + case OPTION_STOP: + log_to_stderr = 1; + mode = c; + break; + + case OPTION_FORCE: + force = 1; + break; default: logmsg (LOG_CRIT, "unknown option: %c", c); @@ -791,7 +1056,7 @@ main(int argc, char **argv) } } - if (argc != optind) + if (argc != optind && mode != 'r') { logmsg (LOG_CRIT, "extra command line arguments"); exit (1); @@ -805,16 +1070,51 @@ main(int argc, char **argv) log_printer = syslog_printer; } + switch (mode) + { + case 'r': + priv_setup (); + umask (jabberd_umask); + exit (request_restart_components (argv + optind)); + + case OPTION_RELOAD: + exit (jabberd_reload ()); + + case OPTION_STATUS: + exit (jabberd_status ()); + + case OPTION_STOP: + exit (jabberd_stop ()); + + default: + priv_setup (); + umask (jabberd_umask); + } + + if (!force) + { + pid = pidfile_read (0); + if (pid != -1) + { + logmsg (LOG_ALERT, + "jabberd seems to be already running at pid %lu", + (unsigned long) pid); + logmsg (LOG_INFO, + "use --status to verify or --force to start up anyway"); + exit (1); + } + } + if (argv[0][0] == '/') { x_argc = argc; x_argv = argv; } else - logmsg (LOG_NOTICE, "jabberd not started as an absolute pathname; SIGHUP will not work"); + logmsg (LOG_NOTICE, + "jabberd not started as an absolute pathname; " + "SIGHUP will not work"); - priv_setup (); - umask (jabberd_umask); logmsg (LOG_NOTICE, "jabberd started"); if (!foreground && daemon (0, 0) == -1) { @@ -841,6 +1141,18 @@ main(int argc, char **argv) got_alarm = 0; progman_wake_disabled (); } + switch (action) + { + case ACTION_COMPRELOAD: + stop_components (); + action = ACTION_CONT; + break; + + case ACTION_DUMPSTATS: + progman_dump_stats (statfile); + action = ACTION_CONT; + break; + } } progman_stop (); diff --git a/jabberd/progman.c b/jabberd/progman.c index f39dd62..26693e4 100644 --- a/jabberd/progman.c +++ b/jabberd/progman.c @@ -20,8 +20,9 @@ #include <sys/stat.h> #include <fcntl.h> -#define TYPE_PROG 0 -#define TYPE_RETR 1 +#define TYPE_CORE 0 +#define TYPE_TRANSPORT 1 +#define TYPE_RETR 2 struct prog { @@ -29,10 +30,12 @@ struct prog 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]; time_t timestamp; /* Time of last startup */ @@ -48,6 +51,8 @@ struct prog }; +#define IS_PROG(p) ((p)->type == TYPE_CORE || (p)->type == TYPE_TRANSPORT) + static struct prog *proghead, *progtail; static size_t prognum; @@ -92,42 +97,110 @@ register_retr (int type, struct prog *master, pid_t pid) } void -register_prog (char *tag, char **argv, int retr[2]) +register_prog (int type, char *tag, char **argv, int retr[2], char **depv) { - struct prog *pp; + 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 (*pp) + size += i + sizeof (argv[0]) * (i + 1) + sizeof (*newp) + (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); + 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]); - pp->v.p.argv[i] = pstr; + newp->v.p.argv[i] = pstr; pstr += strlen (pstr) + 1; } - pp->v.p.argv[i] = NULL; + newp->v.p.argv[i] = NULL; if (tag) - pp->tag = strcpy (pstr, tag); + { + newp->tag = strcpy (pstr, tag); + pstr += strlen (pstr) + 1; + } else - pp->tag = pp->v.p.argv[0]; + newp->tag = newp->v.p.argv[0]; - pp->v.p.retr[0] = retr[0]; - pp->v.p.retr[1] = retr[1]; + 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 (pp, 0); + link_prog (newp, 0); +} + +void +register_transport (char *tag, char **argv, int retr[2], char **depv) +{ + static char *std_dep[] = { "all", NULL }; + if (!depv) + depv = std_dep; + register_prog (TYPE_TRANSPORT, tag, argv, retr, depv); } void @@ -147,7 +220,7 @@ register_jabber_process (char *cmd, char *cfg) argv[argc++] = "-D"; argv[argc] = NULL; - register_prog (NULL, argv, retr); + register_prog (TYPE_CORE, NULL, argv, retr, NULL); } static struct prog * @@ -316,7 +389,7 @@ progman_start () struct prog *prog; for (prog = proghead; prog; prog = prog->next) - if (prog->type == TYPE_PROG) + if (IS_PROG (prog)) prog_start (prog); } @@ -326,7 +399,7 @@ progman_wake_disabled () struct prog *prog; for (prog = proghead; prog; prog = prog->next) - if (prog->type == TYPE_PROG && prog->v.p.disabled) + if (IS_PROG (prog) && prog->v.p.disabled) { prog->v.p.disabled = 0; prog->v.p.count = 0; @@ -336,17 +409,23 @@ progman_wake_disabled () } static void -prog_stop_recursive (struct prog *prog, int sig) +prog_stop (struct prog *prog, int sig) { - if (!prog) - return; - prog_stop_recursive (prog->next, 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 @@ -412,6 +491,21 @@ print_status (char *tag, pid_t pid, int status, int expect_term) } 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; @@ -427,7 +521,87 @@ progman_cleanup (int expect_term) } print_status (prog->tag, prog->pid, status, expect_term); prog->pid = 0; - if (prog->type == TYPE_PROG && !expect_term) - prog_start (prog); + 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]; + + strftime (buf, sizeof buf, "%c", + localtime (&prog->v.p.timestamp)); + 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); } |