Page MenuHomeFreeBSD

D9096.id54425.diff
No OneTemporary

D9096.id54425.diff

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

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)

Event Timeline