Welcome to little lamb

Code » anopa » commit 9eaeb0a

start: Add --dry-list

author Olivier Brunel
2015-07-17 16:39:09 UTC
committer Olivier Brunel
2015-07-21 12:35:50 UTC
parent 5aa91915f09afd405008a9bf1baf3c40da24a82d

start: Add --dry-list

doc/aa-start.pod +5 -1
src/anopa/aa-start.c +25 -14
src/anopa/start-stop.c +31 -10
src/include/anopa/service.h +4 -3
src/libanopa/exec_longrun.c +4 -4
src/libanopa/exec_oneshot.c +1 -1
src/libanopa/service.c +27 -17
src/libanopa/service_start.c +15 -11

diff --git a/doc/aa-start.pod b/doc/aa-start.pod
index a053745..639b163 100644
--- a/doc/aa-start.pod
+++ b/doc/aa-start.pod
@@ -5,7 +5,7 @@ aa-start - Start services
 =head1 SYNOPSIS
 
 B<aa-start> [B<-D>] [B<-r> I<repodir>] [B<-l> I<listdir>] [B<-W>]
-[B<-t> I<timeout>] [I<service...>]
+[B<-t> I<timeout>] [B<-n>] [I<service...>]
 
 =head1 OPTIONS
 
@@ -30,6 +30,10 @@ than once the last one will be used.
 If I<dir> doesn't start with a slash or dot, it will be prefixed with
 I</etc/anopa/listdirs/>
 
+=item B<-n, --dry-list>
+
+Only print the name of the services, but do not start anything.
+
 =item B<-r, --repodir> I<dir>
 
 Use I<dir> as repository directory. This is where servicedirs will be looked
diff --git a/src/anopa/aa-start.c b/src/anopa/aa-start.c
index 3ebb5ef..9df069f 100644
--- a/src/anopa/aa-start.c
+++ b/src/anopa/aa-start.c
@@ -65,6 +65,7 @@ static genalloc ga_depend = GENALLOC_ZERO;
 static genalloc ga_skipped = GENALLOC_ZERO;
 static genalloc ga_unknown = GENALLOC_ZERO;
 static genalloc ga_io = GENALLOC_ZERO;
+static aa_mode mode = AA_MODE_START;
 static int no_wants = 0;
 static int rc = 0;
 
@@ -154,7 +155,8 @@ add_service (const char *name)
         }
         else if (r == -ERR_ALREADY_UP)
         {
-            put_title (1, name, errmsg[-r], 1);
+            if (!(mode & AA_MODE_IS_DRY))
+                put_title (1, name, errmsg[-r], 1);
             ++nb_already;
             r = 0;
         }
@@ -216,6 +218,7 @@ dieusage (int rc)
             " -l, --listdir DIR             Use DIR to list services to start\n"
             " -W, --no-wants                Don't auto-start services from 'wants'\n"
             " -t, --timeout SECS            Use SECS seconds as default timeout\n"
+            " -n, --dry-list                Only show service names (don't start anything)\n"
             " -h, --help                    Show this help screen and exit\n"
             " -V, --version                 Show version information and exit\n"
             );
@@ -243,6 +246,7 @@ main (int argc, char * const argv[])
             { "double-output",      no_argument,        NULL,   'D' },
             { "help",               no_argument,        NULL,   'h' },
             { "listdir",            required_argument,  NULL,   'l' },
+            { "dry-list",           no_argument,        NULL,   'n' },
             { "repodir",            required_argument,  NULL,   'r' },
             { "timeout",            required_argument,  NULL,   't' },
             { "version",            no_argument,        NULL,   'V' },
@@ -251,7 +255,7 @@ main (int argc, char * const argv[])
         };
         int c;
 
-        c = getopt_long (argc, argv, "Dhl:r:t:VW", longopts, NULL);
+        c = getopt_long (argc, argv, "Dhl:nr:t:VW", longopts, NULL);
         if (c == -1)
             break;
         switch (c)
@@ -268,6 +272,10 @@ main (int argc, char * const argv[])
                 path_list = optarg;
                 break;
 
+            case 'n':
+                mode |= AA_MODE_IS_DRY;
+                break;
+
             case 'r':
                 unslash (optarg);
                 path_repo = optarg;
@@ -323,18 +331,21 @@ main (int argc, char * const argv[])
     for (i = 0; i < argc; ++i)
         add_service (argv[i]);
 
-    mainloop (AA_MODE_START, scan_cb);
-
-    aa_bs_noflush (AA_OUT, "\n");
-    put_title (1, PROG, "Completed.", 1);
-    aa_show_stat_nb (nb_already, "Already up", ANSI_HIGHLIGHT_GREEN_ON);
-    aa_show_stat_nb (nb_done, "Started", ANSI_HIGHLIGHT_GREEN_ON);
-    show_stat_service_names (&ga_timedout, "Timed out", ANSI_HIGHLIGHT_RED_ON);
-    show_stat_service_names (&ga_failed, "Failed", ANSI_HIGHLIGHT_RED_ON);
-    show_stat_service_names (&ga_depend, "Dependency failed", ANSI_HIGHLIGHT_RED_ON);
-    aa_show_stat_names (aa_names.s, &ga_io, "I/O error", ANSI_HIGHLIGHT_RED_ON);
-    aa_show_stat_names (aa_names.s, &ga_unknown, "Unknown", ANSI_HIGHLIGHT_RED_ON);
-    aa_show_stat_names (aa_names.s, &ga_skipped, "Skipped", ANSI_HIGHLIGHT_YELLOW_ON);
+    mainloop (mode, scan_cb);
+
+    if (!(mode & AA_MODE_IS_DRY))
+    {
+        aa_bs_noflush (AA_OUT, "\n");
+        put_title (1, PROG, "Completed.", 1);
+        aa_show_stat_nb (nb_already, "Already up", ANSI_HIGHLIGHT_GREEN_ON);
+        aa_show_stat_nb (nb_done, "Started", ANSI_HIGHLIGHT_GREEN_ON);
+        show_stat_service_names (&ga_timedout, "Timed out", ANSI_HIGHLIGHT_RED_ON);
+        show_stat_service_names (&ga_failed, "Failed", ANSI_HIGHLIGHT_RED_ON);
+        show_stat_service_names (&ga_depend, "Dependency failed", ANSI_HIGHLIGHT_RED_ON);
+        aa_show_stat_names (aa_names.s, &ga_io, "I/O error", ANSI_HIGHLIGHT_RED_ON);
+        aa_show_stat_names (aa_names.s, &ga_unknown, "Unknown", ANSI_HIGHLIGHT_RED_ON);
+        aa_show_stat_names (aa_names.s, &ga_skipped, "Skipped", ANSI_HIGHLIGHT_YELLOW_ON);
+    }
 
     genalloc_free (int, &ga_timedout);
     genalloc_free (int, &ga_failed);
diff --git a/src/anopa/start-stop.c b/src/anopa/start-stop.c
index ada245b..6d01cd1 100644
--- a/src/anopa/start-stop.c
+++ b/src/anopa/start-stop.c
@@ -810,7 +810,7 @@ handle_longrun (aa_mode mode, uint16 id, char event)
     }
 
     si = list_get (&aa_main_list, i);
-    if (mode == AA_MODE_START && aa_service (si)->gets_ready)
+    if ((mode & AA_MODE_START) && aa_service (si)->gets_ready)
     {
         if (event == 'u' || event == 'd')
         {
@@ -828,7 +828,7 @@ handle_longrun (aa_mode mode, uint16 id, char event)
 
     aa_service (si)->ft_id = 0;
     put_title (1, aa_service_name (aa_service (si)),
-            (mode == AA_MODE_START) ?
+            (mode & AA_MODE_START) ?
             ((aa_service (si)->gets_ready) ? "Ready" : "Started")
             : "Stopped", 1);
     ++nb_done;
@@ -884,7 +884,7 @@ handle_signals (aa_mode mode)
                 {
                     for (;;)
                     {
-                        int rr = handle_oneshot (mode == AA_MODE_START);
+                        int rr = handle_oneshot (mode & AA_MODE_START);
                         if (rr > 0)
                             r += rr;
                         else
@@ -964,10 +964,11 @@ exec_cb (int si, aa_evt evt, pid_t pid)
         /* ugly hack thing; see aa_exec_service() */
         case 0:
             clear_draw ();
-            aa_bs_noflush (AA_OUT,
-                    (pid == AA_MODE_START) ? "Starting " : "Stopping ");
+            if (!(pid & AA_MODE_IS_DRY))
+                aa_bs_noflush (AA_OUT,
+                        (pid & AA_MODE_START) ? "Starting " : "Stopping ");
             aa_bs_noflush (AA_OUT, aa_service_name (aa_service (si)));
-            aa_bs_flush (AA_OUT, "...\n");
+            aa_bs_flush (AA_OUT, (pid & AA_MODE_IS_DRY) ? "\n" : "...\n");
             break;
 
         case AA_EVT_STARTING:
@@ -1076,7 +1077,7 @@ process_timeouts (aa_mode mode, aa_scan_cb scan_cb)
                 if (aa_service (si)->fd_progress > 0)
                     close_fd_for (aa_service (si)->fd_progress, si);
 
-                svst->event = (mode == AA_MODE_START) ? AA_EVT_STARTING_FAILED: AA_EVT_STOPPING_FAILED;
+                svst->event = (mode & AA_MODE_START) ? AA_EVT_STARTING_FAILED: AA_EVT_STOPPING_FAILED;
                 svst->code = ERR_TIMEDOUT;
                 tain_copynow (&svst->stamp);
                 aa_service_status_set_msg (svst, "");
@@ -1085,7 +1086,7 @@ process_timeouts (aa_mode mode, aa_scan_cb scan_cb)
 
                 put_err_service (aa_service_name (aa_service (si)), ERR_TIMEDOUT, 1);
                 genalloc_append (int, &ga_timedout, &si);
-                if (mode == AA_MODE_START)
+                if (mode & AA_MODE_START)
                     check_essential (si);
 
                 remove_from_list (&aa_main_list, si);
@@ -1139,7 +1140,7 @@ process_timeouts (aa_mode mode, aa_scan_cb scan_cb)
                     aa_service (si)->ft_id = 0;
                     --nb_wait_longrun;
 
-                    svst->event = (mode == AA_MODE_START) ? AA_EVT_STARTING_FAILED: AA_EVT_STOPPING_FAILED;
+                    svst->event = (mode & AA_MODE_START) ? AA_EVT_STARTING_FAILED: AA_EVT_STOPPING_FAILED;
                     svst->code = ERR_TIMEDOUT;
                     tain_copynow (&svst->stamp);
                     aa_service_status_set_msg (svst, "");
@@ -1148,7 +1149,7 @@ process_timeouts (aa_mode mode, aa_scan_cb scan_cb)
 
                     put_err_service (aa_service_name (aa_service (si)), ERR_TIMEDOUT, 1);
                     genalloc_append (int, &ga_timedout, &si);
-                    if (mode == AA_MODE_START)
+                    if (mode & AA_MODE_START)
                         check_essential (si);
 
                     remove_from_list (&aa_main_list, si);
@@ -1223,6 +1224,26 @@ mainloop (aa_mode mode, aa_scan_cb scan_cb)
         int ms1, ms2;
         tain_t tms;
 
+        if (mode & AA_MODE_IS_DRY)
+        {
+            /* in DRY mode, anything w/out after-s should have been "started"
+             * already, so we just remove them... */
+            for (i = 0; i < genalloc_len (int, &aa_main_list); )
+            {
+                int si;
+
+                si = list_get (&aa_main_list, i);
+                if (genalloc_len (int, &aa_service (si)->after) == 0)
+                    remove_from_list (&aa_main_list, si);
+                else
+                    ++i;
+            }
+
+            /* and we can scan again, to keep processing until we're done */
+            aa_scan_mainlist (scan_cb, mode);
+            continue;
+        }
+
         ms1 = process_timeouts (mode, scan_cb);
         ms2 = refresh_draw ();
         tain_from_millisecs (&tms, (ms1 < 0 || ms2 < ms1) ? ms2 : ms1);
diff --git a/src/include/anopa/service.h b/src/include/anopa/service.h
index bb2e886..f14a640 100644
--- a/src/include/anopa/service.h
+++ b/src/include/anopa/service.h
@@ -53,9 +53,10 @@ typedef enum
 
 typedef enum
 {
-    AA_MODE_START = 0,
-    AA_MODE_STOP,
-    AA_MODE_STOP_ALL
+    AA_MODE_START       = (1 << 0),
+    AA_MODE_STOP        = (1 << 1),
+    AA_MODE_STOP_ALL    = (1 << 2),
+    AA_MODE_IS_DRY      = (1 << 3)
 } aa_mode;
 
 typedef enum
diff --git a/src/libanopa/exec_longrun.c b/src/libanopa/exec_longrun.c
index ebc17aa..94e8b77 100644
--- a/src/libanopa/exec_longrun.c
+++ b/src/libanopa/exec_longrun.c
@@ -40,7 +40,7 @@ _exec_longrun (int si, aa_mode mode)
     int l_sn = strlen (aa_service_name (s));
     char fifodir[l_sn + 1 + sizeof (S6_SUPERVISE_EVENTDIR)];
     tain_t deadline;
-    int is_start = (mode == AA_MODE_START) ? 1 : 0;
+    int is_start = (mode & AA_MODE_START) ? 1 : 0;
     char *event = (is_start) ? "u" : "d";
     int already = 0;
 
@@ -117,7 +117,7 @@ _exec_longrun (int si, aa_mode mode)
         }
     }
 
-    if (mode == AA_MODE_STOP_ALL)
+    if (mode & AA_MODE_STOP_ALL)
     {
         char dir[l_sn + 5 + sizeof (S6_SUPERVISE_CTLDIR) + 8];
 
@@ -136,8 +136,8 @@ _exec_longrun (int si, aa_mode mode)
         byte_copy (dir, l_sn, aa_service_name (s));
         byte_copy (dir + l_sn, 9 + sizeof (S6_SUPERVISE_CTLDIR), "/" S6_SUPERVISE_CTLDIR "/control");
 
-        r = s6_svc_write (dir, (mode == AA_MODE_STOP_ALL) ? "dx" : event,
-                (mode == AA_MODE_STOP_ALL) ? 2 : 1);
+        r = s6_svc_write (dir, (mode & AA_MODE_STOP_ALL) ? "dx" : event,
+                (mode & AA_MODE_STOP_ALL) ? 2 : 1);
         if (r <= 0 && !already)
         {
             tain_addsec_g (&deadline, 1);
diff --git a/src/libanopa/exec_oneshot.c b/src/libanopa/exec_oneshot.c
index 50d76d4..9c30b4f 100644
--- a/src/libanopa/exec_oneshot.c
+++ b/src/libanopa/exec_oneshot.c
@@ -41,7 +41,7 @@ int
 _exec_oneshot (int si, aa_mode mode)
 {
     aa_service *s = aa_service (si);
-    int is_start = (mode == AA_MODE_START) ? 1 : 0;
+    int is_start = (mode & AA_MODE_START) ? 1 : 0;
     char * const filename = (is_start) ? AA_START_FILENAME : AA_STOP_FILENAME;
     int l_fn = sizeof ((is_start) ? AA_START_FILENAME : AA_STOP_FILENAME);
     int l_sn = strlen (aa_service_name (s));
diff --git a/src/libanopa/service.c b/src/libanopa/service.c
index 507c20e..d0f3a48 100644
--- a/src/libanopa/service.c
+++ b/src/libanopa/service.c
@@ -215,7 +215,7 @@ aa_ensure_service_loaded (int si, aa_mode mode, int no_wants, aa_load_fail_cb lf
                     || svst->event == AA_EVT_STOPPING_FAILED
                     || svst->event == AA_EVT_STOP_FAILED);
 
-        if (mode == AA_MODE_START && is_up)
+        if ((mode & AA_MODE_START) && is_up)
         {
             /* if already good, we "fail" because there's no need to load the
              * service, it's already good. This error will be silently ignored
@@ -225,7 +225,7 @@ aa_ensure_service_loaded (int si, aa_mode mode, int no_wants, aa_load_fail_cb lf
             svst->code = ERR_ALREADY_UP;
             return -ERR_ALREADY_UP;
         }
-        else if ((mode == AA_MODE_STOP || mode == AA_MODE_STOP_ALL) && !is_up)
+        else if ((mode & (AA_MODE_STOP | AA_MODE_STOP_ALL)) && !is_up)
         {
             /* if not up, we "fail" because we can't stop it */
             aa_service (si)->ls = AA_LOAD_FAIL;
@@ -241,7 +241,7 @@ aa_ensure_service_loaded (int si, aa_mode mode, int no_wants, aa_load_fail_cb lf
 
     stralloc_catb (&sa, "/needs", strlen ("/needs") + 1);
     r = aa_scan_dir (&sa, 1,
-            (mode == AA_MODE_START) ? _it_start_needs : _it_stop_after,
+            (mode & AA_MODE_START) ? _it_start_needs : _it_stop_after,
             &it_data);
     /* we can get ERR_IO either from aa_scan_dir() itself, or from the iterator
      * function. But since we haven't checked that the directory (needs) does
@@ -252,7 +252,7 @@ aa_ensure_service_loaded (int si, aa_mode mode, int no_wants, aa_load_fail_cb lf
         goto err;
 
     sa.len -= strlen ("needs") + 1;
-    if (mode == AA_MODE_START && !no_wants)
+    if ((mode & AA_MODE_START) && !no_wants)
     {
         stralloc_catb (&sa, "wants", strlen ("wants") + 1);
         r = aa_scan_dir (&sa, 1, _it_start_wants, &it_data);
@@ -263,7 +263,7 @@ aa_ensure_service_loaded (int si, aa_mode mode, int no_wants, aa_load_fail_cb lf
     }
     stralloc_catb (&sa, "after", strlen ("after") + 1);
     r = aa_scan_dir (&sa, 1,
-            (mode == AA_MODE_START) ? _it_start_after : _it_stop_after,
+            (mode & AA_MODE_START) ? _it_start_after : _it_stop_after,
             &it_data);
     if (r < 0 && (r != -ERR_IO || errno != ENOENT))
         goto err;
@@ -271,7 +271,7 @@ aa_ensure_service_loaded (int si, aa_mode mode, int no_wants, aa_load_fail_cb lf
     sa.len -= strlen ("after") + 1;
     stralloc_catb (&sa, "before", strlen ("before") + 1);
     r = aa_scan_dir (&sa, 1,
-            (mode == AA_MODE_START) ? _it_start_before : _it_stop_before,
+            (mode & AA_MODE_START) ? _it_start_before : _it_stop_before,
             &it_data);
     if (r < 0 && (r != -ERR_IO || errno != ENOENT))
         goto err;
@@ -499,7 +499,8 @@ aa_scan_mainlist (aa_scan_cb scan_cb, aa_mode mode)
                 continue;
             }
 
-            if (service_is_ok (aa_service (sni)))
+            /* if DRY we assume it's ok, since it wasn't really started */
+            if ((mode & AA_MODE_IS_DRY) || service_is_ok (aa_service (sni)))
             {
                 remove_from_list (&s->needs, sni);
                 remove_from_list (&s->after, sni);
@@ -536,9 +537,15 @@ aa_scan_mainlist (aa_scan_cb scan_cb, aa_mode mode)
         }
 
         if (genalloc_len (int, &s->after) == 0
-                && ((mode == AA_MODE_START && s->st.event != AA_EVT_STARTING)
-                    || ((mode == AA_MODE_STOP || mode == AA_MODE_STOP_ALL)
-                        && s->st.event != AA_EVT_STOPPING))
+                && (
+                    /* either we're in DRY mode (i.e. we should start it) */
+                    (mode & AA_MODE_IS_DRY)
+                    ||
+                    /* or make sure it's in the right state */
+                    (((mode & AA_MODE_START) && s->st.event != AA_EVT_STARTING)
+                     || ((mode & (AA_MODE_STOP | AA_MODE_STOP_ALL))
+                         && s->st.event != AA_EVT_STOPPING))
+                    )
                 && aa_exec_service (si, mode) < 0)
             /* failed to exec service, was removed from main_list, so we need to
              * rescan from top */
@@ -551,7 +558,7 @@ aa_scan_mainlist (aa_scan_cb scan_cb, aa_mode mode)
 int
 aa_exec_service (int si, aa_mode mode)
 {
-    int r;
+    int r = 0;
 
     if (_exec_cb)
         /* ugly hack to announce "Starting/Stopping foobar..."; needed because
@@ -559,13 +566,16 @@ aa_exec_service (int si, aa_mode mode)
         _exec_cb (si, 0, (pid_t) mode);
 
     tain_copynow (&aa_service (si)->ts_exec);
-    if (aa_service (si)->st.type == AA_TYPE_ONESHOT)
-        r = _exec_oneshot (si, mode);
-    else
-        r = _exec_longrun (si, mode);
+    if (!(mode & AA_MODE_IS_DRY))
+    {
+        if (aa_service (si)->st.type == AA_TYPE_ONESHOT)
+            r = _exec_oneshot (si, mode);
+        else
+            r = _exec_longrun (si, mode);
 
-    if (r < 0)
-        remove_from_list (&aa_main_list, si);
+        if (r < 0)
+            remove_from_list (&aa_main_list, si);
+    }
 
     return r;
 }
diff --git a/src/libanopa/service_start.c b/src/libanopa/service_start.c
index dd9b411..72bdf04 100644
--- a/src/libanopa/service_start.c
+++ b/src/libanopa/service_start.c
@@ -92,23 +92,27 @@ _it_start_needs (direntry *d, void *data)
     else if (r < 0)
     {
         aa_service *s = aa_service (it_data->si);
-        const char *name = aa_service_name (s);
-        int l_n = strlen (name);
-        int l_em = strlen (errmsg[-r]);
-        char buf[l_n + 2 + l_em + 1];
         int l = genalloc_len (int, &s->needs);
         int i;
 
         for (i = 0; i < l; ++i)
             aa_unmark_service (list_get (&s->needs, i));
 
-        byte_copy (buf, l_n, name);
-        byte_copy (buf + l_n, 2, ": ");
-        byte_copy (buf + l_n + 2, l_em + 1, errmsg[-r]);
-
-        aa_service_status_set_err (&s->st, ERR_DEPEND, buf);
-        if (aa_service_status_write (&s->st, aa_service_name (s)) < 0)
-            strerr_warnwu2sys ("write service status file for ", aa_service_name (s));
+        if (!(it_data->mode & AA_MODE_IS_DRY))
+        {
+            const char *name = aa_service_name (s);
+            int l_n = strlen (name);
+            int l_em = strlen (errmsg[-r]);
+            char buf[l_n + 2 + l_em + 1];
+
+            byte_copy (buf, l_n, name);
+            byte_copy (buf + l_n, 2, ": ");
+            byte_copy (buf + l_n + 2, l_em + 1, errmsg[-r]);
+
+            aa_service_status_set_err (&s->st, ERR_DEPEND, buf);
+            if (aa_service_status_write (&s->st, aa_service_name (s)) < 0)
+                strerr_warnwu2sys ("write service status file for ", aa_service_name (s));
+        }
 
         if (it_data->lf_cb)
             it_data->lf_cb (it_data->si, AA_LOADFAIL_NEEDS, d->d_name, -r);