mirror of
https://github.com/troglobit/finit.git
synced 2026-10-13 10:14:47 +00:00
Fix #95: Create PID file if program does not
This patch adds support for creating, and removing, a PID file for
programs (services) that for some reason does not create one. With
Finit this is very useful since it allows us to use our condition
support even for "broken" daemons.
To enable this for a service, use the following syntax:
service pid[:[/path/to/]file[.pid]] /path/to/daemon
I.e., `pid` is a required argument if you want to enable the feature,
but the rest is optional:
pid --> /run/`basename $CMD`.pid
pid:file --> /run/file.pid
pid:file.dip --> /run/file.dip
pid:/mnt/k --> /mnt/k.pid
pid:/mnt/k.foo --> /mnt/k.foo
There is an additional feature with this patch. For daemons that run
with a different identiy one usually wants to create the PID file with
that identity, e.g.:
service inadyn -I dyn -- Dyn.com DDNS client
service inadyn -I freedns -- FreeDNS DDNS client
Here inadyn will look for /etc/dyn.conf and create /run/dyn.pid, and
/etc/freedns.conf and create /run/freedns.pid, respetively. While Finit
will in both cases assume the PID file is /run/inadyn.pid ... err fail!
To get out of this mess the `pid` argument can be used to tell Finit
what the real PID file the daemon creates is called:
service pid:!dyn inadyn -I dyn -- Dyn.com DDNS client
service pid:!freedns inadyn -I freedns -- FreeDNS DDNS client
The same composition rules listed above applies also to the `!` variant.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
+89
-10
@@ -114,6 +114,75 @@ static int is_norespawn(void)
|
||||
fexist("/tmp/norespawn");
|
||||
}
|
||||
|
||||
static char *pid_file(svc_t *svc)
|
||||
{
|
||||
static char fn[MAX_ARG_LEN];
|
||||
|
||||
if (svc->pidfile[0]) {
|
||||
if (svc->pidfile[0] == '!')
|
||||
return &svc->pidfile[1];
|
||||
return svc->pidfile;
|
||||
}
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s%s.pid", _PATH_VARRUN, basename(svc->cmd));
|
||||
return fn;
|
||||
}
|
||||
|
||||
static int pid_file_create(svc_t *svc)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (!svc->pidfile[0] || svc->pidfile[0] == '!')
|
||||
return 1;
|
||||
|
||||
fp = fopen(svc->pidfile, "w");
|
||||
if (!fp)
|
||||
return 1;
|
||||
fprintf(fp, "%d\n", svc->pid);
|
||||
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
static int pid_file_parse(svc_t *svc, char *arg)
|
||||
{
|
||||
int len, not = 0;
|
||||
|
||||
/* Always clear, called with some sort of 'pid[:..]' argument */
|
||||
svc->pidfile[0] = 0;
|
||||
|
||||
/* Sanity check ... */
|
||||
if (!arg || !arg[0])
|
||||
return 1;
|
||||
|
||||
/* 'pid:' imples argument following*/
|
||||
if (!strncmp(arg, "pid:", 4)) {
|
||||
arg += 4;
|
||||
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/') {
|
||||
strlcpy(svc->pidfile, arg, sizeof(svc->pidfile));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg[0] == '!') {
|
||||
arg++;
|
||||
not++;
|
||||
}
|
||||
len = snprintf(svc->pidfile, sizeof(svc->pidfile), "%s%s%s",
|
||||
not ? "!" : "", _PATH_VARRUN, arg);
|
||||
if (len > 4 && strcmp(&svc->pidfile[len - 4], ".pid"))
|
||||
strlcat(svc->pidfile, ".pid", sizeof(svc->pidfile));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 'pid' arg, no argument following */
|
||||
if (!strcmp(arg, "pid")) {
|
||||
strlcpy(svc->pidfile, pid_file(svc), sizeof(svc->pidfile));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* service_start - Start service
|
||||
* @svc: Service to start
|
||||
@@ -323,7 +392,10 @@ static int service_start(svc_t *svc)
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (svc_is_daemon(svc))
|
||||
pid_file_create(svc);
|
||||
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
print_result(result);
|
||||
|
||||
@@ -540,7 +612,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
int forking = 0;
|
||||
#endif
|
||||
int log = 0, levels = 0;
|
||||
char *username = NULL, *line;
|
||||
char *line;
|
||||
char *username = NULL, *pid = NULL;
|
||||
char *service = NULL, *proto = NULL, *ifaces = NULL;
|
||||
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
||||
svc_t *svc;
|
||||
@@ -573,7 +646,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
}
|
||||
|
||||
while (cmd) {
|
||||
if (cmd[0] == '@') /* @username[:group] */
|
||||
if (cmd[0] == '@') /* @username[:group] */
|
||||
username = &cmd[1];
|
||||
else if (cmd[0] == '[') /* [runlevels] */
|
||||
runlevels = &cmd[0];
|
||||
@@ -587,10 +660,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
else if (!strncasecmp(cmd, "wait", 4))
|
||||
forking = 0;
|
||||
#endif
|
||||
else if (cmd[0] != '/' && strchr(cmd, '/'))
|
||||
service = cmd; /* inetd service/proto */
|
||||
else if (!strncasecmp(cmd, "log", 3))
|
||||
log = 1;
|
||||
else if (!strncasecmp(cmd, "pid", 3))
|
||||
pid = cmd;
|
||||
else if (cmd[0] != '/' && strchr(cmd, '/'))
|
||||
service = cmd; /* inetd service/proto */
|
||||
else
|
||||
break;
|
||||
|
||||
@@ -679,6 +754,9 @@ recreate:
|
||||
if (desc)
|
||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||
|
||||
if (pid && svc_is_daemon(svc) && pid_file_parse(svc, pid))
|
||||
_e("Invalid 'pid' argument to service: %s", pid);
|
||||
|
||||
if (username) {
|
||||
char *ptr = strchr(username, ':');
|
||||
|
||||
@@ -759,7 +837,6 @@ void service_unregister(svc_t *svc)
|
||||
void service_monitor(pid_t lost)
|
||||
{
|
||||
svc_t *svc;
|
||||
char pidfile[MAX_ARG_LEN];
|
||||
|
||||
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
|
||||
return;
|
||||
@@ -778,10 +855,12 @@ void service_monitor(pid_t lost)
|
||||
_d("collected %s(%d)", svc->cmd, lost);
|
||||
|
||||
/* Try removing PID file (in case service does not clean up after itself) */
|
||||
snprintf(pidfile, sizeof(pidfile), "%s%s.pid", _PATH_VARRUN, basename(svc->cmd));
|
||||
if (remove(pidfile)) {
|
||||
if (errno != ENOENT)
|
||||
logit(LOG_CRIT, "Failed removing service %s pidfile %s", basename(svc->cmd), pidfile);
|
||||
if (svc_is_daemon(svc)) {
|
||||
char *fn;
|
||||
|
||||
fn = pid_file(svc);
|
||||
if (remove(fn) && errno != ENOENT)
|
||||
logit(LOG_CRIT, "Failed removing service %s pidfile %s", basename(svc->cmd), fn);
|
||||
}
|
||||
|
||||
/* No longer running, update books. */
|
||||
|
||||
@@ -90,6 +90,7 @@ typedef struct svc {
|
||||
|
||||
/* Service details */
|
||||
pid_t pid;
|
||||
char pidfile[MAX_ARG_LEN];
|
||||
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
||||
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
||||
svc_type_t type; /* Service, run, task, inetd, ... */
|
||||
|
||||
Reference in New Issue
Block a user