summaryrefslogtreecommitdiffabout
path: root/jabberd/main.c
authorSergey Poznyakoff <gray@gnu.org.ua>2007-06-04 12:35:54 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2007-06-04 12:35:54 (GMT)
commite7ffd40909f60b2230879e2767ad0a057198eb9f (patch) (side-by-side diff)
tree4572199ebe2170e6abc97b77d4e1c4e496009079 /jabberd/main.c
parentc4687307a4e3f4d08d5da97c0537fe0ce95960d1 (diff)
downloadgsc-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/main.c') (more/less context) (ignore whitespace changes)
-rw-r--r--jabberd/main.c412
1 files changed, 362 insertions, 50 deletions
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 ();

Return to:

Send suggestions and report system problems to the System administrator.