author | Olivier Brunel
<jjk@jjacky.com> 2015-10-16 13:15:58 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2015-10-16 18:17:11 UTC |
parent | 1ec37b3c854aef6d09a4d42211c93582b83c76a4 |
doc/aa-status.pod | +22 | -1 |
src/anopa/aa-status.c | +72 | -1 |
diff --git a/doc/aa-status.pod b/doc/aa-status.pod index bcacff5..457463f 100644 --- a/doc/aa-status.pod +++ b/doc/aa-status.pod @@ -5,7 +5,7 @@ aa-status - Show status of services =head1 SYNOPSIS B<aa-status> [B<-D>] [B<-r> I<repodir>] [B<-a>] [B<-f> I<filter>] [B<-L>] -[B<-n>] [B<-l> I<listdir>] [I<service...>] +[B<-n>] [B<-l> I<listdir>] [B<-s> I<sort>] [B<-R>] [B<-N>] [I<service...>] =head1 OPTIONS @@ -45,15 +45,36 @@ I</etc/anopa/listdirs/> Show statuses as a list, with one service per line, elipsizing service name and/or status if needed. +=item B<-N, --name> + +Sort services by name. Default is by time, see B<--sort> for more. + =item B<-n, --dry-list> Only show service names, one per line. +=item B<-R, --reverse> + +Reverse sort order. + =item B<-r, --repodir> I<dir> Use I<dir> as repository directory. This is where servicedirs will be looked for. +=item B<-s, --sort> I<sort> + +Sort services according to I<sort>, which can be one of: + +- I<name> : to sort by names. Can use B<--name> as an alias. + +- I<time> : to sort by times, i.e. the timestamp of the last event for the + service; This can be e.g. when it was started, failed to, or got ready. This + is the default sort order. + +- I<none> : do not sort services. Order will be the one in which they were + processed. + =item B<-V, --version> Show version information and exit. diff --git a/src/anopa/aa-status.c b/src/anopa/aa-status.c index 74cb001..403c9cf 100644 --- a/src/anopa/aa-status.c +++ b/src/anopa/aa-status.c @@ -29,6 +29,7 @@ #include <errno.h> #include <getopt.h> #include <unistd.h> +#include <stdlib.h> #include <sys/stat.h> #include <sys/wait.h> #include <skalibs/bytestr.h> @@ -37,6 +38,7 @@ #include <skalibs/stralloc.h> #include <skalibs/uint.h> #include <skalibs/djbtime.h> +#include <skalibs/tai.h> #include <skalibs/sig.h> #include <skalibs/error.h> #include <s6/s6-supervise.h> @@ -80,10 +82,17 @@ enum FILTER_ERROR }; +enum +{ + SORT_ASC, + SORT_DESC +}; + static genalloc ga_serv = GENALLOC_ZERO; static unsigned int filter_type = AA_TYPE_UNKNOWN; static unsigned int filter_status = FILTER_NONE; +static unsigned int sort_order = SORT_ASC; static int put_s_max (const char *s, int max, int pad); @@ -641,6 +650,35 @@ set_filter (const char *filter) return 1; } +static int +cmp_serv_name (const void *_serv1, const void *_serv2) +{ + const struct serv *serv1 = _serv1; + const struct serv *serv2 = _serv2; + int r; + + r = strcmp (aa_service_name (aa_service (serv1->si)), + aa_service_name (aa_service (serv2->si))); + return (sort_order == SORT_ASC) ? r : -r; +} + +static int +cmp_serv_stamp (const void *_serv1, const void *_serv2) +{ + const struct serv *serv1 = _serv1; + const struct serv *serv2 = _serv2; + int r; + + if (!serv1->is_s6 && aa_service (serv1->si)->st.event == AA_EVT_NONE) + r = (!serv2->is_s6 && aa_service (serv2->si)->st.event == AA_EVT_NONE) ? 0 : -1; + else if (!serv2->is_s6 && aa_service (serv2->si)->st.event == AA_EVT_NONE) + r = 1; + else + r = (tain_less (&serv1->stamp, &serv2->stamp) != 0) ? -1 : 1; + + return (sort_order == SORT_ASC) ? r : -r; +} + static void dieusage (int rc) { @@ -651,6 +689,9 @@ dieusage (int rc) " -a, --all Show status of all services\n" " -f, --filter FILTER Only process services matching FILTER, one of:\n" " oneshot, longrun, up, down, error (see aa-status(1) for more)\n" + " -s, --sort SORT Sort by SORT, one of: none, name, time (default)\n" + " -R, --reverse Reverse sort order\n" + " -N, --name Sort by name\n" " -L, --list Show statuses as one-liners list\n" " -n, --dry-list Only show service names\n" " -h, --help Show this help screen and exit\n" @@ -665,6 +706,7 @@ main (int argc, char * const argv[]) const char *path_repo = "/run/services"; const char *path_list = NULL; struct config cfg = { 0, }; + int (*sort_fn) (const void *, const void *) = cmp_serv_stamp; int all = 0; int i; int r; @@ -678,14 +720,17 @@ main (int argc, char * const argv[]) { "help", no_argument, NULL, 'h' }, { "listdir", required_argument, NULL, 'l' }, { "list", no_argument, NULL, 'L' }, + { "name", no_argument, NULL, 'N' }, { "dry-list", no_argument, NULL, 'n' }, + { "reverse", no_argument, NULL, 'R' }, { "repodir", required_argument, NULL, 'r' }, + { "sort", required_argument, NULL, 's' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, 0, 0 } }; int c; - c = getopt_long (argc, argv, "aDf:hl:Lnr:V", longopts, NULL); + c = getopt_long (argc, argv, "aDf:hl:LNnRr:s:V", longopts, NULL); if (c == -1) break; switch (c) @@ -715,15 +760,37 @@ main (int argc, char * const argv[]) cfg.mode = MODE_LIST; break; + case 'N': + sort_fn = cmp_serv_name; + break; + case 'n': cfg.mode = MODE_DRY_LIST; break; + case 'R': + sort_order = SORT_DESC; + break; + case 'r': unslash (optarg); path_repo = optarg; break; + case 's': + if (str_equal (optarg, "none")) + sort_fn = NULL; + else if (str_equal (optarg, "name")) + sort_fn = cmp_serv_name; + else if (str_equal (optarg, "time")) + sort_fn = cmp_serv_stamp; + else + { + errno = EINVAL; + aa_strerr_diefu3sys (1, "set sort order '", optarg, "'"); + } + break; + case 'V': aa_die_version (); @@ -790,6 +857,10 @@ main (int argc, char * const argv[]) else load_service (argv[i], &cfg); + if (sort_fn) + qsort (genalloc_s(struct serv, &ga_serv), genalloc_len (struct serv, &ga_serv), + sizeof (struct serv), sort_fn); + for (i = 0; i < genalloc_len (struct serv, &ga_serv); ++i) status_service (&genalloc_s (struct serv, &ga_serv)[i], &cfg);