Index: head/bin/setfacl/file.c =================================================================== --- head/bin/setfacl/file.c (revision 333064) +++ head/bin/setfacl/file.c (revision 333065) @@ -1,76 +1,76 @@ /*- * Copyright (c) 2001 Chris D. Faulhaber * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "setfacl.h" /* * read acl text from a file and return the corresponding acl */ acl_t get_acl_from_file(const char *filename) { FILE *file; size_t len; char buf[BUFSIZ+1]; if (filename == NULL) err(1, "(null) filename in get_acl_from_file()"); if (strcmp(filename, "-") == 0) { - if (have_stdin != 0) + if (have_stdin) err(1, "cannot specify more than one stdin"); file = stdin; - have_stdin = 1; + have_stdin = true; } else { file = fopen(filename, "r"); if (file == NULL) err(1, "fopen() %s failed", filename); } len = fread(buf, (size_t)1, sizeof(buf) - 1, file); buf[len] = '\0'; if (ferror(file) != 0) { fclose(file); err(1, "error reading from %s", filename); } else if (feof(file) == 0) { fclose(file); errx(1, "line too long in %s", filename); } fclose(file); return (acl_from_text(buf)); } Index: head/bin/setfacl/mask.c =================================================================== --- head/bin/setfacl/mask.c (revision 333064) +++ head/bin/setfacl/mask.c (revision 333065) @@ -1,114 +1,114 @@ /*- * Copyright (c) 2001-2002 Chris D. Faulhaber * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "setfacl.h" /* set the appropriate mask the given ACL's */ int set_acl_mask(acl_t *prev_acl, const char *filename) { acl_entry_t entry; acl_t acl; acl_tag_t tag; int entry_id; entry = NULL; /* * ... if a mask entry is specified, then the permissions of the mask * entry in the resulting ACL shall be set to the permissions in the * specified ACL mask entry. */ if (have_mask) return (0); acl = acl_dup(*prev_acl); if (acl == NULL) err(1, "%s: acl_dup() failed", filename); - if (n_flag == 0) { + if (!n_flag) { /* * If no mask entry is specified and the -n option is not * specified, then the permissions of the resulting ACL mask * entry shall be set to the union of the permissions * associated with all entries which belong to the file group * class in the resulting ACL */ if (acl_calc_mask(&acl)) { warn("%s: acl_calc_mask() failed", filename); acl_free(acl); return (-1); } } else { /* * If no mask entry is specified and the -n option is * specified, then the permissions of the resulting ACL * mask entry shall remain unchanged ... */ entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (tag == ACL_MASK) { acl_free(acl); return (0); } } /* * If no mask entry is specified, the -n option is specified, * and no ACL mask entry exists in the ACL associated with the * file, then write an error message to standard error and * continue with the next file. */ warnx("%s: warning: no mask entry", filename); acl_free(acl); return (0); } acl_free(*prev_acl); *prev_acl = acl_dup(acl); acl_free(acl); return (0); } Index: head/bin/setfacl/merge.c =================================================================== --- head/bin/setfacl/merge.c (revision 333064) +++ head/bin/setfacl/merge.c (revision 333065) @@ -1,293 +1,293 @@ /*- * Copyright (c) 2001 Chris D. Faulhaber * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "setfacl.h" static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new, int acl_brand); static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new, int acl_brand) { acl_permset_t permset; acl_entry_type_t entry_type; acl_flagset_t flagset; int have_entry; uid_t *id, *id_new; have_entry = 0; id = acl_get_qualifier(*entry); if (id == NULL) err(1, "acl_get_qualifier() failed"); id_new = acl_get_qualifier(*entry_new); if (id_new == NULL) err(1, "acl_get_qualifier() failed"); if (*id == *id_new) { /* any other matches */ if (acl_get_permset(*entry, &permset) == -1) err(1, "acl_get_permset() failed"); if (acl_set_permset(*entry_new, permset) == -1) err(1, "acl_set_permset() failed"); if (acl_brand == ACL_BRAND_NFS4) { if (acl_get_entry_type_np(*entry, &entry_type)) err(1, "acl_get_entry_type_np() failed"); if (acl_set_entry_type_np(*entry_new, entry_type)) err(1, "acl_set_entry_type_np() failed"); if (acl_get_flagset_np(*entry, &flagset)) err(1, "acl_get_flagset_np() failed"); if (acl_set_flagset_np(*entry_new, flagset)) err(1, "acl_set_flagset_np() failed"); } have_entry = 1; } acl_free(id); acl_free(id_new); return (have_entry); } /* * merge an ACL into existing file's ACL */ int merge_acl(acl_t acl, acl_t *prev_acl, const char *filename) { acl_entry_t entry, entry_new; acl_permset_t permset; acl_t acl_new; acl_tag_t tag, tag_new; acl_entry_type_t entry_type, entry_type_new; acl_flagset_t flagset; int entry_id, entry_id_new, have_entry, had_entry, entry_number = 0; int acl_brand, prev_acl_brand; acl_get_brand_np(acl, &acl_brand); acl_get_brand_np(*prev_acl, &prev_acl_brand); if (branding_mismatch(acl_brand, prev_acl_brand)) { warnx("%s: branding mismatch; existing ACL is %s, " "entry to be merged is %s", filename, brand_name(prev_acl_brand), brand_name(acl_brand)); return (-1); } acl_new = acl_dup(*prev_acl); if (acl_new == NULL) err(1, "%s: acl_dup() failed", filename); entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; have_entry = 0; had_entry = 0; /* keep track of existing ACL_MASK entries */ if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed - " "invalid ACL entry", filename); if (tag == ACL_MASK) - have_mask = 1; + have_mask = true; /* check against the existing ACL entries */ entry_id_new = ACL_FIRST_ENTRY; while (acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) { entry_id_new = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (acl_get_tag_type(entry_new, &tag_new) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (tag != tag_new) continue; /* * For NFSv4, in addition to "tag" and "id" we also * compare "entry_type". */ if (acl_brand == ACL_BRAND_NFS4) { if (acl_get_entry_type_np(entry, &entry_type)) err(1, "%s: acl_get_entry_type_np() " "failed", filename); if (acl_get_entry_type_np(entry_new, &entry_type_new)) err(1, "%s: acl_get_entry_type_np() " "failed", filename); if (entry_type != entry_type_new) continue; } switch(tag) { case ACL_USER: case ACL_GROUP: have_entry = merge_user_group(&entry, &entry_new, acl_brand); if (have_entry == 0) break; /* FALLTHROUGH */ case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_OTHER: case ACL_MASK: case ACL_EVERYONE: if (acl_get_permset(entry, &permset) == -1) err(1, "%s: acl_get_permset() failed", filename); if (acl_set_permset(entry_new, permset) == -1) err(1, "%s: acl_set_permset() failed", filename); if (acl_brand == ACL_BRAND_NFS4) { if (acl_get_entry_type_np(entry, &entry_type)) err(1, "%s: acl_get_entry_type_np() failed", filename); if (acl_set_entry_type_np(entry_new, entry_type)) err(1, "%s: acl_set_entry_type_np() failed", filename); if (acl_get_flagset_np(entry, &flagset)) err(1, "%s: acl_get_flagset_np() failed", filename); if (acl_set_flagset_np(entry_new, flagset)) err(1, "%s: acl_set_flagset_np() failed", filename); } had_entry = have_entry = 1; break; default: /* should never be here */ errx(1, "%s: invalid tag type: %i", filename, tag); break; } } /* if this entry has not been found, it must be new */ if (had_entry == 0) { /* * NFSv4 ACL entries must be prepended to the ACL. * Appending them at the end makes no sense, since * in most cases they wouldn't even get evaluated. */ if (acl_brand == ACL_BRAND_NFS4) { if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) { warn("%s: acl_create_entry_np() failed", filename); acl_free(acl_new); return (-1); } /* * Without this increment, adding several * entries at once, for example * "setfacl -m user:1:r:allow,user:2:r:allow", * would make them appear in reverse order. */ entry_number++; } else { if (acl_create_entry(&acl_new, &entry_new) == -1) { warn("%s: acl_create_entry() failed", filename); acl_free(acl_new); return (-1); } } if (acl_copy_entry(entry_new, entry) == -1) err(1, "%s: acl_copy_entry() failed", filename); } } acl_free(*prev_acl); *prev_acl = acl_new; return (0); } int add_acl(acl_t acl, uint entry_number, acl_t *prev_acl, const char *filename) { acl_entry_t entry, entry_new; acl_t acl_new; int entry_id, acl_brand, prev_acl_brand; acl_get_brand_np(acl, &acl_brand); acl_get_brand_np(*prev_acl, &prev_acl_brand); if (prev_acl_brand != ACL_BRAND_NFS4) { warnx("%s: the '-a' option is only applicable to NFSv4 ACLs", filename); return (-1); } if (branding_mismatch(acl_brand, ACL_BRAND_NFS4)) { warnx("%s: branding mismatch; existing ACL is NFSv4, " "entry to be added is %s", filename, brand_name(acl_brand)); return (-1); } acl_new = acl_dup(*prev_acl); if (acl_new == NULL) err(1, "%s: acl_dup() failed", filename); entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) { warn("%s: acl_create_entry_np() failed", filename); acl_free(acl_new); return (-1); } /* * Without this increment, adding several * entries at once, for example * "setfacl -m user:1:r:allow,user:2:r:allow", * would make them appear in reverse order. */ entry_number++; if (acl_copy_entry(entry_new, entry) == -1) err(1, "%s: acl_copy_entry() failed", filename); } acl_free(*prev_acl); *prev_acl = acl_new; return (0); } Index: head/bin/setfacl/remove.c =================================================================== --- head/bin/setfacl/remove.c (revision 333064) +++ head/bin/setfacl/remove.c (revision 333065) @@ -1,173 +1,173 @@ /*- * Copyright (c) 2001 Chris D. Faulhaber * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "setfacl.h" /* * remove ACL entries from an ACL */ int remove_acl(acl_t acl, acl_t *prev_acl, const char *filename) { acl_entry_t entry; acl_t acl_new; acl_tag_t tag; int carried_error, entry_id, acl_brand, prev_acl_brand; carried_error = 0; acl_get_brand_np(acl, &acl_brand); acl_get_brand_np(*prev_acl, &prev_acl_brand); if (branding_mismatch(acl_brand, prev_acl_brand)) { warnx("%s: branding mismatch; existing ACL is %s, " "entry to be removed is %s", filename, brand_name(prev_acl_brand), brand_name(acl_brand)); return (-1); } carried_error = 0; acl_new = acl_dup(*prev_acl); if (acl_new == NULL) err(1, "%s: acl_dup() failed", filename); tag = ACL_UNDEFINED_TAG; /* find and delete the entry */ entry_id = ACL_FIRST_ENTRY; while (acl_get_entry(acl, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (tag == ACL_MASK) - have_mask++; + have_mask = true; if (acl_delete_entry(acl_new, entry) == -1) { carried_error++; warnx("%s: cannot remove non-existent ACL entry", filename); } } acl_free(*prev_acl); *prev_acl = acl_new; if (carried_error) return (-1); return (0); } int remove_by_number(uint entry_number, acl_t *prev_acl, const char *filename) { acl_entry_t entry; acl_t acl_new; acl_tag_t tag; int carried_error, entry_id; uint i; carried_error = 0; acl_new = acl_dup(*prev_acl); if (acl_new == NULL) err(1, "%s: acl_dup() failed", filename); tag = ACL_UNDEFINED_TAG; /* * Find out whether we're removing the mask entry, * to behave the same as the routine above. * * XXX: Is this loop actually needed? */ entry_id = ACL_FIRST_ENTRY; i = 0; while (acl_get_entry(acl_new, entry_id, &entry) == 1) { entry_id = ACL_NEXT_ENTRY; if (i != entry_number) continue; if (acl_get_tag_type(entry, &tag) == -1) err(1, "%s: acl_get_tag_type() failed", filename); if (tag == ACL_MASK) - have_mask++; + have_mask = true; } if (acl_delete_entry_np(acl_new, entry_number) == -1) { carried_error++; warn("%s: acl_delete_entry_np() failed", filename); } acl_free(*prev_acl); *prev_acl = acl_new; if (carried_error) return (-1); return (0); } /* * remove default entries */ int remove_default(acl_t *prev_acl, const char *filename) { acl_free(*prev_acl); *prev_acl = acl_init(ACL_MAX_ENTRIES); if (*prev_acl == NULL) err(1, "%s: acl_init() failed", filename); return (0); } /* * remove extended entries */ void remove_ext(acl_t *prev_acl, const char *filename) { acl_t acl_new; acl_new = acl_strip_np(*prev_acl, !n_flag); if (acl_new == NULL) err(1, "%s: acl_strip_np() failed", filename); acl_free(*prev_acl); *prev_acl = acl_new; } Index: head/bin/setfacl/setfacl.c =================================================================== --- head/bin/setfacl/setfacl.c (revision 333064) +++ head/bin/setfacl/setfacl.c (revision 333065) @@ -1,432 +1,449 @@ /*- * Copyright (c) 2001 Chris D. Faulhaber * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "setfacl.h" /* file operations */ #define OP_MERGE_ACL 0x00 /* merge acl's (-mM) */ #define OP_REMOVE_DEF 0x01 /* remove default acl's (-k) */ #define OP_REMOVE_EXT 0x02 /* remove extended acl's (-b) */ #define OP_REMOVE_ACL 0x03 /* remove acl's (-xX) */ #define OP_REMOVE_BY_NUMBER 0x04 /* remove acl's (-xX) by acl entry number */ #define OP_ADD_ACL 0x05 /* add acls entries at a given position */ /* TAILQ entry for acl operations */ struct sf_entry { uint op; acl_t acl; uint entry_number; TAILQ_ENTRY(sf_entry) next; }; static TAILQ_HEAD(, sf_entry) entrylist; -uint have_mask; -uint need_mask; -uint have_stdin; -uint n_flag; +bool have_mask; +bool have_stdin; +bool n_flag; +static bool h_flag; +static bool H_flag; +static bool L_flag; +static bool R_flag; +static bool need_mask; +static acl_type_t acl_type = ACL_TYPE_ACCESS; +static int handle_file(FTS *ftsp, FTSENT *file); +static char **stdin_files(void); static void usage(void); static void usage(void) { fprintf(stderr, "usage: setfacl [-R [-H | -L | -P]] [-bdhkn] " "[-a position entries] [-m entries] [-M file] " "[-x entries] [-X file] [file ...]\n"); exit(1); } -int -main(int argc, char *argv[]) +static char ** +stdin_files(void) { - acl_t acl; - acl_type_t acl_type; - acl_entry_t unused_entry; + char **files_list; char filename[PATH_MAX]; - int local_error, carried_error, ch, entry_number, ret, fts_options; - bool h_flag, H_flag, L_flag, R_flag, follow_symlink; size_t fl_count, i; + + if (have_stdin) + err(1, "cannot have more than one stdin"); + + i = 0; + have_stdin = true; + bzero(&filename, sizeof(filename)); + /* Start with an array size sufficient for basic cases. */ + fl_count = 1024; + files_list = zmalloc(fl_count * sizeof(char *)); + while (fgets(filename, (int)sizeof(filename), stdin)) { + /* remove the \n */ + filename[strlen(filename) - 1] = '\0'; + files_list[i] = strdup(filename); + if (files_list[i] == NULL) + err(1, "strdup() failed"); + /* Grow array if necessary. */ + if (++i == fl_count) { + fl_count <<= 1; + if (fl_count > SIZE_MAX / sizeof(char *)) + errx(1, "Too many input files"); + files_list = zrealloc(files_list, + fl_count * sizeof(char *)); + } + } + + /* fts_open() requires the last array element to be NULL. */ + files_list[i] = NULL; + + return (files_list); +} + +static int +handle_file(FTS *ftsp, FTSENT *file) +{ + acl_t acl; + acl_entry_t unused_entry; + int local_error, ret; + struct sf_entry *entry; + bool follow_symlink; + + local_error = 0; + switch (file->fts_info) { + case FTS_D: + /* Do not recurse if -R not specified. */ + if (!R_flag) + fts_set(ftsp, file, FTS_SKIP); + break; + case FTS_DP: + /* Skip the second visit to a directory. */ + return (0); + case FTS_DNR: + case FTS_ERR: + warnx("%s: %s", file->fts_path, strerror(file->fts_errno)); + return (0); + default: + break; + } + + if (acl_type == ACL_TYPE_DEFAULT && file->fts_info != FTS_D) { + warnx("%s: default ACL may only be set on a directory", + file->fts_path); + return (1); + } + + follow_symlink = (!R_flag && !h_flag) || (R_flag && L_flag) || + (R_flag && H_flag && file->fts_level == FTS_ROOTLEVEL); + + if (follow_symlink) + ret = pathconf(file->fts_accpath, _PC_ACL_NFS4); + else + ret = lpathconf(file->fts_accpath, _PC_ACL_NFS4); + if (ret > 0) { + if (acl_type == ACL_TYPE_DEFAULT) { + warnx("%s: there are no default entries in NFSv4 ACLs", + file->fts_path); + return (1); + } + 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->fts_path); + } + + if (follow_symlink) + acl = acl_get_file(file->fts_accpath, acl_type); + else + acl = acl_get_link_np(file->fts_accpath, acl_type); + if (acl == NULL) { + if (follow_symlink) + warn("%s: acl_get_file() failed", file->fts_path); + else + warn("%s: acl_get_link_np() failed", file->fts_path); + return (1); + } + + /* 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->fts_path); + break; + case OP_MERGE_ACL: + local_error += merge_acl(entry->acl, &acl, + file->fts_path); + need_mask = true; + 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->fts_path); + break; + } + remove_ext(&acl, file->fts_path); + need_mask = false; + break; + case OP_REMOVE_DEF: + if (acl_type == ACL_TYPE_NFS4) { + warnx("%s: there are no default entries in " + "NFSv4 ACLs; cannot remove", + file->fts_path); + local_error++; + break; + } + if (acl_delete_def_file(file->fts_accpath) == -1) { + warn("%s: acl_delete_def_file() failed", + file->fts_path); + local_error++; + } + if (acl_type == ACL_TYPE_DEFAULT) + local_error += remove_default(&acl, + file->fts_path); + need_mask = false; + break; + case OP_REMOVE_ACL: + local_error += remove_acl(entry->acl, &acl, + file->fts_path); + need_mask = true; + break; + case OP_REMOVE_BY_NUMBER: + local_error += remove_by_number(entry->entry_number, + &acl, file->fts_path); + need_mask = true; + 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->fts_accpath) == -1) { + warn("%s: acl_delete_def_file() failed", + file->fts_path); + return (1); + } + return (0); + } + + /* Don't bother setting the ACL if something is broken. */ + if (local_error) { + return (1); + } + + if (acl_type != ACL_TYPE_NFS4 && need_mask && + set_acl_mask(&acl, file->fts_path) == -1) { + warnx("%s: failed to set ACL mask", file->fts_path); + return (1); + } else if (follow_symlink) { + if (acl_set_file(file->fts_accpath, acl_type, acl) == -1) { + warn("%s: acl_set_file() failed", file->fts_path); + return (1); + } + } else { + if (acl_set_link_np(file->fts_accpath, acl_type, acl) == -1) { + warn("%s: acl_set_link_np() failed", file->fts_path); + return (1); + } + } + + acl_free(acl); + return (0); +} + +int +main(int argc, char *argv[]) +{ + int carried_error, ch, entry_number, fts_options; FTS *ftsp; FTSENT *file; char **files_list; struct sf_entry *entry; char *end; acl_type = ACL_TYPE_ACCESS; - carried_error = local_error = fts_options = 0; - have_mask = have_stdin = n_flag = need_mask = 0; - h_flag = H_flag = L_flag = R_flag = false; + carried_error = fts_options = 0; + have_mask = have_stdin = n_flag = false; TAILQ_INIT(&entrylist); while ((ch = getopt(argc, argv, "HLM:PRX:a:bdhkm:nx:")) != -1) switch(ch) { case 'H': H_flag = true; L_flag = false; break; case 'L': L_flag = true; H_flag = false; break; case 'M': entry = zmalloc(sizeof(struct sf_entry)); entry->acl = get_acl_from_file(optarg); if (entry->acl == NULL) - err(1, "%s: get_acl_from_file() failed", optarg); + err(1, "%s: get_acl_from_file() failed", + optarg); entry->op = OP_MERGE_ACL; TAILQ_INSERT_TAIL(&entrylist, entry, next); break; case 'P': H_flag = L_flag = false; break; case 'R': R_flag = true; break; case 'X': entry = zmalloc(sizeof(struct sf_entry)); entry->acl = get_acl_from_file(optarg); entry->op = OP_REMOVE_ACL; TAILQ_INSERT_TAIL(&entrylist, entry, next); break; case 'a': entry = zmalloc(sizeof(struct sf_entry)); entry_number = strtol(optarg, &end, 10); if (end - optarg != (int)strlen(optarg)) errx(1, "%s: invalid entry number", optarg); if (entry_number < 0) - errx(1, "%s: entry number cannot be less than zero", optarg); + errx(1, + "%s: entry number cannot be less than zero", + optarg); entry->entry_number = entry_number; if (argv[optind] == NULL) errx(1, "missing ACL"); entry->acl = acl_from_text(argv[optind]); if (entry->acl == NULL) err(1, "%s", argv[optind]); optind++; entry->op = OP_ADD_ACL; TAILQ_INSERT_TAIL(&entrylist, entry, next); break; case 'b': entry = zmalloc(sizeof(struct sf_entry)); entry->op = OP_REMOVE_EXT; TAILQ_INSERT_TAIL(&entrylist, entry, next); break; case 'd': acl_type = ACL_TYPE_DEFAULT; break; case 'h': h_flag = 1; break; case 'k': entry = zmalloc(sizeof(struct sf_entry)); entry->op = OP_REMOVE_DEF; TAILQ_INSERT_TAIL(&entrylist, entry, next); break; case 'm': entry = zmalloc(sizeof(struct sf_entry)); entry->acl = acl_from_text(optarg); if (entry->acl == NULL) err(1, "%s", optarg); entry->op = OP_MERGE_ACL; TAILQ_INSERT_TAIL(&entrylist, entry, next); break; case 'n': - n_flag++; + n_flag = true; break; case 'x': entry = zmalloc(sizeof(struct sf_entry)); entry_number = strtol(optarg, &end, 10); if (end - optarg == (int)strlen(optarg)) { if (entry_number < 0) - errx(1, "%s: entry number cannot be less than zero", optarg); + errx(1, + "%s: entry number cannot be less than zero", + optarg); entry->entry_number = entry_number; entry->op = OP_REMOVE_BY_NUMBER; } else { entry->acl = acl_from_text(optarg); if (entry->acl == NULL) err(1, "%s", optarg); entry->op = OP_REMOVE_ACL; } TAILQ_INSERT_TAIL(&entrylist, entry, next); break; default: usage(); break; } argc -= optind; argv += optind; - if (n_flag == 0 && TAILQ_EMPTY(&entrylist)) + if (!n_flag && TAILQ_EMPTY(&entrylist)) usage(); - /* take list of files from stdin */ + /* Take list of files from stdin. */ if (argc == 0 || strcmp(argv[0], "-") == 0) { - if (have_stdin) - err(1, "cannot have more than one stdin"); - have_stdin = 1; - bzero(&filename, sizeof(filename)); - i = 0; - /* Start with an array size sufficient for basic cases. */ - fl_count = 1024; - files_list = zmalloc(fl_count * sizeof(char *)); - while (fgets(filename, (int)sizeof(filename), stdin)) { - /* remove the \n */ - filename[strlen(filename) - 1] = '\0'; - files_list[i] = strdup(filename); - if (files_list[i] == NULL) - err(1, "strdup() failed"); - /* Grow array if necessary. */ - if (++i == fl_count) { - fl_count <<= 1; - if (fl_count > SIZE_MAX / sizeof(char *)) - errx(1, "Too many input files"); - files_list = zrealloc(files_list, - fl_count * sizeof(char *)); - } - } - - /* fts_open() requires the last array element to be NULL. */ - files_list[i] = NULL; + files_list = stdin_files(); } else files_list = argv; if (R_flag) { if (h_flag) errx(1, "the -R and -h options may not be " "specified together."); if (L_flag) { fts_options = FTS_LOGICAL; } else { fts_options = FTS_PHYSICAL; if (H_flag) { fts_options |= FTS_COMFOLLOW; } } } else if (h_flag) { fts_options = FTS_PHYSICAL; } else { fts_options = FTS_LOGICAL; } /* Open all files. */ if ((ftsp = fts_open(files_list, fts_options | FTS_NOSTAT, 0)) == NULL) err(1, "fts_open"); - while ((file = fts_read(ftsp)) != NULL) { - switch (file->fts_info) { - case FTS_D: - /* Do not recurse if -R not specified. */ - if (!R_flag) - fts_set(ftsp, file, FTS_SKIP); - break; - case FTS_DP: - /* Skip the second visit to a directory. */ - continue; - case FTS_DNR: - case FTS_ERR: - warnx("%s: %s", file->fts_path, - strerror(file->fts_errno)); - continue; - default: - break; - } - - if (acl_type == ACL_TYPE_DEFAULT && file->fts_info != FTS_D) { - warnx("%s: default ACL may only be set on " - "a directory", file->fts_path); - carried_error++; - continue; - } - - local_error = 0; - - follow_symlink = ((fts_options & FTS_LOGICAL) || - ((fts_options & FTS_COMFOLLOW) && - file->fts_level == FTS_ROOTLEVEL)); - - if (follow_symlink) - ret = pathconf(file->fts_accpath, _PC_ACL_NFS4); - else - ret = lpathconf(file->fts_accpath, _PC_ACL_NFS4); - if (ret > 0) { - if (acl_type == ACL_TYPE_DEFAULT) { - warnx("%s: there are no default entries " - "in NFSv4 ACLs", file->fts_path); - 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->fts_path); - } - - if (follow_symlink) - acl = acl_get_file(file->fts_accpath, acl_type); - else - acl = acl_get_link_np(file->fts_accpath, acl_type); - if (acl == NULL) { - if (follow_symlink) - warn("%s: acl_get_file() failed", - file->fts_path); - else - warn("%s: acl_get_link_np() failed", - file->fts_path); - 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->fts_path); - break; - case OP_MERGE_ACL: - local_error += merge_acl(entry->acl, &acl, - file->fts_path); - 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->fts_path); - break; - } - remove_ext(&acl, file->fts_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", file->fts_path); - local_error++; - break; - } - if (acl_delete_def_file(file->fts_accpath) == -1) { - warn("%s: acl_delete_def_file() failed", - file->fts_path); - local_error++; - } - if (acl_type == ACL_TYPE_DEFAULT) - local_error += remove_default(&acl, - file->fts_path); - need_mask = 0; - break; - case OP_REMOVE_ACL: - local_error += remove_acl(entry->acl, &acl, - file->fts_path); - need_mask = 1; - break; - case OP_REMOVE_BY_NUMBER: - local_error += remove_by_number(entry->entry_number, - &acl, file->fts_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(file->fts_accpath) == -1) { - warn("%s: acl_delete_def_file() failed", - file->fts_path); - carried_error++; - } - continue; - } - - /* don't bother setting the ACL if something is broken */ - if (local_error) { - carried_error++; - continue; - } - - if (acl_type != ACL_TYPE_NFS4 && need_mask && - set_acl_mask(&acl, file->fts_path) == -1) { - warnx("%s: failed to set ACL mask", file->fts_path); - carried_error++; - } else if (follow_symlink) { - if (acl_set_file(file->fts_accpath, acl_type, - acl) == -1) { - carried_error++; - warn("%s: acl_set_file() failed", - file->fts_path); - } - } else { - if (acl_set_link_np(file->fts_accpath, acl_type, - acl) == -1) { - carried_error++; - warn("%s: acl_set_link_np() failed", - file->fts_path); - } - } - - acl_free(acl); - } + while ((file = fts_read(ftsp)) != NULL) + carried_error += handle_file(ftsp, file); return (carried_error); } Index: head/bin/setfacl/setfacl.h =================================================================== --- head/bin/setfacl/setfacl.h (revision 333064) +++ head/bin/setfacl/setfacl.h (revision 333065) @@ -1,59 +1,62 @@ /*- * Copyright (c) 2001 Chris D. Faulhaber * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SETFACL_H #define _SETFACL_H +#include + #include #include #include /* files.c */ -acl_t get_acl_from_file(const char *filename); +acl_t get_acl_from_file(const char *filename); /* merge.c */ -int merge_acl(acl_t acl, acl_t *prev_acl, const char *filename); -int add_acl(acl_t acl, uint entry_number, acl_t *prev_acl, const char *filename); +int merge_acl(acl_t acl, acl_t *prev_acl, const char *filename); +int add_acl(acl_t acl, uint entry_number, acl_t *prev_acl, + const char *filename); /* remove.c */ -int remove_acl(acl_t acl, acl_t *prev_acl, const char *filename); -int remove_by_number(uint entry_number, acl_t *prev_acl, const char *filename); -int remove_default(acl_t *prev_acl, const char *filename); -void remove_ext(acl_t *prev_acl, const char *filename); +int remove_acl(acl_t acl, acl_t *prev_acl, const char *filename); +int remove_by_number(uint entry_number, acl_t *prev_acl, + const char *filename); +int remove_default(acl_t *prev_acl, const char *filename); +void remove_ext(acl_t *prev_acl, const char *filename); /* mask.c */ -int set_acl_mask(acl_t *prev_acl, const char *filename); +int set_acl_mask(acl_t *prev_acl, const char *filename); /* util.c */ -void *zmalloc(size_t size); -void *zrealloc(void *ptr, size_t size); +void *zmalloc(size_t size); +void *zrealloc(void *ptr, size_t size); const char *brand_name(int brand); -int branding_mismatch(int brand1, int brand2); +int branding_mismatch(int brand1, int brand2); -extern uint have_mask; -extern uint need_mask; -extern uint have_stdin; -extern uint n_flag; +extern bool have_mask; +extern bool have_stdin; +extern bool n_flag; #endif /* _SETFACL_H */