Compare commits

..
Author SHA1 Message Date
Joachim Wiberg ccfea59cb3 Bump version for Finit v4.0-rc2 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 18:50:50 +01:00
Joachim Wiberg 7b315364ca Update initctl help text, and output, relocate screenshot
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 15:38:23 +01:00
Joachim Wiberg e9e28ece1c Add Finit4 + Alpine screenshot
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 15:28:32 +01:00
Joachim Wiberg c1f9b4e1f6 Use .svg for Travis-CI status badge
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 15:17:26 +01:00
Joachim Wiberg 6ebb23e0f0 Travis-CI: Minor, adjust configure line for Coverity
- Drop commented-out sudo:true
- Drop unnecessary configure option

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 15:16:26 +01:00
Joachim Wiberg 026c229005 Revert "Travis-CI: disable clang and unit tests for Coverity Scan run"
This reverts commit c71bafd495.
2021-03-07 15:14:47 +01:00
Joachim Wiberg 4d05bf9359 Mark affected services as dirty if their rdeps are dirty
Provided a configuration that looks like this:

ospfd.conf:
    service [2345] <!pid/zebra> log ospfd -A 127.0.0.1 -u root -g root -- OSPF daemon

zebra.conf:
    service [2345] <!> log zebra -A 127.0.0.1 -u root -g root -- Zebra Routing daemon

If zebra.conf is changed, we restart it when `initctl reload` is issued.

This change ensures that ospfd is also restarted, because ospfd depends
on zebra, we must restart it too.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 14:52:19 +01:00
Joachim Wiberg 289247dab9 plugins: netlink: slightly stricter ifname validation
Check if ifname contains double periods, this should *not* be a valid
name, though eth0.10 is, et0..10 is not.  Should protect better against
directory traversal attacks.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 13:25:40 +01:00
Joachim Wiberg e44dfde54e plugins: tty: validate against read() length, not buffer size
Fix ev->len validation; must check against sz read(), not total buffer
size.  Also, fix off-by-one in comparison.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 12:55:12 +01:00
Joachim Wiberg 35b200d3a9 Validate inotify event against read() length, not buffer size
Fix ev->len validation; must check against sz read(), not total buffer
size.  Also, fix off-by-one in comparison.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 12:55:12 +01:00
Joachim Wiberg 5badf4d376 plugins: pidfile: validate against read() length, not buffer size
Fix ev->len validation; must check against sz read(), not total buffer
size.  Also, fix off-by-one in comparison.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 12:48:42 +01:00
Joachim Wiberg 24f274c126 plugins: netlink: validate interface name
Check for spaces and slashes in interface name to prevent path based
attacks.  Found by Coverity Scan.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 12:23:24 +01:00
Joachim Wiberg 1abd43384b plugins: netlink: minor refactor, collapse for-loop
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 12:20:59 +01:00
Joachim Wiberg 70a1acc210 Highly unlikekly, but chdir() needs to be checked
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 11:40:25 +01:00
Joachim Wiberg 6af0446490 plugins: netlink: fix untrusted loop bound, found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 11:28:39 +01:00
Joachim Wiberg ecaf111a4b plugins: tty: possible out-of-bounds read in inotify_event parser
This is a major refactor to use the same construct as in the pidfile.so
plugin to parse kernel inotify events for when TTYs are added removed
from the system.

Found by Coverity Scan.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 10:58:55 +01:00
Joachim Wiberg 32ec25b070 Check return value from remove(), found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 10:34:23 +01:00
Joachim Wiberg 305ad302f2 Refactor, reduce code duplication
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 10:28:54 +01:00
Joachim Wiberg d6390244ad Fix possible out-of-bounds read in inotify_event parser
Found by Coverity Scan.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 09:57:07 +01:00
Joachim Wiberg 790a316607 Log rotate: improved handling of return values from syscalls
- Align the two implementations in logit.c and utmp-api.c
 - Use libite APIs to handle common constructs
 - If gzip fails, don't remove rotated-to file
 - Don't try gzip if rename fails
 - Issues found by Coverity Scan

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 09:57:07 +01:00
Joachim Wiberg 77aa941e84 Mounting devtmpfs may fail if already mounted
Ignore EBUSY errors, the kernel has the ability to automount /dev as
soon as the rootfs has been mounted.  This may be added to procfs and
sysfs later, so we make this a general change in fs_init().

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-07 09:48:02 +01:00
Joachim Wiberg e0a65f67c9 Minor, staticify, reduce includes and allow debug to kmsg
The loglevel setting should control all logging, regardless of
where we target it.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-06 23:55:54 +01:00
Joachim Wiberg 3ed291789c Fix GCC warnings with _FORTIFY_SOURCE=2
- Decleare some return values with (void)fn(), for cases where
  we don't care (dropping table headers), or best effor
- Check return value from fgets() and chdir() in some cases that
  are valid, i.e., continuing execution is pointless

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 12:36:48 +01:00
Joachim Wiberg 774a24cdd8 Allow building with -D_FORTIFY_SOURCE[=1,2]
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 11:17:59 +01:00
Joachim Wiberg 6011f91f22 Fix possible out-of-bounds read in inotify_event parser
Found by Coverity Scan.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 11:16:37 +01:00
Joachim Wiberg 07a364e570 initctl: fix use of possibly unterminated string, found by Coverity
No point in using rq.data, which could have been modified, instead use
the input argument to the function in the error message.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 10:51:25 +01:00
Joachim Wiberg 5b9d99011b Fix long-standing bug in reset of rlimits between reconf
While skimming through the results of the latest Coverity Scan, I
discovered that that the reset logic of global rlimits was broken.
This it seems to have been since its first introduction in Finit.

We fix this by reading initial rlimits at bootstrap, then for each
reconf, including the first, we seed global rlimits with the initial
ones -- thus resetting between each reconf.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 10:44:01 +01:00
Joachim Wiberg f4f773b4c7 Initialize fallback svc_t in client comms, found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 10:35:12 +01:00
Joachim Wiberg 9d949c4186 Fix possible NULL ptr deref in cmdline option parser
Found by Coverity Scan.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 10:21:58 +01:00
Joachim Wiberg 1434561a46 initctl: fix cut-and-paste error in new 'show' command
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 10:17:52 +01:00
Joachim Wiberg cf3d3f6f8e Properly check return value from mount(2) and display error message
Found by Coverity Scan.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 10:15:46 +01:00
Joachim Wiberg 621da582c2 Fix obvious bug in ismnt() found by Coverity Scan
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 10:10:45 +01:00
Joachim Wiberg 9167d9255d Work around weird finding from Coverity Scan
The utmp_set() function allows id==NULL, so default the line to NULL and
avoid parsing empty lines.  Which is better code anyway.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 09:59:58 +01:00
Joachim Wiberg c71bafd495 Travis-CI: disable clang and unit tests for Coverity Scan run
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 08:25:32 +01:00
Joachim Wiberg b3b7a33252 initctl: developer mode, hidden command
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 08:22:38 +01:00
Joachim Wiberg d1efc60c84 initctl: add show command to cat foo.conf, default finit.conf
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 08:06:01 +01:00
Joachim Wiberg 9a24dfd98d initctl: refactor command composition for status command
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 00:13:01 +01:00
Joachim Wiberg 0e3fe5e3bf initctl: fix too long args list to status command
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-05 00:06:36 +01:00
Joachim Wiberg 224f42c344 cgreaper.sh: drop log message when cleaning up
Mostly used during development, doesn't really provide any value to the
user at normal runtime.  Leave it commented out though so user can do
debug themselves if needed.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-04 23:57:48 +01:00
Joachim Wiberg e60eb94810 initctl: complete rewrite of cgroup dumper in 'ps' command
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-04 23:49:42 +01:00
Joachim Wiberg 464bc831a5 Minor refactor, create FINIT_CGPATH in finit.h to reduce duplicaiton
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-04 23:48:57 +01:00
Joachim Wiberg e84911fe52 cgroup: create 'name' or 'name:id' entries, not 'name:'
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-04 23:46:25 +01:00
Joachim Wiberg 4bcfd606b4 Refactor screen_init(), use methods developed in pimd project
- Refactor screen_init()
  - use native impl. of TTY probing from pimd project
    - check if TIOCWINSZ works
    - check if we're running in watch(1), for initctl
  - check if ANSI goto(999,999) escape seq. works (invasive)
  - fallback to 80x24
- Drop screen_exit()
- Rename screen_init() to get_width(), for now, matching pimd
- Relocate call in main() to banner(), first fn to write to TTY

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-04 23:23:31 +01:00
Joachim Wiberg fe27ed17eb initctl: status command formatting updates, add origin .conf file
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-04 07:27:06 +01:00
Joachim Wiberg b3ea23ed26 initctl: drop old 'job:id' format support, canonical is 'name:id'
With the recent changes to the condition handling it has become more and
more evident that the canonical reference for a task/run/service is the
NAME:ID representation.  Up until now we've kept the older JOB:ID for
some sort of compatibility fallback.

This patch removes the support to simplify maintenance going forward.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-03-04 07:23:19 +01:00
35 changed files with 715 additions and 468 deletions
+2 -5
View File
@@ -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
View File
@@ -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
+55 -33
View File
@@ -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 …"
![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:
@@ -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/)
![Alpine screenshot](img/alpine-screenshot.png)
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
View File
@@ -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
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 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
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
+15 -10
View File
@@ -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;
-20
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+4 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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);
+26 -3
View File
@@ -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)
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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 "$@"
+4
View File
@@ -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
-2
View File
@@ -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
View File
@@ -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 "$@"