]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/setfacl.c
Cygwin: add 3.2.1 release file and add fixes up to this point
[newlib-cygwin.git] / winsup / utils / setfacl.c
1 /* setfacl.c
2
3 Written by Corinna Vinschen <vinschen@redhat.com>
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <errno.h>
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <getopt.h>
18 #include <pwd.h>
19 #include <grp.h>
20 #include <cygwin/acl.h>
21 #include <cygwin/version.h>
22
23 #ifndef BOOL
24 #define BOOL int
25 #endif
26
27 #ifndef TRUE
28 #define TRUE (1)
29 #endif
30
31 #ifndef FALSE
32 #define FALSE (0)
33 #endif
34
35 #ifndef ILLEGAL_MODE
36 #define ILLEGAL_MODE ((mode_t)0xffffffff)
37 #endif
38
39 static char *prog_name;
40
41 typedef enum {
42 NoAction = 0,
43 DeleteExt = 1, /* The values 1,2,3 allow bitmasking below. */
44 DeleteDef = 2,
45 DeleteAll = 3,
46 Set,
47 Modify,
48 Delete,
49 ModNDel,
50 SetFromFile
51 } action_t;
52
53 int mask_opt = 0;
54
55 mode_t getperm (char *in)
56 {
57 if (isdigit ((unsigned char) *in) && !in[1])
58 {
59 int i = atoi (in);
60 if (i < 0 || i > 7)
61 return ILLEGAL_MODE;
62 return i << 6 | i << 3 | i;
63 }
64 if (strlen (in) > 3 && strchr (" \t\n\r#", in[3]))
65 in[3] = '\0';
66 if (strlen (in) != 3)
67 return ILLEGAL_MODE;
68 if (!strchr ("r-", in[0])
69 || !strchr ("w-", in[1])
70 || !strchr ("x-", in[2]))
71 return ILLEGAL_MODE;
72 return (in[0] == 'r' ? S_IROTH : 0)
73 | (in[1] == 'w' ? S_IWOTH : 0)
74 | (in[2] == 'x' ? S_IXOTH : 0);
75 }
76
77 BOOL
78 getaclentry (action_t action, char *c, aclent_t *ace)
79 {
80 char *c2;
81
82 ace->a_type = 0;
83 ace->a_id = (uid_t) -1;
84 ace->a_perm = 0;
85
86 /* First, check if we're handling a default entry. */
87 if (!strncmp (c, "default:", 8) || !strncmp (c, "d:", 2))
88 {
89 ace->a_type = ACL_DEFAULT;
90 c = strchr (c, ':') + 1;
91 }
92 /* c now points to the type. Check for next colon. If we find a colon,
93 NUL it. Otherwise the string is invalid, except when deleting. */
94 c2 = strchrnul (c, ':');
95 if (*c2 == ':')
96 *c2++ = '\0';
97 else if (action != Delete)
98 return FALSE;
99 /* Fetch the type. */
100 if (!strcmp (c, "u") || !strcmp (c, "user"))
101 ace->a_type |= USER_OBJ;
102 else if (!strcmp (c, "g") || !strcmp (c, "group"))
103 ace->a_type |= GROUP_OBJ;
104 else if (!strcmp (c, "m") || !strcmp (c, "mask"))
105 ace->a_type |= CLASS_OBJ;
106 else if (!strcmp (c, "o") || !strcmp (c, "other"))
107 ace->a_type |= OTHER_OBJ;
108 else
109 return FALSE;
110 /* Skip to next field. */
111 c = c2;
112 if (!*c)
113 {
114 /* Nothing follows. This is only valid if action is Delete and the
115 type is CLASS_OBJ, or if ACL_DEFAULT is set. */
116 if (action != Delete
117 || (!(ace->a_type & (CLASS_OBJ | ACL_DEFAULT))))
118 return FALSE;
119 }
120 else if (!(ace->a_type & (USER_OBJ | GROUP_OBJ)))
121 {
122 /* Mask and other entries may contain one or two colons. */
123 if (*c == ':')
124 ++c;
125 }
126 /* If this is a user or group entry, check if next char is a colon char.
127 If so, skip it, otherwise it's the name of a user or group. */
128 else if (*c == ':')
129 ++c;
130 else if (*c)
131 {
132 /* c now points to the id. Check for next colon. If we find a colon,
133 NUL it. Otherwise the string is invalid, except when deleting.
134 If we delete, it must be a default entry since standard ugo entries
135 can't be deleted. */
136 c2 = strchrnul (c + 1, ':');
137 if (*c2 == ':')
138 *c2++ = '\0';
139 else if (action != Delete)
140 return FALSE;
141 /* Fetch user/group id. */
142 if (isdigit ((unsigned char) *c))
143 {
144 char *c3;
145
146 ace->a_id = strtol (c, &c3, 10);
147 if (*c3)
148 return FALSE;
149 }
150 else if (ace->a_type & USER_OBJ)
151 {
152 struct passwd *pw = getpwnam (c);
153 if (!pw)
154 return FALSE;
155 ace->a_id = pw->pw_uid;
156 }
157 else
158 {
159 struct group *gr = getgrnam (c);
160 if (!gr)
161 return FALSE;
162 ace->a_id = gr->gr_gid;
163 }
164 if (ace->a_type & USER_OBJ)
165 {
166 ace->a_type &= ~USER_OBJ;
167 ace->a_type |= USER;
168 }
169 else
170 {
171 ace->a_type &= ~GROUP_OBJ;
172 ace->a_type |= GROUP;
173 }
174 /* Skip to next field. */
175 c = c2;
176 }
177 if (action == Delete)
178 {
179 /* Trailing garbage? */
180 if (*c)
181 return FALSE;
182 /* No, we're good. */
183 ace->a_perm = ILLEGAL_MODE;
184 return TRUE;
185 }
186 /* Check perms. */
187 if ((ace->a_perm = getperm (c)) == ILLEGAL_MODE)
188 return FALSE;
189 return TRUE;
190 }
191
192 BOOL
193 getaclentries (action_t action, char *buf, aclent_t *acls, int *idx)
194 {
195 char *c;
196
197 if (action == SetFromFile)
198 {
199 FILE *fp;
200 char fbuf[256], *fb;
201
202 if (!strcmp (buf, "-"))
203 fp = stdin;
204 else if (! (fp = fopen (buf, "r")))
205 return FALSE;
206 while ((fb = fgets (fbuf, 256, fp)))
207 {
208 while (strchr (" \t", *fb))
209 ++fb;
210 if (strchr ("\n\r#", *fb))
211 continue;
212 if (!getaclentry (action, fb, acls + (*idx)++))
213 {
214 fclose (fp);
215 return FALSE;
216 }
217 }
218 if (fp != stdin)
219 fclose (fp);
220 }
221 else
222 for (c = strtok (buf, ","); c; c = strtok (NULL, ","))
223 if (!getaclentry (action, c, acls + (*idx)++))
224 return FALSE;
225 return TRUE;
226 }
227
228 int
229 searchace (aclent_t *aclp, int nentries, int type, int id)
230 {
231 int i;
232
233 for (i = 0; i < nentries; ++i)
234 if ((aclp[i].a_type == type && (id < 0 || aclp[i].a_id == id))
235 || !aclp[i].a_type)
236 return i;
237 return -1;
238 }
239
240 int
241 delace (aclent_t *tgt, int tcnt, int t)
242 {
243 int i;
244
245 for (i = t + 1; i < tcnt; ++i)
246 tgt[i - 1] = tgt[i];
247 --tcnt;
248 return tcnt;
249 }
250
251 int
252 delacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt)
253 {
254 int t, s;
255
256 for (s = 0; s < scnt; ++s)
257 {
258 t = searchace (tgt, MAX_ACL_ENTRIES, src[s].a_type,
259 (src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1);
260 if (t < 0)
261 return -1;
262 if (t < tcnt)
263 tcnt = delace (tgt, tcnt, t);
264 }
265 return tcnt;
266 }
267
268 int
269 modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt)
270 {
271 int t, s;
272
273 /* Delete, replace or add given acl entries. */
274 for (s = 0; s < scnt; ++s)
275 {
276 t = searchace (tgt, MAX_ACL_ENTRIES, src[s].a_type,
277 (src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1);
278 if (t < 0)
279 return -1;
280 /* ILLEGAL_MODE means "delete". */
281 if (src[s].a_perm == ILLEGAL_MODE && t < tcnt)
282 tcnt = delace (tgt, tcnt, t);
283 else
284 {
285 tgt[t] = src[s];
286 if (t >= tcnt)
287 ++tcnt;
288 }
289 }
290 return tcnt;
291 }
292
293 void
294 check_got_mask (aclent_t *src, int scnt, int *got_mask, int *got_def_mask)
295 {
296 *got_mask = searchace (src, scnt, CLASS_OBJ, -1) >= 0;
297 *got_def_mask = searchace (src, scnt, DEF_CLASS_OBJ, -1) >= 0;
298 }
299
300 int
301 recompute_mask (aclent_t *tgt, int tcnt, int got_mask, int got_def_mask)
302 {
303 int t;
304 int need_mask = 0, need_def_mask = 0;
305 int mask_idx = -1, def_mask_idx = -1;
306 mode_t mask = 0, def_mask = 0;
307
308 /* Now recompute mask, if requested (default) */
309 for (t = 0; t < tcnt; ++t)
310 {
311 switch (tgt[t].a_type)
312 {
313 case USER:
314 case GROUP:
315 /* Do we need a CLASS_OBJ at all? */
316 need_mask = 1;
317 /*FALLTHRU*/
318 case GROUP_OBJ:
319 /* Compute resulting maximum mask. */
320 mask |= tgt[t].a_perm;
321 break;
322 case CLASS_OBJ:
323 /* Do we already have a CLASS_OBJ? */
324 mask_idx = t;
325 break;
326 case DEF_USER:
327 case DEF_GROUP:
328 /* Do we need a DEF_CLASS_OBJ at all? */
329 need_def_mask = 1;
330 /*FALLTHRU*/
331 case DEF_GROUP_OBJ:
332 /* Compute resulting maximum default mask. */
333 def_mask |= tgt[t].a_perm;
334 break;
335 case DEF_CLASS_OBJ:
336 /* Do we already have a DEF_CLASS_OBJ? */
337 def_mask_idx = t;
338 break;
339 }
340 }
341 /* Recompute mask, if requested
342 - If we got a mask in the input string, recompute only if --mask has been
343 specified.
344 - If we got no mask in the input, but we either need a mask or we already
345 have one, and --no-mask has *not* been specified, recompute. */
346 if ((got_mask && mask_opt > 0)
347 || (!got_mask && mask_opt >= 0 && (need_mask || mask_idx >= 0)))
348 {
349 if (mask_idx >= 0)
350 t = mask_idx;
351 else
352 t = searchace (tgt, MAX_ACL_ENTRIES, CLASS_OBJ, -1);
353 if (t < 0)
354 return -1;
355 if (t >= tcnt)
356 ++tcnt;
357 tgt[t].a_type = CLASS_OBJ;
358 tgt[t].a_id = -1;
359 tgt[t].a_perm = mask;
360 }
361 /* Recompute default mask, if requested */
362 if ((got_def_mask && mask_opt > 0)
363 || (!got_def_mask && mask_opt >= 0
364 && (need_def_mask || def_mask_idx >= 0)))
365 {
366 if (def_mask_idx >= 0)
367 t = def_mask_idx;
368 else
369 t = searchace (tgt, MAX_ACL_ENTRIES, DEF_CLASS_OBJ, -1);
370 if (t < 0)
371 return -1;
372 if (t >= tcnt)
373 ++tcnt;
374 tgt[t].a_type = DEF_CLASS_OBJ;
375 tgt[t].a_id = -1;
376 tgt[t].a_perm = def_mask;
377 }
378 return tcnt;
379 }
380
381 int
382 addmissing (aclent_t *tgt, int tcnt)
383 {
384 int t;
385 int types = 0, def_types = 0;
386 int perm = 0, def_perm = 0;
387
388 /* Check if we have all the required entries now. */
389 for (t = 0; t < tcnt; ++t)
390 if (tgt[t].a_type & ACL_DEFAULT)
391 {
392 def_types |= tgt[t].a_type;
393 if (tgt[t].a_type & GROUP_OBJ)
394 def_perm |= tgt[t].a_perm;
395 else if ((tgt[t].a_type & (USER | GROUP)) && mask_opt >= 0)
396 def_perm |= tgt[t].a_perm;
397 }
398 else
399 {
400 types |= tgt[t].a_type;
401 if (tgt[t].a_type & GROUP_OBJ)
402 perm |= tgt[t].a_perm;
403 else if ((tgt[t].a_type & (USER | GROUP)) && mask_opt >= 0)
404 perm |= tgt[t].a_perm;
405 }
406 /* Add missing CLASS_OBJ */
407 if ((types & (USER | GROUP)) && !(types & CLASS_OBJ))
408 {
409 tgt[tcnt].a_type = CLASS_OBJ;
410 tgt[tcnt].a_id = (uid_t) -1;
411 tgt[tcnt++].a_perm = perm;
412 }
413 if (def_types)
414 {
415 /* Add missing default entries. */
416 if (!(def_types & USER_OBJ) && tcnt < MAX_ACL_ENTRIES)
417 {
418 t = searchace (tgt, tcnt, USER_OBJ, -1);
419 tgt[tcnt].a_type = DEF_USER_OBJ;
420 tgt[tcnt].a_id = (uid_t) -1;
421 tgt[tcnt++].a_perm = t >= 0 ? tgt[t].a_perm : S_IRWXO;
422 }
423 if (!(def_types & GROUP_OBJ) && tcnt < MAX_ACL_ENTRIES)
424 {
425 t = searchace (tgt, tcnt, GROUP_OBJ, -1);
426 tgt[tcnt].a_type = DEF_GROUP_OBJ;
427 tgt[tcnt].a_id = (uid_t) -1;
428 tgt[tcnt].a_perm = t >= 0 ? tgt[t].a_perm : (S_IROTH | S_IXOTH);
429 def_perm |= tgt[tcnt++].a_perm;
430 }
431 if (!(def_types & OTHER_OBJ) && tcnt < MAX_ACL_ENTRIES)
432 {
433 t = searchace (tgt, tcnt, OTHER_OBJ, -1);
434 tgt[tcnt].a_type = DEF_OTHER_OBJ;
435 tgt[tcnt].a_id = (uid_t) -1;
436 tgt[tcnt++].a_perm = t >= 0 ? tgt[t].a_perm : (S_IROTH | S_IXOTH);
437 }
438 /* Add missing DEF_CLASS_OBJ */
439 if ((def_types & (USER | GROUP)) && !(def_types & CLASS_OBJ))
440 {
441 tgt[tcnt].a_type = DEF_CLASS_OBJ;
442 tgt[tcnt].a_id = (uid_t) -1;
443 tgt[tcnt++].a_perm = def_perm;
444 }
445 }
446 return tcnt;
447 }
448
449 int
450 delallacl (aclent_t *tgt, int tcnt, action_t action)
451 {
452 int t;
453
454 for (t = 0; t < tcnt; ++t)
455 /* -b (DeleteExt): Remove all extended ACL entries.
456 -k (DeleteDef): Remove all default ACL entries.
457 -b -k (DeleteAll): Remove extended and remove defaults. That means,
458 only preserve standard POSIX perms. */
459 if (((action & DeleteExt) && (tgt[t].a_type & (USER | GROUP | CLASS_OBJ)))
460 || ((action & DeleteDef) && (tgt[t].a_type & ACL_DEFAULT)))
461 {
462 --tcnt;
463 if (t < tcnt)
464 memmove (&tgt[t], &tgt[t + 1], (tcnt - t) * sizeof (aclent_t));
465 --t;
466 }
467 return tcnt;
468 }
469
470 int
471 setfacl (action_t action, const char *path, aclent_t *acls, int cnt)
472 {
473 aclent_t lacl[MAX_ACL_ENTRIES];
474 int lcnt, got_mask = 0, got_def_mask = 0;
475
476 memset (lacl, 0, sizeof lacl);
477 switch (action)
478 {
479 case Set:
480 check_got_mask (acls, cnt, &got_mask, &got_def_mask);
481 memcpy (lacl, acls, (lcnt = cnt) * sizeof (aclent_t));
482 if ((lcnt = recompute_mask (lacl, lcnt, got_mask, got_def_mask)) < 0
483 || (lcnt = addmissing (lacl, lcnt)) < 0
484 || acl (path, SETACL, lcnt, lacl) < 0)
485 {
486 perror (prog_name);
487 return 2;
488 }
489 break;
490 case Delete:
491 check_got_mask (acls, cnt, &got_mask, &got_def_mask);
492 if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0
493 || (lcnt = delacl (lacl, lcnt, acls, cnt)) < 0
494 || (lcnt = recompute_mask (lacl, lcnt, got_mask, got_def_mask)) < 0
495 || acl (path, SETACL, lcnt, lacl) < 0)
496 {
497 perror (prog_name);
498 return 2;
499 }
500 break;
501 case DeleteExt:
502 case DeleteDef:
503 case DeleteAll:
504 if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0
505 || (lcnt = delallacl (lacl, lcnt, action)) < 0
506 || acl (path, SETACL, lcnt, lacl) < 0)
507 {
508 perror (prog_name);
509 return 2;
510 }
511 break;
512 default:
513 check_got_mask (acls, cnt, &got_mask, &got_def_mask);
514 if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0
515 || (lcnt = modacl (lacl, lcnt, acls, cnt)) < 0
516 || (lcnt = recompute_mask (lacl, lcnt, got_mask, got_def_mask)) < 0
517 || (lcnt = addmissing (lacl, lcnt)) < 0
518 || acl (path, SETACL, lcnt, lacl) < 0)
519 {
520 perror (prog_name);
521 return 2;
522 }
523 break;
524 }
525 return 0;
526 }
527
528 static void __attribute__ ((__noreturn__))
529 usage (FILE *stream)
530 {
531 fprintf (stream, ""
532 "Usage: %s [-n] {-f ACL_FILE | -s acl_entries} FILE...\n"
533 " %s [-n] {[-bk]|[-x acl_entries] [-m acl_entries]} FILE...\n"
534 "\n"
535 "Modify file and directory access control lists (ACLs)\n"
536 "\n"
537 " -b, --remove-all remove all extended ACL entries\n"
538 " -x, --delete delete one or more specified ACL entries\n"
539 " -f, --set-file set ACL entries for FILE to ACL entries read\n"
540 " from ACL_FILE\n"
541 " -k, --remove-default remove all default ACL entries\n"
542 " -m, --modify modify one or more specified ACL entries\n"
543 " -n, --no-mask don't recalculate the effective rights mask\n"
544 " --mask do recalculate the effective rights mask\n"
545 " -s, --set set specified ACL entries on FILE\n"
546 " -V, --version print version and exit\n"
547 " -h, --help this help text\n"
548 "\n"
549 "At least one of (-b, -x, -f, -k, -m, -s) must be specified\n"
550 "\n", prog_name, prog_name);
551 if (stream == stdout)
552 {
553 printf(""
554 " Acl_entries are one or more comma-separated ACL entries from the following\n"
555 " list:\n"
556 "\n"
557 " u[ser]::perm\n"
558 " u[ser]:uid:perm\n"
559 " g[roup]::perm\n"
560 " g[roup]:gid:perm\n"
561 " m[ask]:[:]perm\n"
562 " o[ther]:[:]perm\n"
563 "\n"
564 " Default entries are like the above with the additional default identifier.\n"
565 " For example: \n"
566 "\n"
567 " d[efault]:u[ser]:uid:perm\n"
568 "\n"
569 " 'perm' is either a 3-char permissions string in the form \"rwx\" with the\n"
570 " character - for no permission, or it is the octal representation of the\n"
571 " permissions, a value from 0 (equivalent to \"---\") to 7 (\"rwx\").\n"
572 " 'uid' is a user name or a numerical uid.\n"
573 " 'gid' is a group name or a numerical gid.\n"
574 "\n"
575 "For each file given as parameter, %s will either replace its complete ACL\n"
576 "(-s, -f), or it will add, modify, or delete ACL entries.\n"
577 "\n"
578 "The following options are supported:\n"
579 "\n"
580 "-b, --remove-all\n"
581 " Remove all extended ACL entries. The base ACL entries of the owner, group\n"
582 " and others are retained. This option can be combined with the\n"
583 " -k,--remove-default option to delete all non-standard POSIX permissions.\n"
584 "\n"
585 "-x, --delete\n"
586 " Delete one or more specified entries from the file's ACL. The owner, group\n"
587 " and others entries must not be deleted. Acl_entries to be deleted should\n"
588 " be specified without permissions, as in the following list:\n"
589 "\n"
590 " u[ser]:uid[:]\n"
591 " g[roup]:gid[:]\n"
592 " m[ask][:]\n"
593 " d[efault]:u[ser][:uid]\n"
594 " d[efault]:g[roup][:gid]\n"
595 " d[efault]:m[ask][:]\n"
596 " d[efault]:o[ther][:]\n"
597 "\n"
598 "-f, --set-file\n"
599 " Take the Acl_entries from ACL_FILE one per line. Whitespace characters are\n"
600 " ignored, and the character \"#\" may be used to start a comment. The special\n"
601 " filename \"-\" indicates reading from stdin.\n"
602 " Required entries are\n"
603 " - One user entry for the owner of the file.\n"
604 " - One group entry for the group of the file.\n"
605 " - One other entry.\n"
606 " If additional user and group entries are given:\n"
607 " - A mask entry for the file group class of the file.\n"
608 " - No duplicate user or group entries with the same uid/gid.\n"
609 " If it is a directory:\n"
610 " - One default user entry for the owner of the file.\n"
611 " - One default group entry for the group of the file.\n"
612 " - One default mask entry for the file group class.\n"
613 " - One default other entry.\n"
614 "\n"
615 "-k, --remove-default\n"
616 " Remove all default ACL entries. If no default ACL entries exist, no\n"
617 " warnings are issued. This option can be combined with the -b,--remove-all\n"
618 " option to delete all non-standard POSIX permissions.\n"
619 "\n"
620 "-m, --modify\n"
621 " Add or modify one or more specified ACL entries. Acl_entries is a\n"
622 " comma-separated list of entries from the same list as above.\n"
623 "\n"
624 "-n, --no-mask\n"
625 " Valid in conjunction with -m. Do not recalculate the effective rights\n"
626 " mask. The default behavior of setfacl is to recalculate the ACL mask entry,\n"
627 " unless a mask entry was explicitly given. The mask entry is set to the\n"
628 " union of all permissions of the owning group, and all named user and group\n"
629 " entries. (These are exactly the entries affected by the mask entry).\n"
630 "\n"
631 "--mask\n"
632 " Valid in conjunction with -m. Do recalculate the effective rights mask,\n"
633 " even if an ACL mask entry was explicitly given. (See the -n option.)\n"
634 "\n"
635 "-s, --set\n"
636 " Like -f, but set the file's ACL with ACL entries specified in a\n"
637 " comma-separated list on the command line.\n"
638 "\n"
639 "While the -x and -m options may be used in the same command, the -f and -s\n"
640 "options may be used only exclusively.\n"
641 "\n"
642 "Directories may contain default ACL entries. Files created in a directory\n"
643 "that contains default ACL entries will have permissions according to the\n"
644 "combination of the current umask, the explicit permissions requested and\n"
645 "the default ACL entries.\n"
646 "\n", prog_name);
647 }
648 else
649 fprintf(stream, "Try '%s --help' for more information.\n", prog_name);
650 exit (stream == stdout ? 0 : 1);
651 }
652
653 struct option longopts[] = {
654 {"remove-all", no_argument, NULL, 'b'},
655 {"delete", required_argument, NULL, 'x'},
656 {"set-file", required_argument, NULL, 'f'},
657 {"file", required_argument, NULL, 'f'},
658 {"remove-default", no_argument, NULL, 'k'},
659 {"modify", required_argument, NULL, 'm'},
660 {"no-mask", no_argument, NULL, 'n'},
661 {"mask", no_argument, NULL, '\n'},
662 {"replace", no_argument, NULL, 'r'},
663 {"set", required_argument, NULL, 's'},
664 {"substitute", required_argument, NULL, 's'},
665 {"help", no_argument, NULL, 'h'},
666 {"version", no_argument, NULL, 'V'},
667 {0, no_argument, NULL, 0}
668 };
669 const char *opts = "bd:f:hkm:nrs:Vx:";
670
671 static void
672 print_version ()
673 {
674 printf ("setfacl (cygwin) %d.%d.%d\n"
675 "POSIX ACL modification utility\n"
676 "Copyright (C) 2000 - %s Cygwin Authors\n"
677 "This is free software; see the source for copying conditions. There is NO\n"
678 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
679 CYGWIN_VERSION_DLL_MAJOR / 1000,
680 CYGWIN_VERSION_DLL_MAJOR % 1000,
681 CYGWIN_VERSION_DLL_MINOR,
682 strrchr (__DATE__, ' ') + 1);
683 }
684
685 int
686 main (int argc, char **argv)
687 {
688 int c;
689 action_t action = NoAction;
690 aclent_t acls[MAX_ACL_ENTRIES];
691 int aclidx = 0;
692 int ret = 0;
693
694 prog_name = program_invocation_short_name;
695
696 memset (acls, 0, sizeof acls);
697 while ((c = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
698 switch (c)
699 {
700 case 'b':
701 if (action == NoAction)
702 action = DeleteExt;
703 else if (action == DeleteDef)
704 action = DeleteAll;
705 else
706 usage (stderr);
707 break;
708 case 'd': /* Backward compat */
709 case 'x':
710 if (action == NoAction)
711 action = Delete;
712 else if (action == Modify)
713 action = ModNDel;
714 else
715 usage (stderr);
716 if (! getaclentries (Delete, optarg, acls, &aclidx))
717 {
718 fprintf (stderr, "%s: illegal acl entries\n", prog_name);
719 return 2;
720 }
721 break;
722 case 'f':
723 if (action == NoAction)
724 action = Set;
725 else
726 usage (stderr);
727 if (! getaclentries (SetFromFile, optarg, acls, &aclidx))
728 {
729 fprintf (stderr, "%s: illegal acl entries\n", prog_name);
730 return 2;
731 }
732 break;
733 case 'h':
734 usage (stdout);
735 case 'k':
736 if (action == NoAction)
737 action = DeleteDef;
738 else if (action == DeleteExt)
739 action = DeleteAll;
740 else
741 usage (stderr);
742 break;
743 case 'm':
744 if (action == NoAction)
745 action = Modify;
746 else if (action == Delete)
747 action = ModNDel;
748 else
749 usage (stderr);
750 if (! getaclentries (Modify, optarg, acls, &aclidx))
751 {
752 fprintf (stderr, "%s: illegal acl entries\n", prog_name);
753 return 2;
754 }
755 break;
756 case 'n':
757 mask_opt = -1;
758 break;
759 case '\n':
760 mask_opt = 1;
761 break;
762 case 'r':
763 break;
764 case 's':
765 if (action == NoAction)
766 action = Set;
767 else
768 usage (stderr);
769 if (! getaclentries (Set, optarg, acls, &aclidx))
770 {
771 fprintf (stderr, "%s: illegal acl entries\n", prog_name);
772 return 2;
773 }
774 break;
775 case 'V':
776 print_version ();
777 return 0;
778 default:
779 fprintf (stderr, "Try `%s --help' for more information.\n", prog_name);
780 return 1;
781 }
782 if (action == NoAction)
783 usage (stderr);
784 if (optind > argc - 1)
785 usage (stderr);
786 if (action == Set)
787 switch (aclcheck (acls, aclidx, NULL))
788 {
789 case GRP_ERROR:
790 fprintf (stderr, "%s: more than one group entry.\n", prog_name);
791 return 2;
792 case USER_ERROR:
793 fprintf (stderr, "%s: more than one user entry.\n", prog_name);
794 return 2;
795 case CLASS_ERROR:
796 fprintf (stderr, "%s: more than one mask entry.\n", prog_name);
797 return 2;
798 case OTHER_ERROR:
799 fprintf (stderr, "%s: more than one other entry.\n", prog_name);
800 return 2;
801 case DUPLICATE_ERROR:
802 fprintf (stderr, "%s: duplicate additional user or group.\n", prog_name);
803 return 2;
804 case ENTRY_ERROR:
805 fprintf (stderr, "%s: invalid entry type.\n", prog_name);
806 return 2;
807 case MISS_ERROR:
808 fprintf (stderr, "%s: missing entries.\n", prog_name);
809 return 2;
810 case MEM_ERROR:
811 fprintf (stderr, "%s: out of memory.\n", prog_name);
812 return 2;
813 default:
814 break;
815 }
816 for (c = optind; c < argc; ++c)
817 ret |= setfacl (action, argv[c], acls, aclidx);
818 return ret;
819 }
This page took 0.073724 seconds and 5 git commands to generate.