mirror of
https://github.com/troglobit/finit.git
synced 2026-10-08 16:34:45 +07:00
Merge branch 'master' into wip-tests
This commit is contained in:
@@ -101,14 +101,16 @@ in full in [doc/config.md](doc/config.md). Here's a quick overview of
|
||||
some of the most common components needed to start a UNIX daemon:
|
||||
|
||||
```
|
||||
service [LVLS] <COND> /path/to/daemon ARGS -- Some text
|
||||
^ ^ ^ ^ ^ ^
|
||||
| | | | | `-- Optional description
|
||||
| | | | `---------- Daemon arguments
|
||||
| | | `-------------------------- Path to daemon
|
||||
| | `--------------------------------- Optional conditions
|
||||
| `---------------------------------------- Optional Runlevels
|
||||
`------------------------------------------------ Monitored application
|
||||
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
|
||||
^ ^ ^ ^ ^ ^ ^ ^
|
||||
| | | | | | | `-- Optional description
|
||||
| | | | | | `----------- Daemon arguments
|
||||
| | | | | `-------------------------- Path to daemon
|
||||
| | | | `---------------------------------------------------- Optional env. file
|
||||
| | | `-------------------------------------------------------- Redirect output to log
|
||||
| | `--------------------------------------------------------------- Optional conditions
|
||||
| `---------------------------------------------------------------------- Optional Runlevels
|
||||
`------------------------------------------------------------------------------ Monitored application
|
||||
```
|
||||
|
||||
Some components are optional: runlevel(s), condition(s) and description,
|
||||
|
||||
+51
-10
@@ -48,6 +48,7 @@ struct command {
|
||||
int (*cb)(char *arg);
|
||||
};
|
||||
|
||||
int icreate = 0;
|
||||
int heading = 1;
|
||||
int numeric = 0;
|
||||
int verbose = 0;
|
||||
@@ -638,13 +639,33 @@ static int transform(char *nm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int has_conf(char *path, size_t len, char *name)
|
||||
{
|
||||
paste(path, len, FINIT_RCSD, name);
|
||||
if (!fisdir(path)) {
|
||||
strlcpy(path, FINIT_RCSD, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
int has_rcsd = fisdir(FINIT_RCSD);
|
||||
int has_ena;
|
||||
char avail[256];
|
||||
char ena[256];
|
||||
|
||||
has_conf(avail, sizeof(avail), "available");
|
||||
has_ena = has_conf(ena, sizeof(ena), "enabled");
|
||||
|
||||
fprintf(stderr,
|
||||
"Usage: %s [OPTIONS] [COMMAND]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -b, --batch Batch mode, no screen size probing\n"
|
||||
" -c, --create Create missing paths (and files) as needed\n"
|
||||
" -n, --numeric Show JOB:ID instead of NAME:ID\n"
|
||||
" -t, --no-heading Skip table headings\n"
|
||||
" -v, --verbose Verbose output\n"
|
||||
@@ -654,15 +675,30 @@ static int usage(int rc)
|
||||
" debug Toggle Finit (daemon) debug\n"
|
||||
" help This help text\n"
|
||||
" version Show Finit version\n"
|
||||
"\n"
|
||||
" ls | list List all .conf in /etc/finit.d/\n"
|
||||
" create <CONF> Create .conf in /etc/finit.d/available/\n"
|
||||
" enable <CONF> Enable .conf in /etc/finit.d/available/\n"
|
||||
" disable <CONF> Disable .conf in /etc/finit.d/[enabled/]\n"
|
||||
" touch <CONF> Mark .conf in /etc/finit.d/ for reload\n"
|
||||
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
|
||||
"\n", prognm);
|
||||
|
||||
if (has_rcsd)
|
||||
fprintf(stderr,
|
||||
" ls | list List all .conf in " FINIT_RCSD "\n"
|
||||
" create <CONF> Create .conf in %s\n"
|
||||
" edit <CONF> Edit .conf in %s\n"
|
||||
" touch <CONF> Change .conf in %s\n",
|
||||
avail, avail, avail);
|
||||
if (has_ena)
|
||||
fprintf(stderr,
|
||||
" enable <CONF> Enable .conf in %s\n", avail);
|
||||
if (has_ena)
|
||||
fprintf(stderr,
|
||||
" disable <CONF> Disable .conf in %s\n", ena);
|
||||
if (has_rcsd)
|
||||
fprintf(stderr,
|
||||
" reload Reload *.conf in " FINIT_RCSD " (activate changes)\n");
|
||||
else
|
||||
fprintf(stderr,
|
||||
" reload Reload " FINIT_CONF " (activate changes)\n");
|
||||
|
||||
fprintf(stderr,
|
||||
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
||||
" edit <CONF> Edit .conf in /etc/finit.d/available/\n"
|
||||
"\n"
|
||||
" cond show Show condition status\n"
|
||||
" cond dump Dump all conditions and their status\n"
|
||||
@@ -680,7 +716,7 @@ static int usage(int rc)
|
||||
" reboot Reboot system\n"
|
||||
" halt Halt system\n"
|
||||
" poweroff Halt and power off system\n"
|
||||
" suspend Suspend system\n", prognm);
|
||||
" suspend Suspend system\n");
|
||||
|
||||
if (has_utmp())
|
||||
fprintf(stderr,
|
||||
@@ -738,6 +774,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
struct option long_options[] = {
|
||||
{ "batch", 0, NULL, 'b' },
|
||||
{ "create", 0, NULL, 'c' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "numeric", 0, NULL, 'n' },
|
||||
{ "no-heading", 0, NULL, 't' },
|
||||
@@ -748,12 +785,16 @@ int main(int argc, char *argv[])
|
||||
if (transform(progname(argv[0])))
|
||||
return reboot_main(argc, argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "bh?ntv", long_options, NULL)) != EOF) {
|
||||
while ((c = getopt_long(argc, argv, "bch?ntv", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'b':
|
||||
interactive = 0;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
icreate = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
|
||||
+145
-77
@@ -32,20 +32,8 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
static const char *cwd;
|
||||
static const char *available = FINIT_RCSD "/available";
|
||||
static const char *enabled = FINIT_RCSD "/enabled";
|
||||
extern int icreate; /* initctl -c */
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -69,11 +57,9 @@ static void do_list(const char *path)
|
||||
glob_t gl;
|
||||
size_t i;
|
||||
|
||||
pushd(path);
|
||||
if (glob("*.conf", 0, NULL, &gl)) {
|
||||
chdir(cwd);
|
||||
chdir(path);
|
||||
if (glob("*.conf", 0, NULL, &gl))
|
||||
return;
|
||||
}
|
||||
|
||||
if (gl.gl_pathc <= 0)
|
||||
goto done;
|
||||
@@ -105,97 +91,155 @@ static void do_list(const char *path)
|
||||
|
||||
done:
|
||||
globfree(&gl);
|
||||
popd();
|
||||
}
|
||||
|
||||
int serv_list(char *arg)
|
||||
{
|
||||
if (fisdir(available))
|
||||
do_list(available);
|
||||
if (fisdir(enabled))
|
||||
do_list(enabled);
|
||||
char path[256];
|
||||
|
||||
if (arg && arg[0]) {
|
||||
paste(path, sizeof(path), FINIT_RCSD, arg);
|
||||
if (fisdir(path)) {
|
||||
do_list(path);
|
||||
return 0;
|
||||
}
|
||||
/* fall back to list all */
|
||||
}
|
||||
|
||||
paste(path, sizeof(path), FINIT_RCSD, "available");
|
||||
if (fisdir(path))
|
||||
do_list(path);
|
||||
|
||||
paste(path, sizeof(path), FINIT_RCSD, "enabled");
|
||||
if (fisdir(path))
|
||||
do_list(path);
|
||||
|
||||
if (fisdir(FINIT_RCSD))
|
||||
do_list(FINIT_RCSD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return path to configuration file for 'name', relative to FINIT_RCSD.
|
||||
* This may be any of the following, provided sysconfdir is /etc:
|
||||
*
|
||||
* - /etc/finit.d/$name.conf
|
||||
* - /etc/finit.d/available/$name.conf
|
||||
*
|
||||
* The system *may* have a /etc/finit.d/available/ directory, or it may
|
||||
* just use a plain /etc/finit.d/ -- we do not set policy.
|
||||
*
|
||||
* If the resulting file doesn't exist, and creat is not set, *or*
|
||||
* the base directory doesn't exist, we return NULL.
|
||||
.*/
|
||||
static char *conf(char *path, size_t len, char *name, int creat)
|
||||
{
|
||||
char corr[40];
|
||||
|
||||
if (!strstr(name, ".conf")) {
|
||||
snprintf(corr, sizeof(corr), "%s.conf", name);
|
||||
name = corr;
|
||||
}
|
||||
|
||||
if (!fisdir(FINIT_RCSD))
|
||||
return NULL;
|
||||
|
||||
paste(path, len, FINIT_RCSD, "available/");
|
||||
if (!fisdir(path)) {
|
||||
if (creat && mkdir(path, 0755) && errno != EEXIST)
|
||||
return NULL;
|
||||
else
|
||||
paste(path, len, FINIT_RCSD, name);
|
||||
} else
|
||||
strlcat(path, name, len);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
int serv_enable(char *arg)
|
||||
{
|
||||
char corr[40];
|
||||
char link[256];
|
||||
char path[256];
|
||||
int ena;
|
||||
|
||||
if (!arg || !arg[0])
|
||||
return serv_list(NULL);
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to enable, may be one of:");
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
if (!strstr(arg, ".conf")) {
|
||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||
arg = corr;
|
||||
}
|
||||
|
||||
pushd(FINIT_RCSD);
|
||||
if (mkdir("enabled", 0755) && EEXIST != errno)
|
||||
err(1, "Failed creating %s/enabled directory", FINIT_RCSD);
|
||||
if (chdir(FINIT_RCSD))
|
||||
err(1, "failed cd %s", FINIT_RCSD);
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", available, arg);
|
||||
if (icreate && mkdir("enabled", 0755) && EEXIST != errno)
|
||||
err(1, "failed creating %s/enabled directory", FINIT_RCSD);
|
||||
ena = !chdir("enabled"); /* System *may* have enabled/ dir. */
|
||||
|
||||
snprintf(path, sizeof(path), "%savailable/%s", ena ? "../" : "", arg);
|
||||
if (!fexist(path))
|
||||
errx(1, "Cannot find %s", path);
|
||||
errx(1, "cannot find %s", conf(path, sizeof(path), arg, 0));
|
||||
|
||||
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||
if (fexist(link))
|
||||
errx(1, "%s already exists", link);
|
||||
if (fexist(arg))
|
||||
errx(1, "%s already enabled", arg);
|
||||
|
||||
return symlink(path, link) != 0;
|
||||
return symlink(path, arg) != 0;
|
||||
}
|
||||
|
||||
int serv_disable(char *arg)
|
||||
{
|
||||
char corr[40];
|
||||
char link[256];
|
||||
struct stat st;
|
||||
char corr[40];
|
||||
|
||||
if (!arg || !arg[0])
|
||||
return serv_list(NULL);
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to disable, may be one of:");
|
||||
return serv_list("enabled");
|
||||
}
|
||||
|
||||
if (!strstr(arg, ".conf")) {
|
||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||
arg = corr;
|
||||
}
|
||||
|
||||
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||
if (stat(link, &st))
|
||||
err(1, "Cannot find %s", link);
|
||||
if (chdir(FINIT_RCSD))
|
||||
err(1, "failed cd %s", FINIT_RCSD);
|
||||
chdir("enabled"); /* System *may* have enabled/ dir. */
|
||||
|
||||
if (stat(arg, &st))
|
||||
errx(1, "%s not (an) enabled (service).", arg);
|
||||
|
||||
if ((st.st_mode & S_IFMT) == S_IFLNK)
|
||||
errx(1, "%s is not a symlink, move manually to %s first", link, available);
|
||||
errx(1, "cannot disable %s, not a symlink.", arg);
|
||||
|
||||
return remove(link) != 0;
|
||||
return remove(arg) != 0;
|
||||
}
|
||||
|
||||
int serv_touch(char *arg)
|
||||
{
|
||||
char corr[40];
|
||||
char path[256];
|
||||
char *fn;
|
||||
|
||||
if (!arg || !arg[0])
|
||||
return serv_list(NULL);
|
||||
|
||||
if (!strstr(arg, ".conf")) {
|
||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||
arg = corr;
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to touch, may be one of:");
|
||||
return serv_list("enabled");
|
||||
}
|
||||
|
||||
pushd(FINIT_RCSD);
|
||||
if (!fexist(arg)) {
|
||||
popd();
|
||||
fn = conf(path, sizeof(path), arg, 0);
|
||||
if (!fexist(fn)) {
|
||||
if (!strstr(arg, "finit.conf"))
|
||||
errx(1, "Service %s is not enabled", arg);
|
||||
arg = FINIT_CONF;
|
||||
errx(1, "%s not available.", arg);
|
||||
|
||||
strlcpy(path, FINIT_CONF, sizeof(path));
|
||||
fn = path;
|
||||
}
|
||||
|
||||
/* libite:touch() follows symlinks */
|
||||
if (utimensat(AT_FDCWD, arg, NULL, AT_SYMLINK_NOFOLLOW))
|
||||
err(1, "Failed marking %s for reload", arg);
|
||||
if (utimensat(AT_FDCWD, fn, NULL, AT_SYMLINK_NOFOLLOW))
|
||||
err(1, "failed marking %s for reload", fn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -209,28 +253,19 @@ static int do_edit(char *arg, int creat)
|
||||
"mg",
|
||||
"vi"
|
||||
};
|
||||
char corr[40];
|
||||
char path[256];
|
||||
char *fn;
|
||||
|
||||
if (!arg || !arg[0])
|
||||
return serv_list(NULL);
|
||||
|
||||
if (!strstr(arg, ".conf")) {
|
||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||
arg = corr;
|
||||
}
|
||||
|
||||
pushd(FINIT_RCSD);
|
||||
if (mkdir("available", 0755) && EEXIST != errno)
|
||||
err(1, "Failed creating %s/available directory", FINIT_RCSD);
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", available, arg);
|
||||
if (!fexist(path)) {
|
||||
if (!creat)
|
||||
return serv_list(NULL);
|
||||
fn = conf(path, sizeof(path), arg, creat);
|
||||
if (!fexist(fn)) {
|
||||
if (!creat) {
|
||||
warnx("Cannot find %s, use create command, or select one of:", arg);
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
/* XXX: fill with template/commented-out examples */
|
||||
}
|
||||
} else if (creat)
|
||||
warnx("the file %s already exists, falling back to edit.", fn);
|
||||
|
||||
for (size_t i = 0; i < NELEMS(editor); i++) {
|
||||
if (systemf("%s %s 2>/dev/null", editor[i], path))
|
||||
@@ -243,12 +278,45 @@ static int do_edit(char *arg, int creat)
|
||||
|
||||
int serv_edit(char *arg)
|
||||
{
|
||||
return do_edit(arg, 0);
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to edit, may be one of:");
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
return do_edit(arg, icreate);
|
||||
}
|
||||
|
||||
int serv_creat(char *arg)
|
||||
{
|
||||
return do_edit(arg, 1);
|
||||
char buf[256];
|
||||
char *fn;
|
||||
FILE *fp;
|
||||
|
||||
if (!arg || !arg[0])
|
||||
errx(1, "missing argument to create");
|
||||
|
||||
/* Input from a pipe or a proper TTY? */
|
||||
if (isatty(STDIN_FILENO))
|
||||
return do_edit(arg, 1);
|
||||
|
||||
/* Open fn for writing from pipe */
|
||||
fn = conf(buf, sizeof(buf), arg, 1);
|
||||
if (!fn)
|
||||
err(1, "failed creating conf %s", arg);
|
||||
|
||||
if (!icreate && fexist(fn)) {
|
||||
warnx("%s already exists, skipping (use -c to override)", fn);
|
||||
fn = "/dev/null";
|
||||
}
|
||||
|
||||
fp = fopen(fn, "w");
|
||||
if (!fp)
|
||||
err(1, "failed opening %s for writing", fn);
|
||||
|
||||
while (fgets(buf, sizeof(buf), stdin))
|
||||
fputs(buf, fp);
|
||||
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user