aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2025-06-06 13:48:20 +0000
committerLaurent Bercot <ska@appnovation.com>2025-06-06 13:48:20 +0000
commit3f75ffee7c0c7d6b70cf305d60435ac862ea9ab5 (patch)
tree45d86cdc414e6534305d2b723666c1291d74b940
parent73988ba1cfa375582c86302116192fb8ec567f48 (diff)
downloads6-frontend-3f75ffee7c0c7d6b70cf305d60435ac862ea9ab5.tar.gz
Implement "s6 process"
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--package/deps.mak10
-rw-r--r--src/s6/deps-exe/s69
-rw-r--r--src/s6/process.c33
-rw-r--r--src/s6/process_help.c16
-rw-r--r--src/s6/process_kill.c94
-rw-r--r--src/s6/process_restart.c38
-rw-r--r--src/s6/process_start.c38
-rw-r--r--src/s6/process_status.c108
-rw-r--r--src/s6/process_stop.c38
-rw-r--r--src/s6/process_util.c63
-rw-r--r--src/s6/s6-internal.h20
-rw-r--r--src/s6/s6.c27
12 files changed, 491 insertions, 3 deletions
diff --git a/package/deps.mak b/package/deps.mak
index 19ddac1..e2fa383 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -8,6 +8,14 @@ src/alias/s6-frontend-alias-sv.o src/alias/s6-frontend-alias-sv.lo: src/alias/s6
src/alias/s6-frontend-alias.o src/alias/s6-frontend-alias.lo: src/alias/s6-frontend-alias.c src/include/s6-frontend/config.h
src/config/s6-frontend-config-preprocess.o src/config/s6-frontend-config-preprocess.lo: src/config/s6-frontend-config-preprocess.c
src/s6/help.o src/s6/help.lo: src/s6/help.c src/s6/s6-internal.h
+src/s6/process.o src/s6/process.lo: src/s6/process.c src/s6/s6-internal.h
+src/s6/process_help.o src/s6/process_help.lo: src/s6/process_help.c src/s6/s6-internal.h
+src/s6/process_kill.o src/s6/process_kill.lo: src/s6/process_kill.c src/s6/s6-internal.h
+src/s6/process_restart.o src/s6/process_restart.lo: src/s6/process_restart.c src/s6/s6-internal.h
+src/s6/process_start.o src/s6/process_start.lo: src/s6/process_start.c src/s6/s6-internal.h
+src/s6/process_status.o src/s6/process_status.lo: src/s6/process_status.c src/s6/s6-internal.h
+src/s6/process_stop.o src/s6/process_stop.lo: src/s6/process_stop.c src/s6/s6-internal.h
+src/s6/process_util.o src/s6/process_util.lo: src/s6/process_util.c src/s6/s6-internal.h
src/s6/s6.o src/s6/s6.lo: src/s6/s6.c src/include/s6-frontend/config.h src/s6/s6-internal.h
src/s6/util.o src/s6/util.lo: src/s6/util.c src/s6/s6-internal.h
src/s6/version.o src/s6/version.lo: src/s6/version.c src/s6/s6-internal.h
@@ -21,5 +29,5 @@ s6-frontend-alias-sv: src/alias/s6-frontend-alias-sv.o -ls6 -lskarnet
s6-frontend-config-preprocess: EXTRA_LIBS :=
s6-frontend-config-preprocess: src/config/s6-frontend-config-preprocess.o -lskarnet
s6: EXTRA_LIBS :=
-s6: src/s6/s6.o src/s6/help.o src/s6/util.o src/s6/version.o -lskarnet
+s6: src/s6/s6.o src/s6/help.o src/s6/util.o src/s6/process.o src/s6/process_help.o src/s6/process_kill.o src/s6/process_restart.o src/s6/process_start.o src/s6/process_status.o src/s6/process_stop.o src/s6/process_util.o src/s6/version.o -ls6 -lskarnet
INTERNAL_LIBS :=
diff --git a/src/s6/deps-exe/s6 b/src/s6/deps-exe/s6
index 92e3455..6bfee46 100644
--- a/src/s6/deps-exe/s6
+++ b/src/s6/deps-exe/s6
@@ -1,4 +1,13 @@
help.o
util.o
+process.o
+process_help.o
+process_kill.o
+process_restart.o
+process_start.o
+process_status.o
+process_stop.o
+process_util.o
version.o
+-ls6
-lskarnet
diff --git a/src/s6/process.c b/src/s6/process.c
new file mode 100644
index 0000000..bd14c67
--- /dev/null
+++ b/src/s6/process.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/posixplz.h>
+#include <skalibs/strerr.h>
+#include <skalibs/cspawn.h>
+#include <skalibs/djbunix.h>
+#include <s6/config.h>
+
+#include "s6-internal.h"
+
+#define USAGE "s6 process [ process options ] subcommand [ subcommand options ] services... Type \"s6 process help\" for details."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static struct command_s const process_commands[] =
+{
+ { .s = "help", .f = &process_help },
+ { .s = "kill", .f = &process_kill },
+ { .s = "restart", .f = &process_restart },
+ { .s = "start", .f = &process_start },
+ { .s = "status", .f = &process_status },
+ { .s = "stop", .f = &process_stop },
+} ;
+
+int process (char const *const *argv)
+{
+ struct command_s *cmd ;
+
+ PROG = "s6 process" ;
+ if (!*argv) dieusage() ;
+ cmd = BSEARCH(struct command_s, *argv, process_commands) ;
+ if (!cmd) dieusage() ;
+ return (*cmd->f)(++argv) ;
+}
diff --git a/src/s6/process_help.c b/src/s6/process_help.c
new file mode 100644
index 0000000..1e51ebe
--- /dev/null
+++ b/src/s6/process_help.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/strerr.h>
+
+#include "s6-internal.h"
+
+#define HELP_MESSAGE "This is the \"s6 process\" help message.\n"
+
+int process_help (char const *const *argv)
+{
+ (void)argv ;
+ if (!buffer_putsflush(buffer_1, HELP_MESSAGE))
+ strerr_diefu1sys(111, "write to stdout") ;
+ return 0 ;
+}
diff --git a/src/s6/process_kill.c b/src/s6/process_kill.c
new file mode 100644
index 0000000..fdad688
--- /dev/null
+++ b/src/s6/process_kill.c
@@ -0,0 +1,94 @@
+/* ISC license. */
+
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/posixplz.h>
+#include <skalibs/types.h>
+#include <skalibs/strerr.h>
+#include <skalibs/gol.h>
+#include <skalibs/env.h>
+#include <skalibs/sig.h>
+
+#include <s6/supervise.h>
+
+#include "s6-internal.h"
+
+#define USAGE "s6 process kill [ --signal=sig ] services..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static int process_kill_hack_kill (int sig, char const *const *argv)
+{
+ size_t scandirlen = strlen(g->scandir) ;
+ if (g->verbosity)
+ {
+ char fmt[INT_FMT] ;
+ fmt[int_fmt(fmt, sig)] = 0 ;
+ strerr_warnw3x("signal ", fmt, " is not natively supported by s6-svc, results may be unreliable") ;
+ }
+
+ for (; *argv ; argv++)
+ {
+ s6_svstatus_t status ;
+ size_t arglen = strlen(*argv) ;
+ char path[scandirlen + arglen + 2] ;
+ memcpy(path, g->scandir, scandirlen) ;
+ path[scandirlen] = '/' ;
+ memcpy(path + scandirlen + 1, *argv, arglen) ;
+ path[scandirlen + 1 + arglen] = 0 ;
+ if (!s6_svstatus_read(path, &status))
+ strerr_diefu2sys(111, "read status file for service ", path) ;
+ if (status.pid && !status.flagfinishing) kill(status.pid, sig) ;
+ }
+ return 0 ;
+}
+
+
+enum process_kill_gola_e
+{
+ PROCESS_KILL_GOLA_SIGNAL,
+ PROCESS_KILL_GOLA_N
+} ;
+
+static gol_arg const process_kill_gola[PROCESS_KILL_GOLA_N] =
+{
+ { .so = 's', .lo = "signal", .i = PROCESS_KILL_GOLA_SIGNAL },
+} ;
+
+int process_kill (char const *const *argv)
+{
+ uint64_t golb = 0 ;
+ char const *gola[PROCESS_KILL_GOLA_N] = { 0 } ;
+ char const *svcopt = 0 ;
+ size_t argc ;
+ int sig = SIGTERM ;
+ PROG = "s6 process kill" ;
+
+ argv += gol_argv(argv, 0, 0, process_kill_gola, PROCESS_KILL_GOLA_N, &golb, gola) ;
+ if (!argv) dieusage() ;
+ if (gola[PROCESS_KILL_GOLA_SIGNAL])
+ {
+ if (!sig0_scan(gola[PROCESS_KILL_GOLA_SIGNAL], &sig))
+ strerr_dief1x(100, "--signal= argument must be the name or number of a signal") ;
+ }
+ argc = env_len(argv) ;
+ process_check_services(argv, argc) ;
+ switch (sig)
+ {
+ case SIGALRM : svcopt = "-a" ; break ;
+ case SIGABRT : svcopt = "-b" ; break ;
+ case SIGQUIT : svcopt = "-q" ; break ;
+ case SIGHUP : svcopt = "-h" ; break ;
+ case SIGKILL : svcopt = "-k" ; break ;
+ case SIGTERM : svcopt = "-t" ; break ;
+ case SIGINT : svcopt = "-i" ; break ;
+ case SIGUSR1 : svcopt = "-1" ; break ;
+ case SIGUSR2 : svcopt = "-2" ; break ;
+ case SIGSTOP : svcopt = "-p" ; break ;
+ case SIGCONT : svcopt = "-c" ; break ;
+ case SIGWINCH: svcopt = "-y" ; break ;
+ }
+ return svcopt ? process_send_svc(svcopt, argv, argc) : process_kill_hack_kill(sig, argv) ;
+}
diff --git a/src/s6/process_restart.c b/src/s6/process_restart.c
new file mode 100644
index 0000000..9e8c083
--- /dev/null
+++ b/src/s6/process_restart.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <stddef.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/env.h>
+#include <skalibs/strerr.h>
+#include <skalibs/gol.h>
+
+#include "s6-internal.h"
+
+#define USAGE "s6 process restart [ -W|--nowait ] services..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+enum process_restart_golb_e
+{
+ PROCESS_RESTART_GOLB_WAIT,
+ PROCESS_RESTART_GOLB_N
+} ;
+
+static gol_bool const process_restart_golb[2] =
+{
+ { .so = 'W', .lo = "nowait", .set = 0, .mask = 1 << PROCESS_RESTART_GOLB_WAIT },
+ { .so = 'w', .lo = "wait", .set = 1, .mask = 1 << PROCESS_RESTART_GOLB_WAIT }
+} ;
+
+int process_restart (char const *const *argv)
+{
+ uint64_t golb = 1 << PROCESS_RESTART_GOLB_WAIT ;
+ size_t argc ;
+ PROG = "s6 process restart" ;
+
+ argv += gol_argv(argv, process_restart_golb, 2, 0, 0, &golb, 0) ;
+ if (!argv) dieusage() ;
+ argc = env_len(argv) ;
+ process_check_services(argv, argc) ;
+ return process_send_svc(golb & 1 << PROCESS_RESTART_GOLB_WAIT ? "-rwR" : "-r", argv, argc) ;
+}
diff --git a/src/s6/process_start.c b/src/s6/process_start.c
new file mode 100644
index 0000000..a2186cf
--- /dev/null
+++ b/src/s6/process_start.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <stddef.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/env.h>
+#include <skalibs/strerr.h>
+#include <skalibs/gol.h>
+
+#include "s6-internal.h"
+
+#define USAGE "s6 process start [ -W|--nowait | -w|--wait ] services..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+enum process_start_golb_e
+{
+ PROCESS_START_GOLB_WAIT,
+ PROCESS_START_GOLB_N
+} ;
+
+static gol_bool const process_start_golb[2] =
+{
+ { .so = 'W', .lo = "nowait", .set = 0, .mask = 1 << PROCESS_START_GOLB_WAIT },
+ { .so = 'w', .lo = "wait", .set = 1, .mask = 1 << PROCESS_START_GOLB_WAIT }
+} ;
+
+int process_start (char const *const *argv)
+{
+ uint64_t golb = 1 << PROCESS_START_GOLB_WAIT ;
+ size_t argc ;
+ PROG = "s6 process start" ;
+
+ argv += gol_argv(argv, process_start_golb, 2, 0, 0, &golb, 0) ;
+ if (!argv) dieusage() ;
+ argc = env_len(argv) ;
+ process_check_services(argv, argc) ;
+ return process_send_svc(golb & 1 << PROCESS_START_GOLB_WAIT ? "-uwU" : "-u", argv, argc) ;
+}
diff --git a/src/s6/process_status.c b/src/s6/process_status.c
new file mode 100644
index 0000000..2240c85
--- /dev/null
+++ b/src/s6/process_status.c
@@ -0,0 +1,108 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/uint64.h>
+#include <skalibs/env.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr.h>
+#include <skalibs/gol.h>
+#include <skalibs/cspawn.h>
+#include <skalibs/djbunix.h>
+
+#include <s6/config.h>
+
+#include "s6-internal.h"
+
+#define USAGE "s6 process status [ -l|--with-logs ] services..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static int spawn_and_wait (char const *const *argv)
+{
+ int wstat ;
+ pid_t r ;
+ pid_t pid = cspawn(argv[0], argv, (char const *const *)environ, 0, 0, 0) ;
+ if (!pid)
+ {
+ if (g->verbosity) strerr_warnwu2sys("spawn ", argv[0]) ;
+ return 1 ;
+ }
+ r = wait_pid(pid, &wstat) ;
+ if (r != pid)
+ {
+ if (g->verbosity) strerr_warnwu2sys("wait for ", argv[0]) ;
+ return 1 ;
+ }
+ return !!WIFSIGNALED(wstat) || !!WEXITSTATUS(wstat) ;
+}
+
+static int do_status (char const *dir, int withlog)
+{
+ int e ;
+ char const *argv[4] = { S6_EXTBINPREFIX "s6-svstat", "--", dir, 0 } ;
+ size_t dirlen = strlen(dir) ;
+ buffer_puts(buffer_1, dir) ;
+ buffer_putsflush(buffer_1, ": ") ;
+ e = spawn_and_wait(argv) ;
+ if (withlog && (dirlen < 5 || strcmp(dir + dirlen - 4, "/log")))
+ {
+ struct stat st ;
+ char log[dirlen + 5] ;
+ memcpy(log, dir, dirlen) ;
+ memcpy(log + dirlen, "/log", 5) ;
+ if (stat(log, &st) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ if (g->verbosity) strerr_warnwu2sys("stat", log) ;
+ e = 1 ;
+ }
+ }
+ else if (S_ISDIR(st.st_mode))
+ {
+ argv[2] = log ;
+ buffer_puts(buffer_1, log) ;
+ buffer_putsflush(buffer_1, ": ") ;
+ e |= spawn_and_wait(argv) ;
+ }
+ }
+ return e ;
+}
+
+
+enum process_status_golb_e
+{
+ PROCESS_STATUS_GOLB_WITHLOGS,
+ PROCESS_STATUS_GOLB_N
+} ;
+
+static gol_bool const process_status_golb[1] =
+{
+ { .so = 'l', .lo = "with-logs", .set = 1, .mask = 1 << PROCESS_STATUS_GOLB_WITHLOGS }
+} ;
+
+
+int process_status (char const *const *argv)
+{
+ size_t scandirlen = strlen(g->scandir) ;
+ uint64_t golb = 0 ;
+ int e = 0 ;
+ PROG = "s6 process status" ;
+
+ argv += gol_argv(argv, process_status_golb, 1, 0, 0, &golb, 0) ;
+ if (!argv) dieusage() ;
+ process_check_services(argv, env_len(argv)) ;
+ for (; *argv ; argv++)
+ {
+ size_t len = strlen(*argv) ;
+ char path[scandirlen + len + 2] ;
+ memcpy(path, g->scandir, scandirlen) ;
+ path[scandirlen] = '/' ;
+ memcpy(path + scandirlen + 1, *argv, len+1) ;
+ if (do_status(path, !!(golb & 1 << PROCESS_STATUS_GOLB_WITHLOGS))) e = 1 ;
+ }
+ return e ;
+}
diff --git a/src/s6/process_stop.c b/src/s6/process_stop.c
new file mode 100644
index 0000000..6f11b02
--- /dev/null
+++ b/src/s6/process_stop.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <stddef.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/env.h>
+#include <skalibs/strerr.h>
+#include <skalibs/gol.h>
+
+#include "s6-internal.h"
+
+#define USAGE "s6 process stop [ -W|--nowait | -w|--wait ] services..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+enum process_stop_golb_e
+{
+ PROCESS_STOP_GOLB_WAIT,
+ PROCESS_STOP_GOLB_N
+} ;
+
+static gol_bool const process_stop_golb[2] =
+{
+ { .so = 'W', .lo = "nowait", .set = 0, .mask = 1 << PROCESS_STOP_GOLB_WAIT },
+ { .so = 'w', .lo = "wait", .set = 1, .mask = 1 << PROCESS_STOP_GOLB_WAIT }
+} ;
+
+int process_stop (char const *const *argv)
+{
+ uint64_t golb = 1 << PROCESS_STOP_GOLB_WAIT ;
+ size_t argc ;
+ PROG = "s6 process stop" ;
+
+ argv += gol_argv(argv, process_stop_golb, 2, 0, 0, &golb, 0) ;
+ if (!argv) dieusage() ;
+ argc = env_len(argv) ;
+ process_check_services(argv, argc) ;
+ return process_send_svc(golb & 1 << PROCESS_STOP_GOLB_WAIT ? "-dwD" : "-d", argv, argc) ;
+}
diff --git a/src/s6/process_util.c b/src/s6/process_util.c
new file mode 100644
index 0000000..34b9196
--- /dev/null
+++ b/src/s6/process_util.c
@@ -0,0 +1,63 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/strerr.h>
+#include <skalibs/cspawn.h>
+#include <skalibs/djbunix.h>
+
+#include <s6/config.h>
+
+#include "s6-internal.h"
+
+static int check_service (char const *name, size_t scandirlen)
+{
+ struct stat st ;
+ size_t namelen = strlen(name) ;
+ char path[scandirlen + namelen + 2] ;
+ memcpy(path, g->scandir, scandirlen) ;
+ path[scandirlen] = '/' ;
+ memcpy(path + scandirlen + 1, name, namelen) ;
+ path[scandirlen + 1 + namelen] = 0 ;
+ return stat(path, &st) == -1 ? errno == ENOENT ? 0 : -1 : !!S_ISDIR(st.st_mode) ;
+}
+
+void process_check_services (char const *const *argv, size_t argc)
+{
+ size_t scandirlen = strlen(g->scandir) ;
+ for (size_t i = 0 ; i < argc ; i++)
+ {
+ int r = check_service(argv[i], scandirlen) ;
+ if (r == -1)
+ strerr_diefu4sys(111, "stat ", g->scandir, "/", argv[i]) ;
+ else if (!r)
+ strerr_dief3x(100, argv[i], "is not registered as a supervised service in ", g->scandir) ;
+ }
+}
+
+int process_send_svc (char const *svcopt, char const *const *argv, size_t argc)
+{
+ char const *newargv[5] = { S6_EXTBINPREFIX "s6-svc", svcopt, "--", 0, 0 } ;
+ size_t scandirlen = strlen(g->scandir) ;
+ int wstat ;
+ pid_t pids[argc] ;
+
+ for (size_t i = 0 ; i < argc ; i++)
+ {
+ size_t arglen = strlen(argv[i]) ;
+ char path[scandirlen + arglen + 2] ;
+ memcpy(path, g->scandir, scandirlen) ;
+ path[scandirlen] = '/' ;
+ memcpy(path + scandirlen + 1, argv[i], arglen) ;
+ path[scandirlen + 1 + arglen] = 0 ;
+ newargv[3] = path ;
+ pids[i] = cspawn(newargv[0], newargv, (char const *const *)environ, 0, 0, 0) ;
+ if (!pids[i])
+ strerr_diefu4sys(111, "spawn ", newargv[0], " command for service ", argv[i]) ;
+ }
+ waitn_posix(pids, argc, &wstat) ;
+ return 0 ;
+}
diff --git a/src/s6/s6-internal.h b/src/s6/s6-internal.h
index 216d666..7d08d18 100644
--- a/src/s6/s6-internal.h
+++ b/src/s6/s6-internal.h
@@ -3,6 +3,8 @@
#ifndef S6_INTERNAL_H
#define S6_INTERNAL_H
+#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <skalibs/functypes.h>
@@ -25,15 +27,33 @@ extern int help (char const *const *) ;
extern int version (char const *const *) ;
+ /* process */
+
+extern void process_check_services (char const *const *, size_t) ;
+extern int process_send_svc (char const *, char const *const *, size_t) ;
+
+extern int process (char const *const *) ;
+extern int process_help (char const *const *) ;
+extern int process_kill (char const *const *) ;
+extern int process_restart (char const *const *) ;
+extern int process_start (char const *const *) ;
+extern int process_status (char const *const *) ;
+extern int process_stop (char const *const *) ;
+
+
/* main */
struct global_s
{
unsigned int verbosity ;
+ char const *scandir ;
+ uint8_t color : 1 ;
} ;
#define GLOBAL_ZERO \
{ \
.verbosity = 1, \
+ .scandir = "/run/service", \
+ .color = 0 \
}
extern struct global_s *g ;
diff --git a/src/s6/s6.c b/src/s6/s6.c
index b9bc61f..c7d950c 100644
--- a/src/s6/s6.c
+++ b/src/s6/s6.c
@@ -14,7 +14,7 @@
#include <s6-frontend/config.h>
#include "s6-internal.h"
-#define USAGE "s6 [ generic options ] subcommand [ command options ] command_arguments... Type \"s6 help\" for details."
+#define USAGE "s6 [ generic options ] command [ command options ] command_arguments... Type \"s6 help\" for details."
#define dieusage() strerr_dieusage(100, USAGE)
enum main_golb_e
@@ -30,6 +30,7 @@ enum main_gola_e
MAIN_GOLA_LIVEDIR,
MAIN_GOLA_REPODIR,
MAIN_GOLA_VERBOSITY,
+ MAIN_GOLA_COLOR,
MAIN_GOLA_N
} ;
@@ -44,7 +45,8 @@ static gol_arg const main_gola[MAIN_GOLA_N] =
{ .so = 's', .lo = "scandir", .i = MAIN_GOLA_SCANDIR },
{ .so = 'l', .lo = "livedir", .i = MAIN_GOLA_LIVEDIR },
{ .so = 'r', .lo = "repodir", .i = MAIN_GOLA_REPODIR },
- { .so = 'v', .lo = "verbosity", .i = MAIN_GOLA_VERBOSITY }
+ { .so = 'v', .lo = "verbosity", .i = MAIN_GOLA_VERBOSITY },
+ { .so = 0, .lo = "color", .i = MAIN_GOLA_COLOR }
} ;
struct global_s *g ;
@@ -52,6 +54,7 @@ struct global_s *g ;
static struct command_s const main_commands[] =
{
{ .s = "help", .f = &help },
+ { .s = "process", .f = &process },
{ .s = "version", .f = &version },
} ;
@@ -79,6 +82,26 @@ int main (int argc, char const *const *argv, char const *const *envp)
if (gola[MAIN_GOLA_LIVEDIR]) strerr_warni("livedir is ", gola[MAIN_GOLA_LIVEDIR]) ;
if (gola[MAIN_GOLA_REPODIR]) strerr_warni("repodir is ", gola[MAIN_GOLA_REPODIR]) ;
+ {
+ int force_color = 0 ;
+ if (gola[MAIN_GOLA_COLOR])
+ {
+ if (!strcmp(gola[MAIN_GOLA_COLOR], "yes"))
+ {
+ force_color = 1 ;
+ g->color = 1 ;
+ }
+ else if (!strcmp(gola[MAIN_GOLA_COLOR], "no"))
+ {
+ force_color = 1 ;
+ g->color = 0 ;
+ }
+ else if (strcmp(gola[MAIN_GOLA_COLOR], "auto"))
+ strerr_dief1x(100, "--color value must be yes, no, or auto") ;
+ }
+ if (!force_color) g->color = isatty(1) ;
+ }
+
if (!*argv) dieusage() ;
cmd = BSEARCH(struct command_s, *argv, main_commands) ;
if (!cmd) dieusage() ;