]> 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 7d638993a91a11b936d8e7946405e469586b4003..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>
@@ -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;