mirror of
https://github.com/troglobit/finit.git
synced 2026-10-10 16:52:39 +07:00
Merge branch 'master' into wip-tests
This commit is contained in:
+3
-3
@@ -43,17 +43,17 @@ static void setup(void *arg)
|
||||
path = which("/lib/systemd/systemd-udevd");
|
||||
if (path) {
|
||||
/* Register udevd as a monitored service */
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd %s "
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
|
||||
"-- Device event managing daemon", path);
|
||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||
_pe("Failed registering %s", path);
|
||||
} else {
|
||||
snprintf(cmd, sizeof(cmd), ":1 [S] log <pid/udevd> "
|
||||
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t devices "
|
||||
"-- Requesting device events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), ":2 [S] log <pid/udevd> "
|
||||
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
|
||||
"udevadm trigger -c add -t subsystems "
|
||||
"-- Requesting subsystem events");
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
|
||||
+7
-19
@@ -149,36 +149,26 @@ static void pidfile_handle_dir(struct iwatch *iw, char *dir, char *name, int mas
|
||||
|
||||
static void pidfile_callback(void *arg, int fd, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz, off;
|
||||
size_t buflen = 8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1;
|
||||
char *buf;
|
||||
|
||||
buf= malloc(buflen);
|
||||
if (!buf) {
|
||||
_pe("Failed allocating buffer for inotify events");
|
||||
return;
|
||||
}
|
||||
|
||||
_d("Entering ... reading %zu bytes into ev_buf[]", buflen - 1);
|
||||
sz = read(fd, buf, buflen - 1);
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
_pe("invalid inotify event");
|
||||
goto done;
|
||||
return;
|
||||
}
|
||||
buf[sz] = 0;
|
||||
_d("Read %zd bytes, processing ...", sz);
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
off = 0;
|
||||
for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
ev = (struct inotify_event *)&buf[off];
|
||||
|
||||
_d("path %s, event: 0x%08x", ev->name, ev->mask);
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||
|
||||
/* Find base path for this event */
|
||||
iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd);
|
||||
if (!iwp)
|
||||
@@ -197,8 +187,6 @@ static void pidfile_callback(void *arg, int fd, int events)
|
||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
||||
pidfile_update_conds(iwp->path, ev->name, ev->mask);
|
||||
}
|
||||
done:
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+59
-100
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "iwatch.h"
|
||||
#include "service.h"
|
||||
#include "tty.h"
|
||||
#include "helpers.h"
|
||||
@@ -53,7 +54,9 @@ struct conf_change {
|
||||
char *name;
|
||||
};
|
||||
|
||||
static uev_t w1, w2, w3, w4;
|
||||
static struct iwatch iw_conf;
|
||||
static uev_t etcw;
|
||||
|
||||
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||
|
||||
static int parse_conf(char *file);
|
||||
@@ -680,8 +683,9 @@ int conf_reload(void)
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
char *path = gl.gl_pathv[i];
|
||||
size_t len;
|
||||
char *rp = NULL;
|
||||
struct stat st;
|
||||
size_t len;
|
||||
|
||||
/* Check that it's an actual file ... beyond any symlinks */
|
||||
if (lstat(path, &st)) {
|
||||
@@ -697,25 +701,22 @@ int conf_reload(void)
|
||||
|
||||
/* Check for dangling symlinks */
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
char *rp;
|
||||
|
||||
rp = realpath(path, NULL);
|
||||
path = rp = realpath(path, NULL);
|
||||
if (!rp) {
|
||||
logit(LOG_WARNING, "Skipping %s, dangling symlink: %s", path, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
free(rp);
|
||||
}
|
||||
|
||||
/* Check that file ends with '.conf' */
|
||||
len = strlen(path);
|
||||
if (len < 6 || strcmp(&path[len - 5], ".conf")) {
|
||||
if (len < 6 || strcmp(&path[len - 5], ".conf"))
|
||||
_d("Skipping %s, not a valid .conf ... ", path);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
parse_conf_dynamic(path);
|
||||
|
||||
parse_conf_dynamic(path);
|
||||
if (rp)
|
||||
free(rp);
|
||||
}
|
||||
|
||||
globfree(&gl);
|
||||
@@ -742,6 +743,7 @@ static struct conf_change *conf_find(char *file)
|
||||
struct conf_change *node, *tmp;
|
||||
|
||||
TAILQ_FOREACH_SAFE(node, &conf_change_list, link, tmp) {
|
||||
_d("file: %s vs changed file: %s", file, node->name);
|
||||
if (string_compare(node->name, file))
|
||||
return node;
|
||||
}
|
||||
@@ -768,13 +770,15 @@ static void drop_changes(void)
|
||||
drop_change(node);
|
||||
}
|
||||
|
||||
static int do_change(char *name, uint32_t mask)
|
||||
static int do_change(char *dir, char *name, uint32_t mask)
|
||||
{
|
||||
char path[strlen(dir) + strlen(name) + 2];
|
||||
struct conf_change *node;
|
||||
|
||||
_d("Change detected for %s, mask 0x%08x", name, mask);
|
||||
snprintf(path, sizeof(path), "%s%s", dir, name);
|
||||
_d("path: %s", path);
|
||||
|
||||
node = conf_find(name);
|
||||
node = conf_find(path);
|
||||
if (mask & (IN_DELETE | IN_MOVED_FROM)) {
|
||||
drop_change(node);
|
||||
return 0;
|
||||
@@ -789,14 +793,14 @@ static int do_change(char *name, uint32_t mask)
|
||||
if (!node)
|
||||
return 1;
|
||||
|
||||
node->name = strdup(name);
|
||||
node->name = strdup(path);
|
||||
if (!node->name) {
|
||||
free(node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
_d("Event registered for %s, mask 0x%x", name, mask);
|
||||
TAILQ_INSERT_HEAD(&conf_change_list, node,link);
|
||||
_d("Event registered for %s, mask 0x%x", path, mask);
|
||||
TAILQ_INSERT_HEAD(&conf_change_list, node, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -811,14 +815,9 @@ int conf_any_change(void)
|
||||
|
||||
int conf_changed(char *file)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!file)
|
||||
return 0;
|
||||
|
||||
if ((ptr = strrchr(file, '/')))
|
||||
file = ++ptr;
|
||||
|
||||
if (conf_find(file))
|
||||
return 1;
|
||||
|
||||
@@ -829,7 +828,7 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz, len;
|
||||
ssize_t sz, off;
|
||||
|
||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
@@ -837,17 +836,23 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
ev = (struct inotify_event *)ev_buf;
|
||||
|
||||
if (arg) {
|
||||
do_change(arg, ev->mask);
|
||||
return;
|
||||
}
|
||||
for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
for (ev = (void *)ev_buf; sz > (ssize_t)sizeof(*ev);
|
||||
len = sizeof(*ev) + ev->len, ev = (void *)ev + len, sz -= len) {
|
||||
if (do_change(ev->name, ev->mask)) {
|
||||
_pe("conf_monitor: Out of memory");
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||
|
||||
/* Find base path for this event */
|
||||
iwp = iwatch_find_by_wd(&iw_conf, ev->wd);
|
||||
if (!iwp)
|
||||
continue;
|
||||
|
||||
if (do_change(iwp->path, ev->name, ev->mask)) {
|
||||
_pe(" Out of memory");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -858,82 +863,23 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
||||
{
|
||||
struct stat st;
|
||||
uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY | IN_ATTRIB | IN_MOVE;
|
||||
char *arg = NULL;
|
||||
int fd, wd;
|
||||
|
||||
if (!ctx)
|
||||
return 0;
|
||||
|
||||
if (stat(path, &st)) {
|
||||
_d("No such file or directory, skipping %s", path);
|
||||
w->fd = -1;
|
||||
return 0;
|
||||
}
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
arg = strrchr(path, '/');
|
||||
if (!arg)
|
||||
arg = path;
|
||||
else
|
||||
arg++;
|
||||
}
|
||||
|
||||
if (w->fd >= 0)
|
||||
close(w->fd);
|
||||
|
||||
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
_pe("Failed creating inotify descriptor");
|
||||
w->fd = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only forward error, don't report error,
|
||||
* user may not have @path and that's OK
|
||||
*/
|
||||
wd = inotify_add_watch(fd, path, mask | opt);
|
||||
if (wd < 0) {
|
||||
w->fd = -1;
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uev_io_init(ctx, w, conf_cb, arg, fd, UEV_READ)) {
|
||||
_pe("Failed setting up I/O callback for %s watcher", path);
|
||||
w->fd = -1;
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
_d("Set up inotify watcher for %s ...", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up inotify watcher and load all *.conf in /etc/finit.d/
|
||||
*/
|
||||
int conf_monitor(uev_ctx_t *ctx)
|
||||
int conf_monitor(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* Skip second run, when called from finit.c in rescue mode */
|
||||
if (ctx && rescue)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If only one watcher fails, that's OK. A user may have only
|
||||
* one of /etc/finit.conf or /etc/finit.d in use, and may also
|
||||
* have or not have symlinks in place. We need to monitor for
|
||||
* changes to either symlink or target.
|
||||
*/
|
||||
rc += add_watcher(ctx, &w1, FINIT_RCSD, 0);
|
||||
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available/", IN_DONT_FOLLOW);
|
||||
rc += add_watcher(ctx, &w3, FINIT_RCSD "/enabled/", 0);
|
||||
rc += add_watcher(ctx, &w4, FINIT_CONF, 0);
|
||||
rc += iwatch_add(&iw_conf, FINIT_RCSD, IN_ONLYDIR);
|
||||
rc += iwatch_add(&iw_conf, FINIT_RCSD "/available/", IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||
rc += iwatch_add(&iw_conf, FINIT_RCSD "/enabled/", IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||
rc += iwatch_add(&iw_conf, FINIT_CONF, 0);
|
||||
|
||||
return rc + conf_reload();
|
||||
}
|
||||
@@ -941,12 +887,25 @@ int conf_monitor(uev_ctx_t *ctx)
|
||||
/*
|
||||
* Prepare .conf parser and load all .conf files
|
||||
*/
|
||||
int conf_init(void)
|
||||
int conf_init(uev_ctx_t *ctx)
|
||||
{
|
||||
hostname = strdup(DEFHOST);
|
||||
w1.fd = w2.fd = w3.fd = w4.fd = -1;
|
||||
int fd;
|
||||
|
||||
return conf_monitor(NULL);
|
||||
/* default hostname */
|
||||
hostname = strdup(DEFHOST);
|
||||
|
||||
/* prepare /etc watcher */
|
||||
fd = iwatch_init(&iw_conf);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
||||
if (uev_io_init(ctx, &etcw, conf_cb, NULL, fd, UEV_READ)) {
|
||||
_pe("Failed setting up I/O callback for /etc watcher");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -34,11 +34,11 @@ extern struct rlimit global_rlimit[];
|
||||
int str2rlim(char *str);
|
||||
char *rlim2str(int rlim);
|
||||
|
||||
int conf_init (void);
|
||||
int conf_init (uev_ctx_t *ctx);
|
||||
void conf_reload (void);
|
||||
int conf_any_change (void);
|
||||
int conf_changed (char *file);
|
||||
int conf_monitor (uev_ctx_t *ctx);
|
||||
int conf_monitor (void);
|
||||
|
||||
void conf_parse_cmdline (int argc, char *argv[]);
|
||||
int conf_parse_runlevels (char *runlevels);
|
||||
|
||||
+4
-4
@@ -449,7 +449,7 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* Initialize .conf system and load static /etc/finit.conf.
|
||||
*/
|
||||
conf_init();
|
||||
conf_init(&loop);
|
||||
|
||||
/* Base FS up, enable standard SysV init signals */
|
||||
sig_setup(&loop);
|
||||
@@ -458,10 +458,10 @@ int main(int argc, char *argv[])
|
||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||
|
||||
/*
|
||||
* Set up inotify watcher for /etc/finit.d and read all .conf
|
||||
* files to figure out how to bootstrap the system.
|
||||
* Set up inotify watcher for /etc/finit.conf, /etc/finit.d, and
|
||||
* their deps, to figure out how to bootstrap the system.
|
||||
*/
|
||||
conf_monitor(&loop);
|
||||
conf_monitor();
|
||||
|
||||
_d("Starting initctl API responder ...");
|
||||
api_init(&loop);
|
||||
|
||||
@@ -185,9 +185,6 @@ char *strip_line(char *line)
|
||||
|
||||
void enable_progress(int onoff)
|
||||
{
|
||||
if (debug)
|
||||
return;
|
||||
|
||||
if (onoff)
|
||||
progress_style = progress_onoff;
|
||||
else
|
||||
|
||||
@@ -80,6 +80,10 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
||||
if (!initialized)
|
||||
return -1;
|
||||
|
||||
if (!fexist(file)) {
|
||||
_d("No such file or directory, skipping %s", file);
|
||||
return 0;
|
||||
}
|
||||
_d("Adding new watcher for path %s", file);
|
||||
|
||||
path = strdup(file);
|
||||
|
||||
@@ -85,7 +85,6 @@ void log_debug(void)
|
||||
screen_init();
|
||||
}
|
||||
log_open();
|
||||
enable_progress(1);
|
||||
|
||||
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
+46
-36
@@ -620,6 +620,22 @@ static void service_kill(svc_t *svc)
|
||||
print(2, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up any lingering state from dead/killed services
|
||||
*/
|
||||
static void service_cleanup(svc_t *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. */
|
||||
svc->start_time = svc->pid = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* service_stop - Stop service
|
||||
* @svc: Service to stop
|
||||
@@ -629,7 +645,7 @@ static void service_kill(svc_t *svc)
|
||||
*/
|
||||
static int service_stop(svc_t *svc)
|
||||
{
|
||||
int res = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -657,25 +673,15 @@ static int service_stop(svc_t *svc)
|
||||
print_desc("Stopping ", svc->desc);
|
||||
|
||||
if (!svc_is_sysv(svc)) {
|
||||
if (svc->pid <= 1)
|
||||
goto cleanup;
|
||||
if (svc->pid > 1) {
|
||||
/* Kill all children in the same proess group, e.g. logit */
|
||||
rc = kill(-svc->pid, svc->sighalt);
|
||||
|
||||
res = kill(-svc->pid, svc->sighalt);
|
||||
|
||||
/* PID lost or forking process never really started */
|
||||
if (res == -1 && ESRCH == errno) {
|
||||
char *fn;
|
||||
|
||||
/* XXX: Same clenup as done by service_monitor(), refactor */
|
||||
cleanup:
|
||||
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. */
|
||||
svc->start_time = svc->pid = 0;
|
||||
}
|
||||
/* PID lost or forking process never really started */
|
||||
if (rc == -1 && ESRCH == errno)
|
||||
service_cleanup(svc);
|
||||
} else
|
||||
service_cleanup(svc);
|
||||
} else {
|
||||
char *args[] = { svc->cmd, "stop", NULL };
|
||||
pid_t pid;
|
||||
@@ -689,18 +695,18 @@ static int service_stop(svc_t *svc)
|
||||
break;
|
||||
case -1:
|
||||
_pe("Failed fork() to call sysv script '%s stop'", svc->cmd);
|
||||
res = 1;
|
||||
rc = 1;
|
||||
break;
|
||||
default:
|
||||
res = WEXITSTATUS(complete(svc->cmd, pid));
|
||||
rc = WEXITSTATUS(complete(svc->cmd, pid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (runlevel != 1)
|
||||
print_result(res);
|
||||
print_result(rc);
|
||||
|
||||
return res;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -716,6 +722,7 @@ static int service_stop(svc_t *svc)
|
||||
static int service_restart(svc_t *svc)
|
||||
{
|
||||
int do_progress = 1;
|
||||
pid_t lost = 0;
|
||||
int rc;
|
||||
|
||||
/* Ignore if finit is SIGSTOP'ed */
|
||||
@@ -742,19 +749,26 @@ static int service_restart(svc_t *svc)
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s[%d], sending SIGHUP ...",
|
||||
svc_ident(svc, NULL, 0), svc->pid);
|
||||
rc = kill(svc->pid, SIGHUP);
|
||||
if (rc == -1 && errno == ESRCH) {
|
||||
/* nobody home, reset internal state machine */
|
||||
lost = svc->pid;
|
||||
} else {
|
||||
/* Declare we're waiting for svc to re-assert/touch its pidfile */
|
||||
svc_starting(svc);
|
||||
|
||||
/* Declare we're waiting for svc to re-assert/touch its pidfile */
|
||||
svc_starting(svc);
|
||||
|
||||
/* Service does not maintain a PID file on its own */
|
||||
if (svc_has_pidfile(svc)) {
|
||||
sched_yield();
|
||||
touch(pid_file(svc));
|
||||
/* Service does not maintain a PID file on its own */
|
||||
if (svc_has_pidfile(svc)) {
|
||||
sched_yield();
|
||||
touch(pid_file(svc));
|
||||
}
|
||||
}
|
||||
|
||||
if (do_progress)
|
||||
print_result(rc);
|
||||
|
||||
if (lost)
|
||||
service_monitor(lost, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1159,11 +1173,7 @@ void service_monitor(pid_t lost, int status)
|
||||
|
||||
/* Try removing PID file (in case service does not clean up after itself) */
|
||||
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);
|
||||
service_cleanup(svc);
|
||||
} else if (svc_is_runtask(svc)) {
|
||||
if (WIFEXITED(status) && !WEXITSTATUS(status))
|
||||
svc->started = 1;
|
||||
@@ -1172,7 +1182,7 @@ void service_monitor(pid_t lost, int status)
|
||||
}
|
||||
|
||||
/* Terminate any children in the same proess group, e.g. logit */
|
||||
kill(-svc->pid, SIGTERM);
|
||||
kill(-svc->pid, SIGKILL);
|
||||
|
||||
/* No longer running, update books. */
|
||||
svc->start_time = svc->pid = 0;
|
||||
|
||||
Reference in New Issue
Block a user