+/* 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>
*/
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;
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;