summaryrefslogtreecommitdiffabout
path: root/jabberd/progman.c
Unidiff
Diffstat (limited to 'jabberd/progman.c') (more/less context) (ignore whitespace changes)
-rw-r--r--jabberd/progman.c647
1 files changed, 0 insertions, 647 deletions
diff --git a/jabberd/progman.c b/jabberd/progman.c
deleted file mode 100644
index 3dfe3ba..0000000
--- a/jabberd/progman.c
+++ 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.