mirror of
https://github.com/troglobit/finit.git
synced 2026-10-17 10:49:34 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d00a53dfbf | ||
|
|
99a8cf3eb7 | ||
|
|
da95c7d80e | ||
|
|
a9f7f692a9 | ||
|
|
ce55f88a00 | ||
|
|
74a26f559d | ||
|
|
08144df5ea | ||
|
|
230c64927b | ||
|
|
d1e56f300d | ||
|
|
9842786453 | ||
|
|
6d0c679e05 | ||
|
|
5428dea5bf | ||
|
|
4e84ecae89 | ||
|
|
959c9fe5aa | ||
|
|
03d8ef9c8f | ||
|
|
084b4ce8d3 | ||
|
|
31cae6a56d | ||
|
|
1fd45c6f2e | ||
|
|
46995fe446 | ||
|
|
600b2874e6 | ||
|
|
b080b970b7 | ||
|
|
6106574e13 | ||
|
|
2385a1209b | ||
|
|
e8b942cf95 | ||
|
|
ac17d7f5a7 | ||
|
|
1edc4356a6 | ||
|
|
9f06a2db99 | ||
|
|
cfb3a9f2b9 | ||
|
|
8aba63a9e3 | ||
|
|
3d98ad293b | ||
|
|
156e86f395 | ||
|
|
d859ecd21d | ||
|
|
cbec78dbbc | ||
|
|
572291a1d9 | ||
|
|
280608f30e | ||
|
|
5c4146cfe4 | ||
|
|
30e3f5a33c | ||
|
|
2c12379a30 | ||
|
|
5f026c8149 | ||
|
|
90005235e8 | ||
|
|
6b688c4211 | ||
|
|
bdf5f8fc90 | ||
|
|
79f7a8ccfb | ||
|
|
3b19db04e3 | ||
|
|
93402b81d7 | ||
|
|
6dec4c9ca0 | ||
|
|
548acf27cf | ||
|
|
cd0bc57ca8 | ||
|
|
11a3318c02 | ||
|
|
2711b27971 | ||
|
|
05ac9c18c9 | ||
|
|
1a7092f545 | ||
|
|
8000d361b3 | ||
|
|
e3c8febe3b | ||
|
|
32ca117949 | ||
|
|
b966d031c8 | ||
|
|
905c2678a3 | ||
|
|
7d429bdbb1 |
No files matched your search
+4
-1
@@ -4,7 +4,7 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
[4.0][UNRELEASED] - 2021-02-21
|
[4.0][UNRELEASED] - 2021-03-xx
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
This release became v4.0, and not v3.2, because of incompatible changes
|
This release became v4.0, and not v3.2, because of incompatible changes
|
||||||
@@ -18,6 +18,9 @@ make sure to read the whole changelog when upgrading.
|
|||||||
with a fallback to sending signals as per traditional SysV init. The
|
with a fallback to sending signals as per traditional SysV init. The
|
||||||
`-f` (force) flag remains, where `reboot(2)` is called directly
|
`-f` (force) flag remains, where `reboot(2)` is called directly
|
||||||
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
||||||
|
* The `inictl cond set|clear COND` have changed completely. Constrained
|
||||||
|
to a flat `<usr/...>` namespace and automatically activated by a new
|
||||||
|
`usr.so` plugin that checks services for usr condition changes
|
||||||
* Removed built-in inetd super server. If you need this functionality,
|
* Removed built-in inetd super server. If you need this functionality,
|
||||||
use an external inetd, like xinetd, instead. A pull request for a
|
use an external inetd, like xinetd, instead. A pull request for a
|
||||||
stand-alone inetd, like watchdogd and getty, is most welcome!
|
stand-alone inetd, like watchdogd and getty, is most welcome!
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ Options:
|
|||||||
-b, --batch Batch mode, no screen size probing
|
-b, --batch Batch mode, no screen size probing
|
||||||
-c, --create Create missing paths (and files) as needed
|
-c, --create Create missing paths (and files) as needed
|
||||||
-f, --force Ignore missing files and arguments, never prompt
|
-f, --force Ignore missing files and arguments, never prompt
|
||||||
|
-p, --plain Use plain table headings, no ctrl chars
|
||||||
-t, --no-heading Skip table headings
|
-t, --no-heading Skip table headings
|
||||||
-v, --verbose Verbose output
|
-v, --verbose Verbose output
|
||||||
-h, --help This help text
|
-h, --help This help text
|
||||||
@@ -375,6 +376,8 @@ Commands:
|
|||||||
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
||||||
reload Reload *.conf in /etc/finit.d (activate changes)
|
reload Reload *.conf in /etc/finit.d (activate changes)
|
||||||
|
|
||||||
|
cond set <COND> Set (assert) user-defined condition +usr/COND
|
||||||
|
cond clear <COND> Clear (deassert) user-defined condition -usr/COND
|
||||||
cond show Show condition status
|
cond show Show condition status
|
||||||
cond dump Dump all conditions and their status
|
cond dump Dump all conditions and their status
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT(Finit, 4.0-rc2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
AC_INIT(Finit, 4.0-rc3, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|||||||
+27
-1
@@ -45,7 +45,31 @@ being created.
|
|||||||
Triggering
|
Triggering
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Conditions can only be triggered by built-in plugins.
|
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
|
||||||
|
`netlink.so` and `pidfile.so`, see below for built-in conditions. Finit
|
||||||
|
also supports user-defined conditions, sometimes referred to as static
|
||||||
|
or one-shot conditions. They live in the `<usr/...` namespace and are
|
||||||
|
constrained to a flat hierarchy without any sub-directories, unlike the
|
||||||
|
pidfile plugin, for instance.
|
||||||
|
|
||||||
|
User-defined conditions are controlled using the `initctl cond set` and
|
||||||
|
`initctl cond clear` commands:
|
||||||
|
|
||||||
|
initctl cond set foo
|
||||||
|
initctl cond clear foo
|
||||||
|
|
||||||
|
The purpose of user-defined conditions is to be able to start or stop
|
||||||
|
services, or run/task jobs, on external site-dependent stimuli.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
service [2345] <usr/foo> alarm --arg foo -- Foo alarm
|
||||||
|
|
||||||
|
For convenience, prefixing with `usr/` is allowed, but any other slashes
|
||||||
|
or period characters are disallowed. E.g., to trigger the `Foo alarm`,
|
||||||
|
the same as above, can also be achieved like this:
|
||||||
|
|
||||||
|
initctl cond set usr/foo
|
||||||
|
initctl cond clear usr/foo
|
||||||
|
|
||||||
Conditions retain their current state until the next reconfiguration or
|
Conditions retain their current state until the next reconfiguration or
|
||||||
runlevel change. At that point all set conditions transition into the
|
runlevel change. At that point all set conditions transition into the
|
||||||
@@ -57,6 +81,8 @@ unchanged) state of it.
|
|||||||
> **Note:** For `pid/` conditions it is expected that services "touch"
|
> **Note:** For `pid/` conditions it is expected that services "touch"
|
||||||
> or recreate their PID file on `SIGHUP`.
|
> or recreate their PID file on `SIGHUP`.
|
||||||
|
|
||||||
|
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||||
|
|
||||||
|
|
||||||
Built-in Conditions
|
Built-in Conditions
|
||||||
-------------------
|
-------------------
|
||||||
|
|||||||
@@ -483,9 +483,6 @@ Log rotation is controlled using the global `log` setting.
|
|||||||
|
|
||||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
|
||||||
Worth noting is that conditions is allowed for all these stanzas. For a
|
|
||||||
detailed description, see the [Conditions](conditions.md) document.
|
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
|||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
noinst_LTLIBRARIES = libplug.la
|
||||||
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c
|
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c usr.c
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -34,7 +34,7 @@ libplug_la_SOURCES += resolvconf.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la
|
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la usr.la
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
|
|||||||
+20
-30
@@ -99,13 +99,14 @@ static void bootclean(void)
|
|||||||
*/
|
*/
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
int uid, gid;
|
mode_t prev;
|
||||||
|
|
||||||
/* Cleanup stale files, if any still linger on. */
|
/* Cleanup stale files, if any still linger on. */
|
||||||
bootclean();
|
bootclean();
|
||||||
|
|
||||||
|
prev = umask(0);
|
||||||
|
|
||||||
_d("Setting up FHS structure in /var ...");
|
_d("Setting up FHS structure in /var ...");
|
||||||
umask(0);
|
|
||||||
makedir("/var/cache", 0755);
|
makedir("/var/cache", 0755);
|
||||||
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
||||||
makedir("/var/games", 0755);
|
makedir("/var/games", 0755);
|
||||||
@@ -133,19 +134,21 @@ static void setup(void *arg)
|
|||||||
makedir("/var/tmp", 0755);
|
makedir("/var/tmp", 0755);
|
||||||
makedir("/var/empty", 0755);
|
makedir("/var/empty", 0755);
|
||||||
|
|
||||||
/*
|
|
||||||
* If /etc/group or "utmp" group is missing,
|
|
||||||
* default to "root"/"wheel" group
|
|
||||||
*/
|
|
||||||
_d("Setting up necessary UTMP files ...");
|
|
||||||
gid = getgroup("utmp");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UTMP actually needs multiple db files
|
* UTMP actually needs multiple db files
|
||||||
*/
|
*/
|
||||||
if (has_utmp()) {
|
if (has_utmp()) {
|
||||||
|
int gid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If /etc/group or "utmp" group is missing, default to
|
||||||
|
* "root", or "wheel", group.
|
||||||
|
*/
|
||||||
|
_d("Setting up necessary UTMP files ...");
|
||||||
|
gid = getgroup("utmp");
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
||||||
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
||||||
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
||||||
@@ -165,32 +168,19 @@ static void setup(void *arg)
|
|||||||
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
||||||
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
||||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
||||||
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
|
mksubsys("/var/run/quagga", 0755, "quagga", "quagga");
|
||||||
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
|
mksubsys("/var/log/quagga", 0755, "quagga", "quagga");
|
||||||
makedir("/var/run/frr", 0755); /* Needed by FRR */
|
mksubsys("/var/run/frr", 0755, "frr", "frr");
|
||||||
makedir("/var/log/frr", 0755); /* Needed by FRR */
|
mksubsys("/var/log/frr", 0755, "frr", "frr");
|
||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||||
|
|
||||||
gid = getgroup("tty");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
|
||||||
chown("/dev/xconsole", 0, gid);
|
|
||||||
|
|
||||||
if (!fexist("/etc/mtab"))
|
if (!fexist("/etc/mtab"))
|
||||||
symlink("../proc/self/mounts", "/etc/mtab");
|
symlink("../proc/self/mounts", "/etc/mtab");
|
||||||
|
|
||||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||||
uid = getuser("uuidd", NULL);
|
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
||||||
if (uid >= 0) {
|
|
||||||
gid = getgroup("uuidd");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
makedir("/var/run/uuidd", 0755);
|
|
||||||
chown("/var/run/uuidd", uid, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
umask(022);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
+12
-10
@@ -32,13 +32,16 @@
|
|||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#define DAEMON "dbus-daemon"
|
#define DAEMON "dbus-daemon"
|
||||||
#define ARGS "--nofork --system"
|
#define ARGS "--nofork --system --syslog-only"
|
||||||
#define DESC "D-Bus message bus daemon"
|
#define DESC "D-Bus message bus daemon"
|
||||||
|
|
||||||
|
#define DAEMONUSER "messagebus"
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
char *cmd;
|
|
||||||
char line[256];
|
char line[256];
|
||||||
|
mode_t prev;
|
||||||
|
char *cmd;
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
cmd = which(DAEMON);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
@@ -46,24 +49,23 @@ static void setup(void *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
umask(0);
|
prev =umask(0);
|
||||||
|
|
||||||
makedir("/var/run/dbus", 0755);
|
mksubsys("/var/run/dbus", 0755, DAEMONUSER, DAEMONUSER);
|
||||||
makedir("/var/lock/subsys", 0755);
|
|
||||||
makedir("/var/lock/subsys/messagebus", 0755);
|
|
||||||
if (whichp("dbus-uuidgen"))
|
if (whichp("dbus-uuidgen"))
|
||||||
run("dbus-uuidgen --ensure");
|
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||||
|
|
||||||
/* Clean up from any previous pre-bootstrap run */
|
/* Clean up from any previous pre-bootstrap run */
|
||||||
erase("/var/run/dbus/pid");
|
remove("/var/run/dbus/pid");
|
||||||
|
|
||||||
/* Register service with Finit */
|
/* Register service with Finit */
|
||||||
snprintf(line, sizeof(line), "[S12345] pid:!/run/dbus/pid log:prio:daemon.info,tag:dbus %s %s -- %s", cmd, ARGS, DESC);
|
snprintf(line, sizeof(line), "[S12345] @%s:%s %s %s -- %s",
|
||||||
|
DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||||
_pe("Failed registering %s", DAEMON);
|
_pe("Failed registering %s", DAEMON);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
|
|
||||||
umask(022);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
+14
-15
@@ -58,7 +58,7 @@ static int pidfile_add_path(struct iwatch *iw, char *path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return iwatch_add(iw, path, IN_ONLYDIR);
|
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||||
@@ -68,11 +68,11 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
paste(fn, sizeof(fn), dir, name);
|
paste(fn, sizeof(fn), dir, name);
|
||||||
_d("path: %s, mask: %08x", fn, mask);
|
|
||||||
|
|
||||||
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_d("path: %s, mask: %08x", fn, mask);
|
||||||
|
|
||||||
svc = svc_find_by_pidfile(fn);
|
svc = svc_find_by_pidfile(fn);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_d("No matching svc for %s", fn);
|
_d("No matching svc for %s", fn);
|
||||||
@@ -82,15 +82,20 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
_d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
_d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
if (mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
svc_started(svc);
|
svc_started(svc);
|
||||||
|
if (!svc_has_pidfile(svc))
|
||||||
|
pid_file_set(svc, fn, 1);
|
||||||
|
|
||||||
if (svc_is_forking(svc)) {
|
if (svc_is_forking(svc)) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = pid_file_read(pid_file(svc));
|
pid = pid_file_read(pid_file(svc));
|
||||||
_d("Forking service %s changed PID from %d to %d",
|
if (pid != svc->pid) {
|
||||||
svc->cmd, svc->pid, pid);
|
_d("Forking service %s changed PID from %d to %d",
|
||||||
svc->pid = pid;
|
svc->cmd, svc->pid, pid);
|
||||||
|
svc->pid = pid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_set(cond);
|
cond_set(cond);
|
||||||
@@ -174,8 +179,6 @@ static void pidfile_callback(void *arg, int fd, int events)
|
|||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
|
||||||
|
|
||||||
/* Find base path for this event */
|
/* Find base path for this event */
|
||||||
iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd);
|
iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd);
|
||||||
if (!iwp)
|
if (!iwp)
|
||||||
@@ -186,12 +189,7 @@ static void pidfile_callback(void *arg, int fd, int events)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev->mask & IN_DELETE) {
|
if (ev->mask & (IN_CLOSE_WRITE | IN_DELETE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
||||||
_d("pidfile %s/%s removed ...", iwp->path, ev->name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
|
||||||
pidfile_update_conds(iwp->path, ev->name, ev->mask);
|
pidfile_update_conds(iwp->path, ev->name, ev->mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,6 +240,7 @@ static void pidfile_init(void *arg)
|
|||||||
*/
|
*/
|
||||||
path = realpath(_PATH_VARRUN, NULL);
|
path = realpath(_PATH_VARRUN, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
|
_d("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
||||||
path = realpath("/run", NULL);
|
path = realpath("/run", NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
||||||
|
|||||||
+9
-4
@@ -37,10 +37,11 @@ static void setup(void *arg)
|
|||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
if (!fexist(RANDOMSEED)) {
|
if (!fexist(RANDOMSEED)) {
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
mode_t prev;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
print_desc("Bootstrapping random seed", NULL);
|
print_desc("Bootstrapping random seed", NULL);
|
||||||
umask(077);
|
prev = umask(077);
|
||||||
fp = fopen(RANDOMSEED, "w");
|
fp = fopen(RANDOMSEED, "w");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
int iter = 128;
|
int iter = 128;
|
||||||
@@ -57,7 +58,7 @@ static void setup(void *arg)
|
|||||||
ret = fclose(fp);
|
ret = fclose(fp);
|
||||||
}
|
}
|
||||||
print_result(ret);
|
print_result(ret);
|
||||||
umask(0);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc("Initializing random number generator", NULL);
|
print_desc("Initializing random number generator", NULL);
|
||||||
@@ -68,10 +69,14 @@ static void setup(void *arg)
|
|||||||
static void save(void *arg)
|
static void save(void *arg)
|
||||||
{
|
{
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
umask(077);
|
mode_t prev;
|
||||||
|
|
||||||
|
prev = umask(077);
|
||||||
|
|
||||||
print_desc("Saving random seed", NULL);
|
print_desc("Saving random seed", NULL);
|
||||||
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
|
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
|
||||||
umask(0);
|
|
||||||
|
umask(prev);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+133
@@ -0,0 +1,133 @@
|
|||||||
|
/* User-defined condtion event monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "pid.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "iwatch.h"
|
||||||
|
|
||||||
|
static struct iwatch iw_usr;
|
||||||
|
|
||||||
|
|
||||||
|
static void usr_cond(char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
char cond[MAX_COND_LEN] = COND_USR;
|
||||||
|
|
||||||
|
strlcat(cond, name, sizeof(cond));
|
||||||
|
cond_update(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usr_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;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
_pe("invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR)
|
||||||
|
continue; /* unsupported */
|
||||||
|
|
||||||
|
if (ev->mask & IN_DELETE)
|
||||||
|
sync(); /* dont ask */
|
||||||
|
|
||||||
|
usr_cond(ev->name, ev->mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usr_init(void *arg)
|
||||||
|
{
|
||||||
|
char usrdir[MAX_ARG_LEN];
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
||||||
|
_pe("Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = realpath(_PATH_CONDUSR, NULL);
|
||||||
|
if (!path) {
|
||||||
|
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iwatch_add(&iw_usr, path, IN_ONLYDIR))
|
||||||
|
iwatch_exit(&iw_usr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = iwatch_init(&iw_usr);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plugin.io.fd = fd;
|
||||||
|
plugin.io.cb = usr_callback;
|
||||||
|
plugin.io.flags = PLUGIN_IO_READ;
|
||||||
|
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
iwatch_exit(&iw_usr);
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -32,13 +32,14 @@
|
|||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
|
const char *username = "nobody";
|
||||||
|
char line[LINE_SIZE];
|
||||||
|
mode_t prev;
|
||||||
#ifdef PAM_CONSOLE
|
#ifdef PAM_CONSOLE
|
||||||
int fd;
|
int fd;
|
||||||
#endif
|
#endif
|
||||||
char line[LINE_SIZE];
|
|
||||||
const char *username = "nobody";
|
|
||||||
|
|
||||||
umask(0);
|
prev = umask(0);
|
||||||
|
|
||||||
makedir("/var/run/console", 01777);
|
makedir("/var/run/console", 01777);
|
||||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||||
@@ -58,7 +59,7 @@ static void setup(void *arg)
|
|||||||
if (whichp("restorecon"))
|
if (whichp("restorecon"))
|
||||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||||
|
|
||||||
umask(022);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
+4
-4
@@ -59,14 +59,14 @@ else
|
|||||||
finit_LDADD += -ldl
|
finit_LDADD += -ldl
|
||||||
endif
|
endif
|
||||||
|
|
||||||
initctl_SOURCES = initctl.c client.c client.h \
|
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
||||||
reboot.c serv.c serv.h svc.h \
|
client.c client.h cond.c cond.h reboot.c \
|
||||||
cond.c cond.h util.c util.h
|
serv.c serv.h svc.h util.c util.h
|
||||||
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
initctl_CFLAGS += $(lite_CFLAGS)
|
initctl_CFLAGS += $(lite_CFLAGS)
|
||||||
initctl_LDADD = $(lite_LIBS)
|
initctl_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
INIT_LNKS = init
|
INIT_LNKS = init telinit
|
||||||
REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
||||||
|
|
||||||
if WATCHDOGD
|
if WATCHDOGD
|
||||||
|
|||||||
@@ -381,7 +381,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_ITER:
|
case INIT_CMD_SVC_ITER:
|
||||||
_d("svc iter, first: %d", rq.runlevel);
|
// _d("svc iter, first: %d", rq.runlevel);
|
||||||
/*
|
/*
|
||||||
* XXX: This severly limits the number of
|
* XXX: This severly limits the number of
|
||||||
* simultaneous client connections, but will
|
* simultaneous client connections, but will
|
||||||
|
|||||||
+2
-2
@@ -2,10 +2,10 @@
|
|||||||
# Called by kernel when last child in cgroup exists
|
# Called by kernel when last child in cgroup exists
|
||||||
|
|
||||||
BASE=/sys/fs/cgroup/finit
|
BASE=/sys/fs/cgroup/finit
|
||||||
PROC=`basename $1`
|
PROC=$(basename "$1")
|
||||||
DIR="$BASE$1"
|
DIR="$BASE$1"
|
||||||
|
|
||||||
#/libexec/finit/logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
#/libexec/finit/logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
||||||
rmdir $DIR
|
rmdir "$DIR"
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
+83
-22
@@ -26,21 +26,65 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
#include <sys/sysinfo.h> /* get_nprocs_conf() */
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static int cg_init = 0;
|
static char controllers[256] = "none";
|
||||||
|
|
||||||
|
static void group_init(char *path, char *nproc, int share)
|
||||||
|
{
|
||||||
|
char file[strlen(path) + 64];
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "cgroup.clone_children");
|
||||||
|
echo(file, 0, "1");
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "cpuset.cpus");
|
||||||
|
echo(file, 0, nproc);
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "cpuset.mems");
|
||||||
|
echo(file, 0, "0");
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "cpu.shares");
|
||||||
|
echo(file, 0, "%d", share);
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "memory.use_hierarchy");
|
||||||
|
echo(file, 0, "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_ctrl(char *ctrl)
|
||||||
|
{
|
||||||
|
char *wanted[] = {
|
||||||
|
"cpu",
|
||||||
|
"cpuacct",
|
||||||
|
"cpuset",
|
||||||
|
"memory"
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(wanted); i++) {
|
||||||
|
if (strcmp(wanted[i], ctrl))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(controllers, "none"))
|
||||||
|
strlcat(controllers, ",", sizeof(controllers));
|
||||||
|
else
|
||||||
|
strlcpy(controllers, "", sizeof(controllers));
|
||||||
|
|
||||||
|
strlcat(controllers, ctrl, sizeof(controllers));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called by Finit at early boot to mount initial cgroups
|
* Called by Finit at early boot to mount initial cgroups
|
||||||
*/
|
*/
|
||||||
void cgroup_init(void)
|
void cgroup_init(void)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
char buf[80];
|
|
||||||
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||||
|
char buf[80];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen("/proc/cgroups", "r");
|
fp = fopen("/proc/cgroups", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
@@ -55,6 +99,8 @@ void cgroup_init(void)
|
|||||||
|
|
||||||
/* Skip first line, header */
|
/* Skip first line, header */
|
||||||
(void)fgets(buf, sizeof(buf), fp);
|
(void)fgets(buf, sizeof(buf), fp);
|
||||||
|
|
||||||
|
/* Create and mount traditional cgroups v1 hier */
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
char *cgroup;
|
char *cgroup;
|
||||||
char rc[80];
|
char rc[80];
|
||||||
@@ -64,16 +110,28 @@ void cgroup_init(void)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
||||||
|
#if 0
|
||||||
if (mkdir(rc, 0755) && EEXIST != errno)
|
if (mkdir(rc, 0755) && EEXIST != errno)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
||||||
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
||||||
|
#else
|
||||||
|
symlink("finit", rc);
|
||||||
|
append_ctrl(cgroup);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default cgroups for process monitoring */
|
/* Finit default cgroups for process monitoring */
|
||||||
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
|
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (mount("none", FINIT_CGPATH, "cgroup", opts, "none,name=finit")) {
|
|
||||||
|
#if 0
|
||||||
|
strlcpy(controllers, "none,name=finit", sizeof(controllers));
|
||||||
|
#else
|
||||||
|
strlcat(controllers, ",name=finit", sizeof(controllers));
|
||||||
|
#endif
|
||||||
|
if (mount("none", FINIT_CGPATH, "cgroup", opts, controllers)) {
|
||||||
_pe("Failed mounting Finit cgroup hierarchy");
|
_pe("Failed mounting Finit cgroup hierarchy");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -90,24 +148,33 @@ void cgroup_init(void)
|
|||||||
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
|
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up basic limits for our groups. Finit optimized defaults
|
||||||
|
* for embedded and server systems include limiting the groups
|
||||||
|
* init and user to a single CPU with 10% share, the system
|
||||||
|
* group gets the rest. Override this from finit.conf
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
#else
|
||||||
|
snprintf(buf, sizeof(buf), "0-%d", get_nprocs_conf() - 1);
|
||||||
|
|
||||||
|
group_init(FINIT_CGPATH "/init", "0", 50);
|
||||||
|
group_init(FINIT_CGPATH "/user", "0", 75);
|
||||||
|
group_init(FINIT_CGPATH "/system", buf, 900);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Move ourselves to init */
|
/* Move ourselves to init */
|
||||||
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
|
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
|
||||||
|
|
||||||
/* We have signal, main screen turn on! */
|
|
||||||
cg_init = 1;
|
|
||||||
fail:
|
fail:
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int move_pid(char *group, char *name, char *id, int pid)
|
static int move_pid(char *group, char *name, int pid)
|
||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
||||||
if (id && strlen(id)) {
|
|
||||||
strlcat(path, ":", sizeof(path));
|
|
||||||
strlcat(path, id, sizeof(path));
|
|
||||||
}
|
|
||||||
if (mkdir(path, 0755) && errno != EEXIST)
|
if (mkdir(path, 0755) && errno != EEXIST)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -116,25 +183,19 @@ static int move_pid(char *group, char *name, char *id, int pid)
|
|||||||
return echo(path, 0, "%d", pid);
|
return echo(path, 0, "%d", pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cgroup_user(char *name)
|
int cgroup_user(char *name, int pid)
|
||||||
{
|
{
|
||||||
if (!cg_init)
|
return move_pid("finit/user", name, pid);
|
||||||
return 0;
|
|
||||||
|
|
||||||
return move_pid("finit/user", name, "0", getpid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cgroup_service(char *nm, char *id, int pid)
|
int cgroup_service(char *name, int pid)
|
||||||
{
|
{
|
||||||
if (!cg_init)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (pid <= 0) {
|
if (pid <= 0) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return move_pid("finit/system", nm, id, pid);
|
return move_pid("finit/system", name, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
void cgroup_init (void);
|
void cgroup_init (void);
|
||||||
|
|
||||||
int cgroup_user (char *name);
|
int cgroup_user (char *name, int pid);
|
||||||
int cgroup_service (char *cmd, char *id, int pid);
|
int cgroup_service (char *name, int pid);
|
||||||
|
|
||||||
#endif /* FINIT_CGROUP_H_ */
|
#endif /* FINIT_CGROUP_H_ */
|
||||||
+483
@@ -0,0 +1,483 @@
|
|||||||
|
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <search.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
#include <sys/sysinfo.h> /* sysinfo() */
|
||||||
|
|
||||||
|
#include "initctl.h"
|
||||||
|
|
||||||
|
#define CDIM plain ? "" : "\e[2m"
|
||||||
|
#define CRST plain ? "" : "\e[0m"
|
||||||
|
|
||||||
|
#define NONE " "
|
||||||
|
#define PIPE plain ? "| " : "│ "
|
||||||
|
#define FORK plain ? "|-" : "├─"
|
||||||
|
#define END plain ? "`-" : "└─"
|
||||||
|
|
||||||
|
uint64_t total_ram; /* From sysinfo() */
|
||||||
|
|
||||||
|
struct cg {
|
||||||
|
struct cg *cg_next;
|
||||||
|
|
||||||
|
char *cg_path; /* path in /sys/fs/cgroup */
|
||||||
|
uint64_t cg_prev; /* cpuacct.usage */
|
||||||
|
uint64_t cg_rss; /* memory.stat */
|
||||||
|
uint64_t cg_vmlib; /* memory.stat */
|
||||||
|
uint64_t cg_vmsize; /* memory.usage_in_bytes */
|
||||||
|
float cg_mem; /* cg_rss / total_ram * 100 */
|
||||||
|
float cg_load; /* curr - prev / 10000000.0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cg dummy; /* empty result "NULL" */
|
||||||
|
struct cg *list;
|
||||||
|
|
||||||
|
|
||||||
|
static char *pid_cmdline(int pid, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
size_t i, sz;
|
||||||
|
char *ptr;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "/proc/%d/cmdline", pid);
|
||||||
|
if (!fp) {
|
||||||
|
buf[0] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = fread(buf, sizeof(buf[0]), len - 1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
if (!sz)
|
||||||
|
return NULL; /* kernel thread */
|
||||||
|
|
||||||
|
buf[sz] = 0;
|
||||||
|
|
||||||
|
ptr = strchr(buf, 0);
|
||||||
|
if (ptr && ptr != buf) {
|
||||||
|
ptr++;
|
||||||
|
sz -= ptr - buf;
|
||||||
|
memmove(buf, ptr, sz + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sz; i++) {
|
||||||
|
if (buf[i] == 0)
|
||||||
|
buf[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *pid_comm(int pid, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "/proc/%d/comm", pid);
|
||||||
|
if (!fp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fgets(buf, len, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return chomp(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t cgroup_uint64(char *path, char *file)
|
||||||
|
{
|
||||||
|
uint64_t val = 0;
|
||||||
|
char buf[42];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "%s/%s", path, file);
|
||||||
|
if (!fp)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
if (fgets(buf, sizeof(buf), fp))
|
||||||
|
val = strtoull(buf, NULL, 10);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cgroup_shares(char *path)
|
||||||
|
{
|
||||||
|
return (int)cgroup_uint64(path, "cpu.shares");
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t cgroup_memuse(struct cg *cg)
|
||||||
|
{
|
||||||
|
char buf[42];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
|
||||||
|
fp = fopenf("r", "%s/memory.stat", cg->cg_path);
|
||||||
|
if (fp) {
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
if (!strncmp(buf, "total_rss", 9)) {
|
||||||
|
cg->cg_rss = strtoull(&buf[10], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "total_mapped_file", 17)) {
|
||||||
|
cg->cg_vmlib = strtoull(&buf[18], NULL, 10);
|
||||||
|
break; /* done */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
cg->cg_mem = (float)(cg->cg_rss * 100 / total_ram);
|
||||||
|
|
||||||
|
/* "fuzz value for efficient access", sort of like total_cache + total_rss */
|
||||||
|
return cg->cg_vmsize = cgroup_uint64(cg->cg_path, "memory.usage_in_bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *memsz(uint64_t sz, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int gb, mb, kb, b;
|
||||||
|
|
||||||
|
gb = sz / (1024 * 1024 * 1024);
|
||||||
|
sz = sz % (1024 * 1024 * 1024);
|
||||||
|
mb = sz / (1024 * 1024);
|
||||||
|
sz = sz % (1024 * 1024);
|
||||||
|
kb = sz / (1024);
|
||||||
|
b = sz % (1024);
|
||||||
|
|
||||||
|
if (gb)
|
||||||
|
snprintf(buf, len, "%d.%dG", gb, mb / 102);
|
||||||
|
else if (mb)
|
||||||
|
snprintf(buf, len, "%d.%dM", mb, kb / 102);
|
||||||
|
else
|
||||||
|
snprintf(buf, len, "%d.%dk", kb, b / 102);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float cgroup_cpuload(struct cg *cg)
|
||||||
|
{
|
||||||
|
char fn[256];
|
||||||
|
char buf[64];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
snprintf(fn, sizeof(fn), "%s/cpuacct.usage", cg->cg_path);
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(1, "Cannot open %s", fn);
|
||||||
|
|
||||||
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
uint64_t curr;
|
||||||
|
|
||||||
|
curr = strtoull(buf, NULL, 10);
|
||||||
|
if (cg->cg_prev != 0) {
|
||||||
|
uint64_t diff = curr - cg->cg_prev;
|
||||||
|
|
||||||
|
/* this expects 1 sec poll interval */
|
||||||
|
cg->cg_load = (float)(diff / 1000000);
|
||||||
|
cg->cg_load /= 10.0;
|
||||||
|
}
|
||||||
|
cg->cg_prev = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return cg->cg_load;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cg *append(char *path)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
char fn[256];
|
||||||
|
ENTRY item;
|
||||||
|
|
||||||
|
snprintf(fn, sizeof(fn), "%s/cpuacct.usage", path);
|
||||||
|
if (access(fn, F_OK)) {
|
||||||
|
warn("not a cgroup path with cpuacct controller, %s", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cg = calloc(1, sizeof(struct cg));
|
||||||
|
if (!cg)
|
||||||
|
err(1, "failed allocating struct cg");
|
||||||
|
|
||||||
|
cg->cg_path = strdup(path);
|
||||||
|
if (list)
|
||||||
|
cg->cg_next = list;
|
||||||
|
list = cg;
|
||||||
|
|
||||||
|
item.key = cg->cg_path;
|
||||||
|
item.data = cg;
|
||||||
|
if (!hsearch(item, ENTER))
|
||||||
|
err(1, "failed adding to hash table");
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cg *find(char *path)
|
||||||
|
{
|
||||||
|
ENTRY *ep, item = { path, NULL };
|
||||||
|
|
||||||
|
ep = hsearch(item, FIND);
|
||||||
|
if (ep)
|
||||||
|
return ep->data;
|
||||||
|
|
||||||
|
return append(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cg *cg_update(char *path)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
cg = find(path);
|
||||||
|
if (!cg)
|
||||||
|
return &dummy;
|
||||||
|
|
||||||
|
cgroup_cpuload(cg);
|
||||||
|
cgroup_memuse(cg);
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cgroup_filter(const struct dirent *entry)
|
||||||
|
{
|
||||||
|
/* Skip current dir ".", and prev dir "..", from list of files */
|
||||||
|
if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
|
||||||
|
(2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (entry->d_name[0] == '.')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (entry->d_type != DT_DIR)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cgroup_tree(char *path, char *pfx, int top)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
char s[32], r[32], l[32];
|
||||||
|
char row[screen_cols + 9]; /* + control codes */
|
||||||
|
size_t rlen = sizeof(row) - 1;
|
||||||
|
size_t rplen = rlen - 9;
|
||||||
|
struct stat st;
|
||||||
|
struct cg *cg;
|
||||||
|
char buf[512];
|
||||||
|
int rc = 0;
|
||||||
|
FILE *fp;
|
||||||
|
int i, n;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
if (top >= screen_rows)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (-1 == lstat(path, &st))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if ((st.st_mode & S_IFMT) != S_IFDIR) {
|
||||||
|
errno = ENOTDIR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fopenf("r", "%s/cgroup.procs", path);
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
num = 0;
|
||||||
|
while (fgets(buf, sizeof(buf), fp))
|
||||||
|
num++;
|
||||||
|
|
||||||
|
if (!pfx) {
|
||||||
|
pfx = "";
|
||||||
|
if (top) {
|
||||||
|
cg = cg_update(path);
|
||||||
|
snprintf(row, rplen, " %6.6s %6.6s %6.6s %5.1f %5.1f [%s]",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
memsz(cg->cg_rss, r, sizeof(r)),
|
||||||
|
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||||
|
cg->cg_mem, cg->cg_load, path);
|
||||||
|
} else
|
||||||
|
strlcpy(row, path, rplen);
|
||||||
|
|
||||||
|
puts(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = scandir(path, &namelist, cgroup_filter, alphasort);
|
||||||
|
if (n > 0) {
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
char *nm = namelist[i]->d_name;
|
||||||
|
char prefix[80], tmp[42];
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%s/%s", path, nm);
|
||||||
|
if (top) {
|
||||||
|
cg = cg_update(buf);
|
||||||
|
snprintf(row, rplen,
|
||||||
|
" %6.6s %6.6s %6.6s %5.1f %5.1f ",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
memsz(cg->cg_rss, r, sizeof(r)),
|
||||||
|
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||||
|
cg->cg_mem, cg->cg_load);
|
||||||
|
} else
|
||||||
|
row[0] = 0;
|
||||||
|
|
||||||
|
strlcat(row, pfx, rplen);
|
||||||
|
if (i + 1 == n) {
|
||||||
|
strlcat(row, END, rplen);
|
||||||
|
snprintf(prefix, sizeof(prefix), "%s ", pfx);
|
||||||
|
} else {
|
||||||
|
strlcat(row, FORK, rplen);
|
||||||
|
snprintf(prefix, sizeof(prefix), "%s%s ", pfx, PIPE);
|
||||||
|
}
|
||||||
|
strlcat(row, " ", rplen);
|
||||||
|
|
||||||
|
strlcat(row, nm, rplen);
|
||||||
|
strlcat(row, "/ ", rplen);
|
||||||
|
|
||||||
|
snprintf(tmp, sizeof(tmp), "[cpu.shares: %d]", cgroup_shares(buf));
|
||||||
|
strlcat(row, tmp, rplen);
|
||||||
|
puts(row);
|
||||||
|
|
||||||
|
rc += cgroup_tree(buf, prefix, top ? top + i : 0);
|
||||||
|
|
||||||
|
free(namelist[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(namelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num > 0) {
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char comm[80] = { 0 };
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = atoi(chomp(buf));
|
||||||
|
if (pid <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* skip kernel threads for now (no cmdline) */
|
||||||
|
pid_comm(pid, comm, sizeof(comm));
|
||||||
|
if (pid_cmdline(pid, buf, sizeof(buf))) {
|
||||||
|
char proc[screen_cols];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (top)
|
||||||
|
snprintf(row, rplen, "%37s", " ");
|
||||||
|
else
|
||||||
|
row[0] = 0;
|
||||||
|
|
||||||
|
strlcat(row, pfx, rplen);
|
||||||
|
strlcat(row, ++i == num ? END : FORK, rlen);
|
||||||
|
|
||||||
|
snprintf(proc, sizeof(proc), " %d %s %s", pid, comm, buf);
|
||||||
|
|
||||||
|
if (plain) {
|
||||||
|
strlcat(row, proc, rplen);
|
||||||
|
} else {
|
||||||
|
strlcat(row, CDIM, rlen);
|
||||||
|
strlcat(row, proc, rlen);
|
||||||
|
|
||||||
|
len = strlen(row) + strlen(CRST);
|
||||||
|
if (len > (int)rlen)
|
||||||
|
row[rlen - strlen(CRST)] = 0;
|
||||||
|
|
||||||
|
strlcat(row, CRST, sizeof(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
puts(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top) {
|
||||||
|
top += i;
|
||||||
|
if (top >= screen_rows)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_cgroup(char *arg)
|
||||||
|
{
|
||||||
|
char path[512];
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
arg = FINIT_CGPATH;
|
||||||
|
else if (arg[0] != '/') {
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||||
|
arg = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgroup_tree(arg, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_cgtop(char *arg)
|
||||||
|
{
|
||||||
|
struct sysinfo si = { 0 };
|
||||||
|
char path[512];
|
||||||
|
int laps = 0;
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
arg = FINIT_CGPATH;
|
||||||
|
else if (arg[0] != '/') {
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||||
|
arg = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hcreate(screen_rows + 25))
|
||||||
|
err(1, "failed creating hash table");
|
||||||
|
|
||||||
|
sysinfo(&si);
|
||||||
|
total_ram = si.totalram * si.mem_unit;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
fputs("\e[2J\e[1;1H", stdout);
|
||||||
|
if (heading)
|
||||||
|
print_header(" VmSIZE RSS VmLIB %%MEM %%CPU GROUP");
|
||||||
|
cgroup_tree(arg, NULL, 1);
|
||||||
|
|
||||||
|
if (ionce && laps++)
|
||||||
|
break;
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/* Cgroup utility functions for initctl
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FINIT_CGUTIL_H_
|
||||||
|
#define FINIT_CGUTIL_H_
|
||||||
|
|
||||||
|
int show_cgroup (char *arg);
|
||||||
|
int show_cgtop (char *arg);
|
||||||
|
|
||||||
|
#endif /* FINIT_CGUTIL_H_ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+4
-8
@@ -21,6 +21,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
@@ -38,17 +39,12 @@ int client_connect(void)
|
|||||||
|
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (-1 == sd)
|
if (-1 == sd)
|
||||||
goto error;
|
err(1, "Failed creating UNIX domain socket");
|
||||||
|
|
||||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
|
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
|
||||||
close(sd);
|
err(1, "Failed connecting to finit");
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sd;
|
return sd;
|
||||||
error:
|
|
||||||
perror("Failed connecting to finit");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int client_disconnect(void)
|
int client_disconnect(void)
|
||||||
|
|||||||
+13
-11
@@ -99,13 +99,13 @@ static void cond_bump_reconf(void)
|
|||||||
unsigned int rgen;
|
unsigned int rgen;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If %COND_RECONF does not exist, cond_get_gen() returns 0
|
* If %_PATH_RECONF does not exist, cond_get_gen() returns 0
|
||||||
* meaning that rgen++ is always what we want.
|
* meaning that rgen++ is always what we want.
|
||||||
*/
|
*/
|
||||||
rgen = cond_get_gen(COND_RECONF);
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
rgen++;
|
rgen++;
|
||||||
|
|
||||||
cond_set_gen(COND_RECONF, rgen);
|
cond_set_gen(_PATH_RECONF, rgen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cond_checkpath(const char *path)
|
static int cond_checkpath(const char *path)
|
||||||
@@ -119,7 +119,7 @@ static int cond_checkpath(const char *path)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (makepath(dir) && errno != EEXIST) {
|
if (mkpath(dir, 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ int cond_set_path(const char *path, enum cond_state new)
|
|||||||
|
|
||||||
_d("%s", path);
|
_d("%s", path);
|
||||||
|
|
||||||
rgen = cond_get_gen(COND_RECONF);
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
if (!rgen) {
|
if (!rgen) {
|
||||||
_e("Unable to read configuration generation (%s)", path);
|
_e("Unable to read configuration generation (%s)", path);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -162,7 +162,8 @@ int cond_set_path(const char *path, enum cond_state new)
|
|||||||
return new != old;
|
return new != old;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cond_update(const char *name)
|
/* Should only be used by cond_set*(), cond_clear(), and usr plugin! */
|
||||||
|
void cond_update(const char *name)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
@@ -201,7 +202,8 @@ void cond_set_oneshot(const char *name)
|
|||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
symlink(COND_RECONF, path);
|
if (symlink(_PATH_RECONF, path) && errno != EEXIST)
|
||||||
|
_pe("Failed creating onshot cond %s", name);
|
||||||
cond_update(name);
|
cond_update(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,13 +236,13 @@ static int reassert(const char *fpath, const struct stat *sb, int tflg, struct F
|
|||||||
if (tflg != FTW_F)
|
if (tflg != FTW_F)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nm = strstr((char *)fpath, COND_DIR);
|
nm = strstr((char *)fpath, COND_BASE);
|
||||||
if (!nm) {
|
if (!nm) {
|
||||||
_e("Incorrect condtion path %s, cannot reassert", fpath);
|
_e("Incorrect condtion path %s, cannot reassert", fpath);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nm += sizeof(COND_DIR);
|
nm += strlen(COND_BASE);
|
||||||
_d("Reasserting %s => %s", fpath, nm);
|
_d("Reasserting %s => %s", fpath, nm);
|
||||||
cond_set(nm);
|
cond_set(nm);
|
||||||
|
|
||||||
@@ -261,8 +263,8 @@ void cond_init(void)
|
|||||||
{
|
{
|
||||||
char path[MAX_ARG_LEN];
|
char path[MAX_ARG_LEN];
|
||||||
|
|
||||||
if (makepath(pid_runpath(COND_PATH, path, sizeof(path))) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_COND, path, sizeof(path)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating condition base directory '%s'", COND_PATH);
|
_pe("Failed creating condition base directory '%s'", _PATH_COND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -45,7 +45,7 @@ const char *cond_path(const char *name)
|
|||||||
static char path[256];
|
static char path[256];
|
||||||
char tmp[MAX_ARG_LEN];
|
char tmp[MAX_ARG_LEN];
|
||||||
|
|
||||||
snprintf(tmp, sizeof(tmp), COND_PATH "/%s", name);
|
snprintf(tmp, sizeof(tmp), _PATH_COND "%s", name);
|
||||||
|
|
||||||
return pid_runpath(tmp, path, sizeof(path));
|
return pid_runpath(tmp, path, sizeof(path));
|
||||||
}
|
}
|
||||||
@@ -74,14 +74,14 @@ enum cond_state cond_get_path(const char *path)
|
|||||||
{
|
{
|
||||||
int cgen, rgen;
|
int cgen, rgen;
|
||||||
|
|
||||||
rgen = cond_get_gen(COND_RECONF);
|
|
||||||
if (!rgen)
|
|
||||||
return COND_OFF;
|
|
||||||
|
|
||||||
cgen = cond_get_gen(path);
|
cgen = cond_get_gen(path);
|
||||||
if (!cgen)
|
if (!cgen)
|
||||||
return COND_OFF;
|
return COND_OFF;
|
||||||
|
|
||||||
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
|
if (!rgen)
|
||||||
|
return COND_OFF;
|
||||||
|
|
||||||
return (cgen == rgen) ? COND_ON : COND_FLUX;
|
return (cgen == rgen) ? COND_ON : COND_FLUX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -4,9 +4,12 @@
|
|||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <svc.h>
|
#include <svc.h>
|
||||||
|
|
||||||
#define COND_DIR "finit/cond"
|
#define COND_BASE "finit/cond"
|
||||||
#define COND_PATH _PATH_VARRUN COND_DIR
|
#define COND_USR "usr/"
|
||||||
#define COND_RECONF COND_PATH "/reconf"
|
|
||||||
|
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
||||||
|
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||||
|
#define _PATH_RECONF _PATH_COND "reconf"
|
||||||
|
|
||||||
typedef enum cond_state {
|
typedef enum cond_state {
|
||||||
COND_OFF = 0,
|
COND_OFF = 0,
|
||||||
@@ -23,6 +26,7 @@ enum cond_state cond_get (const char *name);
|
|||||||
enum cond_state cond_get_agg (const char *names);
|
enum cond_state cond_get_agg (const char *names);
|
||||||
int cond_affects (const char *name, const char *names);
|
int cond_affects (const char *name, const char *names);
|
||||||
|
|
||||||
|
void cond_update (const char *name);
|
||||||
int cond_set_path (const char *path, enum cond_state new);
|
int cond_set_path (const char *path, enum cond_state new);
|
||||||
void cond_set (const char *name);
|
void cond_set (const char *name);
|
||||||
void cond_set_oneshot (const char *name);
|
void cond_set_oneshot (const char *name);
|
||||||
|
|||||||
@@ -900,6 +900,9 @@ int conf_init(uev_ctx_t *ctx)
|
|||||||
rlim2str(i), strerror(errno));
|
rlim2str(i), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize global rlimits, e.g. for built-in services */
|
||||||
|
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
|
||||||
|
|
||||||
/* prepare /etc watcher */
|
/* prepare /etc watcher */
|
||||||
fd = iwatch_init(&iw_conf);
|
fd = iwatch_init(&iw_conf);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
|||||||
+5
-5
@@ -199,7 +199,6 @@ static void fs_mount(void)
|
|||||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
run("swapon -ea");
|
run("swapon -ea");
|
||||||
umask(0022);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -222,6 +221,9 @@ static void fs_init(void)
|
|||||||
};
|
};
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
/* mask writable bit for g and o */
|
||||||
|
umask(022);
|
||||||
|
|
||||||
for (i = 0; i < NELEMS(fs); i++) {
|
for (i = 0; i < NELEMS(fs); i++) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -448,7 +450,7 @@ int main(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
struct wq final = {
|
struct wq final = {
|
||||||
.cb = final_worker,
|
.cb = final_worker,
|
||||||
.delay = 1000
|
.delay = 100
|
||||||
};
|
};
|
||||||
uev_ctx_t loop;
|
uev_ctx_t loop;
|
||||||
|
|
||||||
@@ -479,14 +481,13 @@ int main(int argc, char *argv[])
|
|||||||
ctx = &loop;
|
ctx = &loop;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set PATH, SHELL, PWD, and umask early to something sane
|
* Set PATH, SHELL, and PWD early to something sane
|
||||||
*/
|
*/
|
||||||
setenv("PATH", _PATH_STDPATH, 1);
|
setenv("PATH", _PATH_STDPATH, 1);
|
||||||
setenv("SHELL", _PATH_BSHELL, 1);
|
setenv("SHELL", _PATH_BSHELL, 1);
|
||||||
|
|
||||||
if (chdir("/"))
|
if (chdir("/"))
|
||||||
_pe("Failed cd /");
|
_pe("Failed cd /");
|
||||||
umask(0);
|
|
||||||
|
|
||||||
/* Allow progress, if enabled */
|
/* Allow progress, if enabled */
|
||||||
enable_progress(1);
|
enable_progress(1);
|
||||||
@@ -548,7 +549,6 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
_d("Starting initctl API responder ...");
|
_d("Starting initctl API responder ...");
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
umask(022);
|
|
||||||
|
|
||||||
_d("Starting the big state machine ...");
|
_d("Starting the big state machine ...");
|
||||||
schedule_work(&crank);
|
schedule_work(&crank);
|
||||||
|
|||||||
+1
-1
@@ -186,7 +186,7 @@ static int do_login(char *name)
|
|||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
cgroup_user(name);
|
cgroup_user(name, getpid());
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+61
-1
@@ -103,6 +103,9 @@ static void add_console(char *cons)
|
|||||||
if (ptr)
|
if (ptr)
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
|
|
||||||
|
if (!strncmp(cons, "/dev/", 5))
|
||||||
|
cons += 5;
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "/dev/%s", cons);
|
snprintf(path, sizeof(path), "/dev/%s", cons);
|
||||||
|
|
||||||
/* check for and skip duplicates */
|
/* check for and skip duplicates */
|
||||||
@@ -131,7 +134,7 @@ static void find_active_consoles(void)
|
|||||||
if (!fp) {
|
if (!fp) {
|
||||||
fallback:
|
fallback:
|
||||||
_d("Using fallback /dev/console");
|
_d("Using fallback /dev/console");
|
||||||
add_console("/dev/console");
|
add_console("console");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,6 +413,63 @@ int getgroup(char *group)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get current user */
|
||||||
|
int getcuser(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = "root";
|
||||||
|
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
struct passwd *pw = getpwuid(getuid());
|
||||||
|
|
||||||
|
if (pw)
|
||||||
|
ptr = pw->pw_name;
|
||||||
|
#endif
|
||||||
|
if (strlcpy(buf, ptr, len) > len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get current group */
|
||||||
|
int getcgroup(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = "root";
|
||||||
|
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
struct group *gr = getgrgid(getgid());
|
||||||
|
|
||||||
|
if (gr)
|
||||||
|
ptr = gr->gr_name;
|
||||||
|
#endif
|
||||||
|
if (strlcpy(buf, ptr, len) > len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
||||||
|
{
|
||||||
|
mode_t omask;
|
||||||
|
int uid, gid;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
omask = umask(0);
|
||||||
|
|
||||||
|
uid = getuser(user, NULL);
|
||||||
|
if (uid >= 0) {
|
||||||
|
gid = getgroup(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
|
rc = makedir(dir, mode);
|
||||||
|
chown(dir, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
umask(omask);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void set_hostname(char **hostname)
|
void set_hostname(char **hostname)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|||||||
@@ -81,6 +81,12 @@ int print_result (int fail);
|
|||||||
|
|
||||||
int getuser (char *username, char **home);
|
int getuser (char *username, char **home);
|
||||||
int getgroup (char *group);
|
int getgroup (char *group);
|
||||||
|
|
||||||
|
int getcuser (char *buf, size_t len);
|
||||||
|
int getcgroup (char *buf, size_t len);
|
||||||
|
|
||||||
|
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||||
|
|
||||||
void set_hostname (char **hostname);
|
void set_hostname (char **hostname);
|
||||||
void networking (int updown);
|
void networking (int updown);
|
||||||
|
|
||||||
|
|||||||
+281
-254
@@ -26,7 +26,6 @@
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@@ -40,22 +39,18 @@
|
|||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "serv.h"
|
#include "serv.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "cgutil.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
struct cmd {
|
||||||
|
char *cmd;
|
||||||
#define NONE " "
|
struct cmd *ctx;
|
||||||
#define PIPE plain ? "|" : "│"
|
int (*cb)(char *arg);
|
||||||
#define FORK plain ? "|-" : "├─"
|
|
||||||
#define END plain ? "`-" : "└─"
|
|
||||||
|
|
||||||
struct command {
|
|
||||||
char *cmd;
|
|
||||||
int (*cb)(char *arg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int icreate = 0;
|
int icreate = 0;
|
||||||
int iforce = 0;
|
int iforce = 0;
|
||||||
|
int ionce = 0;
|
||||||
int heading = 1;
|
int heading = 1;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
int plain = 0;
|
int plain = 0;
|
||||||
@@ -95,6 +90,30 @@ static void col_widths(void)
|
|||||||
pw = 3;
|
pw = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_header(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
|
||||||
|
if (plain) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
vfprintf(stdout, fmt, ap);
|
||||||
|
fputs("\n", stdout);
|
||||||
|
for (len = 0; len < screen_cols; len++)
|
||||||
|
fputc('=', stdout);
|
||||||
|
fputs("\n", stdout);
|
||||||
|
} else {
|
||||||
|
char buf[screen_cols];
|
||||||
|
|
||||||
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||||
|
printheader(stdout, buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
static int runlevel_get(int *prevlevel)
|
static int runlevel_get(int *prevlevel)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
@@ -126,7 +145,6 @@ static int toggle_debug(char *arg)
|
|||||||
|
|
||||||
static int do_log(char *svc)
|
static int do_log(char *svc)
|
||||||
{
|
{
|
||||||
char cmd[128];
|
|
||||||
char *logfile = "/var/log/syslog";
|
char *logfile = "/var/log/syslog";
|
||||||
|
|
||||||
if (!svc || !svc[0])
|
if (!svc || !svc[0])
|
||||||
@@ -135,9 +153,7 @@ static int do_log(char *svc)
|
|||||||
if (!fexist(logfile))
|
if (!fexist(logfile))
|
||||||
logfile = "/var/log/messages";
|
logfile = "/var/log/messages";
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "cat %s | grep %s | tail -10", logfile, svc);
|
return systemf("cat %s | grep %s | tail -10", logfile, svc);
|
||||||
|
|
||||||
return system(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_runlevel(char *arg)
|
static int do_runlevel(char *arg)
|
||||||
@@ -231,7 +247,7 @@ static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, st
|
|||||||
if (tflag != FTW_F)
|
if (tflag != FTW_F)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!strcmp(fpath, _PATH_COND "reconf"))
|
if (!strcmp(fpath, _PATH_RECONF))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
asserted = condstr(cond_get_path(fpath));
|
asserted = condstr(cond_get_path(fpath));
|
||||||
@@ -247,9 +263,15 @@ static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, st
|
|||||||
nm = svc_ident(svc, NULL, 0);
|
nm = svc_ident(svc, NULL, 0);
|
||||||
pid = svc->pid;
|
pid = svc->pid;
|
||||||
}
|
}
|
||||||
|
} else if (strncmp("usr/", cond, 4) == 0) {
|
||||||
|
nm = "static";
|
||||||
|
pid = 0;
|
||||||
|
} else if (strncmp("hook/", cond, 4) == 0) {
|
||||||
|
nm = "static";
|
||||||
|
pid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%-*d %-*s %-6s %s\n", pw, pid, iw, nm, asserted, cond);
|
printf("%-*d %-*s %-6s <%s>\n", pw, pid, iw, nm, asserted, cond);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -262,7 +284,7 @@ static int do_cond_dump(char *arg)
|
|||||||
|
|
||||||
snprintf(title, sizeof(title), "%-*s %-*s %-6s %s", pw, "PID",
|
snprintf(title, sizeof(title), "%-*s %-*s %-6s %s", pw, "PID",
|
||||||
iw, "IDENT", "STATUS", "CONDITION");
|
iw, "IDENT", "STATUS", "CONDITION");
|
||||||
printheader(NULL, title, 0);
|
print_header(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nftw(_PATH_COND, dump_one_cond, 20, 0) == -1) {
|
if (nftw(_PATH_COND, dump_one_cond, 20, 0) == -1) {
|
||||||
@@ -273,41 +295,93 @@ static int do_cond_dump(char *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_cond_one(const char *_conds)
|
static int do_cond_act(char *arg, int creat)
|
||||||
{
|
{
|
||||||
static char conds[MAX_COND_LEN];
|
char oneshot[256];
|
||||||
char *cond;
|
size_t off;
|
||||||
|
|
||||||
strlcpy(conds, _conds, sizeof(conds));
|
if (arg && strncmp(arg, COND_USR, strlen(COND_USR)) == 0)
|
||||||
|
arg += strlen(COND_USR);
|
||||||
|
|
||||||
putchar('<');
|
if (!arg || !arg[0])
|
||||||
|
errx(1, "Invalid condition (empty)");
|
||||||
|
if (strchr(arg, '/'))
|
||||||
|
errx(1, "Invalid condition (slashes)");
|
||||||
|
if (strchr(arg, '.'))
|
||||||
|
errx(1, "Invalid condition (periods)");
|
||||||
|
|
||||||
|
snprintf(oneshot, sizeof(oneshot), _PATH_CONDUSR "%s", arg);
|
||||||
|
off = strlen(_PATH_COND);
|
||||||
|
|
||||||
|
if (creat) {
|
||||||
|
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
|
||||||
|
err(1, "Failed asserting condition <%s>", &oneshot[off]);
|
||||||
|
} else {
|
||||||
|
if (erase(oneshot))
|
||||||
|
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_cond_set(char *arg) { return do_cond_act(arg, 1); }
|
||||||
|
static int do_cond_clr(char *arg) { return do_cond_act(arg, 0); }
|
||||||
|
|
||||||
|
static char *svc_cond(svc_t *svc, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *cond, *conds;
|
||||||
|
|
||||||
|
memset(buf, 0, len);
|
||||||
|
|
||||||
|
if (!svc->cond[0])
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
conds = strdup(svc->cond);
|
||||||
|
if (!conds)
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
strlcat(buf, "<", len);
|
||||||
|
|
||||||
for (cond = strtok(conds, ","); cond; cond = strtok(NULL, ",")) {
|
for (cond = strtok(conds, ","); cond; cond = strtok(NULL, ",")) {
|
||||||
if (cond != conds)
|
if (cond != conds)
|
||||||
putchar(',');
|
strlcat(buf, ",", len);
|
||||||
|
|
||||||
switch (cond_get(cond)) {
|
switch (cond_get(cond)) {
|
||||||
case COND_ON:
|
case COND_ON:
|
||||||
printf("+%s", cond);
|
strlcat(buf, "+", len);
|
||||||
|
strlcat(buf, cond, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COND_FLUX:
|
case COND_FLUX:
|
||||||
printf("\e[1m~%s\e[0m", cond);
|
if (!plain)
|
||||||
|
strlcat(buf, "\e[1m", len);
|
||||||
|
strlcat(buf, "~", len);
|
||||||
|
strlcat(buf, cond, len);
|
||||||
|
if (!plain)
|
||||||
|
strlcat(buf, "\e[0m", len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COND_OFF:
|
case COND_OFF:
|
||||||
printf("\e[1m-%s\e[0m", cond);
|
if (!plain)
|
||||||
|
strlcat(buf, "\e[1m", len);
|
||||||
|
strlcat(buf, "-", len);
|
||||||
|
strlcat(buf, cond, len);
|
||||||
|
if (!plain)
|
||||||
|
strlcat(buf, "\e[0m", len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
putchar('>');
|
strlcat(buf, ">", len);
|
||||||
|
free(conds);
|
||||||
|
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_cond_show(char *arg)
|
static int do_cond_show(char *arg)
|
||||||
{
|
{
|
||||||
char ident[MAX_IDENT_LEN];
|
|
||||||
enum cond_state cond;
|
enum cond_state cond;
|
||||||
|
char buf[512];
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
col_widths();
|
col_widths();
|
||||||
@@ -316,7 +390,7 @@ static int do_cond_show(char *arg)
|
|||||||
|
|
||||||
snprintf(title, sizeof(title), "%-*s %-*s %-6s %s", pw, "PID",
|
snprintf(title, sizeof(title), "%-*s %-*s %-6s %s", pw, "PID",
|
||||||
iw, "IDENT", "STATUS", "CONDITION (+ ON, ~ FLUX, - OFF)");
|
iw, "IDENT", "STATUS", "CONDITION (+ ON, ~ FLUX, - OFF)");
|
||||||
printheader(NULL, title, 0);
|
print_header(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
@@ -325,47 +399,20 @@ static int do_cond_show(char *arg)
|
|||||||
|
|
||||||
cond = cond_get_agg(svc->cond);
|
cond = cond_get_agg(svc->cond);
|
||||||
|
|
||||||
svc_ident(svc, ident, sizeof(ident));
|
svc_ident(svc, buf, sizeof(buf));
|
||||||
printf("%-*d %-*s ", pw, svc->pid, iw, ident);
|
printf("%-*d %-*s ", pw, svc->pid, iw, buf);
|
||||||
|
|
||||||
if (cond == COND_ON)
|
if (cond == COND_ON)
|
||||||
printf("%-6.6s ", condstr(cond));
|
printf("%-6.6s ", condstr(cond));
|
||||||
else
|
else
|
||||||
printf("\e[1m%-6.6s\e[0m ", condstr(cond));
|
printf("\e[1m%-6.6s\e[0m ", condstr(cond));
|
||||||
|
|
||||||
show_cond_one(svc->cond);
|
puts(svc_cond(svc, buf, sizeof(buf)));
|
||||||
puts("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_cond(char *cmd)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
char *arg;
|
|
||||||
struct command command[] = {
|
|
||||||
{ "show", do_cond_show },
|
|
||||||
{ "dump", do_cond_dump },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!cmd)
|
|
||||||
goto fallback;
|
|
||||||
|
|
||||||
arg = strpbrk(cmd, " \0");
|
|
||||||
if (arg)
|
|
||||||
*arg++ = 0;
|
|
||||||
|
|
||||||
for (c = 0; command[c].cmd; c++) {
|
|
||||||
if (string_match(command[c].cmd, cmd))
|
|
||||||
return command[c].cb(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
fallback:
|
|
||||||
return do_cond_show(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_cmd(int cmd)
|
static int do_cmd(int cmd)
|
||||||
{
|
{
|
||||||
struct init_request rq = {
|
struct init_request rq = {
|
||||||
@@ -393,15 +440,18 @@ int do_suspend (char *arg) { return do_cmd(INIT_CMD_SUSPEND); }
|
|||||||
|
|
||||||
int utmp_show(char *file)
|
int utmp_show(char *file)
|
||||||
{
|
{
|
||||||
time_t sec;
|
static int once = 0;
|
||||||
struct utmp *ut;
|
|
||||||
struct tm *sectm;
|
struct tm *sectm;
|
||||||
|
struct utmp *ut;
|
||||||
|
time_t sec;
|
||||||
|
|
||||||
int pid;
|
int pid;
|
||||||
char id[sizeof(ut->ut_id) + 1], user[sizeof(ut->ut_user) + 1], when[80];
|
char id[sizeof(ut->ut_id) + 1], user[sizeof(ut->ut_user) + 1], when[80];
|
||||||
|
|
||||||
if (heading)
|
if (heading) {
|
||||||
printheader(NULL, file, 0);
|
print_header("%s%s ", once ? "\n" : "", file);
|
||||||
|
once++;
|
||||||
|
}
|
||||||
utmpname(file);
|
utmpname(file);
|
||||||
|
|
||||||
setutent();
|
setutent();
|
||||||
@@ -468,7 +518,7 @@ char *runlevel_string(int runlevel, int levels)
|
|||||||
|
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
if (ISSET(levels, i)) {
|
if (ISSET(levels, i)) {
|
||||||
if (runlevel == i)
|
if (!plain && runlevel == i)
|
||||||
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
|
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
@@ -476,7 +526,7 @@ char *runlevel_string(int runlevel, int levels)
|
|||||||
else
|
else
|
||||||
lvl[pos++] = '0' + i;
|
lvl[pos++] = '0' + i;
|
||||||
|
|
||||||
if (runlevel == i)
|
if (!plain && runlevel == i)
|
||||||
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
|
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
|
||||||
} else {
|
} else {
|
||||||
lvl[pos++] = '-';
|
lvl[pos++] = '-';
|
||||||
@@ -489,45 +539,96 @@ char *runlevel_string(int runlevel, int levels)
|
|||||||
return lvl;
|
return lvl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *svc_command(svc_t *svc, char *cmd, size_t len)
|
static int missing(svc_t *svc)
|
||||||
{
|
{
|
||||||
strlcpy(cmd, svc->cmd, len);
|
if (svc->state == SVC_HALTED_STATE && svc_is_missing(svc))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *svc_command(svc_t *svc, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int bold = missing(svc);
|
||||||
|
|
||||||
|
if (plain || whichp(svc->cmd))
|
||||||
|
bold = 0;
|
||||||
|
|
||||||
|
strlcpy(buf, bold ? "\e[1m" : "", len);
|
||||||
|
strlcat(buf, svc->cmd, len);
|
||||||
|
|
||||||
for (int i = 1; i < MAX_NUM_SVC_ARGS; i++) {
|
for (int i = 1; i < MAX_NUM_SVC_ARGS; i++) {
|
||||||
if (!svc->args[i][0])
|
if (!svc->args[i][0])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
strlcat(cmd, " ", len);
|
strlcat(buf, " ", len);
|
||||||
strlcat(cmd, svc->args[i], len);
|
strlcat(buf, svc->args[i], len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd;
|
strlcat(buf, bold ? "\e[0m" : "", len);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *svc_environ(svc_t *svc, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int bold = missing(svc);
|
||||||
|
|
||||||
|
if (plain || svc_checkenv(svc) || svc->env[0] == '-')
|
||||||
|
bold = 0;
|
||||||
|
|
||||||
|
strlcpy(buf, bold ? "\e[1m" : "", len);
|
||||||
|
strlcat(buf, svc->env, len);
|
||||||
|
strlcat(buf, bold ? "\e[0m" : "", len);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *status(svc_t *svc)
|
||||||
|
{
|
||||||
|
static char buf[25];
|
||||||
|
int bold = !plain;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = svc_status(svc);
|
||||||
|
if (svc->state != SVC_HALTED_STATE)
|
||||||
|
bold = 0;
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%s%-8.8s%s",
|
||||||
|
bold ? "\e[1m" : "", s, bold ? "\e[0m" : "");
|
||||||
|
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_status(char *arg)
|
static int show_status(char *arg)
|
||||||
{
|
{
|
||||||
char ident[MAX_IDENT_LEN];
|
char ident[MAX_IDENT_LEN];
|
||||||
char cmd[512];
|
char buf[512];
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
runlevel = runlevel_get(NULL);
|
runlevel = runlevel_get(NULL);
|
||||||
|
|
||||||
if (arg && arg[0]) {
|
if (arg && arg[0]) {
|
||||||
long now = jiffies();
|
long now = jiffies();
|
||||||
char buf[42] = "N/A";
|
char uptm[42] = "N/A";
|
||||||
|
|
||||||
svc = client_svc_find(arg);
|
svc = client_svc_find(arg);
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
printf("Status : %s\n", status(svc));
|
||||||
printf("Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
printf("Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
||||||
printf("Description : %s\n", svc->desc);
|
printf("Description : %s\n", svc->desc);
|
||||||
printf("Origin : %s\n", svc->file[0] ? svc->file : "built-in");
|
printf("Origin : %s\n", svc->file[0] ? svc->file : "built-in");
|
||||||
printf("Environment : %s\n", svc->env);
|
printf("Environment : %s\n", svc_environ(svc, buf, sizeof(buf)));
|
||||||
printf("Command : %s\n", svc_command(svc, cmd, sizeof(cmd)));
|
printf("Condition(s): %s\n", svc_cond(svc, buf, sizeof(buf)));
|
||||||
|
printf("Command : %s\n", svc_command(svc, buf, sizeof(buf)));
|
||||||
|
printf("PID file : %s\n", svc->pidfile);
|
||||||
printf("PID : %d\n", svc->pid);
|
printf("PID : %d\n", svc->pid);
|
||||||
printf("Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, buf, sizeof(buf)) : buf);
|
printf("User : %s\n", svc->username);
|
||||||
|
printf("Group : %s\n", svc->group);
|
||||||
|
printf("Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, uptm, sizeof(uptm)) : uptm);
|
||||||
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||||
printf("Status : %s\n", svc_status(svc));
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
return do_log(svc->cmd);
|
return do_log(svc->cmd);
|
||||||
@@ -544,7 +645,7 @@ static int show_status(char *arg)
|
|||||||
else
|
else
|
||||||
strlcat(title, "COMMAND", sizeof(title));
|
strlcat(title, "COMMAND", sizeof(title));
|
||||||
|
|
||||||
printheader(NULL, title, 0);
|
print_header(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
@@ -553,7 +654,7 @@ static int show_status(char *arg)
|
|||||||
printf("%-*d ", pw, svc->pid);
|
printf("%-*d ", pw, svc->pid);
|
||||||
|
|
||||||
svc_ident(svc, ident, sizeof(ident));
|
svc_ident(svc, ident, sizeof(ident));
|
||||||
printf("%-*s %-8s ", iw, ident, svc_status(svc));
|
printf("%-*s %s ", iw, ident, status(svc));
|
||||||
|
|
||||||
lvls = runlevel_string(runlevel, svc->runlevels);
|
lvls = runlevel_string(runlevel, svc->runlevels);
|
||||||
if (strchr(lvls, '\e'))
|
if (strchr(lvls, '\e'))
|
||||||
@@ -564,123 +665,12 @@ static int show_status(char *arg)
|
|||||||
if (!verbose)
|
if (!verbose)
|
||||||
puts(svc->desc);
|
puts(svc->desc);
|
||||||
else
|
else
|
||||||
puts(svc_command(svc, cmd, sizeof(cmd)));
|
puts(svc_command(svc, buf, sizeof(buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cgroup_filter(const struct dirent *entry)
|
|
||||||
{
|
|
||||||
/* Skip current dir ".", and prev dir "..", from list of files */
|
|
||||||
if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
|
|
||||||
(2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (entry->d_name[0] == '.')
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (entry->d_type != DT_DIR)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dump_cgroup(char *path, char *pfx)
|
|
||||||
{
|
|
||||||
struct dirent **namelist = NULL;
|
|
||||||
struct stat st;
|
|
||||||
char buf[512];
|
|
||||||
int rc = 0;
|
|
||||||
FILE *fp;
|
|
||||||
int i, n;
|
|
||||||
int num;
|
|
||||||
|
|
||||||
if (-1 == lstat(path, &st))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if ((st.st_mode & S_IFMT) != S_IFDIR) {
|
|
||||||
errno = ENOTDIR;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp = fopenf("r", "%s/cgroup.procs", path);
|
|
||||||
if (!fp)
|
|
||||||
return -1;
|
|
||||||
num = 0;
|
|
||||||
while (fgets(buf, sizeof(buf), fp))
|
|
||||||
num++;
|
|
||||||
|
|
||||||
if (!pfx) {
|
|
||||||
pfx = "";
|
|
||||||
puts(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
n = scandir(path, &namelist, cgroup_filter, alphasort);
|
|
||||||
if (n > 0) {
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
char *nm = namelist[i]->d_name;
|
|
||||||
char dir[80];
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", path, nm);
|
|
||||||
|
|
||||||
if (i + 1 == n) {
|
|
||||||
printf("%s%s ", pfx, END);
|
|
||||||
snprintf(dir, sizeof(dir), "%s ", pfx);
|
|
||||||
} else {
|
|
||||||
printf("%s%s ", pfx, FORK);
|
|
||||||
snprintf(dir, sizeof(dir), "%s%s ", pfx, PIPE);
|
|
||||||
}
|
|
||||||
puts(nm);
|
|
||||||
|
|
||||||
rc += dump_cgroup(buf, dir);
|
|
||||||
|
|
||||||
free(namelist[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(namelist);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num > 0) {
|
|
||||||
rewind(fp);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
|
||||||
FILE *cfp;
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
pid = atoi(chomp(buf));
|
|
||||||
cfp = fopenf("r", "/proc/%d/cmdline", pid);
|
|
||||||
if (!cfp)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (fgets(buf, sizeof(buf), cfp))
|
|
||||||
printf("%s%s %d %s\n", pfx, ++i == num ? END : FORK, pid, buf);
|
|
||||||
fclose(cfp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int show_cgroup(char *arg)
|
|
||||||
{
|
|
||||||
char path[512];
|
|
||||||
|
|
||||||
if (!arg)
|
|
||||||
arg = FINIT_CGPATH;
|
|
||||||
else if (arg[0] != '/') {
|
|
||||||
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
|
||||||
arg = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dump_cgroup(arg, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int transform(char *nm)
|
static int transform(char *nm)
|
||||||
{
|
{
|
||||||
char *names[] = {
|
char *names[] = {
|
||||||
@@ -725,6 +715,8 @@ static int usage(int rc)
|
|||||||
" -b, --batch Batch mode, no screen size probing\n"
|
" -b, --batch Batch mode, no screen size probing\n"
|
||||||
" -c, --create Create missing paths (and files) as needed\n"
|
" -c, --create Create missing paths (and files) as needed\n"
|
||||||
" -f, --force Ignore missing files and arguments, never prompt\n"
|
" -f, --force Ignore missing files and arguments, never prompt\n"
|
||||||
|
" -1, --once Only one lap in commands like 'top'\n"
|
||||||
|
" -p, --plain Use plain table headings, no ctrl chars\n"
|
||||||
" -t, --no-heading Skip table headings\n"
|
" -t, --no-heading Skip table headings\n"
|
||||||
" -v, --verbose Verbose output\n"
|
" -v, --verbose Verbose output\n"
|
||||||
" -h, --help This help text\n"
|
" -h, --help This help text\n"
|
||||||
@@ -764,7 +756,9 @@ static int usage(int rc)
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
|
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
|
||||||
"\n"
|
"\n"
|
||||||
" cond show Show condition status\n"
|
" cond set <COND> Set (assert) user-defined condition +usr/COND\n"
|
||||||
|
" cond clear <COND> Clear (deassert) user-defined condition -usr/COND\n"
|
||||||
|
" cond status Show condition status, default cond command\n"
|
||||||
" cond dump Dump all conditions and their status\n"
|
" cond dump Dump all conditions and their status\n"
|
||||||
"\n"
|
"\n"
|
||||||
" log [NAME] Show ten last Finit, or NAME, messages from syslog\n"
|
" log [NAME] Show ten last Finit, or NAME, messages from syslog\n"
|
||||||
@@ -775,6 +769,7 @@ static int usage(int rc)
|
|||||||
" status Show status of services, default command\n"
|
" status Show status of services, default command\n"
|
||||||
"\n"
|
"\n"
|
||||||
" ps List processes based on cgroups\n"
|
" ps List processes based on cgroups\n"
|
||||||
|
" top Show top-like listing based on cgroups\n"
|
||||||
"\n"
|
"\n"
|
||||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||||
" reboot Reboot system\n"
|
" reboot Reboot system\n"
|
||||||
@@ -790,6 +785,11 @@ static int usage(int rc)
|
|||||||
else
|
else
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
printf("Bug report address: %-40s\n", PACKAGE_BUGREPORT);
|
||||||
|
#ifdef PACKAGE_URL
|
||||||
|
printf("Project homepage: %s\n", PACKAGE_URL);
|
||||||
|
#endif
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,62 +807,106 @@ static int do_help(char *arg)
|
|||||||
return usage(0);
|
return usage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; argc > 0 && command[i].cmd; i++) {
|
||||||
|
if (!string_match(command[i].cmd, argv[0]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (command[i].ctx)
|
||||||
|
return cmd_parse(argc - 1, &argv[1], command[i].ctx);
|
||||||
|
|
||||||
|
if (command[i].cb) {
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
return command[i].cb(NULL);
|
||||||
|
|
||||||
|
for (j = 1; j < argc; j++)
|
||||||
|
rc |= command[i].cb(argv[j]);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[0] && strlen(argv[0]) > 0)
|
||||||
|
errx(1, "No such command. See 'initctl help' for an overview of available commands.");
|
||||||
|
|
||||||
|
return command[0].cb(NULL); /* default cmd */
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct command command[] = {
|
|
||||||
{ "debug", toggle_debug },
|
|
||||||
{ "devel", do_devel },
|
|
||||||
{ "help", do_help },
|
|
||||||
{ "version", show_version },
|
|
||||||
|
|
||||||
{ "list", serv_list },
|
|
||||||
{ "ls", serv_list },
|
|
||||||
{ "enable", serv_enable },
|
|
||||||
{ "disable", serv_disable },
|
|
||||||
{ "touch", serv_touch },
|
|
||||||
{ "show", serv_show },
|
|
||||||
{ "edit", serv_edit },
|
|
||||||
{ "create", serv_creat },
|
|
||||||
{ "delete", serv_delete },
|
|
||||||
{ "reload", do_reload },
|
|
||||||
|
|
||||||
{ "cond", do_cond },
|
|
||||||
|
|
||||||
{ "log", do_log },
|
|
||||||
{ "start", do_start },
|
|
||||||
{ "stop", do_stop },
|
|
||||||
{ "restart", do_restart },
|
|
||||||
{ "status", show_status },
|
|
||||||
{ "show", show_status }, /* Convenience alias, for now */
|
|
||||||
|
|
||||||
{ "ps", show_cgroup },
|
|
||||||
|
|
||||||
{ "runlevel", do_runlevel },
|
|
||||||
{ "reboot", do_reboot },
|
|
||||||
{ "halt", do_halt },
|
|
||||||
{ "poweroff", do_poweroff },
|
|
||||||
{ "suspend", do_suspend },
|
|
||||||
|
|
||||||
{ "utmp", do_utmp },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
{ "batch", 0, NULL, 'b' },
|
{ "batch", 0, NULL, 'b' },
|
||||||
{ "create", 0, NULL, 'c' },
|
{ "create", 0, NULL, 'c' },
|
||||||
{ "force", 0, NULL, 'f' },
|
{ "force", 0, NULL, 'f' },
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
|
{ "once", 0, NULL, '1' },
|
||||||
|
{ "plain", 0, NULL, 'p' },
|
||||||
{ "no-heading", 0, NULL, 't' },
|
{ "no-heading", 0, NULL, 't' },
|
||||||
{ "verbose", 0, NULL, 'v' },
|
{ "verbose", 0, NULL, 'v' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
struct cmd cond[] = {
|
||||||
|
{ "status", NULL, do_cond_show }, /* default cmd */
|
||||||
|
{ "dump", NULL, do_cond_dump },
|
||||||
|
{ "set", NULL, do_cond_set },
|
||||||
|
{ "clr", NULL, do_cond_clr },
|
||||||
|
{ "clear", NULL, do_cond_clr },
|
||||||
|
{ NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
struct cmd command[] = {
|
||||||
|
{ "status", NULL, show_status }, /* default cmd */
|
||||||
|
|
||||||
|
{ "debug", NULL, toggle_debug },
|
||||||
|
{ "devel", NULL, do_devel },
|
||||||
|
{ "help", NULL, do_help },
|
||||||
|
{ "version", NULL, show_version },
|
||||||
|
|
||||||
|
{ "list", NULL, serv_list },
|
||||||
|
{ "ls", NULL, serv_list },
|
||||||
|
{ "enable", NULL, serv_enable },
|
||||||
|
{ "disable", NULL, serv_disable },
|
||||||
|
{ "touch", NULL, serv_touch },
|
||||||
|
{ "show", NULL, serv_show },
|
||||||
|
{ "edit", NULL, serv_edit },
|
||||||
|
{ "create", NULL, serv_creat },
|
||||||
|
{ "delete", NULL, serv_delete },
|
||||||
|
{ "reload", NULL, do_reload },
|
||||||
|
|
||||||
|
{ "cond", cond, NULL },
|
||||||
|
|
||||||
|
{ "log", NULL, do_log },
|
||||||
|
{ "start", NULL, do_start },
|
||||||
|
{ "stop", NULL, do_stop },
|
||||||
|
{ "restart", NULL, do_restart },
|
||||||
|
|
||||||
|
{ "ps", NULL, show_cgroup },
|
||||||
|
{ "top", NULL, show_cgtop },
|
||||||
|
|
||||||
|
{ "runlevel", NULL, do_runlevel },
|
||||||
|
{ "reboot", NULL, do_reboot },
|
||||||
|
{ "halt", NULL, do_halt },
|
||||||
|
{ "poweroff", NULL, do_poweroff },
|
||||||
|
{ "suspend", NULL, do_suspend },
|
||||||
|
|
||||||
|
{ "utmp", NULL, do_utmp },
|
||||||
|
{ NULL, NULL, NULL }
|
||||||
|
};
|
||||||
int interactive = 1, c;
|
int interactive = 1, c;
|
||||||
char *cmd;
|
|
||||||
|
|
||||||
if (transform(progname(argv[0])))
|
if (transform(progname(argv[0])))
|
||||||
return reboot_main(argc, argv);
|
return reboot_main(argc, argv);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "bcfh?tv", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "1bcfh?ptv", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
|
case '1':
|
||||||
|
ionce = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
interactive = 0;
|
interactive = 0;
|
||||||
break;
|
break;
|
||||||
@@ -879,6 +923,10 @@ int main(int argc, char *argv[])
|
|||||||
case '?':
|
case '?':
|
||||||
return usage(0);
|
return usage(0);
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
plain = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
heading = 0;
|
heading = 0;
|
||||||
break;
|
break;
|
||||||
@@ -892,10 +940,8 @@ int main(int argc, char *argv[])
|
|||||||
if (interactive)
|
if (interactive)
|
||||||
screen_init();
|
screen_init();
|
||||||
|
|
||||||
if (optind >= argc)
|
|
||||||
return show_status(NULL);
|
|
||||||
|
|
||||||
if (!has_utmp()) {
|
if (!has_utmp()) {
|
||||||
|
/* system w/o utmp support, disable 'utmp' command */
|
||||||
for (c = 0; command[c].cmd; c++) {
|
for (c = 0; command[c].cmd; c++) {
|
||||||
if (!string_compare(command[c].cmd, "utmp"))
|
if (!string_compare(command[c].cmd, "utmp"))
|
||||||
continue;
|
continue;
|
||||||
@@ -905,26 +951,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = argv[optind++];
|
return cmd_parse(argc - optind, &argv[optind], command);
|
||||||
for (c = 0; command[c].cmd; c++) {
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
if (!string_match(command[c].cmd, cmd))
|
|
||||||
continue;
|
|
||||||
if (!command[c].cb)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* no arg, just a command, e.g. initctl ls */
|
|
||||||
if (optind >= argc)
|
|
||||||
return command[c].cb(NULL);
|
|
||||||
|
|
||||||
/* >=1 arg, e.g., initctl del foo bar baz */
|
|
||||||
while (optind < argc)
|
|
||||||
rc |= command[c].cb(argv[optind++]);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return usage(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void logit(int prio, const char *fmt, ...)
|
void logit(int prio, const char *fmt, ...)
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FINIT_INITCTL_H_
|
||||||
|
#define FINIT_INITCTL_H_
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
extern int icreate; /* initctl -c */
|
||||||
|
extern int iforce; /* initctl -f */
|
||||||
|
extern int ionce; /* initctl -1 */
|
||||||
|
extern int heading; /* initctl -t */
|
||||||
|
extern int verbose; /* initctl -v */
|
||||||
|
extern int plain; /* initctl -p */
|
||||||
|
|
||||||
|
extern void print_header(const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif /* FINIT_INITCTL_H_ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+1
-1
@@ -80,7 +80,7 @@ int logrotate(char *file, int num, off_t sz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cnt == 2 && fexist(nfile)) {
|
if (cnt == 2 && fexist(nfile)) {
|
||||||
if (systemf("gzip %s", nfile))
|
if (systemf("gzip %s 2>/dev/null", nfile))
|
||||||
continue; /* no gzip, probably */
|
continue; /* no gzip, probably */
|
||||||
|
|
||||||
(void)remove(nfile);
|
(void)remove(nfile);
|
||||||
|
|||||||
@@ -95,18 +95,15 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
|
|||||||
|
|
||||||
char *pid_file(svc_t *svc)
|
char *pid_file(svc_t *svc)
|
||||||
{
|
{
|
||||||
static char path[256];
|
|
||||||
char fn[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
if (svc->pidfile[0]) {
|
if (svc->pidfile[0]) {
|
||||||
if (svc->pidfile[0] == '!')
|
if (svc->pidfile[0] == '!')
|
||||||
return &svc->pidfile[1];
|
return &svc->pidfile[1];
|
||||||
return svc->pidfile;
|
return svc->pidfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(fn, sizeof(fn), "%s%s.pid", _PATH_VARRUN, basename(svc->cmd));
|
errno = ENOENT;
|
||||||
|
|
||||||
return pid_runpath(fn, path, sizeof(path));
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t pid_file_read(const char *fn)
|
pid_t pid_file_read(const char *fn)
|
||||||
@@ -143,12 +140,13 @@ int pid_file_create(svc_t *svc)
|
|||||||
return fclose(fp);
|
return fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pid_realpath(svc_t *svc, char *file)
|
int pid_file_set(svc_t *svc, char *file, int not)
|
||||||
{
|
{
|
||||||
int not = 0;
|
if (!file) {
|
||||||
|
|
||||||
if (!file)
|
|
||||||
file = pid_file(svc);
|
file = pid_file(svc);
|
||||||
|
if (!file)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (file[0] == '!') {
|
if (file[0] == '!') {
|
||||||
not = 1;
|
not = 1;
|
||||||
@@ -202,7 +200,7 @@ int pid_file_parse(svc_t *svc, char *arg)
|
|||||||
|
|
||||||
arg += 4;
|
arg += 4;
|
||||||
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
||||||
return pid_realpath(svc, arg);
|
return pid_file_set(svc, arg, 0);
|
||||||
|
|
||||||
if (arg[0] == '!') {
|
if (arg[0] == '!') {
|
||||||
arg++;
|
arg++;
|
||||||
@@ -213,12 +211,12 @@ int pid_file_parse(svc_t *svc, char *arg)
|
|||||||
if (len > 4 && strcmp(&path[len - 4], ".pid"))
|
if (len > 4 && strcmp(&path[len - 4], ".pid"))
|
||||||
strlcat(path, ".pid", sizeof(path));
|
strlcat(path, ".pid", sizeof(path));
|
||||||
|
|
||||||
return pid_realpath(svc, path);
|
return pid_file_set(svc, path, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 'pid' arg, no argument following */
|
/* 'pid' arg, no argument following */
|
||||||
if (!strcmp(arg, "pid"))
|
if (!strcmp(arg, "pid"))
|
||||||
return pid_realpath(svc, NULL);
|
return pid_file_set(svc, NULL, 0);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ int pid_alive (pid_t pid);
|
|||||||
char *pid_get_name (pid_t pid, char *name, size_t len);
|
char *pid_get_name (pid_t pid, char *name, size_t len);
|
||||||
|
|
||||||
char *pid_file (svc_t *svc);
|
char *pid_file (svc_t *svc);
|
||||||
|
int pid_file_set (svc_t *svc, char *file, int not);
|
||||||
pid_t pid_file_read (const char *fn);
|
pid_t pid_file_read (const char *fn);
|
||||||
int pid_file_create (svc_t *svc);
|
int pid_file_create (svc_t *svc);
|
||||||
int pid_file_parse (svc_t *svc, char *arg);
|
int pid_file_parse (svc_t *svc, char *arg);
|
||||||
|
|||||||
+22
-7
@@ -30,10 +30,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "initctl.h"
|
||||||
|
|
||||||
extern int icreate; /* initctl -c */
|
|
||||||
extern int iforce; /* initctl -f */
|
|
||||||
|
|
||||||
|
|
||||||
static int calc_width(char *arr[], size_t len)
|
static int calc_width(char *arr[], size_t len)
|
||||||
@@ -53,7 +50,7 @@ static int calc_width(char *arr[], size_t len)
|
|||||||
|
|
||||||
static void do_list(const char *path)
|
static void do_list(const char *path)
|
||||||
{
|
{
|
||||||
char buf[screen_cols];
|
static int once = 0;
|
||||||
int width, num, prev;
|
int width, num, prev;
|
||||||
glob_t gl;
|
glob_t gl;
|
||||||
size_t i;
|
size_t i;
|
||||||
@@ -67,8 +64,26 @@ static void do_list(const char *path)
|
|||||||
if (gl.gl_pathc <= 0)
|
if (gl.gl_pathc <= 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%s ", path);
|
if (plain) {
|
||||||
printheader(NULL, buf, 0);
|
if (heading)
|
||||||
|
print_header("%s%s ", once ? "\n" : "", path);
|
||||||
|
once++;
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
if (!heading) {
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
paste(buf, sizeof(buf), path, gl.gl_pathv[i]);
|
||||||
|
puts(buf);
|
||||||
|
} else
|
||||||
|
puts(gl.gl_pathv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heading)
|
||||||
|
print_header("%s ", path);
|
||||||
|
|
||||||
width = calc_width(gl.gl_pathv, gl.gl_pathc);
|
width = calc_width(gl.gl_pathv, gl.gl_pathc);
|
||||||
if (width <= 0)
|
if (width <= 0)
|
||||||
|
|||||||
+54
-44
@@ -49,8 +49,6 @@
|
|||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
|
|
||||||
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
|
|
||||||
|
|
||||||
static struct wq work = {
|
static struct wq work = {
|
||||||
.cb = service_worker,
|
.cb = service_worker,
|
||||||
};
|
};
|
||||||
@@ -262,37 +260,6 @@ static int redirect(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* non-zero env, no checking if file exists or not
|
|
||||||
*/
|
|
||||||
static char *svc_getenv(svc_t *svc)
|
|
||||||
{
|
|
||||||
int v = 0;
|
|
||||||
|
|
||||||
if (!svc->env[0])
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (svc->env[0] == '-')
|
|
||||||
v = 1;
|
|
||||||
|
|
||||||
return &svc->env[v];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if svc has env, if env file exists returns true
|
|
||||||
* if it doesn't exist, but has '-', also true. if svc
|
|
||||||
* doesn't have env, also true.
|
|
||||||
*/
|
|
||||||
static int check_env(svc_t *svc)
|
|
||||||
{
|
|
||||||
char *env = svc_getenv(svc);
|
|
||||||
|
|
||||||
if (!env)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return fexist(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Source environment file, if it exists
|
* Source environment file, if it exists
|
||||||
* Note: must be called from privsepped child
|
* Note: must be called from privsepped child
|
||||||
@@ -309,7 +276,7 @@ static void source_env(svc_t *svc)
|
|||||||
if (!fn)
|
if (!fn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Warning in service_start() after check_env() */
|
/* Warning in service_start() after svc_checkenv() */
|
||||||
fp = fopen(fn, "r");
|
fp = fopen(fn, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return;
|
return;
|
||||||
@@ -384,6 +351,30 @@ static int is_norespawn(void)
|
|||||||
fexist("/tmp/norespawn");
|
fexist("/tmp/norespawn");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* used for process group name, derived from originating filename,
|
||||||
|
* so to group multiple services, place them in the same .conf
|
||||||
|
*/
|
||||||
|
static char *group_name(svc_t *svc, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (!svc->file[0])
|
||||||
|
return svc_ident(svc, buf, len);
|
||||||
|
|
||||||
|
ptr = strrchr(svc->file, '/');
|
||||||
|
if (ptr)
|
||||||
|
ptr++;
|
||||||
|
else
|
||||||
|
ptr = svc->file;
|
||||||
|
|
||||||
|
strlcpy(buf, ptr, len);
|
||||||
|
ptr = strstr(buf, ".conf");
|
||||||
|
if (ptr)
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* service_start - Start service
|
* service_start - Start service
|
||||||
* @svc: Service to start
|
* @svc: Service to start
|
||||||
@@ -395,6 +386,7 @@ static int service_start(svc_t *svc)
|
|||||||
{
|
{
|
||||||
int result = 0, do_progress = 1;
|
int result = 0, do_progress = 1;
|
||||||
sigset_t nmask, omask;
|
sigset_t nmask, omask;
|
||||||
|
char grnam[80];
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@@ -407,14 +399,15 @@ static int service_start(svc_t *svc)
|
|||||||
|
|
||||||
/* Don't try and start service if it doesn't exist. */
|
/* Don't try and start service if it doesn't exist. */
|
||||||
if (!whichp(svc->cmd)) {
|
if (!whichp(svc->cmd)) {
|
||||||
print(1, "%s: does not exist", svc->cmd);
|
logit(LOG_WARNING, "%s: missing or not in $PATH", svc->cmd);
|
||||||
svc_missing(svc);
|
svc_missing(svc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlike systemd we do not allow starting service if env is missing, unless - */
|
/* Unlike systemd we do not allow starting service if env is missing, unless - */
|
||||||
if (!check_env(svc)) {
|
if (!svc_checkenv(svc)) {
|
||||||
print(1, "%s: environment file %s does not exist (yet)", svc->cmd, svc->env);
|
logit(LOG_WARNING, "%s: missing env file %s", svc->cmd, svc->env);
|
||||||
|
svc_missing(svc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,8 +433,6 @@ static int service_start(svc_t *svc)
|
|||||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
cgroup_service(svc->name, svc->id, pid);
|
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
int status;
|
int status;
|
||||||
char *home = NULL;
|
char *home = NULL;
|
||||||
@@ -579,6 +570,8 @@ static int service_start(svc_t *svc)
|
|||||||
_d("Starting %s %s", svc->cmd, buf);
|
_d("Starting %s %s", svc->cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid);
|
||||||
|
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
|
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
|
||||||
|
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
@@ -648,11 +641,12 @@ static void service_cleanup(svc_t *svc)
|
|||||||
char *fn;
|
char *fn;
|
||||||
|
|
||||||
fn = pid_file(svc);
|
fn = pid_file(svc);
|
||||||
if (remove(fn) && errno != ENOENT)
|
if (fn && remove(fn) && errno != ENOENT)
|
||||||
logit(LOG_CRIT, "Failed removing service %s pidfile %s",
|
logit(LOG_CRIT, "Failed removing service %s pidfile %s",
|
||||||
basename(svc->cmd), fn);
|
basename(svc->cmd), fn);
|
||||||
|
|
||||||
/* No longer running, update books. */
|
/* No longer running, update books. */
|
||||||
|
svc->oldpid = svc->pid;
|
||||||
svc->start_time = svc->pid = 0;
|
svc->start_time = svc->pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1127,6 +1121,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
|
|
||||||
if (type == SVC_TYPE_SERVICE && manual)
|
if (type == SVC_TYPE_SERVICE && manual)
|
||||||
svc_stop(svc);
|
svc_stop(svc);
|
||||||
|
} else {
|
||||||
|
/* e.g., if missing cmd or env before */
|
||||||
|
svc_unblock(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always clear svc PID file, for now. See TODO */
|
/* Always clear svc PID file, for now. See TODO */
|
||||||
@@ -1143,6 +1140,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
strlcpy(svc->group, ptr, sizeof(svc->group));
|
strlcpy(svc->group, ptr, sizeof(svc->group));
|
||||||
}
|
}
|
||||||
strlcpy(svc->username, username, sizeof(svc->username));
|
strlcpy(svc->username, username, sizeof(svc->username));
|
||||||
|
} else {
|
||||||
|
getcuser(svc->username, sizeof(svc->username));
|
||||||
|
getcgroup(svc->group, sizeof(svc->group));
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_cmdline_args(svc, cmd);
|
parse_cmdline_args(svc, cmd);
|
||||||
@@ -1229,6 +1229,7 @@ void service_monitor(pid_t lost, int status)
|
|||||||
if (svc_is_daemon(svc)) {
|
if (svc_is_daemon(svc)) {
|
||||||
service_cleanup(svc);
|
service_cleanup(svc);
|
||||||
} else if (svc_is_runtask(svc)) {
|
} else if (svc_is_runtask(svc)) {
|
||||||
|
/* run/task should run at least once per runlevel */
|
||||||
if (WIFEXITED(status) && !WEXITSTATUS(status))
|
if (WIFEXITED(status) && !WEXITSTATUS(status))
|
||||||
svc->started = 1;
|
svc->started = 1;
|
||||||
else
|
else
|
||||||
@@ -1296,7 +1297,7 @@ static void service_retry(svc_t *svc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*restart_cnt >= RESPAWN_MAX) {
|
if (*restart_cnt >= SVC_RESPAWN_MAX) {
|
||||||
logit(LOG_CONSOLE | LOG_WARNING, "Service %s keeps crashing, not restarting.",
|
logit(LOG_CONSOLE | LOG_WARNING, "Service %s keeps crashing, not restarting.",
|
||||||
svc_ident(svc, NULL, 0));
|
svc_ident(svc, NULL, 0));
|
||||||
svc_crashing(svc);
|
svc_crashing(svc);
|
||||||
@@ -1309,12 +1310,12 @@ static void service_retry(svc_t *svc)
|
|||||||
|
|
||||||
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
|
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
|
||||||
logit(LOG_CONSOLE | LOG_WARNING, "Service %s[%d] died, restarting (%d/%d)",
|
logit(LOG_CONSOLE | LOG_WARNING, "Service %s[%d] died, restarting (%d/%d)",
|
||||||
svc_ident(svc, NULL, 0), svc->pid, *restart_cnt, RESPAWN_MAX);
|
svc_ident(svc, NULL, 0), svc->oldpid, *restart_cnt, SVC_RESPAWN_MAX);
|
||||||
svc_unblock(svc);
|
svc_unblock(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
/* Wait 2s for the first 5 respawns, then back off to 5s */
|
/* Wait 2s for the first 5 respawns, then back off to 5s */
|
||||||
timeout = ((*restart_cnt) <= (RESPAWN_MAX / 2)) ? 2000 : 5000;
|
timeout = ((*restart_cnt) <= (SVC_RESPAWN_MAX / 2)) ? 2000 : 5000;
|
||||||
service_timeout_after(svc, timeout, service_retry);
|
service_timeout_after(svc, timeout, service_retry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1368,10 +1369,15 @@ restart:
|
|||||||
|
|
||||||
case SVC_STOPPING_STATE:
|
case SVC_STOPPING_STATE:
|
||||||
if (!svc->pid) {
|
if (!svc->pid) {
|
||||||
|
char cond[MAX_COND_LEN];
|
||||||
|
|
||||||
/* PID was collected normally, no need to kill it */
|
/* PID was collected normally, no need to kill it */
|
||||||
_d("%s: Stopped normally, no need to send SIGKILL :)", svc->cmd);
|
_d("%s: stopped normally, no need to send SIGKILL :)", svc->cmd);
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
|
|
||||||
|
_d("%s: clearing pid condition ...", svc->name);
|
||||||
|
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
||||||
|
|
||||||
switch (svc->type) {
|
switch (svc->type) {
|
||||||
case SVC_TYPE_SERVICE:
|
case SVC_TYPE_SERVICE:
|
||||||
svc_set_state(svc, SVC_HALTED_STATE);
|
svc_set_state(svc, SVC_HALTED_STATE);
|
||||||
@@ -1400,6 +1406,10 @@ restart:
|
|||||||
|
|
||||||
err = service_start(svc);
|
err = service_start(svc);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
if (svc_is_missing(svc)) {
|
||||||
|
svc_set_state(svc, SVC_HALTED_STATE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
(*restart_cnt)++;
|
(*restart_cnt)++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,10 +192,10 @@ void do_kill(int signo)
|
|||||||
if (fgets(file, sizeof(file), fp)) {
|
if (fgets(file, sizeof(file), fp)) {
|
||||||
if (strstr(file, "gdbserver"))
|
if (strstr(file, "gdbserver"))
|
||||||
_d("Skipping %s ...", file);
|
_d("Skipping %s ...", file);
|
||||||
else if (file[0] != '@')
|
else if (file[0] == '@')
|
||||||
kill(pid, signo);
|
|
||||||
else
|
|
||||||
_d("Skipping %s ...", &file[1]);
|
_d("Skipping %s ...", &file[1]);
|
||||||
|
else
|
||||||
|
kill(pid, signo);
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
@@ -214,11 +214,11 @@ void do_shutdown(shutop_t op)
|
|||||||
utmp_set_halt();
|
utmp_set_halt();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell all remaining non-monitored processes to exit, give them
|
* Tell remaining non-monitored processes to exit, give them
|
||||||
* some time to exit gracefully, 2 sec is customary.
|
* time to exit gracefully, 2 sec was customary, we go for 1.
|
||||||
*/
|
*/
|
||||||
do_kill(SIGTERM);
|
do_kill(SIGTERM);
|
||||||
do_sleep(2);
|
do_sleep(1);
|
||||||
do_kill(SIGKILL);
|
do_kill(SIGKILL);
|
||||||
|
|
||||||
/* Exit plugins and API gracefully */
|
/* Exit plugins and API gracefully */
|
||||||
@@ -274,15 +274,15 @@ void do_shutdown(shutop_t op)
|
|||||||
do_sleep(1);
|
do_sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_e("Rebooting ...");
|
_d("Rebooting ...");
|
||||||
reboot(RB_AUTOBOOT);
|
reboot(RB_AUTOBOOT);
|
||||||
} else if (op == SHUT_OFF) {
|
} else if (op == SHUT_OFF) {
|
||||||
_e("Powering down ...");
|
_d("Powering down ...");
|
||||||
reboot(RB_POWER_OFF);
|
reboot(RB_POWER_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Also fallback if any of the other two fails */
|
/* Also fallback if any of the other two fails */
|
||||||
_e("Halting ...");
|
_d("Halting ...");
|
||||||
reboot(RB_HALT_SYSTEM);
|
reboot(RB_HALT_SYSTEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -156,9 +156,11 @@ restart:
|
|||||||
/* Disable login in single-user mode as well as shutdown/reboot */
|
/* Disable login in single-user mode as well as shutdown/reboot */
|
||||||
nologin();
|
nologin();
|
||||||
|
|
||||||
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
if (runlevel != 0 && runlevel != 6) {
|
||||||
if (conf_any_change())
|
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||||
conf_reload();
|
if (conf_any_change())
|
||||||
|
conf_reload();
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset once flag of runtasks */
|
/* Reset once flag of runtasks */
|
||||||
service_runtask_clean();
|
service_runtask_clean();
|
||||||
|
|||||||
@@ -415,8 +415,20 @@ svc_t *svc_find_by_pidfile(char *fn)
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = pid_file_read(fn);
|
pid = pid_file_read(fn);
|
||||||
if (pid == -1)
|
if (pid <= 0) {
|
||||||
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
|
int v = 0;
|
||||||
|
|
||||||
|
if (svc->pidfile[0] == '!')
|
||||||
|
v = 1;
|
||||||
|
if (strcmp(&svc->pidfile[v], fn))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->pid != pid)
|
if (svc->pid != pid)
|
||||||
@@ -532,6 +544,9 @@ int svc_enabled(svc_t *svc)
|
|||||||
if (svc_is_removed(svc) || svc_is_blocked(svc))
|
if (svc_is_removed(svc) || svc_is_blocked(svc))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (svc_is_missing(svc))
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ typedef enum {
|
|||||||
/* Default kill delay (msec) after SIGTERM (svc->sighalt) that we SIGKILL processes */
|
/* Default kill delay (msec) after SIGTERM (svc->sighalt) that we SIGKILL processes */
|
||||||
#define SVC_TERM_TIMEOUT 3000
|
#define SVC_TERM_TIMEOUT 3000
|
||||||
|
|
||||||
|
/* Prevent endless respawn of faulty services. */
|
||||||
|
#define SVC_RESPAWN_MAX 10
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default enable for all services, can be stopped by means
|
* Default enable for all services, can be stopped by means
|
||||||
* of issuing an initctl call. E.g.
|
* of issuing an initctl call. E.g.
|
||||||
@@ -95,7 +98,7 @@ typedef struct svc {
|
|||||||
/* Service details */
|
/* Service details */
|
||||||
int sighalt; /* Signal to stop prorcess, default: SIGTERM */
|
int sighalt; /* Signal to stop prorcess, default: SIGTERM */
|
||||||
int killdelay; /* Delay in msec before sending SIGKILL */
|
int killdelay; /* Delay in msec before sending SIGKILL */
|
||||||
pid_t pid;
|
pid_t oldpid, pid;
|
||||||
char pidfile[256];
|
char pidfile[256];
|
||||||
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
||||||
int started; /* Set for run/task/sysv to track if started */
|
int started; /* Set for run/task/sysv to track if started */
|
||||||
@@ -194,12 +197,14 @@ static inline void svc_starting (svc_t *svc) { if (svc) svc->starting = 1;
|
|||||||
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
||||||
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
|
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
|
||||||
|
|
||||||
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
||||||
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
||||||
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
||||||
|
|
||||||
static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; }
|
static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; }
|
||||||
static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; }
|
static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; }
|
||||||
|
static inline int svc_is_missing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_MISSING; }
|
||||||
|
|
||||||
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
|
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
|
||||||
#define svc_start(svc) svc_unblock(svc)
|
#define svc_start(svc) svc_unblock(svc)
|
||||||
static inline void svc_stop (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_USER; }
|
static inline void svc_stop (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_USER; }
|
||||||
@@ -347,6 +352,37 @@ static inline char *svc_jobid(svc_t *svc, char *buf, size_t len)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* non-zero env, no checking if file exists or not
|
||||||
|
*/
|
||||||
|
static inline char *svc_getenv(svc_t *svc)
|
||||||
|
{
|
||||||
|
int v = 0;
|
||||||
|
|
||||||
|
if (!svc->env[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (svc->env[0] == '-')
|
||||||
|
v = 1;
|
||||||
|
|
||||||
|
return &svc->env[v];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if svc has env, if env file exists returns true
|
||||||
|
* if it doesn't exist, but has '-', also true. if svc
|
||||||
|
* doesn't have env, also true.
|
||||||
|
*/
|
||||||
|
static inline int svc_checkenv(svc_t *svc)
|
||||||
|
{
|
||||||
|
char *env = svc_getenv(svc);
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return fexist(env);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FINIT_SVC_H_ */
|
#endif /* FINIT_SVC_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user