2 * Copyright (c) 2001 Chris D. Faulhaber
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/param.h>
34 #include <sys/queue.h>
45 static void add_filename(const char *filename);
46 static void usage(void);
49 add_filename(const char *filename)
53 if (strlen(filename) > PATH_MAX - 1) {
54 warn("illegal filename");
57 file = zmalloc(sizeof(struct sf_file));
58 file->filename = filename;
59 TAILQ_INSERT_TAIL(&filelist, file, next);
66 fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] "
67 "[-m entries] [-M file] [-x entries] [-X file] [file ...]\n");
72 main(int argc, char *argv[])
76 char filename[PATH_MAX];
77 int local_error, carried_error, ch, i, entry_number, ret;
80 struct sf_entry *entry;
85 acl_type = ACL_TYPE_ACCESS;
86 carried_error = local_error = 0;
87 h_flag = have_mask = have_stdin = n_flag = need_mask = 0;
89 TAILQ_INIT(&entrylist);
90 TAILQ_INIT(&filelist);
92 while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1)
95 entry = zmalloc(sizeof(struct sf_entry));
96 entry->acl = get_acl_from_file(optarg);
97 if (entry->acl == NULL)
98 err(1, "%s: get_acl_from_file() failed", optarg);
99 entry->op = OP_MERGE_ACL;
100 TAILQ_INSERT_TAIL(&entrylist, entry, next);
103 entry = zmalloc(sizeof(struct sf_entry));
104 entry->acl = get_acl_from_file(optarg);
105 entry->op = OP_REMOVE_ACL;
106 TAILQ_INSERT_TAIL(&entrylist, entry, next);
109 entry = zmalloc(sizeof(struct sf_entry));
111 entry_number = strtol(optarg, &end, 10);
112 if (end - optarg != (int)strlen(optarg))
113 errx(1, "%s: invalid entry number", optarg);
114 if (entry_number < 0)
115 errx(1, "%s: entry number cannot be less than zero", optarg);
116 entry->entry_number = entry_number;
118 if (argv[optind] == NULL)
119 errx(1, "missing ACL");
120 entry->acl = acl_from_text(argv[optind]);
121 if (entry->acl == NULL)
122 err(1, "%s", argv[optind]);
124 entry->op = OP_ADD_ACL;
125 TAILQ_INSERT_TAIL(&entrylist, entry, next);
128 entry = zmalloc(sizeof(struct sf_entry));
129 entry->op = OP_REMOVE_EXT;
130 TAILQ_INSERT_TAIL(&entrylist, entry, next);
133 acl_type = ACL_TYPE_DEFAULT;
139 entry = zmalloc(sizeof(struct sf_entry));
140 entry->op = OP_REMOVE_DEF;
141 TAILQ_INSERT_TAIL(&entrylist, entry, next);
144 entry = zmalloc(sizeof(struct sf_entry));
145 entry->acl = acl_from_text(optarg);
146 if (entry->acl == NULL)
147 err(1, "%s", optarg);
148 entry->op = OP_MERGE_ACL;
149 TAILQ_INSERT_TAIL(&entrylist, entry, next);
155 entry = zmalloc(sizeof(struct sf_entry));
156 entry_number = strtol(optarg, &end, 10);
157 if (end - optarg == (int)strlen(optarg)) {
158 if (entry_number < 0)
159 errx(1, "%s: entry number cannot be less than zero", optarg);
160 entry->entry_number = entry_number;
161 entry->op = OP_REMOVE_BY_NUMBER;
163 entry->acl = acl_from_text(optarg);
164 if (entry->acl == NULL)
165 err(1, "%s", optarg);
166 entry->op = OP_REMOVE_ACL;
168 TAILQ_INSERT_TAIL(&entrylist, entry, next);
177 if (n_flag == 0 && TAILQ_EMPTY(&entrylist))
180 /* take list of files from stdin */
181 if (argc == 0 || strcmp(argv[0], "-") == 0) {
183 err(1, "cannot have more than one stdin");
185 bzero(&filename, sizeof(filename));
186 while (fgets(filename, (int)sizeof(filename), stdin)) {
188 filename[strlen(filename) - 1] = '\0';
189 fn_dup = strdup(filename);
191 err(1, "strdup() failed");
192 add_filename(fn_dup);
195 for (i = 0; i < argc; i++)
196 add_filename(argv[i]);
198 /* cycle through each file */
199 TAILQ_FOREACH(file, &filelist, next) {
202 if (stat(file->filename, &sb) == -1) {
203 warn("%s: stat() failed", file->filename);
208 if (acl_type == ACL_TYPE_DEFAULT && S_ISDIR(sb.st_mode) == 0) {
209 warnx("%s: default ACL may only be set on a directory",
216 ret = lpathconf(file->filename, _PC_ACL_NFS4);
218 ret = pathconf(file->filename, _PC_ACL_NFS4);
220 if (acl_type == ACL_TYPE_DEFAULT) {
221 warnx("%s: there are no default entries "
222 "in NFSv4 ACLs", file->filename);
226 acl_type = ACL_TYPE_NFS4;
227 } else if (ret == 0) {
228 if (acl_type == ACL_TYPE_NFS4)
229 acl_type = ACL_TYPE_ACCESS;
230 } else if (ret < 0 && errno != EINVAL) {
231 warn("%s: pathconf(..., _PC_ACL_NFS4) failed",
236 acl = acl_get_link_np(file->filename, acl_type);
238 acl = acl_get_file(file->filename, acl_type);
241 warn("%s: acl_get_link_np() failed",
244 warn("%s: acl_get_file() failed",
250 /* cycle through each option */
251 TAILQ_FOREACH(entry, &entrylist, next) {
257 local_error += add_acl(entry->acl,
258 entry->entry_number, &acl, file->filename);
261 local_error += merge_acl(entry->acl, &acl,
266 remove_ext(&acl, file->filename);
270 if (acl_type == ACL_TYPE_NFS4) {
271 warnx("%s: there are no default entries in NFSv4 ACLs; "
272 "cannot remove", file->filename);
276 if (acl_delete_def_file(file->filename) == -1) {
277 warn("%s: acl_delete_def_file() failed",
281 if (acl_type == ACL_TYPE_DEFAULT)
282 local_error += remove_default(&acl,
287 local_error += remove_acl(entry->acl, &acl,
291 case OP_REMOVE_BY_NUMBER:
292 local_error += remove_by_number(entry->entry_number,
293 &acl, file->filename);
299 /* don't bother setting the ACL if something is broken */
305 if (acl_type != ACL_TYPE_NFS4 && need_mask &&
306 set_acl_mask(&acl, file->filename) == -1) {
307 warnx("%s: failed to set ACL mask", file->filename);
310 if (acl_set_link_np(file->filename, acl_type,
313 warn("%s: acl_set_link_np() failed",
317 if (acl_set_file(file->filename, acl_type,
320 warn("%s: acl_set_file() failed",
328 return (carried_error);