]> gitweb.michael.orlitzky.com - apply-default-acl.git/blobdiff - src/reapply_default_acl.c
Use getopt for option parsing.
[apply-default-acl.git] / src / reapply_default_acl.c
index a2b4307475752b061fd5304ffca8a18a6382bc05..c48f828674e4a3e47b8b93f3e6e149e7e46d3b98 100644 (file)
@@ -1,6 +1,11 @@
+/* On Linux, ftw.h needs this special voodoo to work. */
+#define _XOPEN_SOURCE 500
+
 #include <errno.h>
-#include <libgen.h> /* dirname() */
-#include <limits.h> /* PATH_MAX */
+#include <ftw.h>    /* nftw() et al. */
+#include <getopt.h>
+#include <libgen.h> /* dirname()     */
+#include <limits.h> /* PATH_MAX      */
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -415,7 +420,7 @@ int reapply_default_acl(const char* path) {
 
   int ace_result = any_can_execute(path);
   if (ace_result == -1) {
-    perror("reapply_default_acl_ng (any_can_execute)");
+    perror("reapply_default_acl (any_can_execute)");
     return -1;
   }
 
@@ -424,7 +429,7 @@ int reapply_default_acl(const char* path) {
   acl_t defacl = acl_get_file(parent, ACL_TYPE_DEFAULT);
 
   if (defacl == (acl_t)NULL) {
-    perror("reapply_default_acl_ng (acl_get_file)");
+    perror("reapply_default_acl (acl_get_file)");
     return -1;
   }
 
@@ -433,7 +438,7 @@ int reapply_default_acl(const char* path) {
 
   int wipe_result = wipe_acls(path);
   if (wipe_result == -1) {
-    perror("reapply_default_acl_ng (wipe_acls)");
+    perror("reapply_default_acl (wipe_acls)");
     result = -1;
     goto cleanup;
   }
@@ -442,14 +447,14 @@ int reapply_default_acl(const char* path) {
      ACL with this one. */
   acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
   if (acl == (acl_t)NULL) {
-    perror("reapply_default_acl_ng (acl_get_file)");
+    perror("reapply_default_acl (acl_get_file)");
     return -1;
   }
 
   /* If it's a directory, inherit the parent's default. */
   int inherit_result = inherit_default_acl(path, parent);
   if (inherit_result == -1) {
-    perror("reapply_default_acl_ng (inherit_acls)");
+    perror("reapply_default_acl (inherit_acls)");
     result = -1;
     goto cleanup;
   }
@@ -472,7 +477,7 @@ int reapply_default_acl(const char* path) {
     acl_permset_t permset;
     int ps_result = acl_get_permset(entry, &permset);
     if (ps_result == -1) {
-      perror("reapply_default_acl_ng (acl_get_permset)");
+      perror("reapply_default_acl (acl_get_permset)");
       result = -1;
       goto cleanup;
     }
@@ -488,14 +493,14 @@ int reapply_default_acl(const char* path) {
           masked, we have to do it manually. */
        int d_result = acl_delete_perm(permset, ACL_EXECUTE);
        if (d_result == -1) {
-         perror("reapply_default_acl_ng (acl_delete_perm)");
+         perror("reapply_default_acl (acl_delete_perm)");
          result = -1;
          goto cleanup;
        }
 
        int sp_result = acl_set_permset(entry, permset);
        if (sp_result == -1) {
-         perror("reapply_default_acl_ng (acl_set_permset)");
+         perror("reapply_default_acl (acl_set_permset)");
          result = -1;
          goto cleanup;
        }
@@ -505,7 +510,7 @@ int reapply_default_acl(const char* path) {
     /* Finally, add the permset to the access ACL. */
     int set_result = acl_set_entry(&acl, entry);
     if (set_result == -1) {
-      perror("reapply_default_acl_ng (acl_set_entry)");
+      perror("reapply_default_acl (acl_set_entry)");
       result = -1;
       goto cleanup;
     }
@@ -516,14 +521,14 @@ int reapply_default_acl(const char* path) {
   /* Catches the first acl_get_entry as well as the ones at the end of
      the loop. */
   if (ge_result == -1) {
-    perror("reapply_default_acl_ng (acl_get_entry)");
+    perror("reapply_default_acl (acl_get_entry)");
     result = -1;
     goto cleanup;
   }
 
   int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl);
   if (sf_result == -1) {
-    perror("reapply_default_acl_ng (acl_set_file)");
+    perror("reapply_default_acl (acl_set_file)");
     result = -1;
     goto cleanup;
   }
@@ -540,22 +545,63 @@ void usage(char* program_name) {
    */
   printf("Reapply any applicable default ACLs to the given files or "
         "directories.\n\n");
-  printf("Usage: %s <target1> [<target2> [ <target3>...]]\n", program_name);
+  printf("Usage: %s [flags] <target1> [<target2> [ <target3>...]]\n\n",
+        program_name);
+  printf("Flags:\n");
+  printf(" -h, --help         Print this help message\n");
+  printf(" -r, --recursive    Act on any given directories recursively\n");
 }
 
 
-bool asked_for_help(int argc, char* argv[]) {
-  /*
-   * Check argv for either form of the "help" flag, -h or --help.
+int reapply_default_acl_nftw(const char *target,
+                            const struct stat *s,
+                            int info,
+                            struct FTW *ftw) {
+  /* A wrapper around the reapply_default_acl() function for use with
+   * nftw(). We need to adjust the return value so that nftw() doesn't
+   * think we've failed.
    */
-  int arg_index = 1;
-  for (arg_index = 1; arg_index < argc; arg_index++) {
-    if (!strcmp(argv[arg_index], "-h")) {
-      return true;
-    }
-    if (!strcmp(argv[arg_index], "--help")) {
-      return true;
-    }
+  bool reapp_result = reapply_default_acl(target);
+  if (reapp_result) {
+    return 0;
+  }
+  else {
+    return 1;
+  }
+}
+
+
+bool reapply_default_acl_recursive(const char *target) {
+  /* Attempt to reapply default ACLs recursively. If target is a
+   * directory, we recurse through its entries. If not, we just
+   * reapply the default ACL to target.
+   *
+   * We ignore symlinks for consistency with chmod -r.
+   *
+   */
+  if (!is_directory(target)) {
+    return reapply_default_acl(target);
+  }
+
+  int max_levels = 256;
+  int flags = FTW_PHYS; /* Don't follow links. */
+
+  int nftw_result = nftw(target,
+                        reapply_default_acl_nftw,
+                        max_levels,
+                        flags);
+
+  if (nftw_result == 0) {
+    /* Success */
+    return true;
+  }
+
+  /* nftw will return -1 on error, or if the supplied function
+   * (reapply_default_acl_nftw) returns a non-zero result, nftw will
+   * return that.
+   */
+  if (nftw_result == -1) {
+    perror("reapply_default_acl_recursive (nftw)");
   }
 
   return false;
@@ -571,17 +617,46 @@ int main(int argc, char* argv[]) {
     return EXIT_FAILURE;
   }
 
-  if (asked_for_help(argc, argv)) {
-    usage(argv[0]);
-    return EXIT_SUCCESS;
+
+  bool recursive = false;
+
+  struct option long_options[] = {
+    /* These options set a flag. */
+    {"help",      no_argument, NULL, 'h'},
+    {"recursive", no_argument, NULL, 'r'},
+    {NULL,        0,           NULL, 0}
+  };
+
+  int opt = 0;
+
+  while ((opt = getopt_long(argc, argv, "hr", long_options, NULL)) != -1) {
+    switch (opt) {
+    case 'h':
+      usage(argv[0]);
+      return EXIT_SUCCESS;
+    case 'r':
+      recursive = true;
+      break;
+    default:
+      usage(argv[0]);
+      return EXIT_FAILURE;
+    }
   }
 
   int result = EXIT_SUCCESS;
 
   int arg_index = 1;
-  for (arg_index = 1; arg_index < argc; arg_index++) {
+  for (arg_index = optind; arg_index < argc; arg_index++) {
     const char* target = argv[arg_index];
-    bool reapp_result = reapply_default_acl(target);
+    bool reapp_result = false;
+
+    if (recursive) {
+      reapp_result = reapply_default_acl_recursive(target);
+    }
+    else {
+      /* It's either normal file, or we're not operating recursively. */
+      reapp_result = reapply_default_acl(target);
+    }
 
     if (!reapp_result) {
       result = EXIT_FAILURE;