Compare commits

..
Author SHA1 Message Date
Jacques de Laval 50c99762f1 Add run target for running Finit as a stand alone unprivileged process
It could be very useful, during development, to be able to run Finit on a
host system without having to provision a full VM. We have all the building
blocks for easily containerizing Finit - in the test framework - so adding
a "run" target that does the orchestration makes sense.

Signed-off-by: Jacques de Laval <jacques@de-laval.se>
2021-03-05 01:39:42 +01:00
Jacques de Laval 067043b298 test: Use STDOUT of parent process instead of a pipe as tty for finit
Signed-off-by: Jacques de Laval <jacques@de-laval.se>
2021-03-05 01:24:31 +01:00
35 changed files with 464 additions and 711 deletions
+5 -2
View File
@@ -5,6 +5,9 @@ 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
@@ -27,7 +30,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 --disable-doc --disable-contrib --enable-watchdog --enable-fallback-shell"
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp"
build_command: "make"
branch_pattern: dev
@@ -45,7 +48,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
- ./configure --prefix=/tmp --enable-x11-common-plugin --enable-fallback-shell --enable-watchdog --enable-logit
- cat config.log
- make clean
- make V=1 -j5
+16
View File
@@ -29,3 +29,19 @@ 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
+33 -55
View File
@@ -26,9 +26,6 @@ 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 …"
![Alpine screenshot](img/finit4-screenshot.png)
*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:
@@ -37,6 +34,9 @@ on server and desktop systems as well. For working examples, see the
* [Alpine Linux](contrib/alpine/), and
* [Debian GNU/Linux](contrib/debian/)
![Alpine screenshot](img/alpine-screenshot.png)
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
Example
-------
@@ -348,15 +348,11 @@ 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.
```
alpine:~# initctl help
```shell
~ $ initctl -h
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
@@ -364,34 +360,29 @@ Commands:
debug Toggle Finit (daemon) debug
help This help text
version Show Finit version
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)
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)
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 <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
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
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
reboot Reboot system
halt Halt system
poweroff Halt and power off system
suspend Suspend system
utmp show Raw dump of UTMP/WTMP db
```
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
@@ -404,31 +395,18 @@ 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
@@ -495,6 +473,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.svg?branch=master
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
[Coverity Scan]: https://scan.coverity.com/projects/3545
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
+6 -5
View File
@@ -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-rc1, 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 sys/ioctl.h])
AC_CHECK_HEADERS([fstaby.h termios.h])
AC_CHECK_FUNCS([strstr getopt getfsenty])
# Check for uint[8,16,32]_t
@@ -153,8 +153,6 @@ 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"], [
@@ -226,6 +224,9 @@ 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
@@ -234,7 +235,7 @@ cat <<EOF
------------------ Summary ------------------
$PACKAGE_NAME version $PACKAGE_VERSION
Prefix................: $prefix
Exec prefix...........: $eprefix
Exec prefix...........: `eval echo $exec_prefix`
Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir`
Finit config file.....: $conf_path
+1 -1
View File
@@ -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 NAME`
- The user has manually stopped the service using `initctl stop JOB`
- 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.

Before

Width:  |  Height:  |  Size: 7.6 KiB

+40 -75
View File
@@ -17,7 +17,6 @@
*/
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <net/if.h> /* IFNAMSIZ */
#include <sys/socket.h>
@@ -49,7 +48,7 @@ static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
return 0;
}
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
static void nl_route(struct nlmsghdr *nlmsg)
{
struct rtmsg *r;
struct rtattr *a;
@@ -64,14 +63,8 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
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);
@@ -112,27 +105,7 @@ static void net_cond_set(char *ifname, char *cond, int set)
cond_clear(msg);
}
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)
static void nl_link(struct nlmsghdr *nlmsg)
{
int la;
char ifname[IFNAMSIZ + 1];
@@ -147,61 +120,53 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
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;
}
for (; RTA_OK(a, la); a = RTA_NEXT(a, la)) {
if (a->rta_type != IFLA_IFNAME)
continue;
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;
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
if (validate_ifname(ifname)) {
_d("Invalid interface name '%s', skipping ...", 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;
}
}
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;
}
a = RTA_NEXT(a, la);
}
}
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);
@@ -214,9 +179,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, len);
nl_route(nh);
else
nl_link(nh, len);
nl_link(nh);
}
}
+2 -9
View File
@@ -151,8 +151,7 @@ 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;
size_t off;
ssize_t sz, off;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
@@ -161,16 +160,10 @@ static void pidfile_callback(void *arg, int fd, int events)
}
ev_buf[sz] = 0;
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
for (off = 0; off < 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;
+21 -36
View File
@@ -53,48 +53,33 @@ 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)
{
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
struct inotify_event *ev;
ssize_t sz;
size_t off;
char buf[EVENT_SIZE];
int len = 0;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
_pe("invalid inotify event");
return;
}
ev_buf[sz] = 0;
while ((len = read(fd, buf, sizeof(buf)))) {
struct inotify_event *notified = (struct inotify_event *)buf;
char name[notified->len + 6];
struct tty *entry;
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
if (off + sizeof(*ev) > (size_t)sz)
break;
if (-1 == len) {
if (errno == EINVAL)
setup();
if (errno == EINTR)
continue;
ev = (struct inotify_event *)&ev_buf[off];
if (off + sizeof(*ev) + ev->len > (size_t)sz)
break;
break; /* Likely EAGAIN */
}
if (!ev->mask)
continue;
_d("tty %s, event: 0x%08x", ev->name, ev->mask);
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
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);
}
}
}
+3 -8
View File
@@ -1,5 +1,6 @@
EXTRA_DIST = cgreaper.sh rescue.conf sample.conf
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
AM_CPPFLAGS = -U_FORTIFY_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
@@ -19,10 +20,8 @@ endif
if LOGIT
pkglibexec_PROGRAMS = logit
logit_SOURCES = logit.c logrotate.c
logit_SOURCES = logit.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 \
@@ -44,10 +43,6 @@ 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
+1 -1
View File
@@ -237,7 +237,7 @@ ev_t ev_list[] = {
static void send_svc(int sd, svc_t *svc)
{
svc_t empty = { 0 };
svc_t empty;
size_t len;
if (!svc) {
+1 -1
View File
@@ -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
+10 -15
View File
@@ -27,7 +27,6 @@
#include <lite/lite.h>
#include <sys/mount.h>
#include "finit.h"
#include "log.h"
#include "util.h"
@@ -54,7 +53,7 @@ void cgroup_init(void)
}
/* Skip first line, header */
(void)fgets(buf, sizeof(buf), fp);
fgets(buf, sizeof(buf), fp);
while (fgets(buf, sizeof(buf), fp)) {
char *cgroup;
char rc[80];
@@ -71,27 +70,27 @@ void cgroup_init(void)
}
/* Default cgroups for process monitoring */
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
if (mkdir("/sys/fs/cgroup/finit", 0755) && EEXIST != errno)
goto fail;
if (mount("none", FINIT_CGPATH, "cgroup", opts, "none,name=finit")) {
if (mount("none", "/sys/fs/cgroup/finit", "cgroup", opts, "none,name=finit")) {
_pe("Failed mounting Finit cgroup hierarchy");
goto fail;
}
/* Set up reaper and enable callbacks */
echo(FINIT_CGPATH "/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
echo(FINIT_CGPATH "/notify_on_release", 0, "1");
echo("/sys/fs/cgroup/finit/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
echo("/sys/fs/cgroup/finit/notify_on_release", 0, "1");
/* Default groups, PID 1, services, and user/login processes */
if (mkdir(FINIT_CGPATH "/init", 0755) && EEXIST != errno)
if (mkdir("/sys/fs/cgroup/finit/init", 0755) && EEXIST != errno)
goto fail;
if (mkdir(FINIT_CGPATH "/system", 0755) && EEXIST != errno)
if (mkdir("/sys/fs/cgroup/finit/system", 0755) && EEXIST != errno)
goto fail;
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
if (mkdir("/sys/fs/cgroup/finit/user", 0755) && EEXIST != errno)
goto fail;
/* Move ourselves to init */
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
echo("/sys/fs/cgroup/finit/init/cgroup.procs", 0, "1");
/* We have signal, main screen turn on! */
cg_init = 1;
@@ -103,11 +102,7 @@ static int move_pid(char *group, char *name, char *id, int pid)
{
char path[256];
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
if (id && strlen(id)) {
strlcat(path, ":", sizeof(path));
strlcat(path, id, sizeof(path));
}
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s:%s", group, name, id);
if (mkdir(path, 0755) && errno != EEXIST)
return 1;
+20
View File
@@ -162,6 +162,26 @@ 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;
+20 -35
View File
@@ -47,7 +47,6 @@
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 {
@@ -79,14 +78,14 @@ static void hide_args(int argc, char *argv[])
}
}
int get_bool(char *arg, int default_value)
int get_bool(char *ptr, int default_value)
{
if (!arg)
if (!ptr)
goto fallback;
if (string_compare(arg, "true") || string_compare(arg, "on") || string_compare(arg, "1"))
if (string_compare(ptr, "true") || string_compare(ptr, "on") || string_compare(ptr, "1"))
return 1;
if (string_compare(arg, "false") || string_compare(arg, "off") || string_compare(arg, "0"))
if (string_compare(ptr, "false") || string_compare(ptr, "off") || string_compare(ptr, "0"))
return 0;
fallback:
return default_value;
@@ -98,24 +97,19 @@ fallback:
*/
static void parse_finit_opts(char *opt)
{
char *arg;
char *ptr;
arg = strchr(opt, '=');
if (arg)
*arg++ = 0;
ptr = strchr(opt, '=');
if (ptr)
*ptr++ = 0;
if (string_compare(opt, "debug")) {
debug = get_bool(arg, 1);
debug = get_bool(ptr, 1);
return;
}
if (string_compare(opt, "status_style")) {
if (!arg) {
_e("status_style option requires an argument, skipping.");
return;
}
if (string_compare(arg, "old") || string_compare(arg, "classic"))
if (string_compare(ptr, "old") || string_compare(ptr, "classic"))
show_progress(PROGRESS_CLASSIC);
else
show_progress(PROGRESS_MODERN);
@@ -123,7 +117,7 @@ static void parse_finit_opts(char *opt)
}
if (string_compare(opt, "show_status")) {
show_progress(get_bool(arg, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
show_progress(get_bool(ptr, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
return;
}
}
@@ -626,9 +620,12 @@ int conf_reload(void)
tty_mark();
/*
* Reset global rlimit to bootstrap values from conf_init().
* 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.
*/
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
for (int i = 0; i < RLIMIT_NLIMITS; i++)
getrlimit(i, &global_rlimit[i]);
if (rescue) {
int rc;
@@ -697,8 +694,6 @@ int conf_reload(void)
globfree(&gl);
/* Mark any reverse deps as chenaged. */
service_update_rdeps();
done:
/* Drop record of all .conf changes */
drop_changes();
@@ -805,8 +800,7 @@ static void conf_cb(uev_t *w, void *arg, int events)
{
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
struct inotify_event *ev;
ssize_t sz;
size_t off;
ssize_t sz, off;
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
@@ -815,16 +809,10 @@ static void conf_cb(uev_t *w, void *arg, int events)
}
ev_buf[sz] = 0;
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
for (off = 0; off < 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;
@@ -894,11 +882,8 @@ 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++) {
if (getrlimit(i, &initial_rlimit[i]))
logit(LOG_WARNING, "rlimit: Failed reading setting %s: %s",
rlim2str(i), strerror(errno));
}
for (int i = 0; i < RLIMIT_NLIMITS; i++)
getrlimit(i, &global_rlimit[i]);
/* prepare /etc watcher */
fd = iwatch_init(&iw_conf);
+10 -18
View File
@@ -179,8 +179,7 @@ static void fs_remount_root(int fsckerr)
* XXX: Untested, in the initramfs age we should
* probably use switch_root instead.
*/
if (mount(SYSROOT, "/", NULL, MS_MOVE, NULL))
_pe("Failed %s / MS_MOVE");
rc = mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
}
#endif /* SYSROOT */
@@ -207,9 +206,6 @@ 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)
{
@@ -222,13 +218,8 @@ static void fs_init(void)
};
size_t i;
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);
}
for (i = 0; i < NELEMS(fs); i++)
mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
}
/*
@@ -484,10 +475,13 @@ int main(int argc, char *argv[])
setenv("PATH", _PATH_STDPATH, 1);
setenv("SHELL", _PATH_BSHELL, 1);
if (chdir("/"))
_pe("Failed cd /");
chdir("/");
umask(0);
/* Set up canvas */
if (!rescue && !debug)
screen_init();
/* Allow progress, if enabled */
enable_progress(1);
@@ -496,10 +490,8 @@ 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);
/*
+1 -10
View File
@@ -36,17 +36,8 @@
#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/"
#endif
#ifndef FINIT_CGPATH
#define FINIT_CGPATH "/sys/fs/cgroup/finit"
#define _PATH_VARRUN "/var/run/"
#endif
#define LOGIT_PATH FINIT_LIBPATH_ "/logit"
+7 -15
View File
@@ -121,7 +121,7 @@ static void add_console(char *cons)
num_cons++;
}
static void find_active_consoles(void)
void console_init(void)
{
char *cons, *ptr, *tok;
char buf[512];
@@ -148,12 +148,6 @@ static void find_active_consoles(void)
}
}
void console_init(void)
{
find_active_consoles();
screen_init();
}
ssize_t cprintf(const char *fmt, ...)
{
const size_t len = strlen(fmt) * 2;
@@ -432,14 +426,14 @@ void set_hostname(char **hostname)
return;
}
if (fgets(*hostname, st.st_size, fp))
chomp(*hostname);
fgets(*hostname, st.st_size, fp);
chomp(*hostname);
fclose(fp);
}
done:
if (*hostname)
(void)sethostname(*hostname, strlen(*hostname));
sethostname(*hostname, strlen(*hostname));
}
/*
@@ -563,12 +557,10 @@ int ismnt(char *file, char *dir, char *mode)
while ((mnt = getmntent(fp))) {
if (!strcmp(mnt->mnt_dir, dir)) {
if (mode) {
if (hasopt(mnt->mnt_opts, mode))
found = 1;
} else
if (mode && hasopt(mnt->mnt_opts, mode))
found = 1;
else
found = 1;
break;
}
}
+99 -152
View File
@@ -26,7 +26,6 @@
#include <err.h>
#include <ftw.h>
#include <ctype.h>
#include <dirent.h>
#include <getopt.h>
#include <paths.h>
#include <signal.h>
@@ -44,11 +43,6 @@
#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);
@@ -57,8 +51,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;
@@ -78,7 +72,11 @@ static void col_widths(void)
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
int w, p;
svc_ident(svc, ident, sizeof(ident));
if (!numeric)
svc_ident(svc, ident, sizeof(ident));
else
svc_jobid(svc, ident, sizeof(ident));
w = (int)strlen(ident);
if (w > iw)
iw = w;
@@ -208,8 +206,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 task or service(s): %s\n\n", arg);
fprintf(stderr, "Usage: initctl %s <NAME>[:ID]\n",
fprintf(stderr, "No such job(s) or service(s): %s\n\n", rq.data);
fprintf(stderr, "Usage: initctl %s <JOB|NAME>[:ID]\n",
cmd == INIT_CMD_START_SVC ? "start" :
(cmd == INIT_CMD_STOP_SVC ? "stop" : "restart"));
return 1;
@@ -325,7 +323,11 @@ static int do_cond_show(char *arg)
cond = cond_get_agg(svc->cond);
svc_ident(svc, ident, sizeof(ident));
if (!numeric)
svc_ident(svc, ident, sizeof(ident));
else
svc_jobid(svc, ident, sizeof(ident));
printf("%-*d %-*s ", pw, svc->pid, iw, ident);
if (cond == COND_ON)
@@ -489,24 +491,9 @@ 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);
@@ -519,11 +506,11 @@ static int show_status(char *arg)
if (!svc)
return 1;
printf("Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
printf("Job : %d\n", svc->job);
printf("Service : %s\n", svc->cmd);
printf("Description : %s\n", svc->desc);
printf("Origin : %s\n", svc->file[0] ? svc->file : "built-in");
printf("Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
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));
@@ -549,10 +536,15 @@ 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);
svc_ident(svc, ident, sizeof(ident));
if (!numeric)
svc_ident(svc, ident, sizeof(ident));
else
svc_jobid(svc, ident, sizeof(ident));
printf("%-*s %-8s ", iw, ident, svc_status(svc));
lvls = runlevel_string(runlevel, svc->runlevels);
@@ -561,124 +553,89 @@ static int show_status(char *arg)
else
printf("%-12.12s ", lvls);
if (!verbose)
puts(svc->desc);
else
puts(svc_command(svc, cmd, sizeof(cmd)));
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);
}
}
return 0;
}
static int cgroup_filter(const struct dirent *entry)
static int dump_cgroup(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
{
/* 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;
char *group;
char path[256];
char buf[256];
int user = 0;
int num = 0;
if (-1 == lstat(path, &st))
return 1;
if (tflag == FTW_F)
return 0;
if ((st.st_mode & S_IFMT) != S_IFDIR) {
errno = ENOTDIR;
return -1;
}
fp = fopenf("r", "%s/cgroup.procs", path);
snprintf(path, sizeof(path), "%s/cgroup.procs", fpath);
fp = fopen(path, "r");
if (!fp)
return -1;
num = 0;
while (fgets(buf, sizeof(buf), 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++;
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);
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);
}
err:
fclose(fp);
if (num)
printf("\r%c\n", user ? ' ' : '|');
return rc;
return 0;
}
static int show_cgroup(char *arg)
{
char path[512];
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);
if (!arg)
arg = FINIT_CGPATH;
else if (arg[0] != '/') {
paste(path, sizeof(path), FINIT_CGPATH, arg);
arg = path;
}
return dump_cgroup(arg, NULL);
return 0;
}
static int transform(char *nm)
@@ -725,6 +682,7 @@ 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"
@@ -740,14 +698,9 @@ 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);
else
fprintf(stderr,
" show Show %s\n", FINIT_CONF);
avail, avail, avail, avail);
if (has_ena)
fprintf(stderr,
" enable <CONF> Enable .conf in %s\n", avail);
@@ -762,17 +715,17 @@ static int usage(int rc)
" reload Reload " FINIT_CONF " (activate changes)\n");
fprintf(stderr,
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or 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 <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"
" 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"
"\n"
" ps List processes based on cgroups\n"
"\n"
@@ -793,15 +746,6 @@ 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);
@@ -811,7 +755,6 @@ int main(int argc, char *argv[])
{
struct command command[] = {
{ "debug", toggle_debug },
{ "devel", do_devel },
{ "help", do_help },
{ "version", show_version },
@@ -820,7 +763,6 @@ 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 },
@@ -833,7 +775,7 @@ int main(int argc, char *argv[])
{ "stop", do_stop },
{ "restart", do_restart },
{ "status", show_status },
{ "show", show_status }, /* Convenience alias, for now */
{ "show", show_status }, /* Convenience alias */
{ "ps", show_cgroup },
@@ -851,6 +793,7 @@ 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 }
@@ -861,7 +804,7 @@ int main(int argc, char *argv[])
if (transform(progname(argv[0])))
return reboot_main(argc, argv);
while ((c = getopt_long(argc, argv, "bcfh?tv", long_options, NULL)) != EOF) {
while ((c = getopt_long(argc, argv, "bcfh?ntv", long_options, NULL)) != EOF) {
switch(c) {
case 'b':
interactive = 0;
@@ -879,6 +822,10 @@ int main(int argc, char *argv[])
case '?':
return usage(0);
case 'n':
numeric = 1;
break;
case 't':
heading = 0;
break;
+7 -4
View File
@@ -22,6 +22,7 @@
*/
#include "config.h"
#include <sched.h> /* sched_yield() */
#include <stdio.h>
#include <stdarg.h>
#include <lite/lite.h>
@@ -49,13 +50,15 @@ void log_exit(void)
* Unless in debug mode at shutdown, Reinitialize screen,
* terminal may have been resized at runtime
*/
if (!debug)
if (debug)
screen_exit();
else
screen_init();
enable_progress(1);
}
static void log_open(void)
void log_open(void)
{
int opts = LOG_PID;
@@ -76,6 +79,7 @@ void log_debug(void)
if (debug) {
loglevel = LOG_DEBUG;
screen_exit();
} else {
loglevel = LOG_NOTICE;
screen_init();
@@ -99,12 +103,11 @@ void logit(int prio, const char *fmt, ...)
if (up || fexist("/dev/log")) {
if (!up)
log_open();
vsyslog(prio, fmt, ap);
goto done;
}
if (prio > loglevel)
if (!debug && prio > loglevel)
goto done;
fp = fopen("/dev/kmsg", "w");
+65 -2
View File
@@ -30,12 +30,75 @@
#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
View File
@@ -1,102 +0,0 @@
/*
* 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;
}
+3 -25
View File
@@ -58,9 +58,7 @@ static void do_list(const char *path)
glob_t gl;
size_t i;
if (chdir(path))
return;
chdir(path);
if (glob("*.conf", 0, NULL, &gl))
return;
@@ -140,11 +138,6 @@ 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;
@@ -215,7 +208,7 @@ int do_disable(char *arg, int check)
if (chdir(FINIT_RCSD))
err(1, "failed cd %s", FINIT_RCSD);
(void)chdir("enabled"); /* System *may* have enabled/ dir. */
chdir("enabled"); /* System *may* have enabled/ dir. */
if (check && stat(arg, &st))
errx(1, "%s not (an) enabled (service).", arg);
@@ -257,20 +250,6 @@ 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
@@ -379,8 +358,7 @@ int serv_delete(char *arg)
if (iforce || yorn("Remove file and symlink(s) to %s (y/N)? ", fn)) {
do_disable(arg, 0);
if (remove(fn))
err(1, "Failed removing %s", fn);
remove(fn);
}
return 0;
-1
View File
@@ -28,7 +28,6 @@ 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);
+3 -38
View File
@@ -464,18 +464,17 @@ static int service_start(svc_t *svc)
/* Set desired user+group */
if (gid >= 0)
(void)setgid(gid);
setgid(gid);
if (uid >= 0) {
(void)setuid(uid);
setuid(uid);
/* Set default path for regular users */
if (uid > 0)
setenv("PATH", _PATH_DEFPATH, 1);
if (home) {
setenv("HOME", home, 1);
if (chdir(home))
(void)chdir("/");
chdir(home);
}
}
@@ -1163,8 +1162,6 @@ 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));
@@ -1250,38 +1247,6 @@ 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;
-1
View File
@@ -33,7 +33,6 @@ 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);
+3 -26
View File
@@ -86,8 +86,9 @@ typedef enum {
typedef struct svc {
TAILQ_ENTRY(svc) link;
/* Origin of service */
char file[MAX_ARG_LEN];
/* Instance specifics */
int job; /* JOB: */
char id[MAX_ID_LEN]; /* :ID */
/* Limits and scoping */
struct rlimit rlimit[RLIMIT_NLIMITS];
@@ -109,11 +110,7 @@ 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 */
@@ -208,26 +205,6 @@ 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)
+1
View File
@@ -30,6 +30,7 @@
#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;
+15 -62
View File
@@ -28,15 +28,9 @@
#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"
@@ -208,66 +202,25 @@ char *sanitize(char *arg, size_t len)
}
/*
* Called by initctl, and by finit at boot and shutdown, to
* (re)initialize the screen size for print() et al.
* Called at boot, and shutdown, to (re)initialize the
* screen size for print() et al.
*/
int screen_init(void)
void screen_init(void)
{
#ifdef HAVE_TERMIOS_H
struct pollfd fd = { STDIN_FILENO, POLLIN, 0 };
struct winsize ws = { 0 };
struct termios tc, saved;
if (!isatty(STDOUT_FILENO))
return;
/*
* 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);
initscr(&screen_rows, &screen_cols);
}
/* 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;
/*
* Called when debug mode is enabled to revert back
* to old-school safe defaults.
*/
void screen_exit(void)
{
screen_rows = 24;
screen_cols = 80;
}
/**
+3 -1
View File
@@ -55,7 +55,9 @@ char *uptime (long secs, char *buf, size_t len);
char *sanitize (char *arg, size_t len);
int screen_init (void);
void screen_init (void);
void screen_exit (void);
int screen_width (void);
static inline char *strterm(char *str, size_t len)
{
+61 -5
View File
@@ -35,9 +35,6 @@
#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;
@@ -49,6 +46,65 @@ 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
*
@@ -138,13 +194,13 @@ static int set_getty(int type, char *tty, char *id, char *user)
return 0;
if (!tty)
line = NULL;
line = "";
else if (!strncmp(tty, "/dev/", 5))
line = tty + 5;
else
line = tty;
if (!id && line) {
if (!id) {
id = line;
if (!strncmp(id, "pts/", 4))
id += 4;
+1 -1
View File
@@ -44,6 +44,6 @@ fi
mkdir -p "$FINIT_RCSD"
tty=/dev/$(cat /sys/class/tty/console/active)
mkfifo "$tty"
ln -fs /shared/pts "$tty"
exec "$@"
-4
View File
@@ -138,7 +138,3 @@ 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
+2
View File
@@ -38,6 +38,7 @@ 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 \
@@ -57,6 +58,7 @@ dirs = $(DEST)/bin \
$(DEST)/etc \
$(DEST)/proc \
$(DEST)/sbin \
$(DEST)/shared \
$(DEST)/sys \
$(DEST)/test_assets \
$(DEST)/tmp
+4 -1
View File
@@ -45,4 +45,7 @@ exec "$unshare" \
--mount \
--mount-proc \
--uts --ipc --net \
"$chroot" "$TENV_ROOT" /bin/chrootsetup.sh "$@"
sh -c "
ln -fs /proc/1/fd/1 $TENV_ROOT/shared/pts;
exec $chroot $TENV_ROOT /bin/chrootsetup.sh $*
"