+/* 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 <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[]) {
+bool asked_for_flag(int argc,
+ char* argv[],
+ const char* short_flag,
+ const char* long_flag) {
/*
- * Check argv for either form of the "help" flag, -h or --help.
+ * Check argv for either form of the flag, e.g. -h or --help.
*/
int arg_index = 1;
for (arg_index = 1; arg_index < argc; arg_index++) {
- if (!strcmp(argv[arg_index], "-h")) {
+ if (!strcmp(argv[arg_index], short_flag)) {
+ return true;
+ }
+ if (!strcmp(argv[arg_index], long_flag)) {
return true;
}
- if (!strcmp(argv[arg_index], "--help")) {
+ }
+
+ return false;
+}
+
+
+bool asked_for_help(int argc, char* argv[]) {
+ return asked_for_flag(argc, argv, "-h", "--help");
+}
+
+bool asked_for_recursive(int argc, char* argv[]) {
+ return asked_for_flag(argc, argv, "-r", "--recursive");
+}
+
+bool is_flag(const char* arg) {
+ /*
+ * Is arg a command-line flag (e.g. --recursive)?
+ */
+ char valid_flags[4][32] = { "-h",
+ "--help",
+ "-r",
+ "--recursive" };
+
+ int flag_index = 0;
+ for (flag_index = 0; flag_index < 4; flag_index++) {
+ if (!strcmp(arg, valid_flags[flag_index])) {
return true;
}
}
}
+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.
+ */
+ 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;
+}
+
+
int main(int argc, char* argv[]) {
/*
* Call reapply_default_acl on each command-line argument.
int result = EXIT_SUCCESS;
+ bool recursive = asked_for_recursive(argc, argv);
+
int arg_index = 1;
for (arg_index = 1; arg_index < argc; arg_index++) {
+ /* Don't bother stripping the flags from argv; just ignore
+ * an argument if it's one of our flags.
+ */
+ if (is_flag(argv[arg_index])) {
+ continue;
+ }
+
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;