Welcome to little lamb

Code » anopa » commit 775b41c

Add incmdline

author Olivier Brunel
2015-02-27 17:43:10 UTC
committer Olivier Brunel
2015-04-04 12:47:35 UTC
parent 3a792d19d71db7f9401c387717fb588d0975d152

Add incmdline

doc/aa-incmdline.pod +51 -0
package/modes +1 -0
package/targets.mak +2 -0
src/utils/aa-incmdline.c +153 -0
src/utils/deps-exe/aa-incmdline +2 -0

diff --git a/doc/aa-incmdline.pod b/doc/aa-incmdline.pod
new file mode 100644
index 0000000..3a730d9
--- /dev/null
+++ b/doc/aa-incmdline.pod
@@ -0,0 +1,51 @@
+=head1 NAME
+
+aa-incmdline - Helper to parse kernel command line
+
+=head1 SYNOPSIS
+
+B<aa-incmdline> [B<-q>] [B<-f> I<FILE>] [B<-r>] [B<-s>] I<NAME>
+
+=head1 OPTIONS
+
+=over
+
+=item B<-f, --file> I<FILE>
+
+Read command line from I<FILE> instead of I</proc/cmdline>
+
+=item B<-h, --help>
+
+Show help screen and exit.
+
+=item B<-q, --quiet>
+
+Do not print value (if any) on stdout
+
+=item B<-r, --required>
+
+Ignore argument (i.e. exit 3) if no value was specified.
+
+=item B<-s, --safe>[=I<C>]
+
+Ignore argument (i.e. exit 3) if it contains I<C> (defaults to I</>).
+
+=item B<-V, --version>
+
+Show version information and exit.
+
+=back
+
+=head1 DESCRIPTION
+
+B<aa-incmdline>(1) is a small helper to parse arguments from the kernel command
+line. It will read I</proc/cmdline> (or I<FILE> specified with B<--file>) and
+look for an argument I<NAME>. If reading the file fails, it exits 2. If no
+I<NAME> was specified, it exits 1.
+
+If there's no such argument on the command line, or B<--safe> was used and the
+argument's value contains I<C>, or there's no value and B<--required> was used,
+it exits 3; Else it exits 0.
+
+If the argument had a value specified it will be printed on stdout unless
+B<--quiet> was used.
diff --git a/package/modes b/package/modes
index e0181ef..5c37527 100644
--- a/package/modes
+++ b/package/modes
@@ -1,6 +1,7 @@
 aa-chroot               0755
 aa-echo                 0755
 aa-enable               0755
+aa-incmdline            0755
 aa-kill                 0755
 aa-mount                0755
 aa-pivot                0755
diff --git a/package/targets.mak b/package/targets.mak
index 4596999..6511818 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -6,6 +6,7 @@ aa-stop
 LIBEXEC_TARGETS := \
 aa-chroot \
 aa-echo \
+aa-incmdline \
 aa-kill \
 aa-mount \
 aa-pivot \
@@ -20,6 +21,7 @@ anopa.1 \
 aa-chroot.1 \
 aa-echo.1 \
 aa-enable.1 \
+aa-incmdline.1 \
 aa-kill.1 \
 aa-mount.1 \
 aa-pivot.1 \
diff --git a/src/utils/aa-incmdline.c b/src/utils/aa-incmdline.c
new file mode 100644
index 0000000..a28d268
--- /dev/null
+++ b/src/utils/aa-incmdline.c
@@ -0,0 +1,153 @@
+
+#include <getopt.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <anopa/common.h>
+
+const char *PROG;
+
+static void
+dieusage (int rc)
+{
+    aa_die_usage (rc, "[OPTION] NAME",
+            " -f, --file FILE               Use FILE instead of /proc/cmdline\n"
+            " -q, --quiet                   Don't write value (if any) to stdout\n"
+            " -s, --safe[=C]                Ignore argument if value contain C (default: '/')\n"
+            " -r, --required                Ignore argument if no value specified\n"
+            " -h, --help                    Show this help screen and exit\n"
+            " -V, --version                 Show version information and exit\n"
+            );
+}
+
+int
+main (int argc, char * const argv[])
+{
+    PROG = "aa-incmdline";
+    stralloc sa = STRALLOC_ZERO;
+    const char *file = "/proc/cmdline";
+    int quiet = 0;
+    int req = 0;
+    char safe = '\0';
+    int len_arg;
+    int start;
+    int i;
+
+    for (;;)
+    {
+        struct option longopts[] = {
+            { "file",               no_argument,        NULL,   'f' },
+            { "help",               no_argument,        NULL,   'h' },
+            { "quiet",              no_argument,        NULL,   'q' },
+            { "required",           no_argument,        NULL,   'r' },
+            { "safe",               optional_argument,  NULL,   's' },
+            { "version",            no_argument,        NULL,   'V' },
+            { NULL, 0, 0, 0 }
+        };
+        int c;
+
+        c = getopt_long (argc, argv, "f:hqrs::V", longopts, NULL);
+        if (c == -1)
+            break;
+        switch (c)
+        {
+            case 'f':
+                file = optarg;
+                break;
+
+            case 'h':
+                dieusage (0);
+
+            case 'q':
+                quiet = 1;
+                break;
+
+            case 'r':
+                req = 1;
+                break;
+
+            case 's':
+                if (!optarg)
+                    safe = '/';
+                else if (!*optarg || optarg[1])
+                    dieusage (1);
+                else
+                    safe = *optarg;
+                break;
+
+            case 'V':
+                aa_die_version ();
+
+            default:
+                dieusage (1);
+        }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 1)
+        dieusage (1);
+
+    if (!openslurpclose (&sa, file))
+            strerr_diefu2sys (2, "read ", file);
+
+    len_arg = strlen (argv[0]);
+    for (start = i = 0; i < sa.len; ++i)
+    {
+        if (sa.s[i] == '=' || sa.s[i] == ' ' || sa.s[i] == '\t'
+                || sa.s[i] == '\n' || sa.s[i] == '\0')
+        {
+            int found = (i - start == len_arg && !str_diffn (sa.s + start, argv[0], len_arg));
+            int len;
+
+            if (sa.s[i] != '=')
+            {
+                if (found)
+                    return (req) ? 3 : 0;
+                start = ++i;
+                goto next;
+            }
+            else if (found && quiet && !safe)
+                return (req) ? 3 : 0;
+
+            start = ++i;
+            if (sa.s[start] != '"')
+                for (len = 0;
+                        start + len < sa.len
+                        && sa.s[start + len] != ' ' && sa.s[start + len] != '\t';
+                        ++len)
+                    ;
+            else
+            {
+                ++start;
+                len = byte_chr (sa.s + start, sa.len - start, '"');
+            }
+
+            if (found)
+            {
+                if (len == sa.len - start)
+                    --len;
+                if (safe && byte_chr (sa.s + start, len, safe) < len)
+                    return 3;
+                if (req && len == 0)
+                    return 3;
+                else if (!quiet)
+                {
+                    buffer_putnoflush (buffer_1small, sa.s + start, len);
+                    buffer_putsflush (buffer_1small, "\n");
+                }
+                return 0;
+            }
+
+            start += len;
+            i = ++start;
+next:
+            while (i < sa.len && (sa.s[i] == ' ' || sa.s[i] == '\t'))
+                start = ++i;
+        }
+    }
+
+    return 3;
+}
diff --git a/src/utils/deps-exe/aa-incmdline b/src/utils/deps-exe/aa-incmdline
new file mode 100644
index 0000000..30987b4
--- /dev/null
+++ b/src/utils/deps-exe/aa-incmdline
@@ -0,0 +1,2 @@
+${LIBANOPA}
+-lskarnet