Extend toolbox with SE Android support.

Add -Z option to ls and ps for displaying security contexts.
Modify id to display security context.
Add new SELinux commands: chcon, getenforce, getsebool, load_policy, restorecon, runcon, setenforce, setsebool.

Change-Id: Ia20941be4a6cd706fe392fed6e38a37d880ec5f1
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
new file mode 100644
index 0000000..5ef0ef1
--- /dev/null
+++ b/toolbox/restorecon.c
@@ -0,0 +1,141 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+
+#define FCPATH "/file_contexts"
+
+static struct selabel_handle *sehandle;
+static const char *progname;
+static int nochange;
+static int verbose;
+
+static void usage(void)
+{
+    fprintf(stderr, "usage:  %s [-f file_contexts] [-nrRv] pathname...\n", progname);
+    exit(1);
+}
+
+static int restore(const char *pathname, const struct stat *sb)
+{
+    char *oldcontext, *newcontext;
+
+    if (lgetfilecon(pathname, &oldcontext) < 0) {
+        fprintf(stderr, "Could not get context of %s:  %s\n",
+                pathname, strerror(errno));
+        return -1;
+    }
+    if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) {
+        fprintf(stderr, "Could not lookup context for %s:  %s\n", pathname,
+                strerror(errno));
+        return -1;
+    }
+    if (strcmp(newcontext, "<<none>>") &&
+        strcmp(oldcontext, newcontext)) {
+        if (verbose)
+            printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext);
+        if (!nochange) {
+            if (lsetfilecon(pathname, newcontext) < 0) {
+                fprintf(stderr, "Could not label %s with %s:  %s\n",
+                        pathname, newcontext, strerror(errno));
+                return -1;
+            }
+        }
+    }
+    freecon(oldcontext);
+    freecon(newcontext);
+    return 0;
+}
+
+int restorecon_main(int argc, char **argv)
+{
+    struct selinux_opt seopts[] = {
+        { SELABEL_OPT_PATH, FCPATH }
+    };
+    int ch, recurse = 0, ftsflags = FTS_PHYSICAL;
+
+    progname = argv[0];
+
+    do {
+        ch = getopt(argc, argv, "f:nrRv");
+        if (ch == EOF)
+            break;
+        switch (ch) {
+        case 'f':
+            seopts[0].value = optarg;
+            break;
+        case 'n':
+            nochange = 1;
+            break;
+        case 'r':
+        case 'R':
+            recurse = 1;
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        default:
+            usage();
+        }
+    } while (1);
+
+    argc -= optind;
+    argv += optind;
+    if (!argc)
+        usage();
+
+    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+    if (!sehandle) {
+        fprintf(stderr, "Could not load file contexts from %s:  %s\n", seopts[0].value,
+                strerror(errno));
+        return -1;
+    }
+
+    if (recurse) {
+        FTS *fts;
+        FTSENT *ftsent;
+        fts = fts_open(argv, ftsflags, NULL);
+        if (!fts) {
+            fprintf(stderr, "Could not traverse filesystems (first was %s):  %s\n",
+                    argv[0], strerror(errno));
+            return -1;
+        }
+        while ((ftsent = fts_read(fts))) {
+            switch (ftsent->fts_info) {
+            case FTS_DP:
+                break;
+            case FTS_DNR:
+            case FTS_ERR:
+            case FTS_NS:
+                fprintf(stderr, "Could not access %s:  %s\n", ftsent->fts_path,
+                        strerror(errno));
+                fts_set(fts, ftsent, FTS_SKIP);
+                break;
+            default:
+                if (restore(ftsent->fts_path, ftsent->fts_statp) < 0)
+                    fts_set(fts, ftsent, FTS_SKIP);
+                break;
+            }
+        }
+    } else {
+        int i, rc;
+        struct stat sb;
+
+        for (i = 0; i < argc; i++) {
+            rc = lstat(argv[i], &sb);
+            if (rc < 0) {
+                fprintf(stderr, "Could not stat %s:  %s\n", argv[i],
+                        strerror(errno));
+                continue;
+            }
+            restore(argv[i], &sb);
+        }
+    }
+
+    return 0;
+}