Issue #223: add type:forking service option, with updated docs

- Add `type:forking` service option to trigger guessing pidfile to
   watch for, instead of `pid:!foo` option, which is not intuitive.
   This option may likely also survive into the new file format :)
 - Update docs and add examples
 - Update start-stop-serv.sh test case with this new variant

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2022-04-04 19:13:28 +02:00
1 parent 462d5b22b4
commit c926160853
7 files changed
+74 -12

No files matched your search

+17 -3
View File
@@ -323,6 +323,10 @@ calls `init-script restart` on `initctl reload`. Similar to how
Forking services started with `sysv` scripts can be monitored by Finit
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
Notice the leading `!`, it signifies Finit should not try to create the
file, but rather watch that file for the resulting forked-off PID. This
syntax also works for forking daemons that do not have a command line
option to run it in the foreground, more on this below in `service`.
> `<COND>` is described in the [Services](#services) section.
@@ -344,9 +348,19 @@ prevent them from forking off a sub-process in the background. This is
the most reliable way to monitor a service.
However, not all daemons support running in the foreground, or they may
start logging to the foreground as well, these are called forking
services and are supported using the same syntax as forking `sysv`
services, using the `pid:!/path/to/pidfile.pid` syntax.
start logging to the foreground as well, these are forking daemons and
are supported using the same syntax as forking `sysv` services, using
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
that may be more intuitive, where Finit can also guess the PID file
based on the daemon's command name:
service type:forking ntpd -- NTP daemon
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
basename of the binary to guess the PID file to watch for the PID:
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
full `pid:!/path/to/file.pid`.
**Example:**
+11 -1
View File
@@ -27,7 +27,17 @@ Finit can *not* start and monitor a daemon that:
### Forks to Background w/ PID File
service pid:!/run/serv.pid serv -- Forking service
There are two syntax variants, type 1 and type 2. The former is the
traditional one used also for `sysv` start/stop scripts, and the latter
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
to look for based on the standard path and the basename of the command.
service pid:!/run/serv.pid serv -- Forking service, type 1
service type:forking serv -- Forking service, type 2
In this example the resulting files to watch for are `/run/serv.pid` and
`/var/run/serv.pid`, respectively. On most modern Linux systems this is
the same directory (`/var/run` is a symlink to `../run`).
### Runs in Foreground w/ PID File
+15 -1
View File
@@ -194,7 +194,21 @@ services and are supported using the same syntax as forking
.Cm sysv
services, using the
.Cm pid:!/path/to/pidfile.pid
command modifier syntax.
command modifier syntax. There is an alternative syntax that may be
more intuitive, where Finit can also guess the PID file based on the
daemon's command name:
.Bd -unfilled -offset indent
service type:forking ntpd -- NTP daemon
.Ed
.Pp
Here we let BusyBox
.Nm ntpd
daemonize itself. Finit uses the basename of the binary to guess the
PID file to watch for the PID:
.Pa /var/run/ntpd.pid .
If Finit guesses wrong, you have to submit the full
.Cm pid:!/path/to/file.pid
option to your service stanza.
.Pp
.Sy Example: in the case of
.Cm ospfd
+5
View File
@@ -158,6 +158,11 @@ int pid_file_set(svc_t *svc, char *file, int not)
file++;
}
if (svc_is_forking(svc) && !not) {
logit(LOG_WARNING, "Service %s is forking, adjusting to pid:!%s", svc->name, file);
not = 1;
}
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
if (not)
svc->pidfile[0] = '!';
+22 -5
View File
@@ -1154,7 +1154,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
char *dev = NULL;
int respawn = 0;
int levels = 0;
int manual = 0;
int forking = 0, manual = 0;
int restart_max = SVC_RESPAWN_MAX;
int restart_tmo = 0;
unsigned oncrash_action = SVC_ONCRASH_IGNORE;
@@ -1213,6 +1213,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
pid = cmd;
else if (!strncasecmp(cmd, "name:", 5))
name = cmd;
else if (!strncasecmp(cmd, "type:forking", 10))
forking = 1;
else if (!strncasecmp(cmd, "manual:yes", 10))
manual = 1;
else if (!strncasecmp(cmd, "restart:", 8))
@@ -1324,10 +1326,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
svc_unblock(svc);
}
/* Decode any optional pid:/optional/path/to/file.pid */
if (pid && (svc_is_daemon(svc) || svc_is_sysv(svc)) && pid_file_parse(svc, pid))
_e("Invalid 'pid' argument to service: %s", pid);
if (username) {
char *ptr = strchr(username, ':');
@@ -1406,6 +1404,25 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
if (file)
strlcpy(svc->file, file, sizeof(svc->file));
svc->respawn = respawn;
svc->forking = forking;
/* Decode any (optional) pid:/optional/path/to/file.pid */
if (svc_is_daemon(svc) || svc_is_sysv(svc)) {
char tmp[sizeof(svc->name) + 6]; /* pid:! + svc->name */
/* no pid: set, figure out a default to track this svc */
if (!pid && forking) {
snprintf(tmp, sizeof(tmp), "pid:!%s", svc->name);
pid = tmp;
logit(LOG_INFO, "%s: forking but no pid:!file set, guessing -> %s", svc->name, tmp);
}
if (pid && pid_file_parse(svc, pid))
logit(LOG_WARNING, "%s: service has invalid 'pid:' config: %s", svc->name, pid);
if (svc->pidfile[0] == '!')
svc->forking = 1;
}
/* Set configured limits */
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
+2 -1
View File
@@ -127,6 +127,7 @@ typedef struct svc {
int starting; /* ... waiting for pidfile to be re-asserted */
int runlevels;
int sighup; /* This service supports SIGHUP :) */
int forking; /* This is a service/sysv daemon that forks, wait for it ... */
svc_block_t block; /* Reason that this service is currently stopped */
char cond[MAX_COND_LEN];
@@ -228,7 +229,7 @@ static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
static inline int svc_is_forking (svc_t *svc) { return (svc_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; }
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
+2 -1
View File
@@ -57,7 +57,8 @@ test_one()
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
test_one "/run/serv.pid" "service pid:!/run/serv.pid /test_assets/serv -- Forking service"
test_one "/run/serv.pid" "service pid:!/run/serv.pid /test_assets/serv -- Forking service, type 1"
test_one "/run/serv.pid" "service type:forking /test_assets/serv -- Forking service, type 2"
# This one could never be started by and monitored by Finit: it forks to
# background and does not create a PID file. Essentially it's lost to
# Finit, and any other sane process monitor.