summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2010-01-28 22:07:31 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2010-01-28 22:07:31 (GMT)
commitdf4a2a61ce0cde5190def22309e9807cb5a56ab0 (patch) (unidiff)
tree364eb6562f6bd41eb3fe0ca15e497a2a76a4b57c
parent5f392fc3cf8e94112ed7b15b2038e51f1b2b3800 (diff)
downloadgsc-df4a2a61ce0cde5190def22309e9807cb5a56ab0.tar.gz
gsc-df4a2a61ce0cde5190def22309e9807cb5a56ab0.tar.bz2
Remove jabberd
git-svn-id: file:///svnroot/gsc/trunk@339 d2de0444-eb31-0410-8365-af798a554d48
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--ChangeLog6
-rw-r--r--Makefile.am3
-rw-r--r--configure.ac3
-rw-r--r--doc/gsc.texi449
-rw-r--r--jabberd/Makefile.am22
-rw-r--r--jabberd/jabberd.h62
-rw-r--r--jabberd/main.c910
-rw-r--r--jabberd/progman.c647
-rw-r--r--mc/trurl.mc15
9 files changed, 15 insertions, 2102 deletions
diff --git a/ChangeLog b/ChangeLog
index 6894c0e..b855c2f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1 +1,7 @@
12010-01-29 Sergey Poznyakoff <gray@gnu.org.ua>
2
3 * jabberd: Removed. Use GNU pies instead.
4 * Makefile.am, configure.ac: Update.
5 * doc/gsc.texi: Update.
6
12009-08-03 Sergey Poznyakoff <gray@gnu.org.ua> 72009-08-03 Sergey Poznyakoff <gray@gnu.org.ua>
diff --git a/Makefile.am b/Makefile.am
index 6215e1f..fcba8a0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,3 +36,2 @@ SUBDIRS=\
36 ppp\ 36 ppp\
37 rc.d\ 37 rc.d
38 jabberd
diff --git a/configure.ac b/configure.ac
index 97a928d..d9dabeb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -118,4 +118,3 @@ mc
118ppp 118ppp
119rc.d 119rc.d'
120jabberd'
121 120
diff --git a/doc/gsc.texi b/doc/gsc.texi
index 29e5e1b..87e1ce5 100644
--- a/doc/gsc.texi
+++ b/doc/gsc.texi
@@ -121,3 +121,2 @@ Root Utilities
121* session-cleanup:: Manage PHP Sessions. 121* session-cleanup:: Manage PHP Sessions.
122* jabberd:: Jabberd dispatcher daemon.
123 122
@@ -127,13 +126,2 @@ firewall
127 126
128Jabberd
129
130* jabintro:: Jabberd Operation Overview
131* jabopts:: Command Line Options.
132* jabberd.cfg:: Main Jabberd Configuration File.
133
134Jabberd Configuration File
135
136* cfgstat:: Configuration File Statements
137* example:: An Example of the Configuration file
138
139Startup Scripts 127Startup Scripts
@@ -843,3 +831,2 @@ cases, though not always. Such files should probably be inspected after
843* session-cleanup:: Manage PHP Sessions. 831* session-cleanup:: Manage PHP Sessions.
844* jabberd:: Jabberd dispatcher daemon.
845@end menu 832@end menu
@@ -1169,438 +1156,2 @@ actually remove them.
1169 1156
1170@node jabberd
1171@section Jabberd
1172@cindex jabberd
1173 The @command{jabberd} utility is a dispatcher daemon for
1174@samp{Jabberd 2.x}
1175(@uref{http://www.jabber.org/software/jabberd2x.shtml}). It is
1176intended as a replacement for the similar utility shipped with the
1177@samp{jabberd 2.x} package. There were two reasons that urged for the
1178replacement: first, the original @command{jabberd} is written in Perl
1179and consumes way too many resources because of that. Secondly, it is
1180not flexible enough. In particular, it is only able to control jabber
1181daemons, but cannot control external transports (such as @acronym{GG}
1182or @acronym{GIT}.
1183
1184@menu
1185* jabintro:: Jabberd Operation Overview
1186* jabopts:: Command Line Options.
1187* jabberd.cfg:: Main Jabberd Configuration File.
1188@end menu
1189
1190@node jabintro
1191@subsection Jabberd Operation Overview
1192
1193 The @acronym{GSC} @command{jabberd} is a supervisor daemon that
1194starts a number of @dfn{components} and controls their execution.
1195A component is either a jabberd core component (as,
1196e.g. @command{c2s}) or some external program (e.g. a transport). The
1197daemon reads the list of components from its configuration file upon
1198startup. By default, the configuration file is named
1199@file{jabberd.cfg} and is located in @code{$sysconfdir} directory, but
1200its exact location can be overridden at startup (see @option{-c}
1201option, below). If run with the root privileges, @command{jabberd}
1202switches to the privileges of a selected user (by default
1203@samp{jabber}) right after startup. Then, the program changes file
1204creation mask to a safe value (the default is @samp{037}). Unless
1205explicitly requested to remain in the foreground, the utility detaches
1206itself from the controlling terminal and switches to the background.
1207The daemon starts the configured components
1208in the order of their appearance in the configuration file. The exact
1209command line options and arguments for each component are specified
1210in the configuration file. If a particular subprocess prints its
1211diagnostics on stderr or stdout, you may instruct @command{jabberd} to
1212capture and divert it to a particular @command{syslogd}
1213priority (@pxref{stdout}). After launching the components
1214@command{jabberd} enters its main loop. It sleeps until either some
1215component finishes or a signal is delivered. If a component finishes,
1216@command{jabberd} scans its internal list to find components that
1217depend on the finished one. Each such component is then terminated
1218by sending it @acronym{SIGTERM} signal. Then, the finished component and
1219its dependent components are started again. If a process is
1220restarted more than 10 times within a two minutes interval, it is
1221disabled for the next five minutes (the same way the standard
1222@acronym{UNIX} @command{init} utility operates).
1223
1224 The @command{jabberd} utility exits if it recieves any of the
1225following signals: @acronym{SIGTERM}, @acronym{SIGQUIT},
1226@acronym{SIGINT}. It attempts to restart itself if delivered the
1227@acronym{SIGHUP} signal. This is possible only if the utility is
1228started using its absolute file name. In any case, before exiting,
1229the utility shuts down all components @emph{in the reverse
1230order} of their appearance in the configuration file. The processes
1231are shut down by sending them @acronym{SIGTERM} signals. If a
1232component does not exit within a 1 second interval, it is re-sent the
1233same signal. This procedure continues until either all components
1234terminate or the @dfn{shutdown timeout} interval expires, whichever
1235happens first. If the latter happens, any components still left
1236running are slayed using @acronym{SIGKILL} signal. The default
1237shutdown timeout is 5 seconds and it may be changed using
1238@code{shutdown-timeout} configuration file statement (@pxref{cfgstat}).
1239
1240 Two signals are special to @command{jabberd}: @acronym{SIGUSR1}
1241and @acronym{SIGUSR2}. The @acronym{SIGUSR1} signal instructs the
1242program to shut down and restart a particular component or a set
1243of components. The list of components to be restarted is passed to
1244the running program via a @dfn{control file} (@pxref{ctlfile}). This
1245mechanism is used by @command{jabberd
1246--restart}. @FIXME-xref{restarting selected components}.
1247
1248 The @acronym{SIGUSR2} signal instructs @command{jabberd} to return
1249statistics about running components. It is used by @command{jabberd
1250--status} (@FIXME-pxref{showing runtime statistics}).
1251
1252@node jabopts
1253@subsection Jabberd Invocation
1254@UNREVISED{}
1255
1256 By default, @command{jabberd} attempts to start in @dfn{dispatcher
1257mode}, which is described in the previous subsection. If started
1258without additional options, the program will use compiled-in defaults.
1259Otherwise, the following options may be given:
1260
1261@table @option
1262@item --config-file=@var{file}
1263@itemx -c @var{file}
1264 Use @var{file} as the main configuration file.
1265
1266@item --debug
1267@itemx -D
1268 Increase debugging level.
1269
1270@item --foreground
1271@itemx -f
1272 Do not disconnect from the controlling terminal, but run in
1273foreground mode instead. This option is mainly useful for debugging.
1274It implies @option{-e} (see below).
1275
1276@item --force
1277 Attempt to start up even if another instance of @command{jabberd}
1278seems to be running.
1279
1280@item --stderr
1281@itemx -e
1282 Print all diagnostics on the standard output.
1283@end table
1284
1285 A set of options may be used to control the running instance of the
1286program and request a detailed information about it.
1287
1288@table @option
1289@item --restart @var{tag} [@var{tags}...]
1290@itemx -r @var{tag} [@var{tag}...]
1291 Restart named components. Any number of arguments can be
1292specified. Each @var{tag} must correspond to a valid tag in
1293@file{jabberd.cfg} file.
1294
1295@item --status
1296 Display information about the running instance. Return 0 if the
1297instance is running, 1 otherwise.
1298
1299@smallexample
1300$ jabberd --status
1301jabberd: [INFO] jabberd is running; PID 537
1302retranslator jit/stderr 548
1303retranslator jit/stdout 547
1304retranslator ggtrans/stderr 545
1305retranslator ggtrans/stdout 544
1306core router 539 router -c /usr/local/etc/jabberd/router.xml
1307core resolver 540 resolver -c /usr/local/etc/jabberd/resolver.xml
1308core sm 541 sm -c /usr/local/etc/jabberd/sm.xml
1309core s2s 542 s2s -c /usr/local/etc/jabberd/s2s.xml
1310core c2s 543 c2s -c /usr/local/etc/jabberd/c2s.xml
1311transport ggtrans 546 /usr/local/sbin/jggtrans -f
1312transport jit 549 /usr/local/bin/jabberd-jit -c /usr/local/etc/jit.xml
1313@end smallexample
1314
1315@item --stop
1316 Stop the running instance by sending it the @acronym{SIGTERM} signal.
1317
1318@item --reload
1319@item --hup
1320 Restart the running instance by sending it the @acronym{SIGHUP} signal.
1321@end table
1322
1323 The following are informational options:
1324
1325@table @option
1326@item --help
1327@itemx -h
1328 Display a terse usage summary.
1329
1330@item --version
1331@itemx -v
1332 Print program version and licensing information and exit.
1333@end table
1334
1335@node jabberd.cfg
1336@subsection Jabberd Configuration File
1337
1338 The configuration file has a line-oriented syntax. Empty lines are
1339ignored. Comments are introduced by a pound sign (@samp{#}),
1340everything starting from the first occurrence of @samp{#} up to the
1341end of line is ignored.
1342
1343 Configuration statements consist of @dfn{command word} and one or
1344several @dfn{arguments}, separated by any amount of whitespace. There
1345are @samp{simple} and @samp{compound} configuration statements.
1346Simple statements occupy a single line. Compound statements begin
1347with a simple statement, occupy several lines, and end with @code{end}
1348statement, appearing on a line by itself. Compound statements in turn
1349contain another simple statements.
1350
1351 The simplest working @file{jabberd.cfg} file is:
1352
1353@smallexample
1354prog router /usr/local/etc/jabberd/router.xml
1355prog resolver /usr/local/etc/jabberd/resolver.xml
1356prog sm /usr/local/etc/jabberd/sm.xml
1357prog s2s /usr/local/etc/jabberd/s2s.xml
1358prog c2s /usr/local/etc/jabberd/c2s.xml
1359@end smallexample
1360
1361 This file instructs @command{jabberd} to launch five basic jabber
1362components and supply the given configuration files to them. The
1363@code{prog} statement is a simple statement taking one to two
1364arguments. The first one names the program to lauch, and an optional
1365second one specifies its configuration file. All the programs will be
1366launched in the order of their appearance in the @file{jabberd.cfg}
1367file, and will be shut down in the reverse order. The @code{prog}
1368statement is designed expressly to start jabber core programs, it
1369should not be used to start third-party programs.
1370
1371 To start third-party programs, e.g. transports, use @code{transport}
1372statement. It is a compound statement that has the following
1373structure:
1374
1375@smallexample
1376transport @var{tag}
1377 command @var{command-line}
1378 depend @var{modlist}
1379 stdout @var{prio}
1380 stderr @var{prio}
1381end
1382@end smallexample
1383
1384 The sub-statement @code{command} specifies the full command line of
1385the program. Notice that most transports behave as daemons. If it is
1386so, you will have to use a special command line option requiring the
1387transport to remain in the foreground (see the transport documentation
1388to find this option). If the program prints its diagnostics on the
1389standard error, the @code{stderr} statement can be used to capture and
1390redirect it to the syslog. For example, @code{stderr debug},
1391instructs @command{jabberd} to divert the program's standard error to
1392the syslog, using priority @samp{debug}. In this case the log entries
1393will be prefixed with @var{tag}, or, if it is absent, with the first
1394word of @var{command-line}.
1395
1396 For example, the @acronym{GG} transport can be started using the
1397following statement:
1398
1399@smallexample
1400transport ggtrans
1401 command /usr/local/sbin/jggtrans -f
1402 depend all
1403 stdout notice
1404 stderr notice
1405end
1406@end smallexample
1407
1408
1409 Several configuration statemenst control various aspects of the
1410behavior of the @command{jabberd}. For example, @code{user} statement
1411instructs it to switch to privileges of the named user after startup.
1412By default the utility will switch to the privileges of the user
1413@samp{jabberd}, this statement can be used to change that, for
1414example:
1415
1416@smallexample
1417user nobody
1418@end smallexample
1419
1420 When switching to user privileges, @command{jabberd} retains only
1421the main user group, as specified in @file{/etc/passwd} file and drops
1422all supplementary groups the user might be a member of. To retain the
1423privileges of a supplementary group, name it with @code{group}
1424statement. This statement can be used several times, to retain
1425several groups. For example, the following statement switches to the
1426privileges of user @samp{nobody} and retains two supplementary groups:
1427@samp{staff} and @samp{ftp}:
1428
1429@smallexample
1430user nobody
1431group staff
1432group ftp
1433@end smallexample
1434
1435 The following subsubsection describes all configuration file
1436statements in detail.
1437
1438@menu
1439* cfgstat:: Configuration File Statements
1440* example:: An Example of the Configuration file
1441@end menu
1442
1443@node cfgstat
1444@subsubsection Configuration File Statements
1445
1446@deffn {Jabber Statement} transport [@var{tag}]
1447Schedule a third-party program (e.g. a transport) for startup.
1448@var{tag} specifies the prefix to identify this program in the
1449diagnostic poutput. The @code{transport} statement is a block statement
1450that have the following structure:
1451
1452@smallexample
1453transport @var{tag}
1454 command @var{command-line}
1455 depend @var{component-list}
1456 stdout @var{prio}
1457 stderr @var{prio}
1458 facility @var{fac}
1459end
1460@end smallexample
1461
1462The subordinate statements are:
1463
1464@deffn {transport statement} command @var{command-line}
1465Set the command line of the transport. @var{command-line} is parsed
1466much the same way as in shell, except that no variable substitution
1467takes place.
1468@end deffn
1469
1470@deffn {transport statement} depend @var{component-list}
1471Declare that this module depends on the components listed in
1472@var{component-list}. Whenever one of these components is restarted,
1473the transport will be restarted as well.
1474
1475@var{component-list} is either a whitespace-separated list of
1476components, or one of the following words: @samp{all}, meaning that
1477this transport depends on all core components started before it, and
1478@samp{none}, meaning that it does not depend on anything.
1479
1480The default is @samp{all}.
1481@end deffn
1482
1483@anchor{stdout}
1484@deffn {transport statement} stdout @var{prio}
1485@deffnx {transport statement} stderr @var{prio}
1486Redirect program's standard output (or error, in case of
1487@code{stderr}) to the given syslog priority. Allowed values for
1488@var{prio} are: @samp{EMERG}, @samp{ALERT}, @samp{CRIT}, @samp{ERR},
1489@samp{WARNING}, @samp{NOTICE}, @samp{INFO}, and @samp{DEBUG},
1490optionally prefixed with @samp{LOG_}. The string matching is
1491case-insensitive.
1492@end deffn
1493
1494@deffn {transport statement} facility @var{facility}
1495This statement does nothing. It is reserved for future use.
1496
1497@deffn {transport statement} pidfile @var{file}
1498Remove @var{file} before starting the transport. It may be useful if
1499the transport fails to delete its pidfile at the exit.
1500@end deffn
1501@end deffn
1502
1503@end deffn
1504@deffn {Jabber Statement} group @var{name}
1505Retain supplementary group @var{name} after switching to the user's
1506privileges.
1507@end deffn
1508
1509@deffn {Jabber Statement} pidfile @var{file}
1510Write master process @acronym{ID} to @var{file}
1511@end deffn
1512
1513@anchor{ctlfile}
1514@deffn {Jabber Statement} ctlfile @var{file}
1515Set location of the control file. This file is used to pass additional
1516information to the running daemon program (e.g., when running
1517@command{jabberd --restart @var{comp}}). The default value is
1518@file{/usr/local/var/jabberd/.jabberd.ctl}.
1519@end deffn
1520
1521@deffn {Jabber Statement} statfile @var{file}
1522Set location of the statistics output file. This file is used to pass
1523statistics information from the running daemon program (e.g., when running
1524@command{jabberd --status}). The default value is
1525@file{/usr/local/var/jabberd/.jabberd.stat}.
1526@end deffn
1527
1528@deffn {Jabber Statement} prog @var{command} [@var{config-file}]
1529Schedule a jabber core program for startup. The program name is given
1530by @var{command} argument. Optional @var{config-file} gives the
1531location of its configuration file. The program command line will be
1532(parts enclosed by square brackets being optional):
1533
1534@smallexample
1535@var{command} [-c @var{config-file}] [-D]
1536@end smallexample
1537
1538 The @option{-D} is given only if the @command{jabberd} debugging
1539level is greater than 2 (e.g. when running it as @command{jabberd -DDD}).
1540@end deffn
1541
1542@deffn {Jabber Statement} umask @var{n}
1543Set file creation mask to @var{n}. The default umask is @samp{037}.
1544@end deffn
1545
1546@deffn {Jabber Statement} user @var{name}
1547Run with this user privileges.
1548@end deffn
1549
1550@deffn {Jabber Statement} shutdown-timeout @var{n}
1551Wait @var{n} seconds for all children to shut down.
1552@end deffn
1553
1554@deffn {Jabber Statement} syslog-facility @var{facility}
1555Output diagnostics to the given syslog facility. The @var{facility}
1556may be one of the following: @samp{USER}, @samp{DAEMON}, @samp{AUTH},
1557@samp{AUTHPRIV}, @samp{LOCAL0} through @samp{LOCAL7}, and @samp{MAIL}.
1558The string matching is case insensitive. Optionally, @samp{LOG_}
1559prefix may be prepended to @var{facility}.
1560@end deffn
1561
1562@deffn {Jabber Statement} syslog-tag @var{tag}
1563Mark @command{jabberd} diagnostics with the given syslog tag. By
1564default @samp{jabberd} is used.
1565@end deffn
1566
1567@node example
1568@subsubsection An Example of @file{jabberd.cfg} file
1569
1570@smallexample
1571# @r{Run as user @samp{jabber}}
1572user jabber
1573# @r{Retain two supplementary groups:}
1574group staff
1575group nobody
1576
1577# @r{Store @acronym{PID} to the given file}
1578pidfile /usr/local/var/jabberd/pid/jabberd.pid
1579# @r{Wait 10 seconds for the shutdown of the children.}
1580shutdown-timeout 10
1581
1582# @r{Start basic jabberd framework:}
1583prog router /usr/local/etc/jabberd/router.xml
1584prog resolver /usr/local/etc/jabberd/resolver.xml
1585prog sm /usr/local/etc/jabberd/sm.xml
1586prog s2s /usr/local/etc/jabberd/s2s.xml
1587prog c2s /usr/local/etc/jabberd/c2s.xml
1588
1589# @r{Start @acronym{GG} transport and capture its output:}
1590transport ggtrans
1591 command /usr/local/sbin/jggtrans -f
1592 stdout notice
1593 stderr notice
1594end
1595
1596# @r{Start @acronym{ICQ} transport and capture its output:}
1597transport jit
1598 command /usr/local/bin/jabberd-jit -c /usr/local/etc/jit.xml
1599 # @r{Ensure the pidfile is removed at the startup.}
1600 pidfile /usr/local/var/jabberd/pid/jit.pid
1601 stdout notice
1602 stderr notice
1603end
1604@end smallexample
1605
1606@node Sendmail mc Files, Startup Scripts, Root Utilities, Top 1157@node Sendmail mc Files, Startup Scripts, Root Utilities, Top
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}
diff --git a/mc/trurl.mc b/mc/trurl.mc
index 8ed304d..a89701f 100644
--- a/mc/trurl.mc
+++ b/mc/trurl.mc
@@ -16,2 +16,3 @@ dnl * Include common defaults
16include(common.mc) 16include(common.mc)
17dnl include(`milter.conf')
17 18
@@ -27,5 +28,5 @@ FEATURE(relay_hosts_only)
27FEATURE(blacklist_recipients) 28FEATURE(blacklist_recipients)
28FEATURE(dnsbl, `rbl.maps.vix.com') 29dnl FEATURE(dnsbl, `rbl.maps.vix.com')
29FEATURE(dnsbl, `rbl.farlep.net') 30dnl FEATURE(dnsbl, `rbl.farlep.net')
30FEATURE(dnsbl, `dialup-rev.farlep.net') 31dnl FEATURE(dnsbl, `dialup-rev.farlep.net')
31 32
@@ -33,6 +34,4 @@ dnl * Mailers
33undefine(`LOCAL_MAILER_PATH') 34undefine(`LOCAL_MAILER_PATH')
34define(`LOCAL_MAILER_PATH', `/usr/local/libexec/mail.local') 35define(`LOCAL_MAILER_PATH', `/usr/local/sbin/maidag')
35# Use mail.local --message-id-header=X-Mailutils-Message-Id in 36define(`LOCAL_MAILER_ARGS', `maidag -xl --lang=sieve -s %h/.filter.sv $u')
36# /etc/mailutils.rc
37define(`LOCAL_MAILER_ARGS', `mail.local -xl -S %h/.filter.sv $u')
38 37
@@ -41,3 +40,3 @@ MAILER(smtp)
41 40
42dnl * Identification string for mail.local/Sieve log messages. 41dnl * Identification string for maidag/Sieve log messages.
43LOCAL_CONFIG 42LOCAL_CONFIG

Return to:

Send suggestions and report system problems to the System administrator.