author | Olivier Brunel
<jjk@jjacky.com> 2015-03-15 20:08:04 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2015-04-04 12:47:36 UTC |
parent | f96b27131a4a4310c8d6db4caf6be39131f1005a |
doc/aa-service.pod | +54 | -0 |
package/modes | +1 | -0 |
package/targets.mak | +2 | -0 |
src/utils/aa-service.c | +217 | -0 |
src/utils/deps-exe/aa-service | +3 | -0 |
diff --git a/doc/aa-service.pod b/doc/aa-service.pod new file mode 100644 index 0000000..88eaec5 --- /dev/null +++ b/doc/aa-service.pod @@ -0,0 +1,54 @@ +=head1 NAME + +aa-service - Helper for execline script to get service name/instance + +=head1 SYNOPSIS + +B<aa-service> [B<-l>] I<PROG...> + +=head1 OPTIONS + +=over + +=item B<-h, --help> + +Show help screen and exit. + +=item B<-l, --log> + +To use for a service logger run script, i.e. when current folder will be +subfolder I<log> of the servicedir. + +=item B<-V, --version> + +Show version information and exit. + +=back + +=head1 DESCRIPTION + +This is a little helper for execline scripts (e.g. a service's I<run> script) +that will perform variable substitution on I<PROG...> for: + +=over + +=item B<SERVICE_NAME> + +Will be the name of the current folder, i.e. full service name (e.g. I<foobar> +or I<bar@foo>) + +=item B<SERVICE> + +Will be the name of the service, without the instance name if any (e.g. +I<foobar> or I<bar>) + +=item B<INSTANCE> + +Will be the instance name of the service if any, else empty string (e.g. empty +string or I<foo>) + +=back + +This can be useful to get the service/instance name dynamicly; e.g. a service +could use I<${INSTANCE}> as argument, and a generic logger could then use +I</var/log/${SERVICE_NAME}> as logdir. diff --git a/package/modes b/package/modes index 2b3c40d..0eee9a1 100644 --- a/package/modes +++ b/package/modes @@ -7,6 +7,7 @@ aa-mount 0755 aa-mvlog 0755 aa-pivot 0755 aa-reboot 0755 +aa-service 0755 aa-shutdown 0755 aa-stage0 0755 aa-stage1 0755 diff --git a/package/targets.mak b/package/targets.mak index ec9efcc..eb86a32 100644 --- a/package/targets.mak +++ b/package/targets.mak @@ -8,6 +8,7 @@ aa-mount \ aa-mvlog \ aa-pivot \ aa-reboot \ +aa-service \ aa-start \ aa-stop \ aa-sync \ @@ -36,6 +37,7 @@ aa-mount.1 \ aa-mvlog.1 \ aa-pivot.1 \ aa-reboot.1 \ +aa-service.1 \ aa-shutdown.1 \ aa-stage0.1 \ aa-stage1.1 \ diff --git a/src/utils/aa-service.c b/src/utils/aa-service.c new file mode 100644 index 0000000..89c29d5 --- /dev/null +++ b/src/utils/aa-service.c @@ -0,0 +1,217 @@ + +#include <unistd.h> +#include <skalibs/djbunix.h> +#include <skalibs/env.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/genalloc.h> +#include <skalibs/stralloc.h> +#include <execline/execline.h> +#include <anopa/common.h> + +typedef struct exlsn_s exlsn_t; +struct exlsn_s +{ + stralloc vars; + stralloc values; + genalloc data; /* array of elsubst */ + stralloc modifs; +}; +#define EXLSN_ZERO { .vars = STRALLOC_ZERO, .values = STRALLOC_ZERO, .data = GENALLOC_ZERO, .modifs = STRALLOC_ZERO } + + +enum +{ + ERR_BAD_KEY = 1, + ERR_ADDVAR, + ERR_DIRNAME, + ERR_NOT_LOG +}; + +static char islog = 0; + +static int +addvar (const char *name, const char *value, exlsn_t *info) +{ + eltransforminfo_t si = ELTRANSFORMINFO_ZERO; + elsubst_t blah; + + blah.var = info->vars.len; + blah.value = info->values.len; + + if (el_vardupl (name, info->vars.s, info->vars.len)) + return -ERR_BAD_KEY; + if (!stralloc_catb (&info->vars, name, str_len (name) + 1)) + return -ERR_ADDVAR; + if (!stralloc_cats (&info->values, value)) + goto err; + + { + register int r; + + r = el_transform (&info->values, blah.value, &si); + if (r < 0) + goto err; + blah.n = r ; + } + + if (!genalloc_append (elsubst_t, &info->data, &blah)) + goto err; + + return 0; + +err: + info->vars.len = blah.var; + info->values.len = blah.value; + return -ERR_ADDVAR; +} + +static int +aa_service (int argc, char const **argv, exlsn_t *info) +{ + stralloc sa = STRALLOC_ZERO; + char *s; + unsigned int len; + int r; + int n; + + if (sagetcwd (&sa) < 0) + return -ERR_DIRNAME; + + n = byte_rchr (sa.s, sa.len, '/'); + if (n == sa.len) + { + r = -ERR_DIRNAME; + goto err; + } + /* current dirname only */ + s = sa.s + n + 1; + + if (islog) + { + if (str_diff (s, "log")) + { + r = -ERR_NOT_LOG; + goto err; + } + + /* i.e. sa.s = "/log" */ + if (n <= 0) + { + r = -ERR_NOT_LOG; + goto err; + } + + /* use parent's dirname instead, i.e. the service we're logger of */ + sa.s[n] = '\0'; + n = byte_rchr (sa.s, n - 1, '/'); + s = sa.s + n + 1; + + if (s > sa.s + sa.len) + { + r = -ERR_DIRNAME; + goto err; + } + } + + r = addvar ("SERVICE_NAME", s, info); + if (r < 0) + goto err; + + len = str_len (s); + n = byte_chr (s, len, '@'); + if (n < len) + s[n] = '\0'; + r = addvar ("SERVICE", s, info); + if (r < 0) + goto err; + + r = addvar ("INSTANCE", (n < len) ? s + n + 1 : "", info); + if (r < 0) + goto err; + +err: + stralloc_free (&sa); + return r; +} + +static void +dieusage (int rc) +{ + aa_die_usage (rc, "[OPTION] PROG...", + " -l, --log Use parent directory as servicedir\n" + ); +} + +int +main (int argc, char const **argv, char const *const *envp) +{ + PROG = "aa_service"; + exlsn_t info = EXLSN_ZERO; + stralloc sa = STRALLOC_ZERO; + stralloc dst = STRALLOC_ZERO; + int r; + + if (argc > 1 && *argv[1] == '-') + { + if (str_equal (argv[1], "-h") || str_equal (argv[1], "--help")) + dieusage (0); + else if (str_equal (argv[1], "-l") || str_equal (argv[1], "--log")) + { + islog = 1; + --argc; + ++argv; + } + else if (str_equal (argv[1], "-V") || str_equal (argv[1], "--version")) + aa_die_version (); + else + dieusage (1); + } + --argc; + ++argv; + + r = aa_service (argc, argv, &info); + if (r < 0) + switch (-r) + { + case ERR_NOT_LOG: + strerr_dief1x (2, "option --log used while not in a subfolder 'log'"); + + case ERR_DIRNAME: + strerr_diefu1x (3, "get current dirname"); + + case ERR_BAD_KEY: + strerr_dief1x (4, "bad substitution key"); + + case ERR_ADDVAR: + strerr_diefu1sys (5, "complete addvar function"); + + default: + strerr_diefu2x (5, "complete addvar function", ": unknown error"); + } + + if (!env_string (&sa, argv, (unsigned int) argc)) + strerr_diefu1sys (5, "env_string"); + + r = el_substitute (&dst, sa.s, sa.len, info.vars.s, info.values.s, + genalloc_s (elsubst_t const, &info.data), + genalloc_len (elsubst_t const, &info.data)); + if (r < 0) + strerr_diefu1sys (5, "el_substitute"); + else if (r == 0) + _exit (0); + + stralloc_free (&sa); + + { + char const *v[r + 1]; + + if (!env_make (v, r, dst.s, dst.len)) + strerr_diefu1sys (5, "env_make"); + v[r] = 0; + pathexec_r (v, envp, env_len (envp), info.modifs.s, info.modifs.len); + } + + strerr_dieexec (6, dst.s); +} diff --git a/src/utils/deps-exe/aa-service b/src/utils/deps-exe/aa-service new file mode 100644 index 0000000..fb41af6 --- /dev/null +++ b/src/utils/deps-exe/aa-service @@ -0,0 +1,3 @@ +${LIBANOPA} +-lexecline +-lskarnet