rc-status: add -f option to allow formatting output
The -f option can be used when showing the status of services in runlevels to allow making the output more easily parsable. Currently, the .ini format is the only one supported.
This commit is contained in:
parent
f43cec34ca
commit
427a1ce299
5
NEWS.md
5
NEWS.md
@ -6,6 +6,11 @@ the information in this file is in reverse order.
|
|||||||
|
|
||||||
## OpenRC 0.41.
|
## OpenRC 0.41.
|
||||||
|
|
||||||
|
This version adds the ability to format the output of rc-status when
|
||||||
|
showing the status of services in a runlevel so that it may be parsed.
|
||||||
|
Currently, the -f switch only accepts ini as an argument which
|
||||||
|
causes the output to be in the .ini format.
|
||||||
|
|
||||||
This version adds an experimental build time switch to allow setting the
|
This version adds an experimental build time switch to allow setting the
|
||||||
default shell to use for service scripts.
|
default shell to use for service scripts.
|
||||||
By default, this is set to /bin/sh if it is changed, the new shell must
|
By default, this is set to /bin/sh if it is changed, the new shell must
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl aclsuC
|
.Op Fl aclsuC
|
||||||
|
.Op Fl f Ar ini
|
||||||
.Op Ar runlevel
|
.Op Ar runlevel
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
@ -37,6 +38,9 @@ The options are as follows:
|
|||||||
Show all runlevels and their services.
|
Show all runlevels and their services.
|
||||||
.It Fl c , -crashed
|
.It Fl c , -crashed
|
||||||
List all services that have crashed.
|
List all services that have crashed.
|
||||||
|
.It Fl f , -format
|
||||||
|
Select a format for the output. Currently, the only one that can be
|
||||||
|
specified is ini, which outputs in *.ini format.
|
||||||
.It Fl l , -list
|
.It Fl l , -list
|
||||||
List all defined runlevels.
|
List all defined runlevels.
|
||||||
.It Fl m , -manual
|
.It Fl m , -manual
|
||||||
|
@ -27,12 +27,18 @@
|
|||||||
#include "rc-misc.h"
|
#include "rc-misc.h"
|
||||||
#include "_usage.h"
|
#include "_usage.h"
|
||||||
|
|
||||||
|
enum format_t {
|
||||||
|
FORMAT_DEFAULT,
|
||||||
|
FORMAT_INI,
|
||||||
|
};
|
||||||
|
|
||||||
const char *applet = NULL;
|
const char *applet = NULL;
|
||||||
const char *extraopts = NULL;
|
const char *extraopts = NULL;
|
||||||
const char *getoptstring = "aclmrsSu" getoptstring_COMMON;
|
const char *getoptstring = "acf:lmrsSu" getoptstring_COMMON;
|
||||||
const struct option longopts[] = {
|
const struct option longopts[] = {
|
||||||
{"all", 0, NULL, 'a'},
|
{"all", 0, NULL, 'a'},
|
||||||
{"crashed", 0, NULL, 'c'},
|
{"crashed", 0, NULL, 'c'},
|
||||||
|
{"format", 1, NULL, 'f'},
|
||||||
{"list", 0, NULL, 'l'},
|
{"list", 0, NULL, 'l'},
|
||||||
{"manual", 0, NULL, 'm'},
|
{"manual", 0, NULL, 'm'},
|
||||||
{"runlevel", 0, NULL, 'r'},
|
{"runlevel", 0, NULL, 'r'},
|
||||||
@ -44,6 +50,7 @@ const struct option longopts[] = {
|
|||||||
const char * const longopts_help[] = {
|
const char * const longopts_help[] = {
|
||||||
"Show services from all run levels",
|
"Show services from all run levels",
|
||||||
"Show crashed services",
|
"Show crashed services",
|
||||||
|
"format status to be parsable (currently arg must be ini)",
|
||||||
"Show list of run levels",
|
"Show list of run levels",
|
||||||
"Show manually started services",
|
"Show manually started services",
|
||||||
"Show the name of the current runlevel",
|
"Show the name of the current runlevel",
|
||||||
@ -53,7 +60,7 @@ const char * const longopts_help[] = {
|
|||||||
longopts_help_COMMON
|
longopts_help_COMMON
|
||||||
};
|
};
|
||||||
const char *usagestring = "" \
|
const char *usagestring = "" \
|
||||||
"Usage: rc-status [options] <runlevel>...\n" \
|
"Usage: rc-status [options] -f ini <runlevel>...\n" \
|
||||||
" or: rc-status [options] [-a | -c | -l | -m | -r | -s | -u]";
|
" or: rc-status [options] [-a | -c | -l | -m | -r | -s | -u]";
|
||||||
|
|
||||||
static RC_DEPTREE *deptree;
|
static RC_DEPTREE *deptree;
|
||||||
@ -62,18 +69,27 @@ static RC_STRINGLIST *types;
|
|||||||
static RC_STRINGLIST *levels, *services, *tmp, *alist;
|
static RC_STRINGLIST *levels, *services, *tmp, *alist;
|
||||||
static RC_STRINGLIST *sservices, *nservices, *needsme;
|
static RC_STRINGLIST *sservices, *nservices, *needsme;
|
||||||
|
|
||||||
static void print_level(const char *prefix, const char *level)
|
static void print_level(const char *prefix, const char *level,
|
||||||
|
enum format_t format)
|
||||||
{
|
{
|
||||||
if (prefix)
|
switch (format) {
|
||||||
printf("%s ", prefix);
|
case FORMAT_DEFAULT:
|
||||||
printf ("Runlevel: ");
|
if (prefix)
|
||||||
if (isatty(fileno(stdout)))
|
printf("%s ", prefix);
|
||||||
printf("%s%s%s\n",
|
printf ("Runlevel: ");
|
||||||
ecolor(ECOLOR_HILITE),
|
if (isatty(fileno(stdout)))
|
||||||
level,
|
printf("%s%s%s\n",
|
||||||
ecolor(ECOLOR_NORMAL));
|
ecolor(ECOLOR_HILITE), level, ecolor(ECOLOR_NORMAL));
|
||||||
else
|
else
|
||||||
printf("%s\n", level);
|
printf("%s\n", level);
|
||||||
|
break;
|
||||||
|
case FORMAT_INI:
|
||||||
|
printf("%s", "[");
|
||||||
|
if (prefix)
|
||||||
|
printf("%s ", prefix);
|
||||||
|
printf("%s]\n", level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_uptime(const char *service)
|
static char *get_uptime(const char *service)
|
||||||
@ -124,13 +140,13 @@ static char *get_uptime(const char *service)
|
|||||||
return uptime;
|
return uptime;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_service(const char *service)
|
static void print_service(const char *service, enum format_t format)
|
||||||
{
|
{
|
||||||
char *status = NULL;
|
char *status = NULL;
|
||||||
char *uptime = NULL;
|
char *uptime = NULL;
|
||||||
char *child_pid = NULL;
|
char *child_pid = NULL;
|
||||||
char *start_time = NULL;
|
char *start_time = NULL;
|
||||||
int cols = printf(" %s", service);
|
int cols;
|
||||||
const char *c = ecolor(ECOLOR_GOOD);
|
const char *c = ecolor(ECOLOR_GOOD);
|
||||||
RC_SERVICE state = rc_service_state(service);
|
RC_SERVICE state = rc_service_state(service);
|
||||||
ECOLOR color = ECOLOR_BAD;
|
ECOLOR color = ECOLOR_BAD;
|
||||||
@ -174,13 +190,22 @@ static void print_service(const char *service)
|
|||||||
xasprintf(&status, " stopped ");
|
xasprintf(&status, " stopped ");
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (c && *c && isatty(fileno(stdout)))
|
switch(format) {
|
||||||
printf("\n");
|
case FORMAT_DEFAULT:
|
||||||
ebracket(cols, color, status);
|
cols = printf(" %s", service);
|
||||||
|
if (c && *c && isatty(fileno(stdout)))
|
||||||
|
printf("\n");
|
||||||
|
ebracket(cols, color, status);
|
||||||
|
break;
|
||||||
|
case FORMAT_INI:
|
||||||
|
printf("%s = %s\n", service, status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
free(status);
|
free(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_services(const char *runlevel, RC_STRINGLIST *svcs)
|
static void print_services(const char *runlevel, RC_STRINGLIST *svcs,
|
||||||
|
enum format_t format)
|
||||||
{
|
{
|
||||||
RC_STRINGLIST *l = NULL;
|
RC_STRINGLIST *l = NULL;
|
||||||
RC_STRING *s;
|
RC_STRING *s;
|
||||||
@ -194,7 +219,7 @@ static void print_services(const char *runlevel, RC_STRINGLIST *svcs)
|
|||||||
TAILQ_FOREACH(s, svcs, entries)
|
TAILQ_FOREACH(s, svcs, entries)
|
||||||
if (!runlevel ||
|
if (!runlevel ||
|
||||||
rc_service_in_runlevel(s->value, runlevel))
|
rc_service_in_runlevel(s->value, runlevel))
|
||||||
print_service(s->value);
|
print_service(s->value, format);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!types) {
|
if (!types) {
|
||||||
@ -214,12 +239,12 @@ static void print_services(const char *runlevel, RC_STRINGLIST *svcs)
|
|||||||
if (!rc_stringlist_find(svcs, s->value))
|
if (!rc_stringlist_find(svcs, s->value))
|
||||||
continue;
|
continue;
|
||||||
if (!runlevel || rc_service_in_runlevel(s->value, runlevel))
|
if (!runlevel || rc_service_in_runlevel(s->value, runlevel))
|
||||||
print_service(s->value);
|
print_service(s->value, format);
|
||||||
}
|
}
|
||||||
rc_stringlist_free(l);
|
rc_stringlist_free(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_stacked_services(const char *runlevel)
|
static void print_stacked_services(const char *runlevel, enum format_t format)
|
||||||
{
|
{
|
||||||
RC_STRINGLIST *stackedlevels, *servicelist;
|
RC_STRINGLIST *stackedlevels, *servicelist;
|
||||||
RC_STRING *stackedlevel;
|
RC_STRING *stackedlevel;
|
||||||
@ -228,9 +253,9 @@ static void print_stacked_services(const char *runlevel)
|
|||||||
TAILQ_FOREACH(stackedlevel, stackedlevels, entries) {
|
TAILQ_FOREACH(stackedlevel, stackedlevels, entries) {
|
||||||
if (rc_stringlist_find(levels, stackedlevel->value) != NULL)
|
if (rc_stringlist_find(levels, stackedlevel->value) != NULL)
|
||||||
continue;
|
continue;
|
||||||
print_level("Stacked", stackedlevel->value);
|
print_level("Stacked", stackedlevel->value, format);
|
||||||
servicelist = rc_services_in_runlevel(stackedlevel->value);
|
servicelist = rc_services_in_runlevel(stackedlevel->value);
|
||||||
print_services(stackedlevel->value, servicelist);
|
print_services(stackedlevel->value, servicelist, format);
|
||||||
rc_stringlist_free(servicelist);
|
rc_stringlist_free(servicelist);
|
||||||
}
|
}
|
||||||
rc_stringlist_free(stackedlevels);
|
rc_stringlist_free(stackedlevels);
|
||||||
@ -241,6 +266,8 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
RC_SERVICE state;
|
RC_SERVICE state;
|
||||||
RC_STRING *s, *l, *t, *level;
|
RC_STRING *s, *l, *t, *level;
|
||||||
|
enum format_t format = FORMAT_DEFAULT;
|
||||||
|
bool levels_given = false;
|
||||||
bool show_all = false;
|
bool show_all = false;
|
||||||
char *p, *runlevel = NULL;
|
char *p, *runlevel = NULL;
|
||||||
int opt, retval = 0;
|
int opt, retval = 0;
|
||||||
@ -263,6 +290,12 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
goto exit;
|
goto exit;
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
case 'f':
|
||||||
|
if (strcasecmp(optarg, "ini") == 0)
|
||||||
|
format = FORMAT_INI;
|
||||||
|
else
|
||||||
|
eerrorx("%s: invalid argument to --format switch\n", applet);
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
levels = rc_runlevel_list();
|
levels = rc_runlevel_list();
|
||||||
TAILQ_FOREACH(l, levels, entries)
|
TAILQ_FOREACH(l, levels, entries)
|
||||||
@ -287,7 +320,7 @@ int main(int argc, char **argv)
|
|||||||
free(s->value);
|
free(s->value);
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
print_services(NULL, services);
|
print_services(NULL, services, FORMAT_DEFAULT);
|
||||||
goto exit;
|
goto exit;
|
||||||
case 'r':
|
case 'r':
|
||||||
runlevel = rc_runlevel_get();
|
runlevel = rc_runlevel_get();
|
||||||
@ -299,12 +332,12 @@ int main(int argc, char **argv)
|
|||||||
TAILQ_FOREACH_SAFE(s, services, entries, t)
|
TAILQ_FOREACH_SAFE(s, services, entries, t)
|
||||||
if (!rc_service_value_get(s->value, "child_pid"))
|
if (!rc_service_value_get(s->value, "child_pid"))
|
||||||
TAILQ_REMOVE(services, s, entries);
|
TAILQ_REMOVE(services, s, entries);
|
||||||
print_services(NULL, services);
|
print_services(NULL, services, FORMAT_DEFAULT);
|
||||||
goto exit;
|
goto exit;
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
case 's':
|
case 's':
|
||||||
services = rc_services_in_runlevel(NULL);
|
services = rc_services_in_runlevel(NULL);
|
||||||
print_services(NULL, services);
|
print_services(NULL, services, FORMAT_DEFAULT);
|
||||||
goto exit;
|
goto exit;
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
case 'u':
|
case 'u':
|
||||||
@ -319,7 +352,7 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print_services(NULL, services);
|
print_services(NULL, services, FORMAT_DEFAULT);
|
||||||
goto exit;
|
goto exit;
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
|
||||||
@ -331,6 +364,7 @@ int main(int argc, char **argv)
|
|||||||
opt = (optind < argc) ? 0 : 1;
|
opt = (optind < argc) ? 0 : 1;
|
||||||
while (optind < argc) {
|
while (optind < argc) {
|
||||||
if (rc_runlevel_exists(argv[optind])) {
|
if (rc_runlevel_exists(argv[optind])) {
|
||||||
|
levels_given = true;
|
||||||
rc_stringlist_add(levels, argv[optind++]);
|
rc_stringlist_add(levels, argv[optind++]);
|
||||||
opt++;
|
opt++;
|
||||||
} else
|
} else
|
||||||
@ -347,21 +381,21 @@ int main(int argc, char **argv)
|
|||||||
deptree = _rc_deptree_load(0, NULL);
|
deptree = _rc_deptree_load(0, NULL);
|
||||||
|
|
||||||
TAILQ_FOREACH(l, levels, entries) {
|
TAILQ_FOREACH(l, levels, entries) {
|
||||||
print_level(NULL, l->value);
|
print_level(NULL, l->value, format);
|
||||||
services = rc_services_in_runlevel(l->value);
|
services = rc_services_in_runlevel(l->value);
|
||||||
print_services(l->value, services);
|
print_services(l->value, services, format);
|
||||||
print_stacked_services(l->value);
|
print_stacked_services(l->value, format);
|
||||||
rc_stringlist_free(nservices);
|
rc_stringlist_free(nservices);
|
||||||
nservices = NULL;
|
nservices = NULL;
|
||||||
rc_stringlist_free(services);
|
rc_stringlist_free(services);
|
||||||
services = NULL;
|
services = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_all || argc < 2) {
|
if (show_all || !levels_given) {
|
||||||
/* Show hotplugged services */
|
/* Show hotplugged services */
|
||||||
print_level("Dynamic", "hotplugged");
|
print_level("Dynamic", "hotplugged", format);
|
||||||
services = rc_services_in_state(RC_SERVICE_HOTPLUGGED);
|
services = rc_services_in_state(RC_SERVICE_HOTPLUGGED);
|
||||||
print_services(NULL, services);
|
print_services(NULL, services, format);
|
||||||
rc_stringlist_free(services);
|
rc_stringlist_free(services);
|
||||||
services = NULL;
|
services = NULL;
|
||||||
|
|
||||||
@ -418,10 +452,10 @@ int main(int argc, char **argv)
|
|||||||
* be added to the list
|
* be added to the list
|
||||||
*/
|
*/
|
||||||
unsetenv("RC_SVCNAME");
|
unsetenv("RC_SVCNAME");
|
||||||
print_level("Dynamic", "needed/wanted");
|
print_level("Dynamic", "needed/wanted", format);
|
||||||
print_services(NULL, nservices);
|
print_services(NULL, nservices, format);
|
||||||
print_level("Dynamic", "manual");
|
print_level("Dynamic", "manual", format);
|
||||||
print_services(NULL, services);
|
print_services(NULL, services, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
Loading…
Reference in New Issue
Block a user