Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44137806e4 | ||
|
|
0848b9b07a | ||
|
|
c64188bfc5 | ||
|
|
5e789401d4 | ||
|
|
744fdd654f | ||
|
|
f51fde4d46 | ||
|
|
85261c9acd | ||
|
|
6a1082a947 | ||
|
|
2094d2a53a | ||
|
|
d7da177742 | ||
|
|
170e5aa3fd | ||
|
|
f8ef8a1616 | ||
|
|
f5f1a55747 | ||
|
|
a36aade7f4 | ||
|
|
76fc72770e | ||
|
|
b64dbbf8d0 | ||
|
|
d371b85c47 | ||
|
|
053304012f | ||
|
|
12d14aae84 | ||
|
|
6a7f115781 | ||
|
|
423c8d41a7 | ||
|
|
f2cab53e55 | ||
|
|
33fd6f0049 | ||
|
|
e83dcafb02 | ||
|
|
9a98bff23f | ||
|
|
1a2f7d162b |
@@ -32,7 +32,10 @@ Bug fix release.
|
||||
event, because services may depend on each other
|
||||
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
||||
the kernel can invalidate deleted events before enqueing to userspace
|
||||
|
||||
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
||||
from the `hwclock` tool. Note: the kernel can also be set to load
|
||||
and store RTC to/from system clock at boot/halt as well.
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix #96: Start udevd as a proper service
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<img align="right" src="images/finit3.png" alt="Finit: Fast Init">
|
||||
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
@@ -35,7 +35,7 @@ on server and desktop systems as well. For working examples, see the
|
||||
* [Debian GNU/Linux](contrib/debian/), and
|
||||
* [Void Linux](contrib/void/)
|
||||
|
||||

|
||||

|
||||
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
|
||||
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864])
|
||||
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
|
||||
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
|
||||
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
|
||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
config.md
|
||||
@@ -30,8 +30,6 @@ Near Future
|
||||
* Cron/At support, see below
|
||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||
`pimd` man pages ...
|
||||
* Add simple, *very* simple, `finit-simple.conf` example. To illustrate
|
||||
how close Finit3 still is to the original easy-to-use Finit0 :)
|
||||
|
||||
|
||||
General
|
||||
@@ -59,6 +57,8 @@ General
|
||||
now inotify listeners should be automatically created (and removed)
|
||||
when a subdirectory is added (or removed).
|
||||
|
||||
[Solaris SMF]: http://www.oracle.com/technetwork/articles/servers-storage-admin/intro-smf-basics-s11-1729181.html
|
||||
|
||||
|
||||
Init
|
||||
----
|
||||
@@ -114,5 +114,3 @@ could support the basic functionality of the `at` command directly from
|
||||
the shell -- that way setting up one-time jobs would not entail
|
||||
re-reading `/etc/finit.conf`
|
||||
|
||||
|
||||
[Solaris SMF]: http://www.oracle.com/technetwork/articles/servers-storage-admin/intro-smf-basics-s11-1729181.html
|
||||
|
||||
@@ -98,6 +98,54 @@ Syntax
|
||||
* `network <PATH>`
|
||||
Script or program to bring up networking, with optional arguments
|
||||
|
||||
* `cgroup <NAME> cpuset:SPEC cpu:SPEC mem:SPEC`
|
||||
Create a control group for resource limiting services using cgroups.
|
||||
Unlike `rlimit` this setting defines a common group to be selected for
|
||||
any set of run/task/services using the `group` directive (below).
|
||||
|
||||
A cpuset for a cgroup can be the traditional list of CPU cores to
|
||||
assign to the group, or a range that Finit will use to dynamically
|
||||
allocate cores based on the amount available. The range values can be
|
||||
either in absolute form or percent.
|
||||
|
||||
```shell
|
||||
cgroup first cpuset:1
|
||||
```
|
||||
|
||||
To create a cgroup with one exclusive CPU:
|
||||
|
||||
```shell
|
||||
cgroup single cpuset:[1,1]
|
||||
```
|
||||
|
||||
To create cgroup that uses at most two shared CPUs:
|
||||
|
||||
```shell
|
||||
cgroup uptotwo cpuset:[,2]
|
||||
```
|
||||
|
||||
To create cgroup with at least two shared CPUs:
|
||||
|
||||
```shell
|
||||
cgroup dual cpuset:[2,]
|
||||
```
|
||||
|
||||
To create cgroup with at least one CPU and at most half of all
|
||||
available CPUs:
|
||||
|
||||
```shell
|
||||
cgroup greedy cpuset:[1,50%]
|
||||
```
|
||||
|
||||
|
||||
* `group <NAME>`
|
||||
All subsequent `service`, `task`, or `run` directives are executed in the
|
||||
given control group `NAME`, which must be defined prior to this line. If
|
||||
`NAME` does not yet exist the default group `default` is used.
|
||||
|
||||
When separate Finit `.conf` files are used for services the default group
|
||||
is reset for each `.conf` file read.
|
||||
|
||||
* `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>` Set the hard or soft
|
||||
limit for a resource, or both if that argument is omitted. `RESOURCE`
|
||||
is the lower-case `RLIMIT_` string constants from `setrlimit(2)`,
|
||||
@@ -185,6 +233,18 @@ Syntax
|
||||
For a detailed description of conditions, and how to debug them, see
|
||||
the [Finit Conditions](conditions.md) document.
|
||||
|
||||
If a service should not be automatically started, it can be configured
|
||||
as manual with the optional `manual` argument. The service can then be
|
||||
started at any time by running `initctl start <service>`.
|
||||
|
||||
manual:yes
|
||||
|
||||
The name of a service, shown by the `initctl` tool, defaults to the
|
||||
basename of the service executable. It can be changed with the
|
||||
optional `name` argument:
|
||||
|
||||
name:<service-name>
|
||||
|
||||
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
|
||||
Launch a daemon when a client initiates a connection on an Internet
|
||||
port. Available services are listed in the UNIX `/etc/services` file.
|
||||
@@ -338,6 +398,7 @@ syslog using the native `logit` tool. The full syntax is:
|
||||
|
||||
log:/path/to/file
|
||||
log:prio:facility.level,tag:ident
|
||||
log:console
|
||||
log:null
|
||||
log
|
||||
|
||||
|
||||
@@ -42,11 +42,12 @@ For your convenience a set of *optional* plugins are available:
|
||||
|
||||
* *discard.so*: RFC 863 plugin. Start as inetd service, like time below.
|
||||
|
||||
* *hwclock.so*: Restore and save system clock from/to RTC on
|
||||
startup/shutdown.
|
||||
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||
|
||||
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
|
||||
|
||||
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||
|
||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||
interfaces. These events are then sent to the Finit service monitor
|
||||
for services that may want to be SIGHUP'ed on new default route or
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c procps.c tty.c urandom.c
|
||||
libplug_la_SOURCES = bootmisc.c rtc.c initctl.c pidfile.c procps.c tty.c urandom.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
@@ -39,6 +39,10 @@ libplug_la_SOURCES += time.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_MODULES_LOAD_PLUGIN
|
||||
libplug_la_SOURCES += modules-load.c
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
libplug_la_SOURCES += netlink.c
|
||||
endif
|
||||
@@ -48,7 +52,7 @@ libplug_la_SOURCES += resolvconf.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la procps.la tty.la urandom.la
|
||||
pkglib_LTLIBRARIES = bootmisc.la rtc.la initctl.la pidfile.la procps.la tty.la urandom.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
@@ -80,6 +84,10 @@ pkglib_LTLIBRARIES += time.la
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_MODULES_LOAD_PLUGIN
|
||||
pkglib_LTLIBRARIES += modules-load.la
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
pkglib_LTLIBRARIES += netlink.la
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/* Scans /etc/modules-load.d for modules to load.
|
||||
*
|
||||
* Copyright (c) 2018 Robert Andersson <robert.m.andersson@se.atlascopco.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 <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
#include "conf.h"
|
||||
|
||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||
#define SERVICE_LINE \
|
||||
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
|
||||
static void load(void *arg)
|
||||
{
|
||||
FILE *fp;
|
||||
DIR *dirp;
|
||||
struct dirent *direntp;
|
||||
char line[256];
|
||||
int index = 1;
|
||||
|
||||
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||
|
||||
dirp = opendir(MODULES_LOAD_PATH);
|
||||
if (!dirp) return;
|
||||
|
||||
while ((direntp = readdir(dirp)))
|
||||
{
|
||||
char module_path[PATH_MAX];
|
||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||
strlcat(module_path, direntp->d_name, sizeof(module_path));
|
||||
|
||||
fp = fopen(module_path, "r");
|
||||
if (!fp) continue;
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
char cmd[CMD_SIZE], *mod, *args;
|
||||
|
||||
mod = strip_line(line);
|
||||
if (!*mod) continue;
|
||||
|
||||
mod = chomp(mod);
|
||||
if (!mod || !*mod) continue;
|
||||
|
||||
mod = strtok_r(mod, " ", &args);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
||||
index, mod, mod, args, mod);
|
||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = load
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -64,7 +64,7 @@ static void pidfile_callback(void *arg, int fd, int events)
|
||||
continue;
|
||||
|
||||
mkcond(cond, sizeof(cond), svc->cmd);
|
||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY)) {
|
||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||
svc_started(svc);
|
||||
cond_set(cond);
|
||||
} else if (ev->mask & IN_DELETE)
|
||||
@@ -111,6 +111,7 @@ static void pidfile_init(void *arg)
|
||||
{
|
||||
char *path;
|
||||
struct context *ctx = arg;
|
||||
uint32_t mask = IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY | IN_MOVED_TO;
|
||||
|
||||
/*
|
||||
* The bootmisc plugin is responsible for setting up /var/run.
|
||||
@@ -123,7 +124,7 @@ static void pidfile_init(void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->wd = inotify_add_watch(ctx->fd, path, IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
|
||||
ctx->wd = inotify_add_watch(ctx->fd, path, mask);
|
||||
free(path);
|
||||
|
||||
if (ctx->wd < 0) {
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/* Save and restore RTC using hwclock
|
||||
*
|
||||
* Copyright (c) 2012-2019 Joachim Nilsson <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 <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
/* Kernel RTC driver validates against this date for sanity check */
|
||||
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
||||
|
||||
static int rtc_open(void)
|
||||
{
|
||||
char *alt[] = {
|
||||
"/dev/rtc",
|
||||
"/dev/rtc0",
|
||||
"/dev/misc/rtc"
|
||||
};
|
||||
size_t i;
|
||||
int fd;
|
||||
|
||||
for (i = 0; i < NELEMS(alt); i++) {
|
||||
fd = open(alt[i], O_RDONLY);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void rtc_save(void *arg)
|
||||
{
|
||||
struct timeval tv = { 0 };
|
||||
struct tm tm = { 0 };
|
||||
int fd, rc = 0;
|
||||
|
||||
fd = rtc_open();
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
rc = gettimeofday(&tv, NULL);
|
||||
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||
invalid:
|
||||
logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
|
||||
rc = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_desc(NULL, "Saving system time (UTC) to RTC");
|
||||
gmtime_r(&tv.tv_sec, &tm);
|
||||
if (ioctl(fd, RTC_SET_TIME, &tm) < 0) {
|
||||
if (EINVAL == errno)
|
||||
goto invalid;
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
print(rc, NULL);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void rtc_restore(void *arg)
|
||||
{
|
||||
struct timeval tv = { 0 };
|
||||
struct tm tm = { 0 };
|
||||
int fd, rc = 0;
|
||||
|
||||
fd = rtc_open();
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
||||
char msg[120];
|
||||
|
||||
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
|
||||
EINVAL == errno ? "RTC time is too old" :
|
||||
ENOENT == errno ? "RTC has no saved time" : "see log for details");
|
||||
print_desc(NULL, msg);
|
||||
|
||||
invalid:
|
||||
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
||||
if (EINVAL == errno)
|
||||
logit(LOG_ERR, "RTC time is too old (before 2000-01-01 00:00)");
|
||||
else if (ENOENT == errno)
|
||||
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||
else
|
||||
logit(LOG_ERR, "RTC error code %d: %m", errno);
|
||||
rc = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||
tv.tv_sec = mktime(&tm);
|
||||
if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||
errno = EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (settimeofday(&tv, NULL) == -1)
|
||||
rc = 1;
|
||||
|
||||
out:
|
||||
print(rc, NULL);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = rtc_restore
|
||||
},
|
||||
.hook[HOOK_SHUTDOWN] = {
|
||||
.cb = rtc_save
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -10,6 +10,7 @@ endif
|
||||
|
||||
bin_PROGRAMS = logit
|
||||
sbin_PROGRAMS = finit initctl reboot
|
||||
pkglibexec_SCRIPTS = cgreaper.sh
|
||||
if WATCHDOGD
|
||||
pkglibexec_PROGRAMS = watchdogd
|
||||
endif
|
||||
@@ -17,7 +18,7 @@ endif
|
||||
logit_SOURCES = logit.c
|
||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
|
||||
finit_SOURCES = api.c \
|
||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
cond.c cond-w.c cond.h \
|
||||
telinit.c \
|
||||
conf.c conf.h \
|
||||
|
||||
@@ -93,17 +93,16 @@ static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
||||
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
||||
|
||||
static char query_buf[368];
|
||||
static int missing(char *job, int id)
|
||||
static int missing(char *job, char *id)
|
||||
{
|
||||
char buf[20];
|
||||
char idstr[13] = "";
|
||||
|
||||
if (!job)
|
||||
job = "";
|
||||
if (id > 1)
|
||||
snprintf(idstr, sizeof(idstr), ":%d", id);
|
||||
if (!id)
|
||||
id = "";
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s ", job, idstr);
|
||||
snprintf(buf, sizeof(buf), "%s:%s ", job, id);
|
||||
strlcat(query_buf, buf, sizeof(query_buf));
|
||||
|
||||
return 1;
|
||||
@@ -122,8 +121,9 @@ static int do_query(struct init_request *rq, size_t len)
|
||||
|
||||
static svc_t *do_find(char *buf, size_t len)
|
||||
{
|
||||
int id = 1;
|
||||
char *id = NULL;
|
||||
char *ptr, *input;
|
||||
svc_t *iter = NULL;
|
||||
|
||||
input = sanitize(buf, len);
|
||||
if (!input)
|
||||
@@ -132,11 +132,28 @@ static svc_t *do_find(char *buf, size_t len)
|
||||
ptr = strchr(input, ':');
|
||||
if (ptr) {
|
||||
*ptr++ = 0;
|
||||
id = atonum(ptr);
|
||||
id = ptr;
|
||||
}
|
||||
|
||||
if (isdigit(input[0]))
|
||||
return svc_find_by_jobid(atonum(input), id);
|
||||
if (isdigit(input[0])) {
|
||||
char *ep;
|
||||
long job = 0;
|
||||
|
||||
errno = 0;
|
||||
job = strtol(input, &ep, 10);
|
||||
if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) ||
|
||||
(errno != 0 && job == 0) ||
|
||||
(input == ep))
|
||||
return NULL;
|
||||
|
||||
if (!id)
|
||||
return svc_job_iterator(&iter, 1, job);
|
||||
|
||||
return svc_find_by_jobid(job, id);
|
||||
}
|
||||
|
||||
if (!id)
|
||||
return svc_named_iterator(&iter, 1, input);
|
||||
|
||||
return svc_find_by_nameid(input, id);
|
||||
}
|
||||
@@ -352,8 +369,8 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
if (wdog) {
|
||||
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
||||
stop(wdog);
|
||||
if (wdog->protected) {
|
||||
wdog->protected = 0;
|
||||
if (wdog->protect) {
|
||||
wdog->protect = 0;
|
||||
wdog->runlevels = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
# Called by kernel when last child in cgroup exists
|
||||
|
||||
BASE=/sys/fs/cgroup/finit
|
||||
PROC=`basename $1`
|
||||
DIR="$BASE$1"
|
||||
|
||||
logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
||||
rmdir $DIR
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,219 @@
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2019 Joachim Nilsson <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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <lite/lite.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
static struct {
|
||||
int active;
|
||||
char cgroup[16];
|
||||
char path[32];
|
||||
} cg_avail[200];
|
||||
|
||||
static int cg_init = 0;
|
||||
static int cg_num = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Called by Finit at early boot to mount initial cgroups
|
||||
*/
|
||||
void cgroup_init(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[80];
|
||||
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||
|
||||
fp = fopen("/proc/cgroups", "r");
|
||||
if (!fp) {
|
||||
_d("No cgroup support");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mount("none", "/sys/fs/cgroup", "tmpfs", opts, NULL)) {
|
||||
_d("Failed mounting cgroups");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Skip first line, header */
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
char *cgroup;
|
||||
char rc[80];
|
||||
|
||||
cgroup = strtok(buf, "\t ");
|
||||
if (!cgroup)
|
||||
continue;
|
||||
|
||||
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
||||
mkdir(rc, 0755);
|
||||
if (mount("cgroup", rc, "cgroup", opts, cgroup)) {
|
||||
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
||||
continue;
|
||||
}
|
||||
|
||||
cg_avail[cg_num].active = 1;
|
||||
strlcpy(cg_avail[cg_num].cgroup, cgroup, sizeof(cg_avail[cg_num].cgroup));
|
||||
strlcpy(cg_avail[cg_num].path, rc, sizeof(cg_avail[cg_num].path));
|
||||
cg_num++;
|
||||
|
||||
/* Create default group in all available cgroups */
|
||||
strlcat(rc, "/default", sizeof(rc));
|
||||
mkdir(rc, 0755);
|
||||
}
|
||||
|
||||
/* Default cgroups for process monitoring */
|
||||
mkdir("/sys/fs/cgroup/finit", 0755);
|
||||
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("/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 */
|
||||
mkdir("/sys/fs/cgroup/finit/init", 0755);
|
||||
mkdir("/sys/fs/cgroup/finit/system", 0755);
|
||||
mkdir("/sys/fs/cgroup/finit/user", 0755);
|
||||
|
||||
/* Move ourselves to init */
|
||||
echo("/sys/fs/cgroup/finit/init/cgroup.procs", 0, "1");
|
||||
|
||||
/* We have signal, main screen turn on! */
|
||||
cg_init = 1;
|
||||
fail:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int cgroup_add(char *name, void (*cb)(char *, void *), void *arg)
|
||||
{
|
||||
int rc = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cg_num; i++) {
|
||||
char path[80];
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", cg_avail[i].path, name);
|
||||
if (mkdir(path, 0755) && EEXIST != errno) {
|
||||
rc++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XXX: Add to cache of added groups, for cgroup_find() */
|
||||
if (cb)
|
||||
cb(path, arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: Temporary hackish implementation */
|
||||
int cgroup_find(char *name, char *group, size_t len)
|
||||
{
|
||||
char path[80];
|
||||
|
||||
if (cg_num <= 0)
|
||||
return 1;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", cg_avail[0].path, name);
|
||||
if (access(path, F_OK))
|
||||
return 1;
|
||||
|
||||
strlcpy(group, name, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* int cgroup_cpuset_range(char *group, int min, int max) */
|
||||
/* { */
|
||||
/* } */
|
||||
|
||||
static int move_pid(char *group, char *name, int pid)
|
||||
{
|
||||
char path[256];
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
||||
if (mkdir(path, 0755) && errno != EEXIST)
|
||||
return 1;
|
||||
|
||||
strlcat(path, "/cgroup.procs", sizeof(path));
|
||||
|
||||
return echo(path, 0, "%d", pid);
|
||||
}
|
||||
|
||||
int cgroup_user(char *name)
|
||||
{
|
||||
if (!cg_init)
|
||||
return 0;
|
||||
|
||||
return move_pid("finit/user", name, getpid());
|
||||
}
|
||||
|
||||
int cgroup_service(char *cmd, int pid)
|
||||
{
|
||||
char *nm;
|
||||
|
||||
if (!cg_init)
|
||||
return 0;
|
||||
|
||||
if (pid <= 0) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
nm = strrchr(cmd, '/');
|
||||
if (nm)
|
||||
nm++;
|
||||
else
|
||||
nm = cmd;
|
||||
|
||||
return move_pid("finit/system", nm, pid);
|
||||
}
|
||||
|
||||
int cgroup_assign(char *name, int pid)
|
||||
{
|
||||
char path[120];
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; i < cg_num; i++) {
|
||||
snprintf(path, sizeof(path), "%s/%s/cgroup.procs",
|
||||
cg_avail[i].path, name);
|
||||
rc += echo(path, 0, "%d", pid);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Save and restore RTC using hwclock
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
* Copyright (c) 2019 Joachim Nilsson <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
|
||||
@@ -21,49 +21,16 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
#ifndef FINIT_CGROUP_H_
|
||||
#define FINIT_CGROUP_H_
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
void cgroup_init (void);
|
||||
|
||||
static void save(void *arg)
|
||||
{
|
||||
_d("Saving system clock to RTC ...");
|
||||
/* -w,--systohc, -u,--utc */
|
||||
run_interactive("hwclock -w -u", "Saving system time (UTC) to RTC");
|
||||
}
|
||||
int cgroup_add (char *name, void (*cb)(char *, void *), void *arg);
|
||||
int cgroup_find (char *name, char *group, size_t len);
|
||||
|
||||
static void restore(void *arg)
|
||||
{
|
||||
_d("Restoring system clock from RTC ...");
|
||||
/* -s,--hctosys, -u,--utc */
|
||||
run_interactive("hwclock -s -u", "Restoring system clock (UTC) from RTC");
|
||||
}
|
||||
int cgroup_user (char *name);
|
||||
int cgroup_service (char *cmd, int pid);
|
||||
int cgroup_assign (char *name, int pid);
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = restore
|
||||
},
|
||||
.hook[HOOK_SHUTDOWN] = {
|
||||
.cb = save
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
#endif /* FINIT_CGROUP_H_ */
|
||||
@@ -125,7 +125,7 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
svc_t *client_svc_find(char *arg)
|
||||
svc_t *client_svc_find(const char *arg)
|
||||
{
|
||||
int sd = -1;
|
||||
struct init_request rq = {
|
||||
|
||||
@@ -32,6 +32,6 @@ int client_disconnect (void);
|
||||
|
||||
int client_send (struct init_request *rq, ssize_t len);
|
||||
svc_t *client_svc_iterator (int first);
|
||||
svc_t *client_svc_find (char *arg);
|
||||
svc_t *client_svc_find (const char *arg);
|
||||
|
||||
#endif /* FINIT_CLIENT_H_ */
|
||||
|
||||
@@ -101,7 +101,7 @@ enum cond_state cond_get_agg(const char *names)
|
||||
{
|
||||
char *cond;
|
||||
enum cond_state s = COND_ON;
|
||||
static char conds[MAX_ARG_LEN];
|
||||
static char conds[MAX_COND_LEN];
|
||||
|
||||
if (!names)
|
||||
return COND_ON;
|
||||
@@ -116,7 +116,7 @@ enum cond_state cond_get_agg(const char *names)
|
||||
int cond_affects(const char *name, const char *names)
|
||||
{
|
||||
char *cond;
|
||||
static char conds[MAX_ARG_LEN];
|
||||
static char conds[MAX_COND_LEN];
|
||||
|
||||
if (!name || !names)
|
||||
return 0;
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
#include <lite/lite.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#include <sys/time.h>
|
||||
#include <glob.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cgroup.h"
|
||||
#include "cond.h"
|
||||
#include "service.h"
|
||||
#include "tty.h"
|
||||
@@ -52,7 +54,8 @@ struct conf_change {
|
||||
char *name;
|
||||
};
|
||||
|
||||
static uev_t w1, w2, w3;
|
||||
static char cgroup[32];
|
||||
static uev_t w1, w2, w3, w4;
|
||||
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||
|
||||
static int parse_conf(char *file);
|
||||
@@ -341,6 +344,45 @@ error:
|
||||
logit(LOG_WARNING, "rlimit: parse error");
|
||||
}
|
||||
|
||||
static void cpuset_cb(char *grp, void *arg)
|
||||
{
|
||||
int cpuset = *(int *)arg;
|
||||
char path[128];
|
||||
|
||||
if (!strstr(grp, "cpuset"))
|
||||
return;
|
||||
|
||||
/* Both .cpus and .mems are mandatory settings */
|
||||
snprintf(path, sizeof(path), "%s/cpuset.cpus", grp);
|
||||
echo(path, 0, "%d", cpuset);
|
||||
snprintf(path, sizeof(path), "%s/cpuset.mems", grp);
|
||||
echo(path, 0, "0");
|
||||
|
||||
/* XXX: HACK for now, fix proper CPU allocation */
|
||||
snprintf(path, sizeof(path), "%s/cpuset.cpu_exclusive", grp);
|
||||
echo(path, 0, "1");
|
||||
}
|
||||
|
||||
static void parse_cgroup(char *line)
|
||||
{
|
||||
char *group, *token;
|
||||
int cpuset = -1;
|
||||
|
||||
group = strtok(line, " ");
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
while ((token = strtok(NULL, " "))) {
|
||||
if (!strncmp(token, "cpuset:", 7)) {
|
||||
token += 7;
|
||||
cpuset = atoi(token); /* XXX: fixme */
|
||||
}
|
||||
}
|
||||
|
||||
if (cpuset >= 0)
|
||||
cgroup_add(group, cpuset_cb, &cpuset);
|
||||
}
|
||||
|
||||
static void parse_static(char *line)
|
||||
{
|
||||
char *x;
|
||||
@@ -429,6 +471,11 @@ static void parse_static(char *line)
|
||||
cfglevel = 2; /* Fallback */
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "cgroup ", x)) {
|
||||
parse_cgroup(strip_line(x));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||
@@ -447,26 +494,26 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||
|
||||
/* Monitored daemon, will be respawned on exit */
|
||||
if (MATCH_CMD(line, "service ", x)) {
|
||||
service_register(SVC_TYPE_SERVICE, x, rlimit, file);
|
||||
service_register(SVC_TYPE_SERVICE, x, rlimit, cgroup, file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* One-shot task, will not be respawned */
|
||||
if (MATCH_CMD(line, "task ", x)) {
|
||||
service_register(SVC_TYPE_TASK, x, rlimit, file);
|
||||
service_register(SVC_TYPE_TASK, x, rlimit, cgroup, file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Like task but waits for completion, useful w/ [S] */
|
||||
if (MATCH_CMD(line, "run ", x)) {
|
||||
service_register(SVC_TYPE_RUN, x, rlimit, file);
|
||||
service_register(SVC_TYPE_RUN, x, rlimit, cgroup, file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Classic inetd service */
|
||||
if (MATCH_CMD(line, "inetd ", x)) {
|
||||
#ifdef INETD_ENABLED
|
||||
service_register(SVC_TYPE_INETD, x, rlimit, file);
|
||||
service_register(SVC_TYPE_INETD, x, rlimit, cgroup, file);
|
||||
#else
|
||||
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
|
||||
#endif
|
||||
@@ -479,9 +526,15 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||
return;
|
||||
}
|
||||
|
||||
/* All subsequent run/task/service/tty/etc. directives to use this cgroup */
|
||||
if (MATCH_CMD(line, "group ", x)) {
|
||||
cgroup_find(x, cgroup, sizeof(cgroup));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Regular or serial TTYs to run getty */
|
||||
if (MATCH_CMD(line, "tty ", x)) {
|
||||
tty_register(strip_line(x), rlimit, file);
|
||||
tty_register(strip_line(x), rlimit, cgroup, file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -499,8 +552,8 @@ static void tabstospaces(char *line)
|
||||
|
||||
static int parse_conf_dynamic(char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (!fp) {
|
||||
@@ -511,6 +564,9 @@ static int parse_conf_dynamic(char *file)
|
||||
/* Prepare default limits for each service */
|
||||
memcpy(rlimit, global_rlimit, sizeof(rlimit));
|
||||
|
||||
/* Prepare default cgroup for each service */
|
||||
strlcpy(cgroup, "default", sizeof(cgroup));
|
||||
|
||||
_d("Parsing %s <<<<<<", file);
|
||||
while (!feof(fp)) {
|
||||
char line[LINE_SIZE] = "";
|
||||
@@ -577,8 +633,8 @@ static int parse_conf(char *file)
|
||||
*/
|
||||
int conf_reload(void)
|
||||
{
|
||||
int i, num;
|
||||
struct dirent **e;
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
|
||||
/* Mark and sweep */
|
||||
svc_mark_dynamic();
|
||||
@@ -591,7 +647,7 @@ int conf_reload(void)
|
||||
/* If rescue.conf is missing, fall back to a root shell */
|
||||
rc = parse_conf(RESCUE_CONF);
|
||||
if (rc)
|
||||
tty_register(line, global_rlimit, NULL);
|
||||
tty_register(line, global_rlimit, cgroup, NULL);
|
||||
|
||||
print(rc, "Entering rescue mode");
|
||||
goto done;
|
||||
@@ -601,20 +657,14 @@ int conf_reload(void)
|
||||
parse_conf(FINIT_CONF);
|
||||
|
||||
/* Next, read all *.conf in /etc/finit.d/ */
|
||||
num = scandir(rcsd, &e, NULL, alphasort);
|
||||
if (num < 0) {
|
||||
_d("Skipping %s, no files found ...", rcsd);
|
||||
goto done;
|
||||
}
|
||||
glob("/etc/finit.d/*.conf", 0, NULL, &gl);
|
||||
glob("/etc/finit.d/enabled/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
char *name = e[i]->d_name;
|
||||
char path[LINE_SIZE];
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
char *path = gl.gl_pathv[i];
|
||||
size_t len;
|
||||
struct stat st;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", rcsd, name);
|
||||
|
||||
/* Check that it's an actual file ... beyond any symlinks */
|
||||
if (lstat(path, &st)) {
|
||||
_d("Skipping %s, cannot access: %s", path, strerror(errno));
|
||||
@@ -650,9 +700,7 @@ int conf_reload(void)
|
||||
parse_conf_dynamic(path);
|
||||
}
|
||||
|
||||
while (num--)
|
||||
free(e[num]);
|
||||
free(e);
|
||||
globfree(&gl);
|
||||
|
||||
done:
|
||||
/* Drop record of all .conf changes */
|
||||
@@ -783,6 +831,9 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf_any_change())
|
||||
service_reload_dynamic();
|
||||
}
|
||||
|
||||
static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
||||
@@ -857,8 +908,9 @@ int conf_monitor(uev_ctx_t *ctx)
|
||||
* changes to either symlink or target.
|
||||
*/
|
||||
rc += add_watcher(ctx, &w1, FINIT_RCSD, 0);
|
||||
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available", IN_DONT_FOLLOW);
|
||||
rc += add_watcher(ctx, &w3, FINIT_CONF, 0);
|
||||
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available/", IN_DONT_FOLLOW);
|
||||
rc += add_watcher(ctx, &w3, FINIT_RCSD "/enabled/", 0);
|
||||
rc += add_watcher(ctx, &w4, FINIT_CONF, 0);
|
||||
|
||||
return rc + conf_reload();
|
||||
}
|
||||
@@ -869,7 +921,7 @@ int conf_monitor(uev_ctx_t *ctx)
|
||||
int conf_init(void)
|
||||
{
|
||||
hostname = strdup(DEFHOST);
|
||||
w1.fd = w2.fd = w3.fd = -1;
|
||||
w1.fd = w2.fd = w3.fd = w4.fd = -1;
|
||||
|
||||
return conf_monitor(NULL);
|
||||
}
|
||||
|
||||
@@ -449,14 +449,18 @@ int run_parts(char *dir, char *cmd)
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
int j = 0;
|
||||
pid_t pid = 0;
|
||||
struct stat st;
|
||||
char *args[NUM_ARGS];
|
||||
char path[512];
|
||||
char *argv[4] = {
|
||||
"sh",
|
||||
"-c",
|
||||
path,
|
||||
NULL
|
||||
};
|
||||
char *name = e[i]->d_name;
|
||||
char path[LINE_SIZE];
|
||||
pid_t pid = 0;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||
snprintf(path, sizeof(path), "%s/%s ", dir, name);
|
||||
if (stat(path, &st)) {
|
||||
_d("Failed stat(%s): %s", path, strerror(errno));
|
||||
continue;
|
||||
@@ -467,29 +471,22 @@ int run_parts(char *dir, char *cmd)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fill in args[], starting with full path to executable */
|
||||
args[j++] = path;
|
||||
|
||||
/* If the callee didn't supply a run_parts() argument */
|
||||
if (!cmd) {
|
||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||
_d("Checking if %s is a sysvinit startstop script ...", name);
|
||||
if (name[0] == 'S' && isdigit(name[1])) {
|
||||
args[j++] = "start";
|
||||
} else if (name[0] == 'K' && isdigit(name[1])) {
|
||||
args[j++] = "stop";
|
||||
}
|
||||
if (name[0] == 'S' && isdigit(name[1]))
|
||||
strlcat(path, "start", sizeof(path));
|
||||
else if (name[0] == 'K' && isdigit(name[1]))
|
||||
strlcat(path, "stop", sizeof(path));
|
||||
} else {
|
||||
args[j++] = cmd;
|
||||
strlcat(path, cmd, sizeof(path));
|
||||
}
|
||||
args[j++] = NULL;
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
_d("Calling %s ...", path);
|
||||
sig_unblock();
|
||||
execv(path, args);
|
||||
exit(0);
|
||||
return execvp(_PATH_BSHELL, argv);
|
||||
}
|
||||
|
||||
complete(path, pid);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cgroup.h"
|
||||
#include "cond.h"
|
||||
#include "conf.h"
|
||||
#include "helpers.h"
|
||||
@@ -222,7 +223,7 @@ static void finalize(void)
|
||||
/*
|
||||
* Track bundled watchdogd in case a better one turns up
|
||||
*/
|
||||
svc = svc_find(FINIT_LIBPATH_ "/watchdogd", 1);
|
||||
svc = svc_find(FINIT_LIBPATH_ "/watchdogd", "1");
|
||||
if (svc)
|
||||
wdog = svc;
|
||||
|
||||
@@ -345,11 +346,18 @@ int main(int argc, char* argv[])
|
||||
*/
|
||||
chdir("/");
|
||||
umask(0);
|
||||
mount("none", "/proc", "proc", 0, NULL);
|
||||
mount("none", "/sys", "sysfs", 0, NULL);
|
||||
if (mount("none", "/proc", "proc", 0, NULL))
|
||||
_pe("Failed mounting /proc");
|
||||
if (mount("none", "/sys", "sysfs", 0, NULL))
|
||||
_pe("Failed mounting /sysfs");
|
||||
if (fisdir("/proc/bus/usb"))
|
||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||
|
||||
/*
|
||||
* Initialize default control groups, if available
|
||||
*/
|
||||
cgroup_init();
|
||||
|
||||
/*
|
||||
* Parse kernel command line (debug, rescue, splash, etc.)
|
||||
* Also calls log_init() to set correct log level
|
||||
@@ -442,19 +450,19 @@ int main(int argc, char* argv[])
|
||||
|
||||
/* Register udevd as a monitored service */
|
||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd %s -- Device event managing daemon", path);
|
||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, "default", NULL)) {
|
||||
_pe("Failed registering %s", path);
|
||||
udev = 0;
|
||||
} else {
|
||||
snprintf(cmd, sizeof(cmd), ":1 [S] <svc%s> "
|
||||
"udevadm trigger -c add -t devices "
|
||||
"-- Requesting device events", path);
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, "default", NULL);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), ":2 [S] <svc%s> "
|
||||
"udevadm trigger -c add -t subsystems "
|
||||
"-- Requesting subsystem events", path);
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, "default", NULL);
|
||||
}
|
||||
free(path);
|
||||
} else {
|
||||
@@ -475,7 +483,7 @@ int main(int argc, char* argv[])
|
||||
* Start bundled watchdogd as soon as possible, if enabled
|
||||
*/
|
||||
if (which(FINIT_LIBPATH_ "/watchdogd"))
|
||||
service_register(SVC_TYPE_SERVICE, FINIT_LIBPATH_ "/watchdogd", global_rlimit, NULL);
|
||||
service_register(SVC_TYPE_SERVICE, FINIT_LIBPATH_ "/watchdogd", global_rlimit, "default", NULL);
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <termios.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cgroup.h"
|
||||
#include "helpers.h"
|
||||
#include "sig.h"
|
||||
#include "utmp-api.h"
|
||||
@@ -192,6 +193,7 @@ static int do_login(char *name)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
cgroup_user(name);
|
||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||
|
||||
/*
|
||||
|
||||
@@ -169,6 +169,7 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
||||
svc_t *svc = (svc_t *)arg, *task;
|
||||
const char *conn = " connection";
|
||||
char iifname[IF_NAMESIZE + 1] = "UNKNOWN";
|
||||
char id[MAX_ID_LEN];
|
||||
int stdin;
|
||||
|
||||
_d("%s: Got socket event ...", svc->cmd);
|
||||
@@ -194,7 +195,8 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
||||
return;
|
||||
}
|
||||
|
||||
task = svc_new(svc->cmd, svc->inetd.next_id++, SVC_TYPE_INETD_CONN);
|
||||
snprintf(id, sizeof(id), "%d", svc->inetd.next_id++);
|
||||
task = svc_new(svc->cmd, id, SVC_TYPE_INETD_CONN);
|
||||
if (!task) {
|
||||
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client", svc->cmd);
|
||||
if (svc->inetd.type == SOCK_STREAM)
|
||||
@@ -226,6 +228,7 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
||||
strlcpy(task->desc, svc->desc, sizeof(task->desc) - strlen(conn));
|
||||
strlcat(task->desc, conn, sizeof(task->desc));
|
||||
strlcpy(task->iifname, iifname, sizeof(task->iifname));
|
||||
strlcpy(task->name, svc->name, sizeof(task->name));
|
||||
|
||||
task->stdin_fd = stdin;
|
||||
service_step(task);
|
||||
|
||||
@@ -173,7 +173,7 @@ static int do_restart(char *arg) { return do_startstop(INIT_CMD_RESTART_SVC, arg
|
||||
|
||||
static void show_cond_one(const char *_conds)
|
||||
{
|
||||
static char conds[MAX_ARG_LEN];
|
||||
static char conds[MAX_COND_LEN];
|
||||
char *cond;
|
||||
|
||||
strlcpy(conds, _conds, sizeof(conds));
|
||||
@@ -438,12 +438,12 @@ static int show_status(char *arg)
|
||||
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
|
||||
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
char jobid[10], args[512] = "", *lvls;
|
||||
char jobid[20], args[512] = "", *lvls;
|
||||
|
||||
// if (svc_is_unique(svc))
|
||||
// snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
||||
// else
|
||||
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
||||
snprintf(jobid, sizeof(jobid), "%d:%s", svc->job, svc->id);
|
||||
|
||||
printf("%-9s %7s ", jobid, svc_status(svc));
|
||||
if (svc_is_inetd(svc))
|
||||
@@ -459,14 +459,7 @@ static int show_status(char *arg)
|
||||
|
||||
if (!verbose) {
|
||||
int adj = screen_cols - 60;
|
||||
char *name = strrchr(svc->cmd, '/');
|
||||
|
||||
if (!name)
|
||||
name = svc->cmd;
|
||||
else
|
||||
name++;
|
||||
|
||||
printf("%-16.16s %-*.*s\n", name, adj, adj, svc->desc);
|
||||
printf("%-16.16s %-*.*s\n", svc->name, adj, adj, svc->desc);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -516,6 +509,70 @@ static int show_status(char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_cgroup(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||
{
|
||||
FILE *fp;
|
||||
char *group;
|
||||
char path[256];
|
||||
char buf[256];
|
||||
int user = 0;
|
||||
int num = 0;
|
||||
|
||||
if (tflag == FTW_F)
|
||||
return 0;
|
||||
|
||||
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)
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (num)
|
||||
printf("\r%c\n", user ? ' ' : '|');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
fprintf(stderr,
|
||||
@@ -550,6 +607,8 @@ static int usage(int rc)
|
||||
" 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"
|
||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||
" reboot Reboot system\n"
|
||||
" halt Halt system\n"
|
||||
@@ -590,6 +649,8 @@ int main(int argc, char *argv[])
|
||||
{ "status", show_status },
|
||||
{ "show", show_status }, /* Convenience alias */
|
||||
|
||||
{ "ps", show_cgroup },
|
||||
|
||||
{ "runlevel", do_runlevel },
|
||||
{ "reboot", do_reboot },
|
||||
{ "halt", do_halt },
|
||||
|
||||
@@ -120,7 +120,7 @@ int serv_list(char *arg)
|
||||
if (fisdir(enabled))
|
||||
do_list("ENABLED ", enabled);
|
||||
if (fisdir(FINIT_RCSD))
|
||||
do_list("ENABLED ", FINIT_RCSD);
|
||||
do_list("STATIC ", FINIT_RCSD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -140,11 +140,13 @@ int serv_enable(char *arg)
|
||||
}
|
||||
|
||||
pushd(FINIT_RCSD);
|
||||
snprintf(path, sizeof(path), "available/%s", arg);
|
||||
mkdir("enabled", 0755);
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", available, arg);
|
||||
if (!fexist(path))
|
||||
errx(1, "Cannot find %s", path);
|
||||
|
||||
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
|
||||
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||
if (fexist(link))
|
||||
errx(1, "%s already exists", link);
|
||||
|
||||
@@ -165,7 +167,7 @@ int serv_disable(char *arg)
|
||||
arg = corr;
|
||||
}
|
||||
|
||||
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
|
||||
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||
if (stat(link, &st))
|
||||
err(1, "Cannot find %s", link);
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <net/if.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "cgroup.h"
|
||||
#include "conf.h"
|
||||
#include "cond.h"
|
||||
#include "finit.h"
|
||||
@@ -139,7 +140,7 @@ static int is_norespawn(void)
|
||||
* @svc: Service to start
|
||||
*
|
||||
* Returns:
|
||||
* 0 if the service was successfully started. Non-zero otherwise.
|
||||
* 0 if the service was successfully started. Non-zero otherwise.
|
||||
*/
|
||||
static int service_start(svc_t *svc)
|
||||
{
|
||||
@@ -185,6 +186,12 @@ static int service_start(svc_t *svc)
|
||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid > 0) {
|
||||
cgroup_service(svc->cmd, pid);
|
||||
cgroup_assign(svc->cgroup, pid);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
int status;
|
||||
char *home = NULL;
|
||||
@@ -243,6 +250,9 @@ static int service_start(svc_t *svc)
|
||||
redirect_null();
|
||||
goto logit_done;
|
||||
}
|
||||
if (svc->log.console) {
|
||||
goto logit_done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open PTY to connect to logger. A pty isn't buffered
|
||||
@@ -466,7 +476,7 @@ static int service_stop(svc_t *svc)
|
||||
*
|
||||
* This function does some basic checks of the runtime state of Finit
|
||||
* and a sanity check of the @svc before sending %SIGHUP.
|
||||
*
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0) or non-zero on error.
|
||||
*/
|
||||
@@ -558,6 +568,8 @@ static void parse_log(svc_t *svc, char *arg)
|
||||
svc->log.enabled = 1;
|
||||
else if (!strcmp(tok, "null") || !strcmp(tok, "/dev/null"))
|
||||
svc->log.null = 1;
|
||||
else if (!strcmp(tok, "console") || !strcmp(tok, "/dev/console"))
|
||||
svc->log.console = 1;
|
||||
else if (tok[0] == '/')
|
||||
strlcpy(svc->log.file, tok, sizeof(svc->log.file));
|
||||
else if (!strcmp(tok, "priority") || !strcmp(tok, "prio"))
|
||||
@@ -569,6 +581,23 @@ static void parse_log(svc_t *svc, char *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* name:<name>
|
||||
*/
|
||||
static void parse_name(svc_t *svc, char *arg)
|
||||
{
|
||||
char *name = NULL;
|
||||
|
||||
if (arg && !strncasecmp(arg, "name:", 5)) {
|
||||
name = arg + 5;
|
||||
} else {
|
||||
name = strrchr(svc->cmd, '/');
|
||||
name = name ? name + 1 : svc->cmd;
|
||||
}
|
||||
|
||||
strlcpy(svc->name, name, sizeof(svc->name));
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_cmdline_args - Update the command line args in the svc struct
|
||||
*
|
||||
@@ -601,6 +630,7 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
||||
* @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
|
||||
* @cfg: Configuration, complete command, with -- for description text
|
||||
* @rlimit: Limits for this service/task/run/inetd, may be global limits
|
||||
* @cgroup: Control group, may be default
|
||||
* @file: The file name service was loaded from
|
||||
*
|
||||
* This function is used to register commands to be run on different
|
||||
@@ -648,17 +678,20 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
||||
* Returns:
|
||||
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
||||
*/
|
||||
int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
int service_register(int type, char *cfg, struct rlimit rlimit[], char *cgroup, char *file)
|
||||
{
|
||||
int id = -1;
|
||||
char id_str[MAX_ID_LEN];
|
||||
#ifdef INETD_ENABLED
|
||||
int forking = 0;
|
||||
#endif
|
||||
int levels = 0;
|
||||
int manual = 0;
|
||||
char *line;
|
||||
char *id = NULL;
|
||||
char *username = NULL, *log = NULL, *pid = NULL;
|
||||
char *service = NULL, *proto = NULL, *ifaces = NULL;
|
||||
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
||||
char *name = NULL;
|
||||
svc_t *svc;
|
||||
plugin_t *plugin = NULL;
|
||||
|
||||
@@ -705,7 +738,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
else if (cmd[0] == '<') /* <[!][cond][,cond..]> */
|
||||
cond = &cmd[1];
|
||||
else if (cmd[0] == ':') /* :ID */
|
||||
id = atoi(&cmd[1]);
|
||||
id = &cmd[1];
|
||||
#ifdef INETD_ENABLED
|
||||
else if (!strncasecmp(cmd, "nowait", 6))
|
||||
forking = 1;
|
||||
@@ -716,6 +749,10 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
log = cmd;
|
||||
else if (!strncasecmp(cmd, "pid", 3))
|
||||
pid = cmd;
|
||||
else if (!strncasecmp(cmd, "name:", 5))
|
||||
name = cmd;
|
||||
else if (!strncasecmp(cmd, "manual:yes", 10))
|
||||
manual = 1;
|
||||
else if (cmd[0] != '/' && strchr(cmd, '/'))
|
||||
service = cmd; /* inetd service/proto */
|
||||
else
|
||||
@@ -773,24 +810,34 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
parse_cmdline_args(svc, cmd);
|
||||
goto inetd_setup;
|
||||
}
|
||||
if (id <= 0)
|
||||
id = svc_next_id(cmd);
|
||||
if (!id) {
|
||||
int n = svc_next_id_int(cmd);
|
||||
|
||||
if (n) {
|
||||
snprintf(id_str, sizeof(id_str), "%d", n);
|
||||
id = id_str;
|
||||
}
|
||||
}
|
||||
}
|
||||
recreate:
|
||||
#endif
|
||||
|
||||
if (id <= 0)
|
||||
id = 1;
|
||||
if (!id)
|
||||
id = "1";
|
||||
|
||||
svc = svc_find(cmd, id);
|
||||
if (!svc) {
|
||||
_d("Creating new svc for %s id #%d type %d", cmd, id, type);
|
||||
_d("Creating new svc for %s id #%s type %d", cmd, id, type);
|
||||
svc = svc_new(cmd, id, type);
|
||||
if (!svc) {
|
||||
_e("Out of memory, cannot register service %s", cmd);
|
||||
free(line);
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
|
||||
if (type == SVC_TYPE_SERVICE && manual) {
|
||||
svc_stop(svc);
|
||||
}
|
||||
}
|
||||
#ifdef INETD_ENABLED
|
||||
else {
|
||||
@@ -831,6 +878,8 @@ recreate:
|
||||
|
||||
conf_parse_cond(svc, cond);
|
||||
|
||||
parse_name(svc, name);
|
||||
|
||||
if (log)
|
||||
parse_log(svc, log);
|
||||
if (desc)
|
||||
@@ -868,6 +917,9 @@ recreate:
|
||||
/* Set configured limits */
|
||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||
|
||||
/* Register desired control group */
|
||||
strlcpy(svc->cgroup, cgroup, sizeof(svc->cgroup));
|
||||
|
||||
/* New, recently modified or unchanged ... used on reload. */
|
||||
if (file && conf_changed(file))
|
||||
svc_mark_dirty(svc);
|
||||
@@ -875,7 +927,7 @@ recreate:
|
||||
svc_mark_clean(svc);
|
||||
|
||||
if (!file)
|
||||
svc->protected = 1;
|
||||
svc->protect = 1;
|
||||
|
||||
/* Free duped line, from above */
|
||||
free(line);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "svc.h"
|
||||
|
||||
void service_runlevel (int newlevel);
|
||||
int service_register (int type, char *line, struct rlimit rlimit[], char *file);
|
||||
int service_register (int type, char *line, struct rlimit rlimit[], char *cgroup, char *file);
|
||||
void service_unregister (svc_t *svc);
|
||||
|
||||
void service_runtask_clean (void);
|
||||
|
||||
@@ -115,6 +115,9 @@ void stty(int fd, speed_t speed)
|
||||
term.c_cc[VKILL] = CTRL('U');
|
||||
term.c_cc[VERASE] = CERASE;
|
||||
tcsetattr(fd, TCSANOW, &term);
|
||||
|
||||
/* Restore cursor if it was hidden previously */
|
||||
write(fd, "\033[?25h", 6);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,10 +77,9 @@ static void svc_gc(void *arg)
|
||||
* Returns:
|
||||
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
|
||||
*/
|
||||
svc_t *svc_new(char *cmd, int id, int type)
|
||||
svc_t *svc_new(char *cmd, char *id, int type)
|
||||
{
|
||||
int job = -1;
|
||||
char *desc;
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
/* Find first job n:o if registering multiple instances */
|
||||
@@ -99,16 +98,11 @@ svc_t *svc_new(char *cmd, int id, int type)
|
||||
|
||||
svc->type = type;
|
||||
svc->job = job;
|
||||
svc->id = id;
|
||||
strlcpy(svc->id, id, sizeof(svc->id));
|
||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||
|
||||
/* Default description, if missing */
|
||||
desc = strrchr(cmd, '/');
|
||||
if (desc)
|
||||
desc++;
|
||||
else
|
||||
desc = cmd;
|
||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||
strlcpy(svc->desc, svc->name, sizeof(svc->desc));
|
||||
|
||||
TAILQ_INSERT_TAIL(&svc_list, svc, link);
|
||||
|
||||
@@ -204,7 +198,7 @@ svc_t *svc_named_iterator(svc_t **iter, int first, char *cmd)
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||
char *name = basename(svc->cmd);
|
||||
char *name = svc->name;
|
||||
|
||||
if (!strncmp(name, cmd, strlen(name)))
|
||||
return svc;
|
||||
@@ -301,12 +295,12 @@ svc_t *svc_stop_completed(void)
|
||||
* Returns:
|
||||
* A pointer to an &svc_t object, or %NULL if not found.
|
||||
*/
|
||||
svc_t *svc_find(char *cmd, int id)
|
||||
svc_t *svc_find(char *cmd, char *id)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc->id == id && !strncmp(svc->cmd, cmd, strlen(svc->cmd)))
|
||||
if (svc->id && !strcmp(svc->id, id) && !strncmp(svc->cmd, cmd, strlen(svc->cmd)))
|
||||
return svc;
|
||||
}
|
||||
|
||||
@@ -340,12 +334,12 @@ svc_t *svc_find_by_pid(pid_t pid)
|
||||
* Returns:
|
||||
* A pointer to an &svc_t object, or %NULL if not found.
|
||||
*/
|
||||
svc_t *svc_find_by_jobid(int job, int id)
|
||||
svc_t *svc_find_by_jobid(int job, char *id)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc->job == job && svc->id == id)
|
||||
if (svc->job == job && svc->id && !strcmp(svc->id, id))
|
||||
return svc;
|
||||
}
|
||||
|
||||
@@ -360,19 +354,12 @@ svc_t *svc_find_by_jobid(int job, int id)
|
||||
* Returns:
|
||||
* A pointer to an &svc_t object, or %NULL if not found.
|
||||
*/
|
||||
svc_t *svc_find_by_nameid(char *name, int id)
|
||||
svc_t *svc_find_by_nameid(char *name, char *id)
|
||||
{
|
||||
char *ptr;
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
ptr = strrchr(svc->cmd, '/');
|
||||
if (ptr)
|
||||
ptr++;
|
||||
else
|
||||
ptr = svc->cmd;
|
||||
|
||||
if (svc->id == id && !strcmp(name, ptr))
|
||||
if (svc->id && !strcmp(svc->id, id) && !strcmp(name, svc->name))
|
||||
return svc;
|
||||
}
|
||||
|
||||
@@ -415,7 +402,7 @@ void svc_mark_dynamic(void)
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc->protected)
|
||||
if (svc->protect)
|
||||
continue;
|
||||
if (svc_is_inetd_conn(svc))
|
||||
continue;
|
||||
@@ -509,18 +496,24 @@ int svc_enabled(svc_t *svc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Same base service, return unique ID */
|
||||
int svc_next_id(char *cmd)
|
||||
/* Same base service, return unique ID as an integer */
|
||||
int svc_next_id_int(char *cmd)
|
||||
{
|
||||
int id = 0;
|
||||
int n = 1;
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (!strcmp(svc->cmd, cmd) && id < svc->id)
|
||||
id = svc->id;
|
||||
char id[MAX_ID_LEN];
|
||||
|
||||
snprintf(id, sizeof(id), "%d", n);
|
||||
|
||||
if (!strcmp(svc->cmd, cmd) && svc->id && strcmp(svc->id, id))
|
||||
return n;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
return id + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int svc_is_unique(svc_t *svc)
|
||||
@@ -547,7 +540,7 @@ int svc_is_unique(svc_t *svc)
|
||||
/*
|
||||
* Used by api.c (to start/stop/restart) and initctl.c (for input validation)
|
||||
*/
|
||||
int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int))
|
||||
int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *))
|
||||
{
|
||||
int result = 0;
|
||||
char *input, *token, *pos;
|
||||
@@ -558,17 +551,27 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
||||
|
||||
token = strtok_r(input, " ", &pos);
|
||||
while (token) {
|
||||
int id = 1;
|
||||
char *id = NULL;
|
||||
svc_t *svc, *iter = NULL;
|
||||
char *ptr = strchr(token, ':');
|
||||
|
||||
if (isdigit(token[0])) {
|
||||
int job = atonum(token);
|
||||
char *ep;
|
||||
long job = 0;
|
||||
|
||||
errno = 0;
|
||||
job = strtol(token, &ep, 10);
|
||||
if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) ||
|
||||
(errno != 0 && job == 0) ||
|
||||
(token == ep)) {
|
||||
result++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
svc = svc_job_iterator(&iter, 1, job);
|
||||
if (!svc && not_found)
|
||||
result += not_found(NULL, job);
|
||||
result += not_found(NULL, token);
|
||||
|
||||
while (svc) {
|
||||
if (found)
|
||||
@@ -577,8 +580,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
||||
}
|
||||
} else {
|
||||
*ptr++ = 0;
|
||||
id = atonum(ptr);
|
||||
job = atonum(token);
|
||||
id = ptr;
|
||||
|
||||
svc = svc_find_by_jobid(job, id);
|
||||
if (!svc && not_found)
|
||||
@@ -599,7 +601,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
||||
}
|
||||
} else {
|
||||
*ptr++ = 0;
|
||||
id = atonum(ptr);
|
||||
id = ptr;
|
||||
|
||||
svc = svc_find_by_nameid(token, id);
|
||||
if (!svc && not_found)
|
||||
|
||||
@@ -66,6 +66,7 @@ typedef enum {
|
||||
SVC_BLOCK_RESTARTING,
|
||||
} svc_block_t;
|
||||
|
||||
#define MAX_ID_LEN 16
|
||||
#define MAX_ARG_LEN 64
|
||||
#define MAX_STR_LEN 64
|
||||
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
||||
@@ -86,24 +87,29 @@ typedef struct svc {
|
||||
TAILQ_ENTRY(svc) link;
|
||||
|
||||
/* Instance specifics */
|
||||
int job, id; /* JOB:ID */
|
||||
int job; /* JOB: */
|
||||
char id[MAX_ID_LEN]; /* :ID */
|
||||
|
||||
/* Limits and scoping */
|
||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||
|
||||
/* Control group */
|
||||
char cgroup[32];
|
||||
|
||||
/* Service details */
|
||||
pid_t pid;
|
||||
char pidfile[MAX_ARG_LEN];
|
||||
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
||||
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
||||
svc_type_t type; /* Service, run, task, inetd, ... */
|
||||
int protected; /* Services like dbus-daemon & udev by Finit */
|
||||
int protect; /* Services like dbus-daemon & udev by Finit */
|
||||
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
|
||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||
int runlevels;
|
||||
int sighup; /* This service supports SIGHUP :) */
|
||||
svc_block_t block; /* Reason that this service is currently stopped */
|
||||
char cond[MAX_COND_LEN];
|
||||
char name[MAX_ARG_LEN];
|
||||
|
||||
/* Counters */
|
||||
char once; /* run/task, (at least) once per runlevel */
|
||||
@@ -118,6 +124,7 @@ typedef struct svc {
|
||||
struct {
|
||||
char enabled;
|
||||
char null;
|
||||
char console;
|
||||
char file[64];
|
||||
char prio[20];
|
||||
char ident[20];
|
||||
@@ -143,13 +150,13 @@ typedef struct svc {
|
||||
struct timespec gc;
|
||||
} svc_t;
|
||||
|
||||
svc_t *svc_new (char *cmd, int id, int type);
|
||||
svc_t *svc_new (char *cmd, char *id, int type);
|
||||
int svc_del (svc_t *svc);
|
||||
|
||||
svc_t *svc_find (char *cmd, int id);
|
||||
svc_t *svc_find (char *cmd, char *id);
|
||||
svc_t *svc_find_by_pid (pid_t pid);
|
||||
svc_t *svc_find_by_jobid (int job, int id);
|
||||
svc_t *svc_find_by_nameid (char *name, int id);
|
||||
svc_t *svc_find_by_jobid (int job, char *id);
|
||||
svc_t *svc_find_by_nameid (char *name, char *id);
|
||||
svc_t *svc_find_by_pidfile (char *fn);
|
||||
|
||||
svc_t *svc_iterator (svc_t **iter, int first);
|
||||
@@ -170,10 +177,10 @@ int svc_clean_bootstrap (svc_t *svc);
|
||||
void svc_prune_bootstrap (void);
|
||||
|
||||
int svc_enabled (svc_t *svc);
|
||||
int svc_next_id (char *cmd);
|
||||
int svc_next_id_int (char *cmd);
|
||||
int svc_is_unique (svc_t *svc);
|
||||
|
||||
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int));
|
||||
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *));
|
||||
|
||||
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
||||
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
#include "finit.h"
|
||||
#include "cgroup.h"
|
||||
#include "conf.h"
|
||||
#include "helpers.h"
|
||||
#include "tty.h"
|
||||
@@ -100,6 +101,7 @@ void tty_sweep(void)
|
||||
* tty_register - Register a getty on a device
|
||||
* @line: Configuration, text after initial "tty"
|
||||
* @rlimit: Limits for this service/task/run/inetd, may be global limits
|
||||
* @cgroup: Control group, may be default
|
||||
* @file: The file name TTY was loaded from
|
||||
*
|
||||
* A Finit tty line can use the internal getty implementation or an
|
||||
@@ -118,7 +120,7 @@ void tty_sweep(void)
|
||||
* Different getty implementations prefer the TTY device argument in
|
||||
* different order, so take care to investigate this first.
|
||||
*/
|
||||
int tty_register(char *line, struct rlimit rlimit[], char *file)
|
||||
int tty_register(char *line, struct rlimit rlimit[], char *cgroup, char *file)
|
||||
{
|
||||
struct tty *entry;
|
||||
size_t i, num = 0;
|
||||
@@ -274,6 +276,9 @@ again:
|
||||
/* Register configured limits */
|
||||
memcpy(entry->rlimit, rlimit, sizeof(entry->rlimit));
|
||||
|
||||
/* Register desired control group */
|
||||
strlcpy(entry->cgroup, cgroup, sizeof(entry->cgroup));
|
||||
|
||||
if (file && conf_changed(file))
|
||||
entry->dirty = 1; /* Modified, restart */
|
||||
else
|
||||
@@ -410,6 +415,8 @@ void tty_start(struct tty *tty)
|
||||
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
||||
else
|
||||
tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
|
||||
|
||||
cgroup_assign(tty->cgroup, tty->pid);
|
||||
}
|
||||
|
||||
void tty_stop(struct tty *tty)
|
||||
|
||||
@@ -51,6 +51,9 @@ struct tty {
|
||||
/* Limits and scoping */
|
||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||
|
||||
/* Control group */
|
||||
char cgroup[32];
|
||||
|
||||
/* Set if modified => reloaded, or -1 when marked for removal */
|
||||
int dirty;
|
||||
};
|
||||
@@ -58,7 +61,7 @@ struct tty {
|
||||
void tty_mark (void);
|
||||
void tty_sweep (void);
|
||||
|
||||
int tty_register (char *line, struct rlimit rlimit[], char *file);
|
||||
int tty_register (char *line, struct rlimit rlimit[], char *cgroup, char *file);
|
||||
int tty_unregister (struct tty *tty);
|
||||
|
||||
struct tty *tty_find (char *dev);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <ctype.h> /* isprint() */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h> /* sysinfo() */
|
||||
@@ -46,6 +47,32 @@ char *progname(char *arg0)
|
||||
return prognm;
|
||||
}
|
||||
|
||||
int echo(char *file, int append, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
if (!file)
|
||||
fp = stdout;
|
||||
else
|
||||
fp = fopen(file, append ? "a" : "w");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
if (fmt) {
|
||||
va_start(ap, fmt);
|
||||
vfprintf(fp, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* echo(1) always adds a newline */
|
||||
fprintf(fp, "\n");
|
||||
if (file)
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strtobytes(char *arg)
|
||||
{
|
||||
int mod = 0, bytes;
|
||||
|
||||
@@ -39,6 +39,7 @@ extern char *prognm;
|
||||
#include <lite/conio.h>
|
||||
|
||||
char *progname (char *arg0);
|
||||
int echo (char *file, int append, char *fmt, ...);
|
||||
int strtobytes (char *arg);
|
||||
void do_sleep (unsigned int sec);
|
||||
|
||||
|
||||