Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142154332
D9096.id54425.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D9096.id54425.diff
View Options
Index: bin/setfacl/setfacl.1
===================================================================
--- bin/setfacl/setfacl.1
+++ bin/setfacl/setfacl.1
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 23, 2016
+.Dd January 8, 2017
.Dt SETFACL 1
.Os
.Sh NAME
@@ -115,6 +115,9 @@
.It Fl n
Do not recalculate the permissions associated with the ACL
mask entry. This option is not applicable to NFSv4 ACLs.
+.It Fl R
+Recurse into the specified directories.
+NFSv4 inheritance flags that only apply to directories are ignored for files.
.It Fl x Ar entries | position
If
.Ar entries
Index: bin/setfacl/setfacl.c
===================================================================
--- bin/setfacl/setfacl.c
+++ bin/setfacl/setfacl.c
@@ -35,6 +35,7 @@
#include <err.h>
#include <errno.h>
+#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -70,8 +71,15 @@
uint need_mask;
uint have_stdin;
uint n_flag;
+static int h_flag;
+static int R_flag;
+static uint carried_error;
+static acl_type_t acl_type;
static void add_filename(const char *filename);
+static acl_t sanitize_inheritance(const struct stat *sb, acl_t acl);
+static int walk_path(const char *path, const struct stat *sb, int flag,
+ struct FTW *ftwp);
static void usage(void);
static void
@@ -88,11 +96,213 @@
TAILQ_INSERT_TAIL(&filelist, file, next);
}
+static acl_t
+sanitize_inheritance(const struct stat *sb, acl_t acl)
+{
+ acl_t acl_new;
+ acl_entry_t acl_entry;
+ acl_flagset_t acl_flagset;
+ int acl_brand, entry_id;
+
+ acl_get_brand_np(acl, &acl_brand);
+ if (acl_brand != ACL_BRAND_NFS4)
+ return (acl);
+ if (S_ISDIR(sb->st_mode) != 0)
+ return (acl);
+ acl_new = acl_dup(acl);
+ if (acl_new == (acl_t)NULL)
+ return ((acl_t)NULL);
+ entry_id = ACL_FIRST_ENTRY;
+ while (acl_get_entry(acl_new, entry_id, &acl_entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ acl_get_flagset_np(acl_entry, &acl_flagset);
+ if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY)) {
+ acl_delete_entry(acl_new, acl_entry);
+ continue;
+ }
+ acl_delete_flag_np(acl_flagset, ACL_ENTRY_FILE_INHERIT
+ | ACL_ENTRY_DIRECTORY_INHERIT
+ | ACL_ENTRY_NO_PROPAGATE_INHERIT);
+ }
+
+ return (acl_new);
+}
+
+static int
+walk_path(const char *path, const struct stat *sb, int flag,
+ struct FTW *ftwp __unused)
+{
+ acl_t acl, acl_backup;
+ acl_entry_t unused_entry;
+ struct sf_entry *entry;
+ uint local_error;
+ int ret;
+
+ local_error = 0;
+ acl_backup = NULL;
+
+ if (acl_type == ACL_TYPE_DEFAULT && (flag & FTW_D) == 0) {
+ warnx("%s: default ACL may only be set on a directory", path);
+ carried_error++;
+ return (R_flag == 0);
+ }
+
+ if (h_flag)
+ ret = lpathconf(path, _PC_ACL_NFS4);
+ else
+ ret = pathconf(path, _PC_ACL_NFS4);
+ if (ret > 0) {
+ if (acl_type == ACL_TYPE_DEFAULT) {
+ warnx("%s: there are no default entries in NFSv4 ACLs",
+ path);
+ carried_error++;
+ return (R_flag == 0);
+ }
+ acl_type = ACL_TYPE_NFS4;
+ } else if (ret == 0) {
+ if (acl_type == ACL_TYPE_NFS4)
+ acl_type = ACL_TYPE_ACCESS;
+ } else if (ret < 0 && errno != EINVAL) {
+ warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path);
+ }
+
+ if (h_flag)
+ acl = acl_get_link_np(path, acl_type);
+ else
+ acl = acl_get_file(path, acl_type);
+ if (acl == NULL) {
+ if (h_flag)
+ warn("%s: acl_get_link_np() failed", path);
+ else
+ warn("%s: acl_get_file() failed", path);
+ carried_error++;
+ return (R_flag == 0);
+ }
+
+ /* Perform each of the requested operation. */
+ TAILQ_FOREACH(entry, &entrylist, next) {
+ if (local_error)
+ continue;
+ switch(entry->op) {
+ case OP_ADD_ACL:
+ if (R_flag && acl_type == ACL_TYPE_NFS4
+ && (flag & FTW_D) == 0) {
+ acl_backup = acl_dup(entry->acl);
+ entry->acl = sanitize_inheritance(sb,
+ entry->acl);
+ if (entry->acl == (acl_t)NULL) {
+ local_error++;
+ break;
+ }
+ }
+ local_error += add_acl(entry->acl,
+ entry->entry_number, &acl, path);
+ if (R_flag && acl_type == ACL_TYPE_NFS4
+ && (flag & FTW_D) == 0) {
+ acl_free(entry->acl);
+ entry->acl = acl_backup;
+ }
+ break;
+ case OP_MERGE_ACL:
+ if (R_flag && acl_type == ACL_TYPE_NFS4
+ && (flag & FTW_D) == 0) {
+ acl_backup = acl_dup(entry->acl);
+ entry->acl = sanitize_inheritance(sb,
+ entry->acl);
+ }
+ local_error += merge_acl(entry->acl, &acl, path);
+ if (R_flag && acl_type == ACL_TYPE_NFS4
+ && (flag & FTW_D) == 0) {
+ acl_free(entry->acl);
+ entry->acl = acl_backup;
+ }
+ need_mask = 1;
+ break;
+ case OP_REMOVE_EXT:
+ /*
+ * Don't try to call remove_ext() for empty
+ * default ACL.
+ */
+ if (acl_type == ACL_TYPE_DEFAULT &&
+ acl_get_entry(acl, ACL_FIRST_ENTRY,
+ &unused_entry) == 0) {
+ local_error += remove_default(&acl, path);
+ break;
+ }
+ remove_ext(&acl, path);
+ need_mask = 0;
+ break;
+ case OP_REMOVE_DEF:
+ if (acl_type == ACL_TYPE_NFS4) {
+ warnx("%s: there are no default entries in "
+ "NFSv4 ACLs; cannot remove", path);
+ local_error++;
+ break;
+ }
+ if (acl_delete_def_file(path) == -1) {
+ warn("%s: acl_delete_def_file() failed", path);
+ local_error++;
+ }
+ if (acl_type == ACL_TYPE_DEFAULT)
+ local_error += remove_default(&acl, path);
+ need_mask = 0;
+ break;
+ case OP_REMOVE_ACL:
+ local_error += remove_acl(entry->acl, &acl, path);
+ need_mask = 1;
+ break;
+ case OP_REMOVE_BY_NUMBER:
+ local_error += remove_by_number(entry->entry_number,
+ &acl, path);
+ need_mask = 1;
+ break;
+ }
+ }
+
+ /*
+ * Don't try to set an empty default ACL; it will always fail.
+ * Use acl_delete_def_file(3) instead.
+ */
+ if (acl_type == ACL_TYPE_DEFAULT &&
+ acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) {
+ if (acl_delete_def_file(path) == -1) {
+ warn("%s: acl_delete_def_file() failed", path);
+ carried_error++;
+ }
+ return (R_flag == 0);
+ }
+
+ /* Don't bother setting the ACL if there has been an error. */
+ if (local_error) {
+ carried_error++;
+ return (R_flag == 0);
+ }
+
+ if (acl_type != ACL_TYPE_NFS4 && need_mask &&
+ set_acl_mask(&acl, path) == -1) {
+ warnx("%s: failed to set ACL mask", path);
+ carried_error++;
+ } else if (h_flag) {
+ if (acl_set_link_np(path, acl_type, acl) == -1) {
+ carried_error++;
+ warn("%s: acl_set_link_np() failed", path);
+ }
+ } else {
+ if (acl_set_file(path, acl_type, acl) == -1) {
+ carried_error++;
+ warn("%s: acl_set_file() failed", path);
+ }
+ }
+
+ acl_free(acl);
+ return (R_flag == 0);
+}
+
static void
usage(void)
{
- fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] "
+ fprintf(stderr, "usage: setfacl [-bdhknR] [-a position entries] "
"[-m entries] [-M file] [-x entries] [-X file] [file ...]\n");
exit(1);
}
@@ -100,26 +310,22 @@
int
main(int argc, char *argv[])
{
- acl_t acl;
- acl_type_t acl_type;
- acl_entry_t unused_entry;
char filename[PATH_MAX];
- int local_error, carried_error, ch, i, entry_number, ret;
- int h_flag;
+ int ch, i, entry_number;
struct sf_file *file;
struct sf_entry *entry;
const char *fn_dup;
char *end;
- struct stat sb;
acl_type = ACL_TYPE_ACCESS;
- carried_error = local_error = 0;
+ carried_error = 0;
h_flag = have_mask = have_stdin = n_flag = need_mask = 0;
+ R_flag = 0;
TAILQ_INIT(&entrylist);
TAILQ_INIT(&filelist);
- while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1)
+ while ((ch = getopt(argc, argv, "M:RX:a:bdhkm:nx:")) != -1)
switch(ch) {
case 'M':
entry = zmalloc(sizeof(struct sf_entry));
@@ -129,6 +335,9 @@
entry->op = OP_MERGE_ACL;
TAILQ_INSERT_TAIL(&entrylist, entry, next);
break;
+ case 'R':
+ R_flag = 1;
+ break;
case 'X':
entry = zmalloc(sizeof(struct sf_entry));
entry->acl = get_acl_from_file(optarg);
@@ -227,157 +436,12 @@
/* cycle through each file */
TAILQ_FOREACH(file, &filelist, next) {
- local_error = 0;
-
- if (stat(file->filename, &sb) == -1) {
- warn("%s: stat() failed", file->filename);
- carried_error++;
- continue;
- }
-
- if (acl_type == ACL_TYPE_DEFAULT && S_ISDIR(sb.st_mode) == 0) {
- warnx("%s: default ACL may only be set on a directory",
- file->filename);
- carried_error++;
- continue;
- }
-
- if (h_flag)
- ret = lpathconf(file->filename, _PC_ACL_NFS4);
- else
- ret = pathconf(file->filename, _PC_ACL_NFS4);
- if (ret > 0) {
- if (acl_type == ACL_TYPE_DEFAULT) {
- warnx("%s: there are no default entries "
- "in NFSv4 ACLs", file->filename);
- carried_error++;
- continue;
- }
- acl_type = ACL_TYPE_NFS4;
- } else if (ret == 0) {
- if (acl_type == ACL_TYPE_NFS4)
- acl_type = ACL_TYPE_ACCESS;
- } else if (ret < 0 && errno != EINVAL) {
- warn("%s: pathconf(..., _PC_ACL_NFS4) failed",
- file->filename);
- }
-
- if (h_flag)
- acl = acl_get_link_np(file->filename, acl_type);
- else
- acl = acl_get_file(file->filename, acl_type);
- if (acl == NULL) {
- if (h_flag)
- warn("%s: acl_get_link_np() failed",
- file->filename);
- else
- warn("%s: acl_get_file() failed",
- file->filename);
- carried_error++;
- continue;
- }
-
- /* cycle through each option */
- TAILQ_FOREACH(entry, &entrylist, next) {
- if (local_error)
- continue;
-
- switch(entry->op) {
- case OP_ADD_ACL:
- local_error += add_acl(entry->acl,
- entry->entry_number, &acl, file->filename);
- break;
- case OP_MERGE_ACL:
- local_error += merge_acl(entry->acl, &acl,
- file->filename);
- need_mask = 1;
- break;
- case OP_REMOVE_EXT:
- /*
- * Don't try to call remove_ext() for empty
- * default ACL.
- */
- if (acl_type == ACL_TYPE_DEFAULT &&
- acl_get_entry(acl, ACL_FIRST_ENTRY,
- &unused_entry) == 0) {
- local_error += remove_default(&acl,
- file->filename);
- break;
- }
- remove_ext(&acl, file->filename);
- need_mask = 0;
- break;
- case OP_REMOVE_DEF:
- if (acl_type == ACL_TYPE_NFS4) {
- warnx("%s: there are no default entries in NFSv4 ACLs; "
- "cannot remove", file->filename);
- local_error++;
- break;
- }
- if (acl_delete_def_file(file->filename) == -1) {
- warn("%s: acl_delete_def_file() failed",
- file->filename);
- local_error++;
- }
- if (acl_type == ACL_TYPE_DEFAULT)
- local_error += remove_default(&acl,
- file->filename);
- need_mask = 0;
- break;
- case OP_REMOVE_ACL:
- local_error += remove_acl(entry->acl, &acl,
- file->filename);
- need_mask = 1;
- break;
- case OP_REMOVE_BY_NUMBER:
- local_error += remove_by_number(entry->entry_number,
- &acl, file->filename);
- need_mask = 1;
- break;
- }
- }
-
- /*
- * Don't try to set an empty default ACL; it will always fail.
- * Use acl_delete_def_file(3) instead.
- */
- if (acl_type == ACL_TYPE_DEFAULT &&
- acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) {
- if (acl_delete_def_file(file->filename) == -1) {
- warn("%s: acl_delete_def_file() failed",
- file->filename);
- carried_error++;
- }
- continue;
- }
-
- /* don't bother setting the ACL if something is broken */
- if (local_error) {
+ if (nftw(file->filename, walk_path, 5,
+ h_flag ? FTW_PHYS : 0) < 0) {
+ warn("%s: nftw() failed", file->filename);
carried_error++;
continue;
}
-
- if (acl_type != ACL_TYPE_NFS4 && need_mask &&
- set_acl_mask(&acl, file->filename) == -1) {
- warnx("%s: failed to set ACL mask", file->filename);
- carried_error++;
- } else if (h_flag) {
- if (acl_set_link_np(file->filename, acl_type,
- acl) == -1) {
- carried_error++;
- warn("%s: acl_set_link_np() failed",
- file->filename);
- }
- } else {
- if (acl_set_file(file->filename, acl_type,
- acl) == -1) {
- carried_error++;
- warn("%s: acl_set_file() failed",
- file->filename);
- }
- }
-
- acl_free(acl);
}
return (carried_error);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 17, 1:25 PM (12 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27693194
Default Alt Text
D9096.id54425.diff (11 KB)
Attached To
Mode
D9096: Add Recursive Functionality to setfacl(1)
Attached
Detach File
Event Timeline
Log In to Comment