author | Olivier Brunel
<jjk@jjacky.com> 2015-07-24 17:23:21 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2015-08-07 17:23:26 UTC |
parent | a5844b628f5c2e69ac6568c7abd7618c0600526b |
doc/aa-enable.pod | +32 | -1 |
src/anopa/aa-enable.c | +52 | -17 |
src/include/anopa/enable_service.h | +4 | -3 |
src/libanopa/enable_service.c | +112 | -7 |
diff --git a/doc/aa-enable.pod b/doc/aa-enable.pod index da09956..c32bbb0 100644 --- a/doc/aa-enable.pod +++ b/doc/aa-enable.pod @@ -6,7 +6,7 @@ aa-enable - Enable services, i.e. copy servicedirs to repodir B<aa-enable> [B<-D>] [B<-r> I<REPODIR>] [B<-c> I<CRASH>] [B<-f> I<FINISH>] [B<-k> I<SERVICE>] [B<-S> I<SOURCEDIR>] [B<-s> I<SOURCEDIR>] [B<-l> I<LISTDIR>] -[B<-N>] [B<-W>] [I<SERVICE...>] +[B<-N>] [B<-W>] [B<-u>] [I<SERVICE...>] =head1 OPTIONS @@ -73,6 +73,10 @@ B<--source>. This is useful to unset the defaults. Add I<SOURCEDIR> as new source. Can be specified multiple times; Source directories will be processed in the order they were added. +=item B<-u, --upgrade> + +Upgrade servicedirs instead of creating them. See below for implications. + =item B<-V, --version> Show version information and exit. @@ -198,3 +202,30 @@ destination servicedir, if it exists. - A file I<+foobar> will have its content be appended to I<foobar> in the destination servicedir. + +=head2 Upgrading servicedirs + +You can upgrade servicedirs using the B<--upgrade> option. This is meant to +apply changes (from source directories and/or configuration) into existing +servicedirs. + +When used, B<aa-enable>(1) will behave as usual with the following changes: + +- The repodir (and the contained scandir) must already exist; + +- Each servicedir must already exist as well. Before copying anything, all its + content will be recursively removed except for regular file I<status.anopa>, + regular file I<down>, folder I<supervise> and folder I<event> (and their + content); + +- For longruns, no I<down> file will be created, nor will a symlink be added + into the scandir; + +- If used, options B<--set-finish> and B<--set-crash> are ignored. + +Services auto-added from I<needs> or I<wants> will also be processed differently +that those specified: + +- If servicedir already exists in repodir, nothing is done + +- Else, they are enabled as usual (i.e. as if without the B<--upgrade> option) diff --git a/src/anopa/aa-enable.c b/src/anopa/aa-enable.c index bcd9939..88d4080 100644 --- a/src/anopa/aa-enable.c +++ b/src/anopa/aa-enable.c @@ -103,16 +103,17 @@ enable_service (const char *name, intptr_t from_next) if (!from_next) { - /* skip what's already planned to be done next (added via auto-enable) */ + /* check if it was already added to be done next (via auto-enable), in + * which case we need to remove it. + * We do this instead of simply skipping it and having it done later + * because: + * - if there's a folder here, we want to use it as config folder + * - in upgrade mode, the auto-added are treated differently, so + * anything specified needs to be treated now (even w/out folder) + */ for (i = 0; i < genalloc_len (int, &ga_next); ++i) if (str_equal (cur_name, names.s + list_get (&ga_next, i))) { - /* just a name, we can skip it (and process it later). Saves the - * memmove needed to remove from ga_next */ - if (cur_name == name) - goto done; - /* there's a config folder, so we need to process it right now - * (and remove it from ga_next) */ offset = list_get (&ga_next, i); ga_remove (int, &ga_next, i); goto process; @@ -147,7 +148,6 @@ process: } ++nb_enabled; -done: cur_name = NULL; return 0; } @@ -182,6 +182,7 @@ dieusage (int rc) " -S, --reset-source DIR Reset list of source directories to DIR\n" " -s, --source DIR Add DIR as source directories\n" " -k, --skip-down SERVICE Don't create file 'down' for SERVICE\n" + " -u, --upgrade Upgrade service dirs instead of creating them\n" " -l, --listdir DIR Use DIR to list services to enable\n" " -f, --set-finish TARGET Create s6-svscan symlink finish to TARGET\n" " -c, --set-crash TARGET Create s6-svscan symlink crash to TARGET\n" @@ -222,13 +223,14 @@ main (int argc, char * const argv[]) { "repodir", required_argument, NULL, 'r' }, { "reset-source", required_argument, NULL, 'S' }, { "source", required_argument, NULL, 's' }, + { "upgrade", no_argument, NULL, 'u' }, { "version", no_argument, NULL, 'V' }, { "no-wants", no_argument, NULL, 'W' }, { NULL, 0, 0, 0 } }; int c; - c = getopt_long (argc, argv, "c:Df:hk:l:Nr:S:s:VW", longopts, NULL); + c = getopt_long (argc, argv, "c:Df:hk:l:Nr:S:s:uVW", longopts, NULL); if (c == -1) break; switch (c) @@ -276,6 +278,10 @@ main (int argc, char * const argv[]) strerr_diefu1sys (1, "stralloc_catb"); break; + case 'u': + flags |= AA_FLAG_UPGRADE_SERVICEDIR; + break; + case 'V': aa_die_version (); @@ -295,7 +301,8 @@ main (int argc, char * const argv[]) if (!path_list && argc < 1) dieusage (1); - r = aa_init_repo (path_repo, AA_REPO_CREATE); + r = aa_init_repo (path_repo, + (flags & AA_FLAG_UPGRADE_SERVICEDIR) ? AA_REPO_WRITE : AA_REPO_CREATE); if (r < 0) { if (r == -ERR_IO_REPODIR) @@ -337,7 +344,32 @@ main (int argc, char * const argv[]) i = genalloc_len (int, &ga_next) - 1; offset = list_get (&ga_next, i); genalloc_setlen (int, &ga_next, i); - enable_service (names.s + offset, 1 + offset); + if (!(flags & AA_FLAG_UPGRADE_SERVICEDIR)) + enable_service (names.s + offset, 1 + offset); + else + { + /* upgrade mode: check if it already exists or not. If so, we do + * nothing. If not however, we do the "standard" enabling */ + + if (access (names.s + offset, F_OK) < 0) + { + if (errno != ENOENT) + { + int e = errno; + + aa_put_err (names.s + offset, errmsg[ERR_IO], 1); + aa_bs_noflush (AA_ERR, ": " "unable to check for existing servicedir" ": "); + aa_bs_noflush (AA_ERR, error_str (e)); + aa_end_err (); + } + else + { + flags &= ~AA_FLAG_UPGRADE_SERVICEDIR; + enable_service (names.s + offset, 1 + offset); + flags |= AA_FLAG_UPGRADE_SERVICEDIR; + } + } + } } aa_bs_noflush (AA_OUT, "\n"); @@ -345,12 +377,15 @@ main (int argc, char * const argv[]) aa_show_stat_nb (nb_enabled, "Enabled", ANSI_HIGHLIGHT_GREEN_ON); aa_show_stat_names (names.s, &ga_failed, "Failed", ANSI_HIGHLIGHT_RED_ON); - if ((set_crash || set_finish) && mkdir (SVSCANDIR, S_IRWXU) < 0) - aa_put_err ("Failed to create " SVSCANDIR, error_str (errno), 1); - if (set_crash && symlink (set_crash, SCANDIR_CRASH) < 0) - aa_put_err ("Failed to create symlink " SCANDIR_CRASH, error_str (errno), 1); - if (set_finish && symlink (set_finish, SCANDIR_FINISH) < 0) - aa_put_err ("Failed to create symlink " SCANDIR_FINISH, error_str (errno), 1); + if (!(flags & AA_FLAG_UPGRADE_SERVICEDIR)) + { + if ((set_crash || set_finish) && mkdir (SVSCANDIR, S_IRWXU) < 0) + aa_put_err ("Failed to create " SVSCANDIR, error_str (errno), 1); + if (set_crash && symlink (set_crash, SCANDIR_CRASH) < 0) + aa_put_err ("Failed to create symlink " SCANDIR_CRASH, error_str (errno), 1); + if (set_finish && symlink (set_finish, SCANDIR_FINISH) < 0) + aa_put_err ("Failed to create symlink " SCANDIR_FINISH, error_str (errno), 1); + } genalloc_free (int, &ga_failed); genalloc_free (int, &ga_next); diff --git a/src/include/anopa/enable_service.h b/src/include/anopa/enable_service.h index abd9fc8..b994cf4 100644 --- a/src/include/anopa/enable_service.h +++ b/src/include/anopa/enable_service.h @@ -31,10 +31,11 @@ typedef enum AA_FLAG_AUTO_ENABLE_NEEDS = (1 << 0), AA_FLAG_AUTO_ENABLE_WANTS = (1 << 1), AA_FLAG_SKIP_DOWN = (1 << 2), + AA_FLAG_UPGRADE_SERVICEDIR = (1 << 3), /* private */ - _AA_FLAG_IS_SERVICEDIR = (1 << 3), - _AA_FLAG_IS_CONFIGDIR = (1 << 4), - _AA_FLAG_IS_1OF4 = (1 << 5) + _AA_FLAG_IS_SERVICEDIR = (1 << 4), + _AA_FLAG_IS_CONFIGDIR = (1 << 5), + _AA_FLAG_IS_1OF4 = (1 << 6) } aa_enable_flags; extern stralloc aa_sa_sources; diff --git a/src/libanopa/enable_service.c b/src/libanopa/enable_service.c index 6f2b298..12e50f7 100644 --- a/src/libanopa/enable_service.c +++ b/src/libanopa/enable_service.c @@ -20,6 +20,8 @@ * anopa. If not, see http://www.gnu.org/licenses/ */ +#define _BSD_SOURCE + #include <errno.h> #include <unistd.h> #include <sys/stat.h> @@ -104,6 +106,91 @@ copy_log (const char *name, const char *cfg, mode_t mode, aa_warn_fn warn_fn) return r; } +static int +clear_dir (const char *path, int excludes, aa_warn_fn warn_fn) +{ + DIR *dir; + int salen = satmp.len; + + dir = opendir (path); + if (!dir) + return -ERR_IO; + errno = 0; + for (;;) + { + direntry *d; + int r = 0; + + d = readdir (dir); + if (!d) + break; + if (d->d_name[0] == '.' + && (d->d_name[1] == '\0' || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; + + if (stralloc_cats (&satmp, path) < 0) + goto err; + if (stralloc_catb (&satmp, "/", 1) < 0) + goto err; + if (stralloc_cats (&satmp, d->d_name) < 0) + goto err; + if (!stralloc_0 (&satmp)) + goto err; + + if (d->d_type == DT_UNKNOWN) + { + struct stat st; + + r = stat (satmp.s + salen, &st); + if (r < 0) + goto err; + + if (S_ISREG (st.st_mode)) + d->d_type = DT_REG; + else if (S_ISDIR (st.st_mode)) + d->d_type = DT_DIR; + } + + if (excludes) + { + if (d->d_type == DT_REG + && (str_equal (d->d_name, "status.anopa") + || str_equal (d->d_name, "down"))) + goto skip; + else if (d->d_type == DT_DIR + && (str_equal (d->d_name, "supervise") + || str_equal (d->d_name, "event"))) + goto skip; + } + + if (d->d_type == DT_DIR) + { + r = clear_dir (satmp.s + salen, 0, warn_fn); + if (r == 0) + r = rmdir (satmp.s + salen); + } + else + r = unlink (satmp.s + salen); +err: + if (r < 0) + warn_fn (satmp.s + salen, errno); +skip: + satmp.len = salen; + if (r < 0) + break; + } + if (errno) + { + int e = errno; + dir_close (dir); + errno = e; + return -ERR_IO; + } + dir_close (dir); + + return 0; +} + static int copy_dir (const char *src, const char *dst, @@ -150,7 +237,9 @@ copy_dir (const char *src, l_max = len; if (!stralloc_catb (&satmp, d->d_name, len + 1)) break; - if (depth == 0 && (flags & _AA_FLAG_IS_SERVICEDIR)) + if (depth == 0 && (flags & _AA_FLAG_IS_SERVICEDIR) + /* if UPGRADE we don't need this, so skip those tests */ + && !(flags & AA_FLAG_UPGRADE_SERVICEDIR)) { if (!has.run && str_equal (d->d_name, "run")) has.run = 1; @@ -167,19 +256,35 @@ copy_dir (const char *src, } dir_close (dir); - if (mkdir (dst, S_IRWXU) < 0) + if ((flags & (_AA_FLAG_IS_SERVICEDIR | AA_FLAG_UPGRADE_SERVICEDIR)) + == (_AA_FLAG_IS_SERVICEDIR | AA_FLAG_UPGRADE_SERVICEDIR)) { - if (errno != EEXIST || stat (dst, &st) < 0) + if (stat (dst, &st) < 0) goto err; else if (!S_ISDIR (st.st_mode)) { errno = ENOTDIR; goto err; } - else if (flags & _AA_FLAG_IS_SERVICEDIR) - { - errno = EEXIST; + else if (clear_dir (dst, 1, warn_fn) < 0) goto err; + } + else + { + if (mkdir (dst, S_IRWXU) < 0) + { + if (errno != EEXIST || stat (dst, &st) < 0) + goto err; + else if (!S_ISDIR (st.st_mode)) + { + errno = ENOTDIR; + goto err; + } + else if (flags & _AA_FLAG_IS_SERVICEDIR) + { + errno = EEXIST; + goto err; + } } } @@ -316,7 +421,7 @@ next: i += len + 1; } - if (has.run) + if (has.run && !(flags & AA_FLAG_UPGRADE_SERVICEDIR)) { if (!has.down) {