mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
45
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccfea59cb3 | ||
|
|
7b315364ca | ||
|
|
e9e28ece1c | ||
|
|
c1f9b4e1f6 | ||
|
|
6ebb23e0f0 | ||
|
|
026c229005 | ||
|
|
4d05bf9359 | ||
|
|
289247dab9 | ||
|
|
e44dfde54e | ||
|
|
35b200d3a9 | ||
|
|
5badf4d376 | ||
|
|
24f274c126 | ||
|
|
1abd43384b | ||
|
|
70a1acc210 | ||
|
|
6af0446490 | ||
|
|
ecaf111a4b | ||
|
|
32ec25b070 | ||
|
|
305ad302f2 | ||
|
|
d6390244ad | ||
|
|
790a316607 | ||
|
|
77aa941e84 | ||
|
|
e0a65f67c9 | ||
|
|
3ed291789c | ||
|
|
774a24cdd8 | ||
|
|
6011f91f22 | ||
|
|
07a364e570 | ||
|
|
5b9d99011b | ||
|
|
f4f773b4c7 | ||
|
|
9d949c4186 | ||
|
|
1434561a46 | ||
|
|
cf3d3f6f8e | ||
|
|
621da582c2 | ||
|
|
9167d9255d | ||
|
|
c71bafd495 | ||
|
|
b3b7a33252 | ||
|
|
d1efc60c84 | ||
|
|
9a24dfd98d | ||
|
|
0e3fe5e3bf | ||
|
|
224f42c344 | ||
|
|
e60eb94810 | ||
|
|
464bc831a5 | ||
|
|
e84911fe52 | ||
|
|
4bcfd606b4 | ||
|
|
fe27ed17eb | ||
|
|
b3ea23ed26 |
+2
-5
@@ -5,9 +5,6 @@ language: c
|
||||
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
|
||||
sudo: false
|
||||
|
||||
# Use non-docker builds atm. to install libuEv and libite from source
|
||||
#sudo: true
|
||||
|
||||
# Test build with both GCC and Clang (LLVM)
|
||||
compiler:
|
||||
- gcc
|
||||
@@ -30,7 +27,7 @@ addons:
|
||||
name: "troglobit/finit"
|
||||
description: "finit | Fast & Extensible init for Linux"
|
||||
notification_email: troglobit@gmail.com
|
||||
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp"
|
||||
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp --disable-doc --disable-contrib --enable-watchdog --enable-fallback-shell"
|
||||
build_command: "make"
|
||||
branch_pattern: dev
|
||||
|
||||
@@ -48,7 +45,7 @@ script:
|
||||
- ./configure --prefix=/tmp --enable-static
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
- ./configure --prefix=/tmp --enable-x11-common-plugin --enable-fallback-shell --enable-watchdog --enable-logit
|
||||
- ./configure --prefix=/tmp --enable-x11-common-plugin --enable-fallback-shell --enable-watchdog
|
||||
- cat config.log
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
|
||||
-16
@@ -29,19 +29,3 @@ release: distcheck
|
||||
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
|
||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||
done
|
||||
|
||||
run:
|
||||
srcdir=@srcdir@/test \
|
||||
top_builddir=@top_builddir@ \
|
||||
TENV_ROOT=$(tenv_root) \
|
||||
@srcdir@/test/setup-root.sh
|
||||
|
||||
mkdir -p $(dir $(tenv_root)/@FINIT_CONF@)
|
||||
echo 'tty [12345] @console linux noclear nologin' > $(tenv_root)/@FINIT_CONF@
|
||||
|
||||
-TENV_ROOT=$(tenv_root) \
|
||||
TESTENV_PATH=@sbindir@:/bin \
|
||||
FINIT_RCSD=@FINIT_RCSD@ \
|
||||
test/tenv/start.sh finit
|
||||
|
||||
run : tenv_root ?= @abs_top_builddir@/run-rootfs
|
||||
|
||||
@@ -26,6 +26,9 @@ Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
||||
was reverse engineered from the [EeePC fastinit][] over ten years ago
|
||||
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
||||
|
||||

|
||||
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
||||
|
||||
Focus is on small and embedded systems, although Finit is fully usable
|
||||
on server and desktop systems as well. For working examples, see the
|
||||
[contrib/](contrib/) section with tutorials for:
|
||||
@@ -34,9 +37,6 @@ on server and desktop systems as well. For working examples, see the
|
||||
* [Alpine Linux](contrib/alpine/), and
|
||||
* [Debian GNU/Linux](contrib/debian/)
|
||||
|
||||

|
||||
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
@@ -348,11 +348,15 @@ Finit also implements a modern API to query status, and start/stop
|
||||
services, called `initctl`. Unlike `telinit` the `initctl` tool does
|
||||
not return until the given command has fully completed.
|
||||
|
||||
```shell
|
||||
~ $ initctl -h
|
||||
```
|
||||
alpine:~# initctl help
|
||||
Usage: initctl [OPTIONS] [COMMAND]
|
||||
|
||||
Options:
|
||||
-b, --batch Batch mode, no screen size probing
|
||||
-c, --create Create missing paths (and files) as needed
|
||||
-f, --force Ignore missing files and arguments, never prompt
|
||||
-t, --no-heading Skip table headings
|
||||
-v, --verbose Verbose output
|
||||
-h, --help This help text
|
||||
|
||||
@@ -360,29 +364,34 @@ Commands:
|
||||
debug Toggle Finit (daemon) debug
|
||||
help This help text
|
||||
version Show Finit version
|
||||
|
||||
list List all .conf in /etc/finit.d/
|
||||
enable <CONF> Enable .conf in /etc/finit.d/available/
|
||||
disable <CONF> Disable .conf in /etc/finit.d/[enabled/]
|
||||
touch <CONF> Mark .conf in /etc/finit.d/ for reload
|
||||
reload Reload *.conf in /etc/finit.d/ (activates changes)
|
||||
|
||||
|
||||
ls | list List all .conf in /etc/finit.d
|
||||
create <CONF> Create .conf in /etc/finit.d/available
|
||||
delete <CONF> Delete .conf in /etc/finit.d/available
|
||||
show <CONF> Show .conf in /etc/finit.d/available
|
||||
edit <CONF> Edit .conf in /etc/finit.d/available
|
||||
touch <CONF> Change .conf in /etc/finit.d/available
|
||||
enable <CONF> Enable .conf in /etc/finit.d/available
|
||||
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
||||
reload Reload *.conf in /etc/finit.d (activate changes)
|
||||
|
||||
cond show Show condition status
|
||||
cond dump Dump all conditions and their status
|
||||
|
||||
|
||||
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
||||
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
|
||||
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
|
||||
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
||||
status <JOB|NAME>[:ID] Show service status, by job# or name
|
||||
status | show Show status of services, default command
|
||||
|
||||
start <NAME>[:ID] Start service by name, with optional ID
|
||||
stop <NAME>[:ID] Stop/Pause a running service by name
|
||||
restart <NAME>[:ID] Restart (stop/start) service by name
|
||||
status <NAME>[:ID] Show service status, by name
|
||||
status Show status of services, default command
|
||||
|
||||
ps List processes based on cgroups
|
||||
|
||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||
reboot Reboot system
|
||||
halt Halt system
|
||||
poweroff Halt and power off system
|
||||
|
||||
utmp show Raw dump of UTMP/WTMP db
|
||||
suspend Suspend system
|
||||
```
|
||||
|
||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||
@@ -395,18 +404,31 @@ the current runlevel these services will not be respawned automatically
|
||||
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||
Dropbear SSH service will not be restarted if it is killed or exits.
|
||||
|
||||
```shell
|
||||
~ $ initctl status -v
|
||||
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
|
||||
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
|
||||
3 running 478 [S12345] /sbin/klogd -n
|
||||
4:1 inetd 0 [2345] internal time allow *:37,!eth0
|
||||
4:2 inetd 0 [2345] internal time allow eth0:3737
|
||||
5:1 inetd 0 [2345] /sbin/telnetd allow *:23 deny eth0,eth1
|
||||
5:2 inetd 0 [2345] /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
|
||||
6:1 inetd 0 [345] /sbin/dropbear allow eth0:222
|
||||
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
|
||||
```
|
||||
alpine:~# initctl
|
||||
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
||||
======================================================================
|
||||
1506 acpid running [--2345----] ACPI daemon
|
||||
1509 crond running [--2345----] Cron daemon
|
||||
1489 dropbear running [--2345----] Dropbear SSH daemon
|
||||
1511 klogd running [S12345----] Kernel log daemon
|
||||
1512 ntpd running [--2345----] NTP daemon
|
||||
1473 syslogd running [S12345----] Syslog daemon
|
||||
|
||||
alpine:~# initctl -v
|
||||
PID IDENT STATUS RUNLEVELS COMMAND
|
||||
======================================================================
|
||||
1506 acpid running [--2345----] acpid -f
|
||||
1509 crond running [--2345----] crond -f -S $CRON_OPTS
|
||||
1489 dropbear running [--2345----] dropbear -R -F $DROPBEAR_OPTS
|
||||
1511 klogd running [S12345----] klogd -n $KLOGD_OPTS
|
||||
1512 ntpd running [--2345----] ntpd -n $NTPD_OPTS
|
||||
1473 syslogd running [S12345----] syslogd -n
|
||||
```
|
||||
|
||||
The environment variables to each of the services above are read from,
|
||||
in the case of Alpine Linux, `/etc/conf.d/`. Other distributions may
|
||||
have other directories, e.g., Debian use `/etc/default/`.
|
||||
|
||||
|
||||
Requirements
|
||||
@@ -473,6 +495,6 @@ and proposed extensions.
|
||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||
[Travis]: https://travis-ci.org/troglobit/finit
|
||||
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
|
||||
[Travis Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
|
||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||
|
||||
+5
-6
@@ -1,4 +1,4 @@
|
||||
AC_INIT(Finit, 4.0-rc1, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||
AC_INIT(Finit, 4.0-rc2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -32,7 +32,7 @@ AC_PROG_MKDIR_P
|
||||
|
||||
# Configuration.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([fstaby.h termios.h])
|
||||
AC_CHECK_HEADERS([fstaby.h termios.h sys/ioctl.h])
|
||||
AC_CHECK_FUNCS([strstr getopt getfsenty])
|
||||
|
||||
# Check for uint[8,16,32]_t
|
||||
@@ -153,6 +153,8 @@ AS_IF([test "x$enable_logit" != "xno"], [
|
||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||
|
||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$with_config" != "xno"], [
|
||||
AS_IF([test "x$conf" = "xyes"], [
|
||||
@@ -224,9 +226,6 @@ AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
|
||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||
|
||||
AC_EXPAND_DIR(path_stdpath, "$sbindir:$bindir:/usr/sbin:/usr/bin:/sbin:/bin")
|
||||
AC_DEFINE_UNQUOTED(_PATH_STDPATH, "$path_stdpath", [Default PATH])
|
||||
|
||||
# Generate all files
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -235,7 +234,7 @@ cat <<EOF
|
||||
------------------ Summary ------------------
|
||||
$PACKAGE_NAME version $PACKAGE_VERSION
|
||||
Prefix................: $prefix
|
||||
Exec prefix...........: `eval echo $exec_prefix`
|
||||
Exec prefix...........: $eprefix
|
||||
Sysconfdir............: `eval echo $sysconfdir`
|
||||
Localstatedir.........: `eval echo $localstatedir`
|
||||
Finit config file.....: $conf_path
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ The current state depends on the two following conditions:
|
||||
|
||||
A service may be stopped, or blocked, for several reasons:
|
||||
|
||||
- The user has manually stopped the service using `initctl stop JOB`
|
||||
- The user has manually stopped the service using `initctl stop NAME`
|
||||
- The program exits immediately. I.e. keeps crashing (make sure to use
|
||||
the 'run this service in the foreground' command line option)
|
||||
- The binary is missing in the filesystem
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
+75
-40
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <sys/socket.h>
|
||||
@@ -48,7 +49,7 @@ static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_route(struct nlmsghdr *nlmsg)
|
||||
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
{
|
||||
struct rtmsg *r;
|
||||
struct rtattr *a;
|
||||
@@ -63,8 +64,14 @@ static void nl_route(struct nlmsghdr *nlmsg)
|
||||
r = NLMSG_DATA(nlmsg);
|
||||
a = RTM_RTA(r);
|
||||
la = RTM_PAYLOAD(nlmsg);
|
||||
if (la >= len) {
|
||||
_e("Packet too large!");
|
||||
return;
|
||||
}
|
||||
|
||||
while (RTA_OK(a, la)) {
|
||||
void *data = RTA_DATA(a);
|
||||
|
||||
switch (a->rta_type) {
|
||||
case RTA_GATEWAY:
|
||||
gw = *((int *)data);
|
||||
@@ -105,7 +112,27 @@ static void net_cond_set(char *ifname, char *cond, int set)
|
||||
cond_clear(msg);
|
||||
}
|
||||
|
||||
static void nl_link(struct nlmsghdr *nlmsg)
|
||||
static int validate_ifname(const char *ifname)
|
||||
{
|
||||
if (!ifname || !ifname[0])
|
||||
return 1;
|
||||
|
||||
if (strlen(ifname) >= IFNAMSIZ)
|
||||
return 1;
|
||||
|
||||
if (strstr(ifname, ".."))
|
||||
return 1;
|
||||
|
||||
while (*ifname) {
|
||||
if (*ifname == '/' || isspace(*ifname))
|
||||
return 1;
|
||||
ifname++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
{
|
||||
int la;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
@@ -120,53 +147,61 @@ static void nl_link(struct nlmsghdr *nlmsg)
|
||||
i = NLMSG_DATA(nlmsg);
|
||||
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
|
||||
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
|
||||
if (la >= len) {
|
||||
_e("Packet too large!");
|
||||
return;
|
||||
}
|
||||
|
||||
while (RTA_OK(a, la)) {
|
||||
if (a->rta_type == IFLA_IFNAME) {
|
||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||
switch (nlmsg->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
/*
|
||||
* New interface has appeared, or interface flags has changed.
|
||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||
*/
|
||||
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||
net_cond_set(ifname, "exist", 1);
|
||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||
break;
|
||||
for (; RTA_OK(a, la); a = RTA_NEXT(a, la)) {
|
||||
if (a->rta_type != IFLA_IFNAME)
|
||||
continue;
|
||||
|
||||
case RTM_DELLINK:
|
||||
/* NOTE: Interface has disappeared, not link down ... */
|
||||
_d("%s: Delete link", ifname);
|
||||
net_cond_set(ifname, "exist", 0);
|
||||
net_cond_set(ifname, "up", 0);
|
||||
net_cond_set(ifname, "running", 0);
|
||||
break;
|
||||
|
||||
case RTM_NEWADDR:
|
||||
_d("%s: New Address", ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELADDR:
|
||||
_d("%s: Deconfig Address", ifname);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||
if (validate_ifname(ifname)) {
|
||||
_d("Invalid interface name '%s', skipping ...", ifname);
|
||||
continue;
|
||||
}
|
||||
|
||||
a = RTA_NEXT(a, la);
|
||||
switch (nlmsg->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
/*
|
||||
* New interface has appeared, or interface flags has changed.
|
||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||
*/
|
||||
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||
net_cond_set(ifname, "exist", 1);
|
||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
/* NOTE: Interface has disappeared, not link down ... */
|
||||
_d("%s: Delete link", ifname);
|
||||
net_cond_set(ifname, "exist", 0);
|
||||
net_cond_set(ifname, "up", 0);
|
||||
net_cond_set(ifname, "running", 0);
|
||||
break;
|
||||
|
||||
case RTM_NEWADDR:
|
||||
_d("%s: New Address", ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELADDR:
|
||||
_d("%s: Deconfig Address", ifname);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void nl_callback(void *arg, int sd, int events)
|
||||
{
|
||||
ssize_t len;
|
||||
static char buf[4096];
|
||||
struct nlmsghdr *nh;
|
||||
ssize_t len;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
len = recv(sd, buf, sizeof(buf), 0);
|
||||
@@ -179,9 +214,9 @@ static void nl_callback(void *arg, int sd, int events)
|
||||
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
|
||||
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
|
||||
nl_route(nh);
|
||||
nl_route(nh, len);
|
||||
else
|
||||
nl_link(nh);
|
||||
nl_link(nh, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-2
@@ -151,7 +151,8 @@ static void pidfile_callback(void *arg, int fd, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz, off;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
@@ -160,10 +161,16 @@ static void pidfile_callback(void *arg, int fd, int events)
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
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;
|
||||
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
|
||||
+36
-21
@@ -53,33 +53,48 @@ static void setup(void)
|
||||
_pe("Failed starting TTY watcher");
|
||||
}
|
||||
|
||||
static void do_tty(char *tty, size_t len, int creat)
|
||||
{
|
||||
char name[len + 6];
|
||||
struct tty *entry;
|
||||
|
||||
snprintf(name, sizeof(name), "/dev/%s", tty);
|
||||
entry = tty_find(name);
|
||||
if (entry && tty_enabled(entry)) {
|
||||
if (creat)
|
||||
tty_start(entry);
|
||||
else if (entry->pid)
|
||||
tty_stop(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void watcher(void *arg, int fd, int events)
|
||||
{
|
||||
char buf[EVENT_SIZE];
|
||||
int len = 0;
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
while ((len = read(fd, buf, sizeof(buf)))) {
|
||||
struct inotify_event *notified = (struct inotify_event *)buf;
|
||||
char name[notified->len + 6];
|
||||
struct tty *entry;
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
_pe("invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
if (-1 == len) {
|
||||
if (errno == EINVAL)
|
||||
setup();
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
if (off + sizeof(*ev) > (size_t)sz)
|
||||
break;
|
||||
|
||||
break; /* Likely EAGAIN */
|
||||
}
|
||||
ev = (struct inotify_event *)&ev_buf[off];
|
||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||
break;
|
||||
|
||||
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
||||
entry = tty_find(name);
|
||||
if (entry && tty_enabled(entry)) {
|
||||
if (notified->mask & IN_CREATE)
|
||||
tty_start(entry);
|
||||
else if (entry->pid)
|
||||
tty_stop(entry);
|
||||
}
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
_d("tty %s, event: 0x%08x", ev->name, ev->mask);
|
||||
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -1,6 +1,5 @@
|
||||
EXTRA_DIST = cgreaper.sh rescue.conf sample.conf
|
||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
if STATIC
|
||||
AM_CPPFLAGS += -DENABLE_STATIC
|
||||
AM_LDFLAGS = -static-libtool-libs
|
||||
@@ -20,8 +19,10 @@ endif
|
||||
|
||||
if LOGIT
|
||||
pkglibexec_PROGRAMS = logit
|
||||
logit_SOURCES = logit.c
|
||||
logit_SOURCES = logit.c logrotate.c
|
||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
logit_CFLAGS += $(lite_CFLAGS)
|
||||
logit_LDADD = $(lite_LIBS)
|
||||
endif
|
||||
|
||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
@@ -43,6 +44,10 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
tty.c tty.h \
|
||||
util.c util.h \
|
||||
utmp-api.c utmp-api.h
|
||||
if LOGROTATE
|
||||
finit_SOURCES += logrotate.c
|
||||
endif
|
||||
|
||||
pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h
|
||||
|
||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
|
||||
@@ -237,7 +237,7 @@ ev_t ev_list[] = {
|
||||
|
||||
static void send_svc(int sd, svc_t *svc)
|
||||
{
|
||||
svc_t empty;
|
||||
svc_t empty = { 0 };
|
||||
size_t len;
|
||||
|
||||
if (!svc) {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ BASE=/sys/fs/cgroup/finit
|
||||
PROC=`basename $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
|
||||
|
||||
exit 0
|
||||
|
||||
+15
-10
@@ -27,6 +27,7 @@
|
||||
#include <lite/lite.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -53,7 +54,7 @@ void cgroup_init(void)
|
||||
}
|
||||
|
||||
/* Skip first line, header */
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
(void)fgets(buf, sizeof(buf), fp);
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
char *cgroup;
|
||||
char rc[80];
|
||||
@@ -70,27 +71,27 @@ void cgroup_init(void)
|
||||
}
|
||||
|
||||
/* Default cgroups for process monitoring */
|
||||
if (mkdir("/sys/fs/cgroup/finit", 0755) && EEXIST != errno)
|
||||
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
if (mount("none", "/sys/fs/cgroup/finit", "cgroup", opts, "none,name=finit")) {
|
||||
if (mount("none", FINIT_CGPATH, "cgroup", opts, "none,name=finit")) {
|
||||
_pe("Failed mounting Finit cgroup hierarchy");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set up reaper and enable callbacks */
|
||||
echo("/sys/fs/cgroup/finit/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
|
||||
echo("/sys/fs/cgroup/finit/notify_on_release", 0, "1");
|
||||
echo(FINIT_CGPATH "/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
|
||||
echo(FINIT_CGPATH "/notify_on_release", 0, "1");
|
||||
|
||||
/* Default groups, PID 1, services, and user/login processes */
|
||||
if (mkdir("/sys/fs/cgroup/finit/init", 0755) && EEXIST != errno)
|
||||
if (mkdir(FINIT_CGPATH "/init", 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
if (mkdir("/sys/fs/cgroup/finit/system", 0755) && EEXIST != errno)
|
||||
if (mkdir(FINIT_CGPATH "/system", 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
if (mkdir("/sys/fs/cgroup/finit/user", 0755) && EEXIST != errno)
|
||||
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
|
||||
goto fail;
|
||||
|
||||
/* Move ourselves to init */
|
||||
echo("/sys/fs/cgroup/finit/init/cgroup.procs", 0, "1");
|
||||
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
|
||||
|
||||
/* We have signal, main screen turn on! */
|
||||
cg_init = 1;
|
||||
@@ -102,7 +103,11 @@ static int move_pid(char *group, char *name, char *id, int pid)
|
||||
{
|
||||
char path[256];
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s:%s", group, name, id);
|
||||
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)
|
||||
return 1;
|
||||
|
||||
|
||||
@@ -162,26 +162,6 @@ int cond_set_path(const char *path, enum cond_state new)
|
||||
return new != old;
|
||||
}
|
||||
|
||||
/* Has condition in configuration and cond is allowed? */
|
||||
static int svc_has_cond(svc_t *svc)
|
||||
{
|
||||
if (!svc->cond[0])
|
||||
return 0;
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_SERVICE:
|
||||
case SVC_TYPE_TASK:
|
||||
case SVC_TYPE_RUN:
|
||||
case SVC_TYPE_SYSV:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cond_update(const char *name)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
+35
-20
@@ -47,6 +47,7 @@
|
||||
int logfile_size_max = 200000; /* 200 kB */
|
||||
int logfile_count_max = 5;
|
||||
|
||||
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||
|
||||
struct conf_change {
|
||||
@@ -78,14 +79,14 @@ static void hide_args(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
int get_bool(char *ptr, int default_value)
|
||||
int get_bool(char *arg, int default_value)
|
||||
{
|
||||
if (!ptr)
|
||||
if (!arg)
|
||||
goto fallback;
|
||||
|
||||
if (string_compare(ptr, "true") || string_compare(ptr, "on") || string_compare(ptr, "1"))
|
||||
if (string_compare(arg, "true") || string_compare(arg, "on") || string_compare(arg, "1"))
|
||||
return 1;
|
||||
if (string_compare(ptr, "false") || string_compare(ptr, "off") || string_compare(ptr, "0"))
|
||||
if (string_compare(arg, "false") || string_compare(arg, "off") || string_compare(arg, "0"))
|
||||
return 0;
|
||||
fallback:
|
||||
return default_value;
|
||||
@@ -97,19 +98,24 @@ fallback:
|
||||
*/
|
||||
static void parse_finit_opts(char *opt)
|
||||
{
|
||||
char *ptr;
|
||||
char *arg;
|
||||
|
||||
ptr = strchr(opt, '=');
|
||||
if (ptr)
|
||||
*ptr++ = 0;
|
||||
arg = strchr(opt, '=');
|
||||
if (arg)
|
||||
*arg++ = 0;
|
||||
|
||||
if (string_compare(opt, "debug")) {
|
||||
debug = get_bool(ptr, 1);
|
||||
debug = get_bool(arg, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(opt, "status_style")) {
|
||||
if (string_compare(ptr, "old") || string_compare(ptr, "classic"))
|
||||
if (!arg) {
|
||||
_e("status_style option requires an argument, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(arg, "old") || string_compare(arg, "classic"))
|
||||
show_progress(PROGRESS_CLASSIC);
|
||||
else
|
||||
show_progress(PROGRESS_MODERN);
|
||||
@@ -117,7 +123,7 @@ static void parse_finit_opts(char *opt)
|
||||
}
|
||||
|
||||
if (string_compare(opt, "show_status")) {
|
||||
show_progress(get_bool(ptr, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
|
||||
show_progress(get_bool(arg, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -620,12 +626,9 @@ int conf_reload(void)
|
||||
tty_mark();
|
||||
|
||||
/*
|
||||
* Get current global limits, which may be overridden from both
|
||||
* finit.conf, for Finit and its services like getty+watchdogd,
|
||||
* and *.conf in finit.d/, for each service(s) listed there.
|
||||
* Reset global rlimit to bootstrap values from conf_init().
|
||||
*/
|
||||
for (int i = 0; i < RLIMIT_NLIMITS; i++)
|
||||
getrlimit(i, &global_rlimit[i]);
|
||||
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
|
||||
|
||||
if (rescue) {
|
||||
int rc;
|
||||
@@ -694,6 +697,8 @@ int conf_reload(void)
|
||||
|
||||
globfree(&gl);
|
||||
|
||||
/* Mark any reverse deps as chenaged. */
|
||||
service_update_rdeps();
|
||||
done:
|
||||
/* Drop record of all .conf changes */
|
||||
drop_changes();
|
||||
@@ -800,7 +805,8 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz, off;
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
@@ -809,10 +815,16 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
|
||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||
struct iwatch_path *iwp;
|
||||
|
||||
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;
|
||||
|
||||
if (!ev->mask)
|
||||
continue;
|
||||
|
||||
@@ -882,8 +894,11 @@ int conf_init(uev_ctx_t *ctx)
|
||||
* finit.conf, for Finit and its services like getty+watchdogd,
|
||||
* and *.conf in finit.d/, for each service(s) listed there.
|
||||
*/
|
||||
for (int i = 0; i < RLIMIT_NLIMITS; i++)
|
||||
getrlimit(i, &global_rlimit[i]);
|
||||
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
||||
if (getrlimit(i, &initial_rlimit[i]))
|
||||
logit(LOG_WARNING, "rlimit: Failed reading setting %s: %s",
|
||||
rlim2str(i), strerror(errno));
|
||||
}
|
||||
|
||||
/* prepare /etc watcher */
|
||||
fd = iwatch_init(&iw_conf);
|
||||
|
||||
+18
-10
@@ -179,7 +179,8 @@ static void fs_remount_root(int fsckerr)
|
||||
* XXX: Untested, in the initramfs age we should
|
||||
* probably use switch_root instead.
|
||||
*/
|
||||
rc = mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||
if (mount(SYSROOT, "/", NULL, MS_MOVE, NULL))
|
||||
_pe("Failed %s / MS_MOVE");
|
||||
}
|
||||
#endif /* SYSROOT */
|
||||
|
||||
@@ -206,6 +207,9 @@ static void fs_mount(void)
|
||||
* for early multi-console, and /sys for the cgroups support. Any
|
||||
* occurrence of these file systems in /etc/fstab will replace these
|
||||
* mounts later in fs_mount()
|
||||
*
|
||||
* Ignore any mount errors with EBUSY, kernel likely alread mounted
|
||||
* the filesystem for us automatically, e.g., CONFIG_DEVTMPFS_MOUNT.
|
||||
*/
|
||||
static void fs_init(void)
|
||||
{
|
||||
@@ -218,8 +222,13 @@ static void fs_init(void)
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NELEMS(fs); i++)
|
||||
mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
|
||||
for (i = 0; i < NELEMS(fs); i++) {
|
||||
int rc;
|
||||
|
||||
rc = mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
|
||||
if (rc && errno != EBUSY)
|
||||
_pe("Failed mounting %s on %s", fs[i].spec, fs[i].file);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -475,13 +484,10 @@ int main(int argc, char *argv[])
|
||||
setenv("PATH", _PATH_STDPATH, 1);
|
||||
setenv("SHELL", _PATH_BSHELL, 1);
|
||||
|
||||
chdir("/");
|
||||
if (chdir("/"))
|
||||
_pe("Failed cd /");
|
||||
umask(0);
|
||||
|
||||
/* Set up canvas */
|
||||
if (!rescue && !debug)
|
||||
screen_init();
|
||||
|
||||
/* Allow progress, if enabled */
|
||||
enable_progress(1);
|
||||
|
||||
@@ -490,8 +496,10 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
emergency_shell();
|
||||
|
||||
/* Load plugins early, the first hook is in banner(), so we
|
||||
* need plugins loaded before calling it. */
|
||||
/*
|
||||
* Load plugins early, the first hook is in banner(), so we
|
||||
* need plugins loaded before calling it.
|
||||
*/
|
||||
plugin_init(&loop);
|
||||
|
||||
/*
|
||||
|
||||
+10
-1
@@ -36,8 +36,17 @@
|
||||
#include <lite/lite.h>
|
||||
#include <uev/uev.h>
|
||||
|
||||
/* just in case */
|
||||
#ifndef _PATH_STDPATH
|
||||
#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_VARRUN
|
||||
#define _PATH_VARRUN "/var/run/"
|
||||
#define _PATH_VARRUN "/var/run/"
|
||||
#endif
|
||||
|
||||
#ifndef FINIT_CGPATH
|
||||
#define FINIT_CGPATH "/sys/fs/cgroup/finit"
|
||||
#endif
|
||||
|
||||
#define LOGIT_PATH FINIT_LIBPATH_ "/logit"
|
||||
|
||||
+15
-7
@@ -121,7 +121,7 @@ static void add_console(char *cons)
|
||||
num_cons++;
|
||||
}
|
||||
|
||||
void console_init(void)
|
||||
static void find_active_consoles(void)
|
||||
{
|
||||
char *cons, *ptr, *tok;
|
||||
char buf[512];
|
||||
@@ -148,6 +148,12 @@ void console_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
void console_init(void)
|
||||
{
|
||||
find_active_consoles();
|
||||
screen_init();
|
||||
}
|
||||
|
||||
ssize_t cprintf(const char *fmt, ...)
|
||||
{
|
||||
const size_t len = strlen(fmt) * 2;
|
||||
@@ -426,14 +432,14 @@ void set_hostname(char **hostname)
|
||||
return;
|
||||
}
|
||||
|
||||
fgets(*hostname, st.st_size, fp);
|
||||
chomp(*hostname);
|
||||
if (fgets(*hostname, st.st_size, fp))
|
||||
chomp(*hostname);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
done:
|
||||
if (*hostname)
|
||||
sethostname(*hostname, strlen(*hostname));
|
||||
(void)sethostname(*hostname, strlen(*hostname));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -557,10 +563,12 @@ int ismnt(char *file, char *dir, char *mode)
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (!strcmp(mnt->mnt_dir, dir)) {
|
||||
if (mode && hasopt(mnt->mnt_opts, mode))
|
||||
found = 1;
|
||||
else
|
||||
if (mode) {
|
||||
if (hasopt(mnt->mnt_opts, mode))
|
||||
found = 1;
|
||||
} else
|
||||
found = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+156
-103
@@ -26,6 +26,7 @@
|
||||
#include <err.h>
|
||||
#include <ftw.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <getopt.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
@@ -43,6 +44,11 @@
|
||||
|
||||
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
||||
|
||||
#define NONE " "
|
||||
#define PIPE plain ? "|" : "│"
|
||||
#define FORK plain ? "|-" : "├─"
|
||||
#define END plain ? "`-" : "└─"
|
||||
|
||||
struct command {
|
||||
char *cmd;
|
||||
int (*cb)(char *arg);
|
||||
@@ -51,8 +57,8 @@ struct command {
|
||||
int icreate = 0;
|
||||
int iforce = 0;
|
||||
int heading = 1;
|
||||
int numeric = 0;
|
||||
int verbose = 0;
|
||||
int plain = 0;
|
||||
int runlevel = 0;
|
||||
int iw, pw;
|
||||
|
||||
@@ -72,11 +78,7 @@ static void col_widths(void)
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
int w, p;
|
||||
|
||||
if (!numeric)
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
else
|
||||
svc_jobid(svc, ident, sizeof(ident));
|
||||
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
w = (int)strlen(ident);
|
||||
if (w > iw)
|
||||
iw = w;
|
||||
@@ -206,8 +208,8 @@ static int do_startstop(int cmd, char *arg)
|
||||
|
||||
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||
if (client_send(&rq, sizeof(rq))) {
|
||||
fprintf(stderr, "No such job(s) or service(s): %s\n\n", rq.data);
|
||||
fprintf(stderr, "Usage: initctl %s <JOB|NAME>[:ID]\n",
|
||||
fprintf(stderr, "No such task or service(s): %s\n\n", arg);
|
||||
fprintf(stderr, "Usage: initctl %s <NAME>[:ID]\n",
|
||||
cmd == INIT_CMD_START_SVC ? "start" :
|
||||
(cmd == INIT_CMD_STOP_SVC ? "stop" : "restart"));
|
||||
return 1;
|
||||
@@ -323,11 +325,7 @@ static int do_cond_show(char *arg)
|
||||
|
||||
cond = cond_get_agg(svc->cond);
|
||||
|
||||
if (!numeric)
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
else
|
||||
svc_jobid(svc, ident, sizeof(ident));
|
||||
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
printf("%-*d %-*s ", pw, svc->pid, iw, ident);
|
||||
|
||||
if (cond == COND_ON)
|
||||
@@ -491,9 +489,24 @@ char *runlevel_string(int runlevel, int levels)
|
||||
return lvl;
|
||||
}
|
||||
|
||||
static char *svc_command(svc_t *svc, char *cmd, size_t len)
|
||||
{
|
||||
strlcpy(cmd, svc->cmd, len);
|
||||
for (int i = 1; i < MAX_NUM_SVC_ARGS; i++) {
|
||||
if (!svc->args[i][0])
|
||||
break;
|
||||
|
||||
strlcat(cmd, " ", len);
|
||||
strlcat(cmd, svc->args[i], len);
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static int show_status(char *arg)
|
||||
{
|
||||
char ident[MAX_IDENT_LEN];
|
||||
char cmd[512];
|
||||
svc_t *svc;
|
||||
|
||||
runlevel = runlevel_get(NULL);
|
||||
@@ -506,11 +519,11 @@ static int show_status(char *arg)
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
printf("Job : %d\n", svc->job);
|
||||
printf("Service : %s\n", svc->cmd);
|
||||
printf("Description : %s\n", svc->desc);
|
||||
printf("Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
||||
printf("Description : %s\n", svc->desc);
|
||||
printf("Origin : %s\n", svc->file[0] ? svc->file : "built-in");
|
||||
printf("Environment : %s\n", svc->env);
|
||||
printf("Command : %s\n", svc_command(svc, cmd, sizeof(cmd)));
|
||||
printf("PID : %d\n", svc->pid);
|
||||
printf("Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, buf, sizeof(buf)) : buf);
|
||||
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||
@@ -536,15 +549,10 @@ static int show_status(char *arg)
|
||||
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
char *lvls;
|
||||
int i;
|
||||
|
||||
printf("%-*d ", pw, svc->pid);
|
||||
|
||||
if (!numeric)
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
else
|
||||
svc_jobid(svc, ident, sizeof(ident));
|
||||
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
printf("%-*s %-8s ", iw, ident, svc_status(svc));
|
||||
|
||||
lvls = runlevel_string(runlevel, svc->runlevels);
|
||||
@@ -553,89 +561,124 @@ static int show_status(char *arg)
|
||||
else
|
||||
printf("%-12.12s ", lvls);
|
||||
|
||||
if (!verbose) {
|
||||
printf("%s\n", svc->desc);
|
||||
} else {
|
||||
char args[CMD_SIZE] = "";
|
||||
|
||||
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
|
||||
if (strlen(svc->args[i]) == 0)
|
||||
continue;
|
||||
if (args[0])
|
||||
strlcat(args, " ", sizeof(args));
|
||||
strlcat(args, svc->args[i], sizeof(args));
|
||||
}
|
||||
|
||||
printf("%s %s\n", svc->cmd, args);
|
||||
}
|
||||
if (!verbose)
|
||||
puts(svc->desc);
|
||||
else
|
||||
puts(svc_command(svc, cmd, sizeof(cmd)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_cgroup(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||
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;
|
||||
char *group;
|
||||
char path[256];
|
||||
char buf[256];
|
||||
int user = 0;
|
||||
int num = 0;
|
||||
int i, n;
|
||||
int num;
|
||||
|
||||
if (tflag == FTW_F)
|
||||
return 0;
|
||||
if (-1 == lstat(path, &st))
|
||||
return 1;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/cgroup.procs", fpath);
|
||||
fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
if (strstr(fpath, "finit/user"))
|
||||
user = 1;
|
||||
|
||||
group = strrchr(fpath, '/');
|
||||
if (!group)
|
||||
goto err;
|
||||
group++;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
FILE *cfp;
|
||||
int pid;
|
||||
|
||||
if (num == 0)
|
||||
printf("%c :- %s/", user ? ' ' : '|', group);
|
||||
num++;
|
||||
|
||||
pid = atoi(chomp(buf));
|
||||
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
|
||||
cfp = fopen(path, "r");
|
||||
if (!cfp)
|
||||
continue;
|
||||
fgets(buf, sizeof(buf), cfp);
|
||||
fclose(cfp);
|
||||
|
||||
printf("\n%c :- %d %s", user ? ' ' : '|', pid, buf);
|
||||
if ((st.st_mode & S_IFMT) != S_IFDIR) {
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
err:
|
||||
fclose(fp);
|
||||
if (num)
|
||||
printf("\r%c\n", user ? ' ' : '|');
|
||||
fp = fopenf("r", "%s/cgroup.procs", path);
|
||||
if (!fp)
|
||||
return -1;
|
||||
num = 0;
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
num++;
|
||||
|
||||
return 0;
|
||||
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)
|
||||
{
|
||||
puts("finit/");
|
||||
puts("|- init/");
|
||||
nftw("/sys/fs/cgroup/finit/init", dump_cgroup, 20, 0);
|
||||
puts("|- system/");
|
||||
nftw("/sys/fs/cgroup/finit/system", dump_cgroup, 20, 0);
|
||||
puts("`- user/");
|
||||
nftw("/sys/fs/cgroup/finit/user", dump_cgroup, 20, 0);
|
||||
char path[512];
|
||||
|
||||
return 0;
|
||||
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)
|
||||
@@ -682,7 +725,6 @@ static int usage(int rc)
|
||||
" -b, --batch Batch mode, no screen size probing\n"
|
||||
" -c, --create Create missing paths (and files) as needed\n"
|
||||
" -f, --force Ignore missing files and arguments, never prompt\n"
|
||||
" -n, --numeric Show JOB:ID instead of NAME:ID\n"
|
||||
" -t, --no-heading Skip table headings\n"
|
||||
" -v, --verbose Verbose output\n"
|
||||
" -h, --help This help text\n"
|
||||
@@ -698,9 +740,14 @@ static int usage(int rc)
|
||||
" ls | list List all .conf in " FINIT_RCSD "\n"
|
||||
" create <CONF> Create .conf in %s\n"
|
||||
" delete <CONF> Delete .conf in %s\n"
|
||||
" show <CONF> Show .conf in %s\n"
|
||||
" edit <CONF> Edit .conf in %s\n"
|
||||
" touch <CONF> Change .conf in %s\n",
|
||||
avail, avail, avail, avail);
|
||||
avail, avail, avail, avail, avail);
|
||||
else
|
||||
fprintf(stderr,
|
||||
" show Show %s\n", FINIT_CONF);
|
||||
|
||||
if (has_ena)
|
||||
fprintf(stderr,
|
||||
" enable <CONF> Enable .conf in %s\n", avail);
|
||||
@@ -715,17 +762,17 @@ static int usage(int rc)
|
||||
" reload Reload " FINIT_CONF " (activate changes)\n");
|
||||
|
||||
fprintf(stderr,
|
||||
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
||||
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
|
||||
"\n"
|
||||
" cond show Show condition status\n"
|
||||
" cond dump Dump all conditions and their status\n"
|
||||
"\n"
|
||||
" log [NAME] Show ten last Finit, or NAME, messages from syslog\n"
|
||||
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
|
||||
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
|
||||
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
|
||||
" status <JOB|NAME>[:ID] Show service status, by job# or name\n"
|
||||
" status | show Show status of services, default command\n"
|
||||
" start <NAME>[:ID] Start service by name, with optional ID\n"
|
||||
" stop <NAME>[:ID] Stop/Pause a running service by name\n"
|
||||
" restart <NAME>[:ID] Restart (stop/start) service by name\n"
|
||||
" status <NAME>[:ID] Show service status, by name\n"
|
||||
" status Show status of services, default command\n"
|
||||
"\n"
|
||||
" ps List processes based on cgroups\n"
|
||||
"\n"
|
||||
@@ -746,6 +793,15 @@ static int usage(int rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int do_devel(char *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
printf("Screen %dx%d\n", screen_cols, screen_rows);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_help(char *arg)
|
||||
{
|
||||
return usage(0);
|
||||
@@ -755,6 +811,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
struct command command[] = {
|
||||
{ "debug", toggle_debug },
|
||||
{ "devel", do_devel },
|
||||
{ "help", do_help },
|
||||
{ "version", show_version },
|
||||
|
||||
@@ -763,6 +820,7 @@ int main(int argc, char *argv[])
|
||||
{ "enable", serv_enable },
|
||||
{ "disable", serv_disable },
|
||||
{ "touch", serv_touch },
|
||||
{ "show", serv_show },
|
||||
{ "edit", serv_edit },
|
||||
{ "create", serv_creat },
|
||||
{ "delete", serv_delete },
|
||||
@@ -775,7 +833,7 @@ int main(int argc, char *argv[])
|
||||
{ "stop", do_stop },
|
||||
{ "restart", do_restart },
|
||||
{ "status", show_status },
|
||||
{ "show", show_status }, /* Convenience alias */
|
||||
{ "show", show_status }, /* Convenience alias, for now */
|
||||
|
||||
{ "ps", show_cgroup },
|
||||
|
||||
@@ -793,7 +851,6 @@ int main(int argc, char *argv[])
|
||||
{ "create", 0, NULL, 'c' },
|
||||
{ "force", 0, NULL, 'f' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "numeric", 0, NULL, 'n' },
|
||||
{ "no-heading", 0, NULL, 't' },
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
@@ -804,7 +861,7 @@ int main(int argc, char *argv[])
|
||||
if (transform(progname(argv[0])))
|
||||
return reboot_main(argc, argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "bcfh?ntv", long_options, NULL)) != EOF) {
|
||||
while ((c = getopt_long(argc, argv, "bcfh?tv", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'b':
|
||||
interactive = 0;
|
||||
@@ -822,10 +879,6 @@ int main(int argc, char *argv[])
|
||||
case '?':
|
||||
return usage(0);
|
||||
|
||||
case 'n':
|
||||
numeric = 1;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
heading = 0;
|
||||
break;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <sched.h> /* sched_yield() */
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <lite/lite.h>
|
||||
@@ -50,15 +49,13 @@ void log_exit(void)
|
||||
* Unless in debug mode at shutdown, Reinitialize screen,
|
||||
* terminal may have been resized at runtime
|
||||
*/
|
||||
if (debug)
|
||||
screen_exit();
|
||||
else
|
||||
if (!debug)
|
||||
screen_init();
|
||||
|
||||
enable_progress(1);
|
||||
}
|
||||
|
||||
void log_open(void)
|
||||
static void log_open(void)
|
||||
{
|
||||
int opts = LOG_PID;
|
||||
|
||||
@@ -79,7 +76,6 @@ void log_debug(void)
|
||||
|
||||
if (debug) {
|
||||
loglevel = LOG_DEBUG;
|
||||
screen_exit();
|
||||
} else {
|
||||
loglevel = LOG_NOTICE;
|
||||
screen_init();
|
||||
@@ -103,11 +99,12 @@ void logit(int prio, const char *fmt, ...)
|
||||
if (up || fexist("/dev/log")) {
|
||||
if (!up)
|
||||
log_open();
|
||||
|
||||
vsyslog(prio, fmt, ap);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!debug && prio > loglevel)
|
||||
if (prio > loglevel)
|
||||
goto done;
|
||||
|
||||
fp = fopen("/dev/kmsg", "w");
|
||||
|
||||
+2
-65
@@ -30,75 +30,12 @@
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
|
||||
extern int logrotate(char *file, int num, off_t sz);
|
||||
|
||||
|
||||
static int create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
return mknod(path, S_IFREG | mode, 0) || chown(path, uid, gid);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function triggers a log rotates of @file when size >= @sz bytes
|
||||
* At most @num old versions are kept and by default it starts gzipping
|
||||
* .2 and older log files. If gzip is not available in $PATH then @num
|
||||
* files are kept uncompressed.
|
||||
*/
|
||||
static int logrotate(char *file, int num, off_t sz)
|
||||
{
|
||||
int cnt;
|
||||
struct stat st;
|
||||
|
||||
if (stat(file, &st))
|
||||
return 1;
|
||||
|
||||
if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) {
|
||||
if (num > 0) {
|
||||
size_t len = strlen(file) + 10 + 1;
|
||||
char ofile[len];
|
||||
char nfile[len];
|
||||
|
||||
/* First age zipped log files */
|
||||
for (cnt = num; cnt > 2; cnt--) {
|
||||
snprintf(ofile, len, "%s.%d.gz", file, cnt - 1);
|
||||
snprintf(nfile, len, "%s.%d.gz", file, cnt);
|
||||
|
||||
/* May fail because ofile doesn't exist yet, ignore. */
|
||||
(void)rename(ofile, nfile);
|
||||
}
|
||||
|
||||
for (cnt = num; cnt > 0; cnt--) {
|
||||
snprintf(ofile, len, "%s.%d", file, cnt - 1);
|
||||
snprintf(nfile, len, "%s.%d", file, cnt);
|
||||
|
||||
/* May fail because ofile doesn't exist yet, ignore. */
|
||||
(void)rename(ofile, nfile);
|
||||
|
||||
if (cnt == 2 && !access(nfile, F_OK)) {
|
||||
size_t len = 5 + strlen(nfile) + 1;
|
||||
char cmd[len];
|
||||
|
||||
snprintf(cmd, len, "gzip %s", nfile);
|
||||
system(cmd);
|
||||
|
||||
remove(nfile);
|
||||
}
|
||||
}
|
||||
|
||||
if (rename(file, nfile))
|
||||
(void)truncate(file, 0);
|
||||
else
|
||||
create(file, st.st_mode, st.st_uid, st.st_gid);
|
||||
} else {
|
||||
if (truncate(file, 0))
|
||||
syslog(LOG_ERR | LOG_PERROR, "Failed truncating %s during logrotate: %s", file, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int checksz(FILE *fp, off_t sz)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2018-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 <lite/lite.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int recreate(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
if (mknod(path, S_IFREG | mode, 0) || chown(path, uid, gid)) {
|
||||
syslog(LOG_ERR, "Failed recreating %s: %s", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function triggers a log rotates of @file when size >= @sz bytes
|
||||
* At most @num old versions are kept and by default it starts gzipping
|
||||
* .2 and older log files. If gzip is not available in $PATH then @num
|
||||
* files are kept uncompressed.
|
||||
*/
|
||||
int logrotate(char *file, int num, off_t sz)
|
||||
{
|
||||
int cnt;
|
||||
struct stat st;
|
||||
|
||||
if (stat(file, &st))
|
||||
return 1;
|
||||
|
||||
if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) {
|
||||
if (num > 0) {
|
||||
size_t len = strlen(file) + 10 + 1;
|
||||
char ofile[len];
|
||||
char nfile[len];
|
||||
|
||||
/* First age zipped log files */
|
||||
for (cnt = num; cnt > 2; cnt--) {
|
||||
snprintf(ofile, len, "%s.%d.gz", file, cnt - 1);
|
||||
snprintf(nfile, len, "%s.%d.gz", file, cnt);
|
||||
|
||||
/* May fail because ofile doesn't exist yet, ignore. */
|
||||
if (rename(ofile, nfile) && errno != ENOENT)
|
||||
syslog(LOG_ERR, "Failed logrotate %s: %s",
|
||||
ofile, strerror(errno));
|
||||
}
|
||||
|
||||
for (cnt = num; cnt > 0; cnt--) {
|
||||
snprintf(ofile, len, "%s.%d", file, cnt - 1);
|
||||
snprintf(nfile, len, "%s.%d", file, cnt);
|
||||
|
||||
/* May fail because ofile doesn't exist yet, ignore. */
|
||||
if (rename(ofile, nfile) && errno != ENOENT) {
|
||||
syslog(LOG_ERR, "Failed logrotate %s: %s",
|
||||
ofile, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cnt == 2 && fexist(nfile)) {
|
||||
if (systemf("gzip %s", nfile))
|
||||
continue; /* no gzip, probably */
|
||||
|
||||
(void)remove(nfile);
|
||||
}
|
||||
}
|
||||
|
||||
if (rename(file, nfile))
|
||||
goto fallback;
|
||||
recreate(file, st.st_mode, st.st_uid, st.st_gid);
|
||||
} else {
|
||||
fallback:
|
||||
if (truncate(file, 0))
|
||||
syslog(LOG_ERR, "Failed truncating %s during logrotate: %s",
|
||||
file, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+25
-3
@@ -58,7 +58,9 @@ static void do_list(const char *path)
|
||||
glob_t gl;
|
||||
size_t i;
|
||||
|
||||
chdir(path);
|
||||
if (chdir(path))
|
||||
return;
|
||||
|
||||
if (glob("*.conf", 0, NULL, &gl))
|
||||
return;
|
||||
|
||||
@@ -138,6 +140,11 @@ static char *conf(char *path, size_t len, char *name, int creat)
|
||||
{
|
||||
char corr[40];
|
||||
|
||||
if (!name || !name[0]) {
|
||||
strlcpy(path, FINIT_CONF, len);
|
||||
return path;
|
||||
}
|
||||
|
||||
if (!strstr(name, ".conf")) {
|
||||
snprintf(corr, sizeof(corr), "%s.conf", name);
|
||||
name = corr;
|
||||
@@ -208,7 +215,7 @@ int do_disable(char *arg, int check)
|
||||
|
||||
if (chdir(FINIT_RCSD))
|
||||
err(1, "failed cd %s", FINIT_RCSD);
|
||||
chdir("enabled"); /* System *may* have enabled/ dir. */
|
||||
(void)chdir("enabled"); /* System *may* have enabled/ dir. */
|
||||
|
||||
if (check && stat(arg, &st))
|
||||
errx(1, "%s not (an) enabled (service).", arg);
|
||||
@@ -250,6 +257,20 @@ int serv_touch(char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serv_show(char *arg)
|
||||
{
|
||||
char path[256];
|
||||
char *fn;
|
||||
|
||||
fn = conf(path, sizeof(path), arg, 0);
|
||||
if (!fexist(fn)) {
|
||||
warnx("Cannot find %s", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return systemf("cat %s", fn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to open an editor for the given file, if creat is given we
|
||||
* create a new file based on /lib/finit/sample.conf
|
||||
@@ -358,7 +379,8 @@ int serv_delete(char *arg)
|
||||
|
||||
if (iforce || yorn("Remove file and symlink(s) to %s (y/N)? ", fn)) {
|
||||
do_disable(arg, 0);
|
||||
remove(fn);
|
||||
if (remove(fn))
|
||||
err(1, "Failed removing %s", fn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -28,6 +28,7 @@ int serv_list (char *arg);
|
||||
int serv_enable (char *arg);
|
||||
int serv_disable (char *arg);
|
||||
int serv_touch (char *arg);
|
||||
int serv_show (char *arg);
|
||||
int serv_edit (char *arg);
|
||||
int serv_creat (char *arg);
|
||||
int serv_delete (char *arg);
|
||||
|
||||
+38
-3
@@ -464,17 +464,18 @@ static int service_start(svc_t *svc)
|
||||
|
||||
/* Set desired user+group */
|
||||
if (gid >= 0)
|
||||
setgid(gid);
|
||||
(void)setgid(gid);
|
||||
|
||||
if (uid >= 0) {
|
||||
setuid(uid);
|
||||
(void)setuid(uid);
|
||||
|
||||
/* Set default path for regular users */
|
||||
if (uid > 0)
|
||||
setenv("PATH", _PATH_DEFPATH, 1);
|
||||
if (home) {
|
||||
setenv("HOME", home, 1);
|
||||
chdir(home);
|
||||
if (chdir(home))
|
||||
(void)chdir("/");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,6 +1163,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||
if (env)
|
||||
parse_env(svc, env);
|
||||
if (file)
|
||||
strlcpy(svc->file, file, sizeof(svc->file));
|
||||
|
||||
/* Set configured limits */
|
||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||
@@ -1247,6 +1250,38 @@ void service_monitor(pid_t lost, int status)
|
||||
sm_step(&sm);
|
||||
}
|
||||
|
||||
static void svc_mark_affected(char *cond)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (!svc_has_cond(svc))
|
||||
continue;
|
||||
|
||||
if (cond_affects(cond, svc->cond))
|
||||
svc_mark_dirty(svc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called on conf_reload() to update service reverse dependencies.
|
||||
* E.g., if ospfd depends on zebra and the zebra Finit conf has
|
||||
* changed, we need to mark the ospfd Finit conf as changed too.
|
||||
*/
|
||||
void service_update_rdeps(void)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
char cond[MAX_COND_LEN];
|
||||
|
||||
if (!svc_is_changed(svc))
|
||||
continue;
|
||||
|
||||
svc_mark_affected(mkcond(svc, cond, sizeof(cond)));
|
||||
}
|
||||
}
|
||||
|
||||
static void service_retry(svc_t *svc)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
@@ -33,6 +33,7 @@ void service_unregister (svc_t *svc);
|
||||
|
||||
void service_runtask_clean (void);
|
||||
void service_reload_dynamic (void);
|
||||
void service_update_rdeps (void);
|
||||
|
||||
int service_step (svc_t *svc);
|
||||
void service_step_all (int types);
|
||||
|
||||
@@ -86,9 +86,8 @@ typedef enum {
|
||||
typedef struct svc {
|
||||
TAILQ_ENTRY(svc) link;
|
||||
|
||||
/* Instance specifics */
|
||||
int job; /* JOB: */
|
||||
char id[MAX_ID_LEN]; /* :ID */
|
||||
/* Origin of service */
|
||||
char file[MAX_ARG_LEN];
|
||||
|
||||
/* Limits and scoping */
|
||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||
@@ -110,7 +109,11 @@ typedef struct svc {
|
||||
int sighup; /* This service supports SIGHUP :) */
|
||||
svc_block_t block; /* Reason that this service is currently stopped */
|
||||
char cond[MAX_COND_LEN];
|
||||
|
||||
/* Instance specifics */
|
||||
int job; /* For intenal use only, canonical ref is NAME:ID */
|
||||
char name[MAX_ARG_LEN];
|
||||
char id[MAX_ID_LEN]; /* :ID */
|
||||
|
||||
/* Counters */
|
||||
char once; /* run/task, (at least) once per runlevel */
|
||||
@@ -205,6 +208,26 @@ static inline void svc_missing (svc_t *svc) { if (svc) svc->block = SVC_BLOC
|
||||
static inline void svc_restarting (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_RESTARTING; }
|
||||
static inline void svc_crashing (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_CRASHING; }
|
||||
|
||||
/* Has condition in configuration and cond is allowed? */
|
||||
static inline int svc_has_cond(svc_t *svc)
|
||||
{
|
||||
if (!svc->cond[0])
|
||||
return 0;
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_SERVICE:
|
||||
case SVC_TYPE_TASK:
|
||||
case SVC_TYPE_RUN:
|
||||
case SVC_TYPE_SYSV:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char *svc_status(svc_t *svc)
|
||||
{
|
||||
if (!svc)
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
|
||||
#define TTY_MAX_ARGS 16
|
||||
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
|
||||
|
||||
struct tty {
|
||||
LIST_ENTRY(tty) link;
|
||||
|
||||
+62
-15
@@ -28,9 +28,15 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# include <termios.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <sys/sysinfo.h> /* sysinfo() */
|
||||
#include <lite/lite.h> /* strlcat() */
|
||||
#include "util.h"
|
||||
@@ -202,25 +208,66 @@ char *sanitize(char *arg, size_t len)
|
||||
}
|
||||
|
||||
/*
|
||||
* Called at boot, and shutdown, to (re)initialize the
|
||||
* screen size for print() et al.
|
||||
* Called by initctl, and by finit at boot and shutdown, to
|
||||
* (re)initialize the screen size for print() et al.
|
||||
*/
|
||||
void screen_init(void)
|
||||
int screen_init(void)
|
||||
{
|
||||
if (!isatty(STDOUT_FILENO))
|
||||
return;
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
struct pollfd fd = { STDIN_FILENO, POLLIN, 0 };
|
||||
struct winsize ws = { 0 };
|
||||
struct termios tc, saved;
|
||||
|
||||
initscr(&screen_rows, &screen_cols);
|
||||
}
|
||||
/*
|
||||
* Basic TTY init, CLOCaL is important or TIOCWINSZ will block
|
||||
* until DCD is asserted, and we won't ever get it.
|
||||
*/
|
||||
tcgetattr(STDERR_FILENO, &tc);
|
||||
saved = tc;
|
||||
tc.c_cflag |= (CLOCAL | CREAD);
|
||||
tc.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &tc);
|
||||
|
||||
/*
|
||||
* Called when debug mode is enabled to revert back
|
||||
* to old-school safe defaults.
|
||||
*/
|
||||
void screen_exit(void)
|
||||
{
|
||||
screen_rows = 24;
|
||||
screen_cols = 80;
|
||||
/* 1. Try TIOCWINSZ to query window size from kernel */
|
||||
if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)) {
|
||||
screen_rows = ws.ws_row;
|
||||
screen_cols = ws.ws_col;
|
||||
|
||||
/* Likely doesn't work in PID 1 after kernel starts us ... */
|
||||
if (!ws.ws_row && !ws.ws_col)
|
||||
goto fallback;
|
||||
} else if (!isatty(STDOUT_FILENO)) {
|
||||
/* 2. We may be running under watch(1) */
|
||||
screen_cols = atonum(getenv("COLUMNS"));
|
||||
screen_rows = atonum(getenv("LINES"));
|
||||
} else {
|
||||
fallback:
|
||||
/* 3. ANSI goto + query cursor position trick as fallback */
|
||||
fprintf(stderr, "\e7\e[r\e[999;999H\e[6n");
|
||||
|
||||
if (poll(&fd, 1, 300) > 0) {
|
||||
int row, col;
|
||||
|
||||
if (scanf("\e[%d;%dR", &row, &col) == 2) {
|
||||
screen_cols = col;
|
||||
screen_rows = row;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump back to where we started (\e7) */
|
||||
fprintf(stderr, "\e8");
|
||||
}
|
||||
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &saved);
|
||||
|
||||
/* Sanity check */
|
||||
if (screen_cols <= 0)
|
||||
screen_cols = 80;
|
||||
if (screen_rows <= 0)
|
||||
screen_rows = 24;
|
||||
#endif
|
||||
|
||||
return screen_cols;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-3
@@ -55,9 +55,7 @@ char *uptime (long secs, char *buf, size_t len);
|
||||
|
||||
char *sanitize (char *arg, size_t len);
|
||||
|
||||
void screen_init (void);
|
||||
void screen_exit (void);
|
||||
int screen_width (void);
|
||||
int screen_init (void);
|
||||
|
||||
static inline char *strterm(char *str, size_t len)
|
||||
{
|
||||
|
||||
+5
-61
@@ -35,6 +35,9 @@
|
||||
#define MAX_NO 5
|
||||
#define MAX_SZ 100 * 1024
|
||||
|
||||
extern int logrotate(char *file, int num, off_t sz);
|
||||
|
||||
|
||||
static void utmp_strncpy(char *dst, const char *src, size_t dlen)
|
||||
{
|
||||
size_t i;
|
||||
@@ -46,65 +49,6 @@ static void utmp_strncpy(char *dst, const char *src, size_t dlen)
|
||||
dst[i] = 0;
|
||||
}
|
||||
|
||||
#ifdef LOGROTATE_ENABLED
|
||||
/*
|
||||
* This function triggers a log rotates of @file when size >= @sz bytes
|
||||
* At most @num old versions are kept and by default it starts gzipping
|
||||
* .2 and older log files. If gzip is not available in $PATH then @num
|
||||
* files are kept uncompressed.
|
||||
*/
|
||||
static int logrotate(char *file, int num, off_t sz)
|
||||
{
|
||||
int cnt;
|
||||
struct stat st;
|
||||
|
||||
if (stat(file, &st))
|
||||
return 1;
|
||||
|
||||
if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) {
|
||||
if (num > 0) {
|
||||
size_t len = strlen(file) + 10 + 1;
|
||||
char ofile[len];
|
||||
char nfile[len];
|
||||
|
||||
/* First age zipped log files */
|
||||
for (cnt = num; cnt > 2; cnt--) {
|
||||
snprintf(ofile, len, "%s.%d.gz", file, cnt - 1);
|
||||
snprintf(nfile, len, "%s.%d.gz", file, cnt);
|
||||
|
||||
/* May fail because ofile doesn't exist yet, ignore. */
|
||||
(void)rename(ofile, nfile);
|
||||
}
|
||||
|
||||
for (cnt = num; cnt > 0; cnt--) {
|
||||
snprintf(ofile, len, "%s.%d", file, cnt - 1);
|
||||
snprintf(nfile, len, "%s.%d", file, cnt);
|
||||
|
||||
/* May fail because ofile doesn't exist yet, ignore. */
|
||||
(void)rename(ofile, nfile);
|
||||
|
||||
if (cnt == 2 && fexist(nfile)) {
|
||||
size_t len = 5 + strlen(nfile) + 1;
|
||||
char cmd[len];
|
||||
|
||||
snprintf(cmd, len, "gzip %s", nfile);
|
||||
run(cmd);
|
||||
|
||||
remove(nfile);
|
||||
}
|
||||
}
|
||||
|
||||
(void)rename(file, nfile);
|
||||
create(file, st.st_mode, st.st_uid, st.st_gid);
|
||||
} else {
|
||||
truncate(file, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* LOGROTATE_ENABLED */
|
||||
|
||||
/*
|
||||
* Rotate /var/log/wtmp (+ btmp?) and /run/utmp
|
||||
*
|
||||
@@ -194,13 +138,13 @@ static int set_getty(int type, char *tty, char *id, char *user)
|
||||
return 0;
|
||||
|
||||
if (!tty)
|
||||
line = "";
|
||||
line = NULL;
|
||||
else if (!strncmp(tty, "/dev/", 5))
|
||||
line = tty + 5;
|
||||
else
|
||||
line = tty;
|
||||
|
||||
if (!id) {
|
||||
if (!id && line) {
|
||||
id = line;
|
||||
if (!strncmp(id, "pts/", 4))
|
||||
id += 4;
|
||||
|
||||
@@ -44,6 +44,6 @@ fi
|
||||
mkdir -p "$FINIT_RCSD"
|
||||
|
||||
tty=/dev/$(cat /sys/class/tty/console/active)
|
||||
ln -fs /shared/pts "$tty"
|
||||
mkfifo "$tty"
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -138,3 +138,7 @@ echo "$finit_ppid" > "$TENV_ROOT"/running_test.pid
|
||||
log "$color_reset" 'Setup of test environment done' ''
|
||||
|
||||
finit_pid=$(retry "pgrep -P $finit_ppid")
|
||||
|
||||
tty=/dev/$(texec cat /sys/class/tty/console/active)
|
||||
texec cat "$tty" &
|
||||
sleep 1
|
||||
|
||||
@@ -38,7 +38,6 @@ binaries = $(DEST)/bin/cat \
|
||||
$(DEST)/bin/env \
|
||||
$(DEST)/bin/find \
|
||||
$(DEST)/bin/kill \
|
||||
$(DEST)/bin/ln \
|
||||
$(DEST)/bin/ls \
|
||||
$(DEST)/bin/mkdir \
|
||||
$(DEST)/bin/mkfifo \
|
||||
@@ -58,7 +57,6 @@ dirs = $(DEST)/bin \
|
||||
$(DEST)/etc \
|
||||
$(DEST)/proc \
|
||||
$(DEST)/sbin \
|
||||
$(DEST)/shared \
|
||||
$(DEST)/sys \
|
||||
$(DEST)/test_assets \
|
||||
$(DEST)/tmp
|
||||
|
||||
+1
-4
@@ -45,7 +45,4 @@ exec "$unshare" \
|
||||
--mount \
|
||||
--mount-proc \
|
||||
--uts --ipc --net \
|
||||
sh -c "
|
||||
ln -fs /proc/1/fd/1 $TENV_ROOT/shared/pts;
|
||||
exec $chroot $TENV_ROOT /bin/chrootsetup.sh $*
|
||||
"
|
||||
"$chroot" "$TENV_ROOT" /bin/chrootsetup.sh "$@"
|
||||
|
||||
Reference in New Issue
Block a user