chsmack: add recursive option
authorJosé Bollo <jose.bollo@iot.bzh>
Thu, 7 Jan 2016 16:41:21 +0000 (17:41 +0100)
committerJosé Bollo <jose.bollo@iot.bzh>
Mon, 4 Apr 2016 09:53:24 +0000 (11:53 +0200)
The option if set will enter the directories
and apply the settings of properties or just
list properties of files.

The symbolic links will not be followed except
if present in the command line.

Signed-off-by: José Bollo <jose.bollo@iot.bzh>
doc/chsmack.8
utils/chsmack.c

index 28b64f0..7925fb8 100644 (file)
@@ -24,11 +24,11 @@ chsmack \- Change or list the Smack properties of filesystem objects
 
 .SH SYNOPSIS 
 
-.B chsmack [-L|--dereference] [--] files...
+.B chsmack [-L] [-r] [--] files...
 
-.B chsmack [-L|--dereference] props... [--] files...
+.B chsmack [-L] [-r] props... [--] files...
 
-chsmack (-d|--remove) [-L|--dereference] [props]... [--] files...
+chsmack -d [-L] [-r] [props]... [--] files...
 
 .SH DESCRIPTION
 
@@ -155,6 +155,12 @@ Use this option to remove the smack properties that are not set for files.
 If no property is specified, it means that all the properties will
 be removed.
 
+.TP
+.B -r, --recursive
+
+Use this option to list or modify files in subdirectories.
+It follows symbolic links only if in the command line.
+
 .SH OBSOLETE OPTIONS
 
 .TP
index 2d9e704..3e7522d 100644 (file)
@@ -32,6 +32,8 @@
 #include <getopt.h>
 #include <errno.h>
 #include <libgen.h>
+#include <dirent.h>
+
 #include "config.h"
 
 static const char usage[] =
@@ -39,21 +41,22 @@ static const char usage[] =
        "Options:\n"  
        " -v --version         output version information and exit\n"
        " -h --help            output usage information and exit\n"
-       " -a --access          set/remove "XATTR_NAME_SMACK"\n"
-       " -e --exec            set/remove "XATTR_NAME_SMACKEXEC"\n"
-       " -m --mmap            set/remove "XATTR_NAME_SMACKMMAP"\n"
-       " -t --transmute       set/remove "XATTR_NAME_SMACKTRANSMUTE"\n"
+       " -a --access          set "XATTR_NAME_SMACK"\n"
+       " -e --exec            set "XATTR_NAME_SMACKEXEC"\n"
+       " -m --mmap            set "XATTR_NAME_SMACKMMAP"\n"
+       " -t --transmute       set "XATTR_NAME_SMACKTRANSMUTE"\n"
        " -L --dereference     tell to follow the symbolic links\n"
        " -D --drop            remove unset attributes\n"
        " -A --drop-access     remove "XATTR_NAME_SMACK"\n"
        " -E --drop-exec       remove "XATTR_NAME_SMACKEXEC"\n"
        " -M --drop-mmap       remove "XATTR_NAME_SMACKMMAP"\n"
        " -T --drop-transmute  remove "XATTR_NAME_SMACKTRANSMUTE"\n"
+       " -r --recursive       list or modify also files in subdirectories\n"
        "Obsolete option:\n"
        " -d --remove          tell to remove the attribute\n"
 ;
 
-static const char shortoptions[] = "vha::e::m::tdLDAEMT";
+static const char shortoptions[] = "vha::e::m::tdLDAEMTr";
 static struct option options[] = {
        {"version", no_argument, 0, 'v'},
        {"help", no_argument, 0, 'h'},
@@ -67,6 +70,7 @@ static struct option options[] = {
        {"drop-exec", no_argument, 0, 'E'},
        {"drop-mmap", no_argument, 0, 'M'},
        {"drop-transmute", no_argument, 0, 'T'},
+       {"recursive", no_argument, 0, 'r'},
        {"remove", no_argument, 0, 'd'},
        {NULL, 0, 0, 0}
 };
@@ -89,6 +93,7 @@ static struct labelset exec_set = { unset, NULL }; /* for option "exec" */
 static struct labelset mmap_set = { unset, NULL }; /* for option "mmap" */
 static enum state transmute_flag = unset; /* for option "transmute" */
 static enum state follow_flag = unset; /* for option "dereference" */
+static enum state recursive_flag = unset; /* for option "recursive" */
 
 /* get the option for the given char */
 static struct option *option_by_char(int car)
@@ -125,12 +130,15 @@ static void modify_transmute(const char *path)
        int rc;
        switch (transmute_flag) {
        case positive:
-               rc = follow_flag ?  stat(path, &st) : lstat(path, &st);
+               rc = follow_flag ? stat(path, &st) : lstat(path, &st);
                if (rc < 0)
                        perror(path);
                else if (!S_ISDIR(st.st_mode)) {
-                       fprintf(stderr, "%s: transmute: not a directory\n",
-                               path);
+                       if (!recursive_flag) {
+                               fprintf(stderr,
+                                       "%s: transmute: not a directory\n",
+                                       path);
+                       }
                }
                else {
                        rc = smack_set_label_for_path(path,
@@ -162,6 +170,7 @@ static void print_file(const char *path)
 {
        int rc;
        char *label;
+       int n = 0;
 
        /* Print file path. */
        printf("%s", path);
@@ -172,9 +181,7 @@ static void print_file(const char *path)
        if (rc > 0) {
                printf(" access=\"%s\"", label);
                free(label);
-       }
-       else if (errno != 0) {
-               printf(": %s", strerror(errno));
+               n = 1;
        }
 
        rc = (int)smack_new_label_from_path(path,
@@ -182,6 +189,7 @@ static void print_file(const char *path)
        if (rc > 0) {
                printf(" execute=\"%s\"", label);
                free(label);
+               n = 1;
        }
 
        rc = (int)smack_new_label_from_path(path,
@@ -189,6 +197,7 @@ static void print_file(const char *path)
        if (rc > 0) {
                printf(" mmap=\"%s\"", label);
                free(label);
+               n = 1;
        }
 
        rc = (int)smack_new_label_from_path(path,
@@ -196,9 +205,75 @@ static void print_file(const char *path)
        if (rc > 0) {
                printf(" transmute=\"%s\"", label);
                free(label);
+               n = 1;
        }
 
-       printf("\n");
+       printf(n ? "\n" : ": No smack property found\n");
+}
+
+static void explore(const char *path, void (*fun)(const char*), int follow)
+{
+       struct stat st;
+       int rc;
+       char *file;
+       size_t last, length, l;
+       DIR *dir;
+       struct dirent dent, *pent;
+
+       /* type of the path */
+       rc = (follow ? stat : lstat)(path ? path : ".", &st);
+       if (rc < 0) {
+               perror(path);
+               return;
+       }
+
+       /* no a directory, skip */
+       if (!S_ISDIR(st.st_mode))
+               return;
+
+       /* open the directory */
+       dir = opendir(path ? path : ".");
+       if (dir == NULL) {
+               perror(path);
+               return;
+       }
+
+       /* iterate ove the directory's entries */
+       last = path ? strlen(path) : 0;
+       length = last + 100;
+       file = malloc(length);
+       if (file == NULL) {
+               fprintf(stderr, "error: out of memory.\n");
+               exit(1);
+       }
+       if (last != 0) {
+               memcpy(file, path, last);
+               file[last++] = '/';
+       }
+       for(;;) {
+               rc = readdir_r(dir, &dent, &pent);
+               if (rc != 0 || pent == NULL) {
+                       free(file);
+                       closedir(dir);
+                       return;
+               }
+               l = strlen(dent.d_name);
+               if (l && dent.d_name[0] == '.'
+                       && (l == 1 || l == 2 && dent.d_name[1] == '.'))
+                       continue;
+               if (last + l >= length) {
+                       file = realloc(file, last + l + 20);
+                       if (file == NULL) {
+                               fprintf(stderr, "error: out of memory.\n");
+                               exit(1);
+                       }
+                       length = last + l + 20;
+               }
+               memcpy(file + last, dent.d_name, l + 1);
+               fun(file);
+               if (recursive_flag)
+                       explore(file, fun, 0);
+       }
 }
 
 /* set the state to to */
@@ -276,6 +351,9 @@ int main(int argc, char *argv[])
                        case 'L':
                                set_state(&follow_flag, positive, c, 0);
                                break;
+                       case 'r':
+                               set_state(&recursive_flag, positive, c, 0);
+                               break;
                        case 'v':
                                printf("%s (libsmack) version " PACKAGE_VERSION "\n",
                                       basename(argv[0]));
@@ -367,7 +445,15 @@ int main(int argc, char *argv[])
 
        /* process */
        fun = modify ? modify_file : print_file;
-       for (i = optind; i < argc; i++)
-               fun(argv[i]);
+       if (optind == argc) {
+               explore(NULL, fun, 0);
+       }
+       else {
+               for (i = optind; i < argc; i++) {
+                       fun(argv[i]);
+                       if (recursive_flag)
+                               explore(argv[i], fun, 1);
+               }
+       }
        exit(0);
 }