Welcome to little lamb

Code » anopa » commit 150e465

Add aa-test

author Olivier Brunel
2015-02-21 13:47:50 UTC
committer Olivier Brunel
2015-04-04 12:47:34 UTC
parent 294bb6aa2451a7b4078ceed32068f859fd182113

Add aa-test

doc/aa-test.pod +67 -0
package/modes +1 -0
package/targets.mak +2 -0
src/utils/aa-test.c +174 -0
src/utils/deps-exe/aa-test +2 -0

diff --git a/doc/aa-test.pod b/doc/aa-test.pod
new file mode 100644
index 0000000..a1558ad
--- /dev/null
+++ b/doc/aa-test.pod
@@ -0,0 +1,67 @@
+=head1 NAME
+
+aa-test - Test file types
+
+=head1 SYNOPSIS
+
+B<aa-test> [B<-b> | B<-d> | B<-e> | B<-f> | B<-L> | B<-p> | B<-S> | B<-r> |
+B<-w> | B<-x>] I<FILE>
+
+=head1 OPTIONS
+
+=over
+
+=item B<-b, --block>
+
+Test whether I<FILE> exists and is a block special
+
+=item B<-d, --directory>
+
+Test whether I<FILE> exists and is a directory
+
+=item B<-e, --exists>
+
+Test whether I<FILE> exists
+
+=item B<-f, --file>
+
+Test whether I<FILE> exists and is a regular file
+
+=item B<-h, --help>
+
+Show help screen and exit.
+
+=item B<-L, --symlink>
+
+Test whether I<FILE> exists and is a symlink
+
+=item B<-p, --pipe>
+
+Test whether I<FILE> exists and is a named pipe (FIFO)
+
+=item B<-r, --read>
+
+Test whether I<FILE> exists and read permission is granted
+
+=item B<-S, --socket>
+
+Test whether I<FILE> exists and is a socket
+
+=item B<-V, --version>
+
+Show version information and exit.
+
+=item B<-w, --write>
+
+Test whether I<FILE> exists and write permission is granted
+
+=item B<-x, --execute>
+
+Test whether I<FILE> exists and execute (search) permission is granted
+
+=back
+
+=head1 DESCRIPTION
+
+B<aa-test>(1) is a simple tool to check file types/permissions as specified, and
+return 0 when true, else 1.
diff --git a/package/modes b/package/modes
index a126d1b..a5a2f3c 100644
--- a/package/modes
+++ b/package/modes
@@ -6,4 +6,5 @@ aa-mount                0755
 aa-pivot                0755
 aa-start                0755
 aa-stop                 0755
+aa-test                 0755
 aa-umount               0755
diff --git a/package/targets.mak b/package/targets.mak
index 06f758e..dfb1ecc 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -9,6 +9,7 @@ aa-echo \
 aa-kill \
 aa-mount \
 aa-pivot \
+aa-test \
 aa-umount
 
 DOC_TARGETS := \
@@ -21,6 +22,7 @@ aa-mount.1 \
 aa-pivot.1 \
 aa-start.1 \
 aa-stop.1 \
+aa-test.1 \
 aa-umount.1
 
 ifdef DO_ALLSTATIC
diff --git a/src/utils/aa-test.c b/src/utils/aa-test.c
new file mode 100644
index 0000000..e7b820d
--- /dev/null
+++ b/src/utils/aa-test.c
@@ -0,0 +1,174 @@
+
+#include <getopt.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <skalibs/strerr2.h>
+#include <anopa/common.h>
+
+static int
+is_group_member (gid_t gid)
+{
+    int nb = getgroups (0, NULL);
+    gid_t groups[nb];
+    int i;
+
+    if (gid == getgid () || gid == getegid())
+        return 1;
+
+    if (getgroups (nb, groups) < 0)
+        return 0;
+
+    for (i = 0; i < nb; ++i)
+        if (gid == groups[i])
+            return 1;
+
+    return 0;
+}
+
+static void
+dieusage (int rc)
+{
+    aa_die_usage (rc, "OPTION FILE",
+            " -b, --block                   Test whether FILE is a block special\n"
+            " -d, --directory               Test whether FILE is a directory\n"
+            " -e, --exists                  Test whether FILE exists\n"
+            " -f, --file                    Test whether FILE is a regular file\n"
+            " -L, --symlink                 Test whether FILE is a symbolic link\n"
+            " -p, --pipe                    Test whether FILE is a named pipe\n"
+            " -S, --socket                  Test whether FILE is a socket\n"
+            " -r, --read                    Test for read permission on FILE\n"
+            " -w, --write                   Test for write permission on FILE\n"
+            " -x, --execute                 Test for execute permission on FILE\n"
+            "\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-test";
+    struct stat st;
+    uid_t euid;
+    int mode;
+    char test;
+
+    for (;;)
+    {
+        struct option longopts[] = {
+            { "block",              no_argument,        NULL,   'b' },
+            { "directory",          no_argument,        NULL,   'd' },
+            { "exists",             no_argument,        NULL,   'e' },
+            { "file",               no_argument,        NULL,   'f' },
+            { "help",               no_argument,        NULL,   'h' },
+            { "symlink",            no_argument,        NULL,   'L' },
+            { "pipe",               no_argument,        NULL,   'p' },
+            { "read",               no_argument,        NULL,   'r' },
+            { "socket",             no_argument,        NULL,   'S' },
+            { "version",            no_argument,        NULL,   'V' },
+            { "write",              no_argument,        NULL,   'w' },
+            { "execute",            no_argument,        NULL,   'x' },
+            { NULL, 0, 0, 0 }
+        };
+        int c;
+
+        c = getopt_long (argc, argv, "bdefhLprSVwx", longopts, NULL);
+        if (c == -1)
+            break;
+        switch (c)
+        {
+            case 'b':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'L':
+            case 'p':
+            case 'r':
+            case 'S':
+            case 'w':
+            case 'x':
+                test = c;
+                break;
+
+            case 'h':
+                dieusage (0);
+
+            case 'V':
+                aa_die_version ();
+
+            default:
+                dieusage (1);
+        }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (argc != 1)
+        dieusage (1);
+
+    if (lstat (argv[0], &st) < 0)
+    {
+        if (errno != ENOENT)
+            strerr_diefu2sys (1, "stat ", argv[0]);
+        else
+            return 1;
+    }
+
+    switch (test)
+    {
+        case 'b':
+            return (S_ISBLK (st.st_mode)) ? 0 : 1;
+
+        case 'd':
+            return (S_ISDIR (st.st_mode)) ? 0 : 1;
+
+        case 'e':
+            return 0;
+
+        case 'f':
+            return (S_ISREG (st.st_mode)) ? 0 : 1;
+
+        case 'L':
+            return (S_ISLNK (st.st_mode)) ? 0 : 1;
+
+        case 'p':
+            return (S_ISFIFO (st.st_mode)) ? 0 : 1;
+
+        case 'r':
+            mode = R_OK;
+            break;
+
+        case 'S':
+            return (S_ISSOCK (st.st_mode)) ? 0 : 1;
+
+        case 'w':
+            mode = W_OK;
+            break;
+
+        case 'x':
+            mode = X_OK;
+            break;
+    }
+
+    euid = geteuid ();
+    if (euid == 0)
+    {
+        /* root can read/write any file */
+        if (mode != X_OK)
+            return 0;
+        /* and execute anything any execute permission set */
+        else if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+            return 0;
+        else
+            return 1;
+    }
+
+    if (st.st_uid == euid)
+        mode <<= 6;
+    else if (is_group_member (st.st_gid))
+        mode <<= 3;
+
+    return (st.st_mode & mode) ? 0 : 1;
+}
diff --git a/src/utils/deps-exe/aa-test b/src/utils/deps-exe/aa-test
new file mode 100644
index 0000000..30987b4
--- /dev/null
+++ b/src/utils/deps-exe/aa-test
@@ -0,0 +1,2 @@
+${LIBANOPA}
+-lskarnet