Merge branch 'enable-disable-services'

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson committed 2017-07-01 18:02:52 +02:00
commit b2ac81540f
7 files changed
+362 -28

No files matched your search

+2
View File
@@ -51,6 +51,8 @@ General
That is: (r)esolve dependencies and only enable ssh (t)emporary That is: (r)esolve dependencies and only enable ssh (t)emporary
in the default runlevel when networking is available. in the default runlevel when networking is available.
* `initctl add /sbin/service -n -- Service description`, for details
https://github.com/troglobit/finit/issues/69#issuecomment-287907610
Init Init
+75
View File
@@ -0,0 +1,75 @@
Distro Recommendations
======================
By default Finit uses the following directories for configuration files:
```
/etc/
|-- finit.d/ -- Regular (enabled) services
| |-- lighttpd.conf
| `- *.conf
|-- finit.conf -- Bootstrap tasks and services
:
```
To enable a standard (non-bootstrap) service one simply drops a small
configuration file in `/etc/finit.d/`. This works fine on system that
keep disabled services elsewhere, or generates them as needed from some
other tool.
Disitributions, however, may want a clearer separation of enabled and
available (installed but not enabled) services. They may even want to
customize the directories used, for brand labling or uniformity.
To that end Finit allows for a sub-directory `/etc/finit.d/available/`
where installed but disabled services can reside. Adding a symlink to a
configuration in this sub-directory enables the service, but it will not
be started.
To change the default configuration directory and configuration file
names the Finit `configure` script offers the following two options at
build time:
```sh
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
```
The resulting directory structure is depicted below. Please notice how
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink
`/etc/init.d/init.conf`:
```
/etc/
|-- init.d/
| |-- available/ -- Regular (disabled) services
| | |-- httpd.conf
| | |-- ntpd.conf
| | `-- sshd.conf
| |-- sshd.conf -- Symlink to available/sshd.conf
| `- init.conf -- Bootstrap tasks and services
:
```
To facilitate the task of managing configurations, be it a service,
task, run, or other stanza, the `initctl` tool has a a few built-in
commands:
```
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/]
reload Reload *.conf in /etc/finit.d/ (activates changes)
```
To enable a service like `sshd.conf`, above, use
initctl enable sshd
The `.conf` suffix is not needed, `initctl` adds it implicitly if it's
missing. The `disable` command works in a similar fashion.
Note, however, that `initctl` only operates on symlinks and it always
requires the `available/` sub-directory. Any non-symlink in the parent
directory, here `/etc/init.d/`, will be considered a system override by
`initctl`.
+3 -3
View File
@@ -41,9 +41,9 @@ else
finit_LDADD += -ldl finit_LDADD += -ldl
endif endif
initctl_SOURCES = initctl.c svc.c svc.h cond.c cond.h \ initctl_SOURCES = initctl.c serv.c serv.h svc.c svc.h \
util.c util.h cond.c cond.h util.c util.h
initctl_CFLAGS = $(lite_CFLAGS) initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter $(lite_CFLAGS)
initctl_LDADD = $(lite_LIBS) initctl_LDADD = $(lite_LIBS)
reboot_SOURCES = reboot.c util.c util.h reboot_SOURCES = reboot.c util.c util.h
+37 -10
View File
@@ -388,13 +388,15 @@ static void tabstospaces(char *line)
static int parse_conf_dynamic(char *file, struct timeval *mtime) static int parse_conf_dynamic(char *file, struct timeval *mtime)
{ {
FILE *fp = fopen(file, "r"); FILE *fp;
fp = fopen(file, "r");
if (!fp) { if (!fp) {
_pe("Failed opening %s", file); _pe("Failed opening %s", file);
return 1; return 1;
} }
_d("Parsing %s", file);
while (!feof(fp)) { while (!feof(fp)) {
char line[LINE_SIZE] = ""; char line[LINE_SIZE] = "";
@@ -403,7 +405,7 @@ static int parse_conf_dynamic(char *file, struct timeval *mtime)
chomp(line); chomp(line);
tabstospaces(line); tabstospaces(line);
_d("dyn conf: %s", line); _d("%s", line);
parse_dynamic(line, mtime); parse_dynamic(line, mtime);
} }
@@ -445,13 +447,15 @@ static int parse_conf(char *file)
if (!silent) if (!silent)
print(0, "Loading %sconfiguration", line); print(0, "Loading %sconfiguration", line);
_d("Parsing %s", file);
while (!feof(fp)) { while (!feof(fp)) {
if (!fgets(line, sizeof(line), fp)) if (!fgets(line, sizeof(line), fp))
continue; continue;
chomp(line); chomp(line);
tabstospaces(line); tabstospaces(line);
_d("conf: %s", line); _d("%s", line);
parse_static(line); parse_static(line);
parse_dynamic(line, NULL); parse_dynamic(line, NULL);
@@ -474,29 +478,52 @@ void conf_reload_dynamic(void)
num = scandir(dir, &e, NULL, alphasort); num = scandir(dir, &e, NULL, alphasort);
if (num < 0) { if (num < 0) {
_d("No files found in %s, skipping ...", dir); _d("Skipping %s, no files found ...", dir);
return; return;
} }
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
char *name = e[i]->d_name; char *name = e[i]->d_name;
char path[CMD_SIZE]; char path[CMD_SIZE];
size_t len;
struct stat st; struct stat st;
struct timeval mtime; struct timeval mtime;
snprintf(path, sizeof(path), "%s/%s", dir, name); snprintf(path, sizeof(path), "%s/%s", dir, name);
/* Check that it's an actual file ... */ /* Check that it's an actual file ... beyond any symlinks */
if (stat(path, &st)) { if (lstat(path, &st)) {
_d("Cannot even read .conf file %s, skipping ...", path); _d("Skipping %s, cannot access: %s", path, strerror(errno));
continue; continue;
} }
if (S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode))
/* Skip directories */
if (S_ISDIR(st.st_mode)) {
_d("Skipping directory %s", path);
continue; continue;
}
/* Check for dangling symlinks */
if (S_ISLNK(st.st_mode)) {
char *rp;
rp = realpath(path, NULL);
if (!rp) {
/*
* XXX: Prune from rcsd?
* XXX: Possibly temporary service from last boot
*/
logit(LOG_WARNING, "Skipping %s, dangling symlink: %s", path, strerror(errno));
continue;
}
free(rp);
}
/* Check that file ends with '.conf' */ /* Check that file ends with '.conf' */
if (strcmp(&path[strlen(path) - 5], ".conf")) { len = strlen(path);
_d("File %s is not a .conf, skipping ... ", path); if (len < 6 || strcmp(&path[len - 5], ".conf")) {
_d("Skipping %s, not a valid .conf ... ", path);
continue; continue;
} }
+44 -15
View File
@@ -21,11 +21,12 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "config.h"
#include <err.h> #include <err.h>
#include <ftw.h> #include <ftw.h>
#include <ctype.h> #include <ctype.h>
#include <getopt.h> #include <getopt.h>
#include <glob.h>
#include <paths.h> #include <paths.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
@@ -36,9 +37,9 @@
#include <sys/un.h> #include <sys/un.h>
#include <lite/lite.h> #include <lite/lite.h>
#include "config.h"
#include "finit.h" #include "finit.h"
#include "cond.h" #include "cond.h"
#include "serv.h"
#include "service.h" #include "service.h"
#include "util.h" #include "util.h"
@@ -54,6 +55,7 @@ int verbose = 0;
int silent = 1; /* For helpers.c */ int silent = 1; /* For helpers.c */
int runlevel = 0; int runlevel = 0;
static int do_send(struct init_request *rq, ssize_t len) static int do_send(struct init_request *rq, ssize_t len)
{ {
int sd, result = 255; int sd, result = 255;
@@ -572,53 +574,79 @@ static int show_status(char *arg)
static int usage(int rc) static int usage(int rc)
{ {
fprintf(stderr, "Usage: %s [OPTIONS] <COMMAND>\n\n" fprintf(stderr,
"Usage: %s [OPTIONS] <COMMAND>\n"
"\n"
"Options:\n" "Options:\n"
" -d, --debug Debug initctl (client)\n" " -d, --debug Debug initctl (client)\n"
" -v, --verbose Verbose output\n" " -v, --verbose Verbose output\n"
" -h, --help This help text\n\n" " -h, --help This help text\n"
"\n"
"Commands:\n" "Commands:\n"
" debug Toggle Finit (daemon) debug\n" " debug Toggle Finit (daemon) debug\n"
" help This help text\n" " help This help text\n"
" log [NAME] Show ten last Finit, or NAME, messages from syslog\n" " version Show Finit version\n"
" reload Reload *.conf in /etc/finit.d and activate changes\n" "\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n" " list List all .conf in /etc/finit.d/\n"
" status | show Show status of services\n" " enable <CONF> Enable .conf in /etc/finit.d/available/\n"
" disable <CONF> Disable .conf in /etc/finit.d/[enabled/]\n"
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
"\n"
" cond set <COND> Set (assert) condition => +COND\n" " cond set <COND> Set (assert) condition => +COND\n"
" cond clear <COND> Clear (deassert) condition => -COND\n" " cond clear <COND> Clear (deassert) condition => -COND\n"
" cond show Show condition status\n" " cond show Show condition status\n"
" cond dump Show all conditions and their status\n" " cond dump Show 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" " 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" " 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" " restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
" status | show Show status of services\n"
"\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
" reboot Reboot system\n" " reboot Reboot system\n"
" halt Halt system\n" " halt Halt system\n"
" poweroff Halt and power off system\n" " poweroff Halt and power off system\n"
"\n"
" utmp show Raw dump of UTMP/WTMP db\n" " utmp show Raw dump of UTMP/WTMP db\n"
" version Show Finit version\n\n", prognm); "\n", prognm);
return rc; return rc;
} }
static int do_help(char *arg)
{
return usage(0);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int c; int c;
command_t command[] = { command_t command[] = {
{ "debug", toggle_debug }, { "debug", toggle_debug },
{ "log", do_log }, { "help", do_help },
{ "version", show_version },
{ "list", serv_list },
{ "enable", serv_enable },
{ "disable", serv_disable },
{ "reload", do_reload }, { "reload", do_reload },
{ "runlevel", do_runlevel },
{ "status", show_status },
{ "show", show_status }, /* Convenience alias */
{ "cond", do_cond }, { "cond", do_cond },
{ "log", do_log },
{ "start", do_start }, { "start", do_start },
{ "stop", do_stop }, { "stop", do_stop },
{ "restart", do_restart }, { "restart", do_restart },
{ "status", show_status },
{ "show", show_status }, /* Convenience alias */
{ "runlevel", do_runlevel },
{ "reboot", do_reboot }, { "reboot", do_reboot },
{ "halt", do_halt }, { "halt", do_halt },
{ "poweroff", do_poweroff }, { "poweroff", do_poweroff },
{ "utmp", do_utmp }, { "utmp", do_utmp },
{ "version", show_version },
{ NULL, NULL } { NULL, NULL }
}; };
struct option long_options[] = { struct option long_options[] = {
@@ -652,7 +680,8 @@ int main(int argc, char *argv[])
while (optind < argc) { while (optind < argc) {
strlcat(arg, argv[optind++], sizeof(arg)); strlcat(arg, argv[optind++], sizeof(arg));
strlcat(arg, " ", sizeof(arg)); if (optind < argc)
strlcat(arg, " ", sizeof(arg));
} }
for (c = 0; command[c].cmd; c++) { for (c = 0; command[c].cmd; c++) {
+163
View File
@@ -0,0 +1,163 @@
/* List and enable/disable service configurations
*
* Copyright (c) 2017 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 "config.h"
#include <err.h>
#include <glob.h>
#include <stdio.h>
#include <lite/lite.h>
#define SCREEN_WIDTH 80 /* Calculate screen width as well, later */
static const char *cwd;
static const char *available = FINIT_RCSD "/available";
static const char *enabled = FINIT_RCSD "/enabled";
static void pushd(const char *dir)
{
cwd = get_current_dir_name();
chdir(dir);
}
static void popd(void)
{
chdir(cwd);
}
static int calc_width(char *arr[], size_t len)
{
int width = 0;
size_t i;
for (i = 0; i < len; i++) {
int w = strlen(arr[i]);
if (w > width)
width = w;
}
return width;
}
static void do_list(const char *heading, const char *path)
{
int num;
int width;
size_t i;
glob_t gl;
char h[SCREEN_WIDTH] = "===============================================================================";
pushd(path);
if (glob("*.conf", 0, NULL, &gl)) {
chdir(cwd);
return;
}
if (gl.gl_pathc <= 0)
goto done;
num = snprintf(h, sizeof(h) - 1, "%s", path);
h[num] = ' ';
puts(h);
width = calc_width(gl.gl_pathv, gl.gl_pathc);
num = SCREEN_WIDTH / width;
if ((num - 1) * 2 + num * width > SCREEN_WIDTH)
num--;
for (i = 0; i < gl.gl_pathc; i++) {
if (i > 0 && !(i % num))
puts("");
printf("%-*s ", width, gl.gl_pathv[i]);
}
puts("\n");
done:
globfree(&gl);
popd();
}
int serv_list(char *arg)
{
if (fisdir(available))
do_list("Available", available);
if (fisdir(enabled))
do_list("Enabled", enabled);
else if (fisdir(FINIT_RCSD))
do_list("Always enabled", FINIT_RCSD);
return 0;
}
int serv_enable(char *arg)
{
char corr[40];
char link[80];
char path[80];
if (!strstr(arg, ".conf")) {
snprintf(corr, sizeof(corr), "%s.conf", arg);
arg = corr;
}
pushd(FINIT_RCSD);
snprintf(path, sizeof(path), "available/%s", arg);
if (!fexist(path))
errx(1, "Cannot find %s", path);
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
if (fexist(link))
errx(1, "%s already exists", link);
return symlink(path, link) != 0;
}
int serv_disable(char *arg)
{
char corr[40];
char link[80];
struct stat st;
if (!strstr(arg, ".conf")) {
snprintf(corr, sizeof(corr), "%s.conf", arg);
arg = corr;
}
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
if (stat(link, &st))
err(1, "Cannot find %s", link);
if ((st.st_mode & S_IFMT) == S_IFLNK)
errx(1, "%s is not a symlink, move manually to %s first", link, available);
return remove(link) != 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+38
View File
@@ -0,0 +1,38 @@
/* List and enable/disable service configurations
*
* Copyright (c) 2017 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.
*/
#ifndef FINIT_SERV_H_
#define FINIT_SERV_H_
int serv_list (char *arg);
int serv_enable (char *arg);
int serv_disable (char *arg);
#endif /* FINIT_SERV_H_ */
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/