Welcome to little lamb

Code » anopa » commit a6ffa90

Add aa-service

author Olivier Brunel
2015-03-15 20:08:04 UTC
committer Olivier Brunel
2015-04-04 12:47:36 UTC
parent f96b27131a4a4310c8d6db4caf6be39131f1005a

Add aa-service

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