summaryrefslogtreecommitdiffabout
path: root/jabberd
Unidiff
Diffstat (limited to 'jabberd') (more/less context) (ignore whitespace changes)
-rw-r--r--jabberd/Makefile.am22
-rw-r--r--jabberd/jabberd.h62
-rw-r--r--jabberd/main.c910
-rw-r--r--jabberd/progman.c647
4 files changed, 0 insertions, 1641 deletions
diff --git a/jabberd/Makefile.am b/jabberd/Makefile.am
deleted file mode 100644
index 726eeb4..0000000
--- a/jabberd/Makefile.am
+++ b/dev/null
@@ -1,22 +0,0 @@
1# This file is part of GSC
2# Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff
3#
4# GSC is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option)
7# any later version.
8#
9# GSC is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with GSC. If not, see <http://www.gnu.org/licenses/>.
16
17bin_PROGRAMS = jabberd
18jabberd_SOURCES = main.c progman.c jabberd.h
19LDADD = ../lib/libgsc.a ../gnu/libgnu.a
20INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/gnu -I../gnu
21AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"\
22 -DSTATEDIR=\"$(localstatedir)/jabberd\"
diff --git a/jabberd/jabberd.h b/jabberd/jabberd.h
deleted file mode 100644
index 1537db4..0000000
--- a/jabberd/jabberd.h
+++ b/dev/null
@@ -1,62 +0,0 @@
1/* jabberd - a dispatcher program for jabber 2.x
2 Copyright (C) 2007 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <sys/types.h>
21#include <sys/wait.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <unistd.h>
26#include <syslog.h>
27#include <getopt.h>
28#include <errno.h>
29#include <string.h>
30#include <pwd.h>
31#include <grp.h>
32#include <signal.h>
33
34#include "gsc.h"
35
36#define RETR_OUT 0
37#define RETR_ERR 1
38
39#define TESTTIME 2*60
40#define SLEEPTIME 5*60
41#define MAXSPAWN 10
42
43void register_transport (char *tag, char **argv, int retr[2], char **depv,
44 char *pidfile);
45void register_jabber_process (char *cmd, char *cfg);
46void logmsg (int prio, char *fmt, ...);
47void signal_setup (RETSIGTYPE (*sf)(int));
48
49void *emalloc (size_t size);
50
51void progman_start (void);
52void progman_stop (void);
53void progman_cleanup (int);
54void progman_wake_disabled (void);
55void progman_stop_component (const char *);
56void progman_dump_stats (const char *);
57
58extern int debug_level;
59extern char *syslog_tag;
60extern int log_facility;
61extern unsigned long shutdown_timeout;
62
diff --git a/jabberd/main.c b/jabberd/main.c
deleted file mode 100644
index de0551f..0000000
--- a/jabberd/main.c
+++ b/dev/null
@@ -1,910 +0,0 @@
1/* jabberd - a dispatcher program for jabber 2.x
2 Copyright (C) 2007 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "jabberd.h"
18
19char *progname;
20char *config_file = SYSCONFDIR "/jabberd.cfg";
21int debug_level = 0;
22int foreground = 0;
23int log_to_stderr = 0;
24char *user = "jabber";
25char *syslog_tag = "jabberd";
26int log_facility = LOG_LOCAL7;
27int x_argc;
28char **x_argv;
29char *pidfile = STATEDIR "/jabberd.pid";
30char *ctlfile = STATEDIR "/.jabberd.ctl";
31char *statfile = STATEDIR "/.jabberd.stat";
32unsigned long shutdown_timeout = 5;
33mode_t jabberd_umask = 037;
34
35void
36syslog_printer (int prio, const char *fmt, va_list ap)
37{
38#if HAVE_VSYSLOG
39 vsyslog (prio, fmt, ap);
40#else
41 char buf[128];
42 vsnprintf (buf, sizeof buf, fmt, ap);
43 syslog (prio, "%s", buf);
44#endif
45}
46
47void
48stderr_printer (int prio, const char *fmt, va_list ap)
49{
50 const char *p = gsc_syslog_priority_to_str (prio);
51 fprintf (stderr, "%s: ", progname);
52
53 if (p)
54 fprintf (stderr, "[%s] ", p);
55
56 vfprintf (stderr, fmt, ap);
57 fputc ('\n', stderr);
58}
59
60
61static void (*log_printer) (int prio, const char *fmt, va_list ap) =
62 stderr_printer;
63
64void
65logmsg (int prio, char *fmt, ...)
66{
67 va_list ap;
68 va_start (ap, fmt);
69 log_printer (prio, fmt, ap);
70 va_end (ap);
71}
72
73void *
74emalloc (size_t size)
75{
76 char *p = malloc (size);
77 if (!p)
78 {
79 logmsg (LOG_EMERG, "%s", strerror (errno));
80 exit (1);
81 }
82 return p;
83}
84
85void
86usage ()
87{
88 printf ("usage: jabberd [-Dfehv][-c config][-r tag [tag...]]\n");
89 printf ("jabberd -- A dispatcher program for jabber 2.x\n");
90 printf ("\n");
91 printf ("General-purpose options:\n");
92 printf (" -c, --config-file=FILE use this configuration file\n");
93 printf (" -D, --debug increase debugging level\n");
94 printf (" -e, --stderr use standard error for diagnostics output\n");
95 printf (" -f, --foreground run in foreground mode (implies -e)\n");
96 printf (" --force start up even if another copy seems to be running\n");
97
98 printf ("\nControlling running instance:\n");
99 printf (" --status display status information\n");
100 printf (" --stop stop the running copy\n");
101 printf (" --reload, --hup reload the running copy\n");
102 printf (" -r, --restart tag [tag...] restart named components\n");
103
104 printf ("\nInformational options:\n");
105 printf (" -h, --help display this help list\n");
106 printf (" -v, --version display program version\n");
107
108
109 printf ("\n");
110 printf ("Report bugs to <%s>\n", PACKAGE_BUGREPORT);
111}
112
113
114/* Configuration file handling */
115
116void
117cfg_syslog_tag (gsc_config_file_t *file, char *kw, char *val, void *unused)
118{
119 syslog_tag = strdup (val);
120}
121
122void
123cfg_syslog_facility (gsc_config_file_t *file, char *kw, char *val, void *unused)
124{
125 if (gsc_str_to_syslog_facility (val, &log_facility))
126 file->error_msg (file->file_name, file->line, "Unknown facility `%s'",
127 val);
128}
129
130void
131cfg_user (gsc_config_file_t *file, char *kw, char *val, void *unused)
132{
133 struct passwd *pwd = getpwnam (val);
134 if (!pwd)
135 file->error_msg (file->file_name, file->line, "no such user `%s'",
136 val);
137 else if (pwd->pw_uid == 0)
138 file->error_msg (file->file_name, file->line, "user `%s' has zero UID",
139 val);
140 else
141 user = strdup (val);
142}
143
144struct group_list
145{
146 struct group_list *next;
147 gid_t gid;
148};
149
150static struct group_list *group_list;
151
152void
153cfg_group (gsc_config_file_t *file, char *kw, char *val, void *unused)
154{
155 struct group *group = getgrnam (val);
156 if (group)
157 {
158 struct group_list *p = emalloc (sizeof *p);
159 p->gid = group->gr_gid;
160 p->next = group_list;
161 group_list = p;
162 }
163 else
164 file->error_msg (file->file_name, file->line, "unknown group `%s'",
165 val);
166}
167
168void
169cfg_pidfile (gsc_config_file_t *file, char *kw, char *val, void *unused)
170{
171 pidfile = strdup (val);
172}
173
174void
175cfg_ctlfile (gsc_config_file_t *file, char *kw, char *val, void *unused)
176{
177 ctlfile = strdup (val);
178}
179
180void
181cfg_statfile (gsc_config_file_t *file, char *kw, char *val, void *unused)
182{
183 ctlfile = strdup (val);
184}
185
186void
187cfg_umask (gsc_config_file_t *file, char *kw, char *val, void *unused)
188{
189 char *p;
190 unsigned long n = strtoul (val, &p, 8);
191 if (*p)
192 file->error_msg (file->file_name, file->line,
193 "invalid umask; stopped near `%s'", p);
194 else
195 jabberd_umask = (mode_t) n;
196}
197
198void
199cfg_prog (gsc_config_file_t *file, char *kw, char *val, void *unused)
200{
201 char *prog = val;
202 char *p = val;
203
204 for (; *p && !isspace (*p); p++)
205 ;
206
207 if (*p)
208 {
209 *p++ = 0;
210 for (; *p && isspace (*p); p++)
211 ;
212
213 val = p;
214 }
215 else
216 val = 0;
217
218 register_jabber_process (prog, val);
219}
220
221struct transport_rec
222{
223 char *tag;
224 char *command;
225 int facility;
226 int retr[2];
227 int depc;
228 char **depv;
229 char *pidfile;
230};
231
232static void
233cfg_transport_command (gsc_config_file_t *file, char *kw, char *val, void *data)
234{
235 struct transport_rec *prec = data;
236 prec->command = strdup (val);
237}
238
239void
240cfg_transport_facility (gsc_config_file_t *file, char *kw, char *val, void *data)
241{
242 struct transport_rec *prec = data;
243 if (gsc_str_to_syslog_facility (val, &prec->facility))
244 file->error_msg (file->file_name, file->line,
245 "Unknown facility `%s'",
246 val);
247}
248
249void
250cfg_transport_stdout (gsc_config_file_t *file, char *kw, char *val, void *data)
251{
252 struct transport_rec *prec = data;
253 if (gsc_str_to_syslog_priority (val, &prec->retr[RETR_OUT]))
254 file->error_msg (file->file_name, file->line, "Unknown priority `%s'",
255 val);
256}
257
258void
259cfg_transport_stderr (gsc_config_file_t *file, char *kw, char *val, void *data)
260{
261 struct transport_rec *prec = data;
262 if (gsc_str_to_syslog_priority (val, &prec->retr[RETR_ERR]))
263 file->error_msg (file->file_name, file->line, "Unknown priority `%s'",
264 val);
265}
266
267void
268cfg_transport_depend (gsc_config_file_t *file, char *kw, char *val, void *data)
269{
270 struct transport_rec *prec = data;
271 int rc;
272 if (rc = argcv_get (val, NULL, NULL, &prec->depc, &prec->depv))
273 file->error_msg (file->file_name, file->line,
274 "cannot split dependency line: %s",
275 strerror (rc));
276}
277
278void
279cfg_transport_pidfile (gsc_config_file_t *file, char *kw, char *val,
280 void *data)
281{
282 struct transport_rec *prec = data;
283 prec->pidfile = strdup (val);
284}
285
286void
287cfg_transport (gsc_config_file_t *file, char *kw, char *val, void *unused)
288{
289 int rc;
290 int argc;
291 char **argv;
292
293 struct transport_rec rec;
294 static struct gsc_config_keyword kwtab[] = {
295 { "command", cfg_transport_command },
296 { "stdout", cfg_transport_stdout },
297 { "stderr", cfg_transport_stderr },
298 { "facility", cfg_transport_facility },
299 { "depend", cfg_transport_depend },
300 { "pidfile", cfg_transport_pidfile },
301 { NULL }
302 };
303 memset (&rec, 0, sizeof rec);
304 rec.retr[RETR_OUT] = rec.retr[RETR_ERR] = -1;
305 if (val)
306 rec.tag = strdup (val);
307
308 gsc_config_parse_block (file, &rec, kwtab, "end");
309
310 if (rc = argcv_get (rec.command, NULL, NULL, &argc, &argv))
311 {
312 file->error_msg (file->file_name, file->line,
313 "cannot split command line: %s",
314 strerror (rc));
315 return;
316 }
317 register_transport (rec.tag, argv, rec.retr, rec.depv, rec.pidfile);
318 free (rec.tag);
319 free (rec.command);
320 free (rec.pidfile);
321 argcv_free (rec.depc, rec.depv);
322 argcv_free (argc, argv);
323}
324
325void
326cfg_shutdown_timeout (gsc_config_file_t *file, char *kw, char *val, void *unused)
327{
328 char *p;
329
330 shutdown_timeout = strtoul (val, &p, 10);
331 if (*p)
332 file->error_msg (file->file_name, file->line,
333 "unrecognized timeout value, stopped near %s", p);
334}
335
336struct gsc_config_keyword kw_handler[] = {
337 { "syslog-tag", cfg_syslog_tag },
338 { "syslog-facility", cfg_syslog_facility },
339 { "user", cfg_user },
340 { "group", cfg_group },
341 { "pidfile", cfg_pidfile },
342 { "ctlfile", cfg_ctlfile },
343 { "statfile", cfg_statfile },
344 { "umask", cfg_umask },
345 { "prog", cfg_prog },
346 { "transport", cfg_transport },
347 { "exec", cfg_transport },
348 { "shutdown-timeout", cfg_shutdown_timeout },
349 { NULL }
350};
351
352void
353jabber_cfg_error (const char *name, unsigned line, const char *fmt, ...)
354{
355 va_list ap;
356 size_t n;
357 char buffer[128];
358
359 n = snprintf (buffer, sizeof buffer, "%s:%u: ", name, line);
360 va_start (ap, fmt);
361 vsnprintf (buffer + n, sizeof buffer - n, fmt, ap);
362 va_end (ap);
363 logmsg (LOG_ERR, "%s", buffer);
364}
365
366void
367parse_config ()
368{
369 switch (gsc_config_parse (config_file, jabber_cfg_error, kw_handler))
370 {
371 case gsc_config_success:
372 break;
373
374 case gsc_config_open:
375 logmsg (LOG_EMERG, "cannot open config file `%s': %s",
376 config_file, strerror (errno));
377 exit (1);
378
379 case gsc_config_error:
380 exit (1);
381 }
382}
383
384
385void
386pidfile_write ()
387{
388 FILE *fp = fopen (pidfile, "w");
389 if (!fp)
390 {
391 logmsg (LOG_CRIT, "cannot open pidfile `%s' for writing: %s",
392 pidfile, strerror (errno));
393 return;
394 }
395 fprintf (fp, "%lu\n", (unsigned long) getpid ());
396 fclose (fp);
397}
398
399pid_t
400pidfile_read (int must_exist)
401{
402 int c;
403 pid_t n = 0;
404 FILE *fp = fopen (pidfile, "r");
405 if (!fp)
406 {
407 if (must_exist && errno != ENOENT)
408 logmsg (LOG_ERR, "cannot open pid file `%s': %s",
409 pidfile,
410 strerror (errno));
411 return -1;
412 }
413
414 while ((c = fgetc (fp)) != EOF)
415 {
416 if (isdigit (c))
417 n = n * 10 + c - '0';
418 else if (c == '\n')
419 break;
420 else
421 {
422 logmsg (LOG_ERR, "unexpected character %#03o in pidfile `%s'",
423 c, pidfile);
424 return -1;
425 }
426 }
427 fclose (fp);
428 if (kill (n, 0))
429 {
430 logmsg (LOG_ERR, "Cannot signal master process %lu: %s",
431 (unsigned long) n, strerror (errno));
432 if (errno == EPERM)
433 return n; /* be on the safe side */
434 return -1;
435 }
436 return n;
437}
438
439void
440pidfile_remove ()
441{
442 if (unlink (pidfile))
443 logmsg (LOG_ERR, "cannot remove pidfile `%s': %s",
444 pidfile, strerror (errno));
445}
446
447
448/* Switch to the given UID/GID */
449int
450switch_to_privs (uid_t uid, gid_t gid)
451{
452 int rc = 0;
453 gid_t *emptygidset;
454 size_t size = 1, j = 1;
455 struct group_list *gp;
456
457 if (uid == 0)
458 {
459 logmsg (LOG_EMERG, "refusing to run as root");
460 return 1;
461 }
462
463 /* Create a list of supplementary groups */
464 for (gp = group_list; gp; gp = gp->next)
465 size++;
466 emptygidset = emalloc (size * sizeof emptygidset[0]);
467 emptygidset[0] = gid ? gid : getegid ();
468
469 for (gp = group_list; gp; gp = gp->next)
470 emptygidset[j++] = gp->gid;
471
472 rc = gsc_userprivs (uid, emptygidset, j);
473 free (emptygidset);
474 if (rc)
475 logmsg (LOG_ERR, "%s", gsc_userprivs_errstring ());
476
477 return rc;
478}
479
480void
481priv_setup ()
482{
483 if (getuid () == 0)
484 {
485 if (!user)
486 {
487 logmsg (LOG_ERR, "non-privileged user not given");
488 exit (1);
489 }
490 else
491 {
492 struct passwd *pw = getpwnam (user);
493 if (!pw)
494 {
495 logmsg (LOG_ERR, "No such user: %s", user);
496 exit (1);
497 }
498 if (pw && switch_to_privs (pw->pw_uid, pw->pw_gid))
499 exit (1);
500 }
501 }
502}
503
504
505#define ACTION_CONT 0
506#define ACTION_STOP 1
507#define ACTION_RESTART 2
508#define ACTION_COMPRELOAD 3
509#define ACTION_DUMPSTATS 4
510
511int action = ACTION_CONT;
512int children_cleanup = 0;
513int got_alarm = 0;
514
515RETSIGTYPE
516sig_handler(int sig)
517{
518 switch (sig)
519 {
520 case SIGCHLD:
521 children_cleanup = 1;
522 break;
523
524 case SIGTERM:
525 case SIGINT:
526 case SIGQUIT:
527 action = ACTION_STOP;
528 logmsg (LOG_NOTICE, "received signal %d", sig);
529 break;
530
531 case SIGHUP:
532 logmsg (LOG_NOTICE, "received signal %d", sig);
533 if (x_argc == 0)
534 {
535 logmsg (LOG_NOTICE,
536 "SIGHUP: not started with an absolute pathname");
537 action = ACTION_STOP;
538 }
539 else
540 action = ACTION_RESTART;
541 break;
542
543 case SIGALRM:
544 got_alarm = 1;
545 break;
546
547 case SIGUSR1:
548 action = ACTION_COMPRELOAD;
549 break;
550
551 case SIGUSR2:
552 action = ACTION_DUMPSTATS;
553 break;
554 }
555 signal (sig, sig_handler);
556}
557
558void
559signal_setup (RETSIGTYPE (*sf)(int))
560{
561 signal (SIGCHLD, sf);
562 signal (SIGTERM, sf);
563 signal (SIGQUIT, sf);
564 signal (SIGINT, sf);
565 signal (SIGHUP, sf);
566 signal (SIGALRM, sf);
567 signal (SIGUSR1, sf);
568 signal (SIGUSR2, sf);
569}
570
571void
572syslog_setup ()
573{
574 log_printer = syslog_printer;
575}
576
577
578
579void
580stop_components ()
581{
582 FILE *fp;
583 size_t size = 0;
584 char *buf = NULL;
585
586 logmsg (LOG_INFO, "stopping components");
587
588 fp = fopen (ctlfile, "r");
589 if (!fp)
590 {
591 logmsg (LOG_ERR, "cannot open control file `%s': %s",
592 ctlfile, strerror (errno));
593 return;
594 }
595 if (unlink (ctlfile))
596 {
597 logmsg (LOG_ERR, "cannot open control file `%s': %s",
598 ctlfile, strerror (errno));
599 fclose (fp);
600 return;
601 }
602
603 while (getline (&buf, &size, fp) > 0)
604 {
605 size_t len = strlen (buf);
606 if (len == 0)
607 continue;
608 if (buf[len-1] == '\n')
609 buf[len-1] = 0;
610 progman_stop_component (buf);
611 }
612
613 free (buf);
614 fclose (fp);
615}
616
617int
618request_restart_components (char **argv)
619{
620 FILE *fp;
621 pid_t pid = pidfile_read (1);
622
623 if (pid == -1)
624 return 1;
625
626 fp = fopen (ctlfile, "w");
627 if (!fp)
628 {
629 logmsg (LOG_ERR, "cannot open control file `%s': %s",
630 ctlfile, strerror (errno));
631 return 1;
632 }
633 for (; *argv; argv++)
634 fprintf (fp, "%s\n", *argv);
635 fclose (fp);
636
637 kill (pid, SIGUSR1);
638 return 0;
639}
640
641
642int
643jabberd_reload ()
644{
645 pid_t pid = pidfile_read (1);
646
647 if (pid == -1)
648 {
649 logmsg (LOG_CRIT, "jabberd is not running");
650 return 1;
651 }
652
653 logmsg (LOG_INFO, "reloading jabberd at PID %lu", (unsigned long) pid);
654 return kill (pid, SIGHUP) ? 2 : 0;
655}
656
657int
658jabberd_status ()
659{
660 FILE *fp;
661 pid_t pid = pidfile_read (0);
662 int i;
663
664 if (pid == -1)
665 {
666 logmsg (LOG_INFO, "jabberd is not running");
667 return 1;
668 }
669
670 if (kill (pid, SIGUSR2))
671 {
672 logmsg (LOG_INFO,
673 "jabberd is not running, but a pidfile is found (pid %lu)\n",
674 (unsigned long) pid);
675 return 1;
676 }
677 logmsg (LOG_INFO, "jabberd is running; PID %lu",
678 (unsigned long) pid);
679
680 for (i = 0; i < 4 && access (statfile, R_OK); i++)
681 sleep (1);
682
683 fp = fopen (statfile, "r");
684 if (!fp)
685 logmsg (LOG_ERR, "cannot open statfile `%s': %s",
686 statfile, strerror (errno));
687 else
688 {
689 char c;
690
691 if (unlink (statfile))
692 logmsg (LOG_ERR, "cannot unlink statfile `%s': %s",
693 statfile, strerror (errno));
694 while ((c = fgetc (fp)) != EOF)
695 fputc (c, stdout);
696 fclose (fp);
697 }
698 return 0;
699}
700
701int
702jabberd_stop ()
703{
704 pid_t pid = pidfile_read (1);
705
706 if (pid == -1)
707 {
708 logmsg (LOG_CRIT, "jabberd is not running");
709 return 1;
710 }
711
712 logmsg (LOG_INFO, "stopping jabberd at PID %lu", (unsigned long) pid);
713 return kill (pid, SIGTERM) ? 2 : 0;
714}
715
716
717enum {
718 OPTION_RELOAD = 256,
719 OPTION_STATUS,
720 OPTION_STOP,
721 OPTION_FORCE
722};
723
724struct option options[] = {
725 { "config-file", required_argument, NULL, 'c' },
726 { "debug", no_argument, NULL, 'D' },
727 { "foreground", no_argument, NULL, 'f' },
728 { "stderr", no_argument, NULL, 'e' },
729 { "help", no_argument, NULL, 'h' },
730 { "restart-module", no_argument, NULL, 'r' },
731 { "reload", no_argument, NULL, OPTION_RELOAD },
732 { "hup", no_argument, NULL, OPTION_RELOAD },
733 { "status", no_argument, NULL, OPTION_STATUS },
734 { "stop", no_argument, NULL, OPTION_STOP },
735 { "version", no_argument, NULL, 'v' },
736 { "force", no_argument, NULL, OPTION_FORCE },
737 { NULL }
738};
739
740int
741main(int argc, char **argv)
742{
743 int c;
744 int mode = 0;
745 pid_t pid;
746 int force = 0;
747
748 progname = argv[0];
749 while ((c = getopt_long (argc, argv, "c:Dfehrv", options, NULL)) != EOF)
750 {
751 switch (c)
752 {
753 case 'c':
754 config_file = optarg;
755 break;
756
757 case 'D':
758 debug_level++;
759 break;
760
761 case 'f':
762 foreground = 1;
763
764 case 'e':
765 log_to_stderr = 1;
766 break;
767
768 case 'h':
769 usage ();
770 exit (0);
771
772 case 'v':
773 gsc_version ("jabberd");
774 exit (0);
775
776 case 'r':
777 case OPTION_RELOAD:
778 case OPTION_STATUS:
779 case OPTION_STOP:
780 log_to_stderr = 1;
781 mode = c;
782 break;
783
784 case OPTION_FORCE:
785 force = 1;
786 break;
787
788 default:
789 logmsg (LOG_CRIT, "unknown option: %c", c);
790 exit (1);
791 }
792 }
793
794 if (argc != optind && mode != 'r')
795 {
796 logmsg (LOG_CRIT, "extra command line arguments");
797 exit (1);
798 }
799
800 parse_config ();
801
802 if (!log_to_stderr)
803 {
804 openlog (syslog_tag, LOG_PID, log_facility);
805 log_printer = syslog_printer;
806 }
807
808 switch (mode)
809 {
810 case 'r':
811 priv_setup ();
812 umask (jabberd_umask);
813 exit (request_restart_components (argv + optind));
814
815 case OPTION_RELOAD:
816 exit (jabberd_reload ());
817
818 case OPTION_STATUS:
819 exit (jabberd_status ());
820
821 case OPTION_STOP:
822 exit (jabberd_stop ());
823
824 default:
825 priv_setup ();
826 umask (jabberd_umask);
827 }
828
829 if (!force)
830 {
831 pid = pidfile_read (0);
832 if (pid != -1)
833 {
834 logmsg (LOG_ALERT,
835 "jabberd seems to be already running at pid %lu",
836 (unsigned long) pid);
837 logmsg (LOG_INFO,
838 "use --status to verify or --force to start up anyway");
839 exit (1);
840 }
841 }
842
843 if (argv[0][0] == '/')
844 {
845 x_argc = argc;
846 x_argv = argv;
847 }
848 else
849 logmsg (LOG_NOTICE,
850 "jabberd not started as an absolute pathname; "
851 "SIGHUP will not work");
852
853 logmsg (LOG_NOTICE, "jabberd started");
854 if (!foreground && daemon (0, 0) == -1)
855 {
856 logmsg (LOG_CRIT, "cannot become a daemon: %s",
857 strerror (errno));
858 exit (1);
859 }
860 pidfile_write ();
861
862 signal_setup (sig_handler);
863
864 progman_start ();
865
866 while (action == ACTION_CONT)
867 {
868 pause ();
869 if (children_cleanup)
870 {
871 children_cleanup = 0;
872 progman_cleanup (0);
873 }
874 if (got_alarm)
875 {
876 got_alarm = 0;
877 progman_wake_disabled ();
878 }
879 switch (action)
880 {
881 case ACTION_COMPRELOAD:
882 stop_components ();
883 action = ACTION_CONT;
884 break;
885
886 case ACTION_DUMPSTATS:
887 progman_dump_stats (statfile);
888 action = ACTION_CONT;
889 break;
890 }
891 }
892 progman_stop ();
893
894 pidfile_remove ();
895 if (action == ACTION_RESTART)
896 {
897 int i;
898
899 for (i = getmaxfd (); i > 0; i--)
900 close (i);
901
902 signal_setup (SIG_DFL);
903
904 execv (x_argv[0], x_argv);
905 openlog (syslog_tag, LOG_PID, log_facility);
906 logmsg (LOG_EMERG, "cannot restart: %s", strerror (errno));
907 }
908 logmsg (LOG_NOTICE, "jabberd finished");
909 exit (0);
910}
diff --git a/jabberd/progman.c b/jabberd/progman.c
deleted file mode 100644
index 3dfe3ba..0000000
--- a/jabberd/progman.c
+++ b/dev/null
@@ -1,647 +0,0 @@
1/* jabberd - a dispatcher program for jabber 2.x
2 Copyright (C) 2007 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "jabberd.h"
18#include <sys/stat.h>
19#include <fcntl.h>
20
21#define TYPE_CORE 0
22#define TYPE_TRANSPORT 1
23#define TYPE_RETR 2
24
25struct prog
26{
27 struct prog *next; /* Next program in the list */
28 int type;
29 pid_t pid; /* PID */
30 char *tag; /* Entry tag (for diagnostics purposes) */
31 char **depend;
32 union
33 {
34 struct
35 {
36 int argc;
37 char **argv; /* Command line arguments */
38 int retr[2];
39 char *pidfile; /* Pidfile location */
40 time_t timestamp; /* Time of last startup */
41 size_t count; /* Number of failed starts since timestamp */
42 int disabled; /* 1 if this entry is disabled */
43 } p;
44
45 struct
46 {
47 struct prog *master;
48 } r;
49 } v;
50};
51
52
53#define IS_PROG(p) ((p)->type == TYPE_CORE || (p)->type == TYPE_TRANSPORT)
54
55static struct prog *proghead, *progtail;
56static size_t prognum;
57
58static void prog_stop (struct prog *prog, int sig);
59
60void
61link_prog (struct prog *pp, int prepend)
62{
63 if (prepend)
64 {
65 pp->next = proghead;
66 proghead = pp;
67 if (!progtail)
68 progtail = pp;
69 }
70 else
71 {
72 pp->next = NULL;
73 if (progtail)
74 progtail->next = pp;
75 else
76 proghead = pp;
77 progtail = pp;
78 }
79}
80
81void
82register_retr (int type, struct prog *master, pid_t pid)
83{
84 struct prog *pp;
85 static char *retrstr[2] = { "stdout", "stderr" };
86 size_t taglen = strlen (master->tag) + 1 + strlen (retrstr[type]);
87 char *tag = emalloc (taglen + 1);
88
89 strcpy (tag, master->tag);
90 strcat (tag, "/");
91 strcat (tag, retrstr[type]);
92
93 for (pp = proghead; pp; pp = pp->next)
94 if (pp->type == TYPE_RETR && pp->v.r.master == master
95 && strcmp (pp->tag, tag) == 0)
96 {
97 free (tag);
98 prog_stop (pp, SIGKILL);
99 break;
100 }
101
102 if (!pp)
103 {
104 pp = emalloc (sizeof(*pp) + taglen + 1);
105 memset (pp, 0, sizeof(*pp));
106 pp->type = TYPE_RETR;
107 pp->tag = (char *) (pp + 1);
108 strcpy (pp->tag, tag);
109 free (tag);
110 pp->v.r.master = master;
111 link_prog (pp, 1);
112 }
113
114 pp->pid = pid;
115}
116
117void
118register_prog (int type, char *tag, char **argv, int retr[2], char **depv,
119 char *pidfile)
120{
121 struct prog *p, *newp;
122 char *pstr;
123 int i;
124 size_t size = 0;
125 int dep_all = 0;
126 int depc = 0;
127
128 if (depv)
129 {
130 if (depv[0] && depv[1] == NULL)
131 {
132 if (strcmp (depv[0], "all") == 0)
133 {
134 dep_all = 1;
135 for (p = proghead; p; p = p->next)
136 if (p->type == TYPE_CORE)
137 {
138 depc++;
139 size += strlen (p->tag) + 1;
140 }
141 }
142 else if (strcmp (depv[0], "none") == 0)
143 depv = NULL;
144 }
145
146 if (depc == 0)
147 for (depc = 0; depv[depc]; depc++)
148 ;
149 size += sizeof (depv[0]) * (depc + 1);
150 }
151
152 for (i = 0; argv[i]; i++)
153 size += strlen (argv[i]);
154 size += i + sizeof (argv[0]) * (i + 1) + sizeof (*newp)
155 + (tag ? (strlen (tag) + 1) : 0);
156 if (pidfile)
157 size += strlen (pidfile) + 1;
158
159 newp = emalloc (size);
160 memset (newp, 0, sizeof(*newp));
161 newp->type = type;
162 newp->pid = 0;
163 newp->v.p.argc = i;
164 newp->v.p.argv = (char **) (newp + 1);
165 pstr = (char*) (newp->v.p.argv + i + 1);
166
167 for (i = 0; argv[i]; i++)
168 {
169 strcpy (pstr, argv[i]);
170 newp->v.p.argv[i] = pstr;
171 pstr += strlen (pstr) + 1;
172 }
173 newp->v.p.argv[i] = NULL;
174
175 if (tag)
176 {
177 newp->tag = strcpy (pstr, tag);
178 pstr += strlen (pstr) + 1;
179 }
180 else
181 newp->tag = newp->v.p.argv[0];
182
183 if (pidfile)
184 {
185 newp->v.p.pidfile = strcpy (pstr, pidfile);
186 pstr += strlen (pstr) + 1;
187 }
188 else
189 newp->v.p.pidfile = NULL;
190
191 if (depv)
192 {
193 newp->depend = (char**) pstr;
194 pstr = (char*) (newp->depend + depc + 1);
195 if (dep_all)
196 {
197 depc = 0;
198 for (p = proghead; p; p = p->next)
199 if (p->type == TYPE_CORE)
200 {
201 newp->depend[depc++] = pstr;
202 strcpy (pstr, p->tag);
203 pstr += strlen (pstr) + 1;
204 }
205 }
206 else
207 {
208 for (depc = 0; depv[depc]; depc++)
209 {
210 newp->depend[depc] = pstr;
211 strcpy (pstr, p->tag);
212 pstr += strlen (pstr) + 1;
213 }
214 }
215 depv[depc] = NULL;
216 }
217 else
218 newp->depend = NULL;
219
220 newp->v.p.retr[0] = retr[0];
221 newp->v.p.retr[1] = retr[1];
222
223 link_prog (newp, 0);
224}
225
226void
227register_transport (char *tag, char **argv, int retr[2], char **depv,
228 char *pidfile)
229{
230 static char *std_dep[] = { "all", NULL };
231 if (!depv)
232 depv = std_dep;
233 register_prog (TYPE_TRANSPORT, tag, argv, retr, depv, pidfile);
234}
235
236void
237register_jabber_process (char *cmd, char *cfg)
238{
239 int retr[2] = { -1, -1 };
240 char *argv[5];
241 int argc = 0;
242
243 argv[argc++] = cmd;
244 if (cfg)
245 {
246 argv[argc++] = "-c";
247 argv[argc++] = cfg;
248 }
249 if (debug_level > 2)
250 {
251 argv[argc++] = "-D";
252 retr[RETR_ERR] = LOG_DEBUG;
253 }
254 argv[argc] = NULL;
255
256 register_prog (TYPE_CORE, NULL, argv, retr, NULL, NULL);
257}
258
259static struct prog *
260find_prog (pid_t pid)
261{
262 struct prog *prog;
263
264 for (prog = proghead; prog; prog = prog->next)
265 if (prog->pid == pid)
266 break;
267 return prog;
268}
269
270size_t
271progman_running_count ()
272{
273 size_t size = 0;
274 struct prog *prog;
275
276 for (prog = proghead; prog; prog = prog->next)
277 if (prog->pid > 0)
278 size++;
279 return size;
280}
281
282RETSIGTYPE
283retr_exit (int sig)
284{
285 exit (0);
286}
287
288int
289open_retranslator (struct prog *master, int type)
290{
291 int p[2];
292 FILE *fp;
293 char *buf = NULL;
294 size_t size = 0;
295 pid_t pid;
296
297 if (master->v.p.retr[type] == -1)
298 return -1;
299 pipe (p);
300 switch (pid = fork ())
301 {
302 case 0:
303 /* Retranslator process */
304
305 syslog_setup ();
306 signal_setup (retr_exit);
307
308 close (p[1]);
309 fp = fdopen (p[0], "r");
310 if (fp == NULL)
311 exit (1);
312
313 openlog (master->tag, LOG_PID, log_facility);
314
315 while (getline (&buf, &size, fp) > 0)
316 logmsg (master->v.p.retr[type], "%s", buf);
317 exit (0);
318
319 case -1:
320 logmsg (LOG_CRIT, "cannot run retranslator `%s': fork failed: %s",
321 master->tag, strerror (errno));
322 return -1;
323
324 default:
325 register_retr (type, master, pid);
326
327 close (p[0]);
328 return p[1];
329 }
330}
331
332static void
333prog_start (struct prog *prog)
334{
335 int i;
336 pid_t pid;
337 time_t now;
338 int retr[2];
339
340 time (&now);
341
342 if (prog->v.p.timestamp + TESTTIME > now)
343 prog->v.p.count++;
344 else
345 {
346 prog->v.p.count = 0;
347 prog->v.p.timestamp = now;
348 }
349
350 if (prog->v.p.count > MAXSPAWN)
351 {
352 int old_alarm;
353
354 logmsg(LOG_ERR, "%s is respawning too fast, disabled for %d minutes",
355 prog->tag, SLEEPTIME / 60);
356 prog->v.p.timestamp = now;
357 prog->v.p.disabled = 1;
358
359 old_alarm = alarm (0);
360 if (old_alarm > SLEEPTIME || old_alarm <= 0)
361 old_alarm = SLEEPTIME;
362 alarm (old_alarm);
363 return;
364 }
365
366 logmsg (LOG_DEBUG, "starting %s", prog->tag);
367
368 if (prog->v.p.pidfile)
369 {
370 if (unlink (prog->v.p.pidfile) && errno != ENOENT)
371 logmsg (LOG_ERR, "%s: cannot remove pidfile `%s': %s",
372 prog->tag, prog->v.p.pidfile, strerror (errno));
373 }
374
375 retr[RETR_OUT] = open_retranslator (prog, RETR_OUT);
376 retr[RETR_ERR] = open_retranslator (prog, RETR_ERR);
377
378 switch (pid = fork ())
379 {
380 /* The child branch. */
381 case 0:
382 if (retr[RETR_OUT] == -1)
383 {
384 close (1);
385 open ("/dev/null", O_RDWR);
386 }
387 else if (retr[RETR_OUT] != 1)
388 {
389 close (1);
390 dup2 (retr[RETR_OUT], 1);
391 }
392
393 if (retr[RETR_ERR] == -1)
394 {
395 close (2);
396 open ("/dev/null", O_RDWR);
397 }
398 else if (retr[RETR_ERR] != 1)
399 {
400 close (2);
401 dup2 (retr[RETR_ERR], 2);
402 }
403
404 /* Close unneded descripitors */
405 for (i = getmaxfd (); i > 2; i--)
406 close (i);
407
408 signal_setup (SIG_DFL);
409
410 execvp(prog->v.p.argv[0], prog->v.p.argv);
411 openlog (syslog_tag, LOG_PID, log_facility);
412 logmsg (LOG_CRIT, "cannot start `%s': %s", prog->tag,
413 strerror (errno));
414 exit (1);
415
416 case -1:
417 logmsg (LOG_CRIT, "cannot run `%s': fork failed: %s",
418 prog->tag, strerror (errno));
419 break;
420
421 default:
422 prog->pid = pid;
423 }
424}
425
426void
427progman_start ()
428{
429 struct prog *prog;
430
431 for (prog = proghead; prog; prog = prog->next)
432 if (IS_PROG (prog))
433 prog_start (prog);
434}
435
436void
437progman_wake_disabled ()
438{
439 struct prog *prog;
440
441 for (prog = proghead; prog; prog = prog->next)
442 if (IS_PROG (prog) && prog->v.p.disabled)
443 {
444 prog->v.p.disabled = 0;
445 prog->v.p.count = 0;
446 prog->v.p.timestamp = 0;
447 prog_start (prog);
448 }
449}
450
451static void
452prog_stop (struct prog *prog, int sig)
453{
454 if (prog->pid > 0)
455 {
456 logmsg (LOG_DEBUG, "Stopping %s",
457 prog->tag, (unsigned long) prog->pid);
458 kill (prog->pid, sig);
459 }
460}
461
462static void
463prog_stop_recursive (struct prog *prog, int sig)
464{
465 if (!prog)
466 return;
467 prog_stop_recursive (prog->next, sig);
468 prog_stop (prog, sig);
469}
470
471void
472progman_stop ()
473{
474 unsigned long i;
475
476 prog_stop_recursive (proghead, SIGTERM);
477 for (i = 0; i < shutdown_timeout; i++)
478 {
479 progman_cleanup (1);
480 if (progman_running_count () == 0)
481 return;
482 sleep (1);
483 }
484 prog_stop_recursive (proghead, SIGKILL);
485}
486
487static void
488print_status (char *tag, pid_t pid, int status, int expect_term)
489{
490 if (WIFEXITED (status))
491 {
492 if (WEXITSTATUS (status) == 0)
493 logmsg (LOG_DEBUG,
494 "%s (%lu) exited successfully",
495 tag, (unsigned long) pid);
496 else
497 logmsg (LOG_ERR,
498 "%s (%lu) failed with status %d",
499 tag, (unsigned long) pid,
500 WEXITSTATUS (status));
501 }
502 else if (WIFSIGNALED (status))
503 {
504 int prio;
505
506 if (expect_term && WTERMSIG (status) == SIGTERM)
507 prio = LOG_DEBUG;
508 else
509 prio = LOG_ERR;
510
511 logmsg(prio,
512 "%s (%lu) terminated on signal %d",
513 tag, (unsigned long) pid,
514 WTERMSIG (status));
515 }
516 else if (WIFSTOPPED (status))
517 logmsg(LOG_ERR,
518 "%s (%lu) stopped on signal %d",
519 tag, (unsigned long) pid,
520 WSTOPSIG (status));
521#ifdef WCOREDUMP
522 else if (WCOREDUMP (status))
523 logmsg (LOG_ERR,
524 "%s (%lu) dumped core",
525 tag, (unsigned long) pid);
526#endif
527 else
528 logmsg(LOG_ERR,
529 "%s (%lu) terminated with unrecognized status",
530 tag, (unsigned long) pid);
531}
532
533void
534prog_stop_dependent (struct prog *prog)
535{
536 struct prog *p;
537
538 for (p = proghead; p; p = p->next)
539 if (p->depend)
540 {
541 int i;
542 for (i = 0; p->depend[i]; i++)
543 if (strcmp (prog->tag, p->depend[i]) == 0)
544 prog_stop (p, SIGTERM);
545 }
546}
547
548void
549progman_cleanup (int expect_term)
550{
551 pid_t pid;
552 int status;
553 while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
554 {
555 struct prog *prog = find_prog (pid);
556 if (!prog)
557 {
558 logmsg (LOG_NOTICE, "unknown child %lu finished",
559 (unsigned long) pid);
560 continue;
561 }
562 print_status (prog->tag, prog->pid, status, expect_term);
563 prog->pid = 0;
564 if (IS_PROG (prog))
565 {
566 prog_stop_dependent (prog);
567 if (!expect_term)
568 prog_start (prog);
569 }
570 }
571}
572
573void
574progman_stop_component (const char *name)
575{
576 struct prog *prog;
577
578 logmsg (LOG_INFO, "stopping component `%s'", name);
579 for (prog = proghead; prog; prog = prog->next)
580 if (IS_PROG (prog) && strcmp (prog->tag, name) == 0)
581 {
582 if (prog->v.p.disabled)
583 logmsg (LOG_INFO, "stopping component `%s': component not started",
584 name);
585 else
586 prog_stop (prog, SIGTERM);
587 }
588}
589
590void
591progman_dump_stats (const char *filename)
592{
593 FILE *fp;
594 struct prog *prog;
595 char *s;
596 int rc;
597
598 logmsg (LOG_INFO, "dumping statistics to `%s'", filename);
599 fp = fopen (filename, "w");
600 if (!fp)
601 {
602 logmsg (LOG_ERR, "cannot open file `%s' for writing: %s",
603 filename, strerror (errno));
604 return;
605 }
606
607 for (prog = proghead; prog; prog = prog->next)
608 {
609 switch (prog->type)
610 {
611 case TYPE_CORE:
612 case TYPE_TRANSPORT:
613 fprintf (fp, "%s %s ",
614 prog->type == TYPE_CORE ? "core" : "transport",
615 prog->tag);
616 if (prog->pid)
617 fprintf (fp, "%lu", (unsigned long) prog->pid);
618 else if (prog->v.p.disabled)
619 {
620 char buf[48];
621 time_t t = prog->v.p.timestamp + SLEEPTIME;
622 strftime (buf, sizeof buf, "%c",
623 localtime (&t));
624 fprintf (fp, "[disabled; scheduled for %s]", buf);
625 }
626 else
627 fprintf (fp, "[not running]");
628 if (rc = argcv_string (prog->v.p.argc, prog->v.p.argv, &s))
629 {
630 logmsg (LOG_ERR, "cannot convert argument list: %s",
631 strerror (rc));
632 }
633 else
634 {
635 fprintf (fp, " %s", s);
636 free (s);
637 }
638 fputc ('\n', fp);
639 break;
640
641 case TYPE_RETR:
642 fprintf (fp, "retranslator %s %lu\n", prog->tag,
643 (unsigned long) prog->pid);
644 }
645 }
646 fclose (fp);
647}

Return to:

Send suggestions and report system problems to the System administrator.