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