summaryrefslogtreecommitdiffabout
path: root/jabberd/main.c
Unidiff
Diffstat (limited to 'jabberd/main.c') (more/less context) (ignore whitespace changes)
-rw-r--r--jabberd/main.c910
1 files changed, 0 insertions, 910 deletions
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}

Return to:

Send suggestions and report system problems to the System administrator.