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