diff --git a/winsup/doc/ChangeLog b/winsup/doc/ChangeLog index 05cf5199a..fdf3708ec 100644 --- a/winsup/doc/ChangeLog +++ b/winsup/doc/ChangeLog @@ -1,3 +1,7 @@ +2015-04-16 Corinna Vinschen + + * utils.xml (setfacl): Show new option output. + 2015-04-16 Corinna Vinschen * utils.xml (getfacl): Show new option output. diff --git a/winsup/doc/utils.xml b/winsup/doc/utils.xml index d711cf242..09df8e02b 100644 --- a/winsup/doc/utils.xml +++ b/winsup/doc/utils.xml @@ -1698,34 +1698,31 @@ Example: regtool.exe get '\user\software\Microsoft\Clock\iFormat' setfacl -Usage: setfacl [-r] {-f ACL_FILE | -s acl_entries} FILE... - setfacl [-r] {-b|[-d acl_entries] [-m acl_entries]} FILE... +Usage: %s {-f ACL_FILE | -s acl_entries} FILE...\n" + %s {-b|[-x acl_entries] [-m acl_entries]} FILE...\n" +Modify file and directory access control lists (ACLs)\n" -Modify file and directory access control lists (ACLs) + -b, --remove-all remove all extended ACL entries\n" + -x, --delete delete one or more specified ACL entries\n" + -f, --file set ACL entries for FILE to ACL entries read\n" + from ACL_FILE\n" + -k, --remove-default remove all default ACL entries\n" + -m, --modify modify one or more specified ACL entries\n" + -n, --no-mask don't recalculate the effective rights mask\n" + --mask do recalculate the effective rights mask\n" + -s, --substitute substitute specified ACL entries on FILE\n" + -V, --version print version and exit\n" + -h, --help this help text\n" - -b, --remove-all remove all extended ACL entries - -d, --delete delete one or more specified ACL entries - -f, --file set ACL entries for FILE to ACL entries read - from a ACL_FILE - -k, --remove-default - remove all default ACL entries - -m, --modify modify one or more specified ACL entries - -r, --replace replace mask entry with maximum permissions - needed for the file group class - -s, --substitute substitute specified ACL entries for the - ACL of FILE - -h, --help output usage information and exit - -V, --version output version information and exit - -At least one of (-b, -d, -f, -k, -m, -s) must be specified +At least one of (-b, -x, -f, -k, -m, -s) must be specified\n" For each file given as parameter, setfacl will either replace its complete ACL (-s, -f), or it will add, modify, or delete ACL entries. - For more information on Cygwin and Windows ACLs, see see in the Cygwin User's Guide. + For more information on Cygwin and Windows ACLs, see + in the Cygwin User's Guide. Acl_entries are one or more comma-separated ACL entries from the following list: @@ -1752,13 +1749,14 @@ At least one of (-b, -d, -f, -k, -m, -s) must be specified The following options are supported: - -b Remove all extended ACL entries. The base - ACL entries of the owner, group and others are retained. + -b,--remove-all Remove all + extended ACL entries. The base ACL entries of the owner, group and + others are retained. - -d Delete one or more specified entries from the - file's ACL. The owner, group and others entries must not be deleted. - Acl_entries to be deleted should be specified without permissions, as in - the following list: + -x,--delete Delete one or + more specified entries from the file's ACL. The owner, group and others + entries must not be deleted. Acl_entries to be deleted should be + specified without permissions, as in the following list: u[ser]:uid[:] g[roup]:gid[:] @@ -1769,11 +1767,12 @@ At least one of (-b, -d, -f, -k, -m, -s) must be specified d[efault]:o[ther][:] - -f Take the Acl_entries from ACL_FILE one per - line. Whitespace characters are ignored, and the character "#" may be - used to start a comment. The special filename "-" indicates reading from - stdin. Note that you can use this with getfacl and - setfacl to copy ACLs from one file to another: + -f,--file Take the Acl_entries + from ACL_FILE one per line. Whitespace characters are ignored, and the + character "#" may be used to start a comment. The special filename "-" + indicates reading from stdin. Note that you can use this with + getfacl and setfacl to copy ACLs + from one file to another: $ getfacl source_file | setfacl -f - target_file @@ -1789,22 +1788,31 @@ $ getfacl source_file | setfacl -f - target_file file, one default group entry for the group of the file, one default mask entry for the file group class, and one default other entry. - -k Remove all default ACL entries. If no default - ACL entries exist, no warnings are issued. + -k,--remove-default Remove all + default ACL entries. If no default ACL entries exist, no warnings are + issued. - -m Add or modify one or more specified ACL - entries. Acl_entries is a comma-separated list of entries from the same - list as above. + -m,--modify Add or modify one + or more specified ACL entries. Acl_entries is a comma-separated list of + entries from the same list as above. - -r Causes the permissions specified in the mask - entry to be ignored and replaced by the maximum permissions needed for - the file group class. + -n,--no-mask Valid in + conjunction with -m. Do not recalculate the effective rights mask. + The default behavior of setfacl is to recalculate the ACL mask entry, + unless a mask entry was explicitly given. The mask entry is set to + the union of all permissions of the owning group, and all named user + and group entries. (These are exactly the entries affected by the + mask entry). - -s Like -f, but substitute the - file's ACL with Acl_entries specified in a comma-separated list on the - command line. + --mask Valid in conjunction with -m. Do + recalculate the effective rights mask, even if an ACL mask entry was + explicitly given. (See the -n option.) - While the -d and -m options + -s,--substitute Like + -f, but substitute the file's ACL with Acl_entries + specified in a comma-separated list on the command line. + + While the -x and -m options may be used in the same command, the -f and -s options may be used only exclusively. diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 5e7025da6..a48f8693f 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,19 @@ +2015-04-16 Corinna Vinschen + + * setfacl.c: Align more to Linux tool. + (delacl): New function to delete acl entries only. + (modacl): Drop delete functionality. Add handling of recomputing the + mask and default mask values. + (delallacl): Rename from delacl. + (setfacl): Call delacl in Delete case. Call delallacl in DeleteAll + and DeleteDef case. + (usage): Accommodate new options. Rearrange and rephrase slightly. + (longopts): Emit 'x' in --delete case. Add --no-mask and --mask + options. + (opts): Add -x and -n options. + (main): Handle -d and -x the same. Handle -n and --mask options. + Drop handling for -r option. + 2015-04-16 Corinna Vinschen * getfacl.c (usage): Align more closely to Linux version. Add new diff --git a/winsup/utils/setfacl.c b/winsup/utils/setfacl.c index ba674d009..20a42f33c 100644 --- a/winsup/utils/setfacl.c +++ b/winsup/utils/setfacl.c @@ -1,7 +1,7 @@ /* setfacl.c - Copyright 2000, 2001, 2002, 2003, 2006, 2008, 2009, 2010, 2011, 2014 - Red Hat Inc. + Copyright 2000, 2001, 2002, 2003, 2006, 2008, 2009, 2010, 2011, 2014, + 2015 Red Hat Inc. Written by Corinna Vinschen @@ -53,6 +53,8 @@ typedef enum { SetFromFile } action_t; +int mask_opt = 0; + mode_t getperm (char *in) { if (isdigit ((unsigned char) *in) && !in[1]) @@ -239,7 +241,7 @@ searchace (aclent_t *aclp, int nentries, int type, int id) } int -modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt) +delacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt) { int t, s, i; @@ -249,25 +251,115 @@ modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt) (src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1); if (t < 0) return -1; - if (src[s].a_perm == ILLEGAL_MODE) + if (t < tcnt) { - if (t < tcnt) - { - for (i = t + 1; i < tcnt; ++i) - tgt[i - 1] = tgt[i]; - --tcnt; - } - } - else - { - tgt[t] = src[s]; - if (t >= tcnt) - ++tcnt; + for (i = t + 1; i < tcnt; ++i) + tgt[i - 1] = tgt[i]; + --tcnt; } } return tcnt; } +int +modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt) +{ + int t, s; + int recompute_mask = 0, recompute_def_mask = 0; + int need_mask = 0, need_def_mask = 0; + int has_mask = 0, has_def_mask = 0; + int mask_idx = -1, def_mask_idx = -1; + mode_t mask = 0, def_mask = 0; + + /* Replace or add given acl entries. */ + for (s = 0; s < scnt; ++s) + { + t = searchace (tgt, MAX_ACL_ENTRIES, src[s].a_type, + (src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1); + if (t < 0) + return -1; + tgt[t] = src[s]; + if (t >= tcnt) + ++tcnt; + /* Note if CLASS_OBJ and/or DEF_CLASS_OBJ are present in input. */ + if (src[s].a_type == CLASS_OBJ) + has_mask = 1; + else if (src[s].a_type == DEF_CLASS_OBJ) + has_def_mask = 1; + else if (src[s].a_type & ACL_DEFAULT) + recompute_def_mask = 1; + else + recompute_mask = 1; + } + /* Now recompute mask, if requested (default) */ + for (t = 0; t < tcnt; ++t) + { + switch (tgt[t].a_type) + { + case USER: + case GROUP: + /* Do we need a CLASS_OBJ at all? */ + need_mask = 1; + /*FALLTHRU*/ + case GROUP_OBJ: + /* Compute resulting maximum mask. */ + mask |= tgt[t].a_perm; + break; + case CLASS_OBJ: + /* Do we already have a CLASS_OBJ? */ + mask_idx = t; + break; + case DEF_USER: + case DEF_GROUP: + /* Do we need a DEF_CLASS_OBJ at all? */ + need_def_mask = 1; + /*FALLTHRU*/ + case DEF_GROUP_OBJ: + /* Compute resulting maximum default mask. */ + def_mask |= tgt[t].a_perm; + break; + case DEF_CLASS_OBJ: + /* Do we already have a DEF_CLASS_OBJ? */ + def_mask_idx = t; + break; + } + } + /* Recompute mask, if requested */ + if (recompute_mask && need_mask && mask_opt >= 0 + && (mask_opt > 0 || !has_mask)) + { + if (mask_idx >= 0) + t = mask_idx; + else + t = searchace (tgt, MAX_ACL_ENTRIES, CLASS_OBJ, -1); + if (t < 0) + return -1; + if (t >= tcnt) + ++tcnt; + tgt[t].a_type = CLASS_OBJ; + tgt[t].a_id = -1; + tgt[t].a_perm = mask; + } + /* Recompute default mask, if requested */ + if (recompute_def_mask && need_def_mask && mask_opt >= 0 + && (mask_opt > 0 || !has_def_mask)) + { + if (def_mask_idx >= 0) + t = def_mask_idx; + else + t = searchace (tgt, MAX_ACL_ENTRIES, DEF_CLASS_OBJ, -1); + if (t < 0) + return -1; + if (t >= tcnt) + ++tcnt; + tgt[t].a_type = DEF_CLASS_OBJ; + tgt[t].a_id = -1; + tgt[t].a_perm = def_mask; + } + + return tcnt; +} + int addmissing (aclent_t *tgt, int tcnt) { @@ -333,7 +425,7 @@ addmissing (aclent_t *tgt, int tcnt) } int -delacl (aclent_t *tgt, int tcnt, action_t action) +delallacl (aclent_t *tgt, int tcnt, action_t action) { int t; @@ -369,7 +461,7 @@ setfacl (action_t action, const char *path, aclent_t *acls, int cnt) break; case Delete: if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0 - || (lcnt = modacl (lacl, lcnt, acls, cnt)) < 0 + || (lcnt = delacl (lacl, lcnt, acls, cnt)) < 0 || (lcnt = acl (path, SETACL, lcnt, lacl)) < 0) { perror (prog_name); @@ -379,7 +471,7 @@ setfacl (action_t action, const char *path, aclent_t *acls, int cnt) case DeleteAll: case DeleteDef: if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0 - || (lcnt = delacl (lacl, lcnt, action)) < 0 + || (lcnt = delallacl (lacl, lcnt, action)) < 0 || (lcnt = acl (path, SETACL, lcnt, lacl)) < 0) { perror (prog_name); @@ -404,114 +496,126 @@ static void usage (FILE *stream) { fprintf (stream, "" - "Usage: %s [-r] {-f ACL_FILE | -s acl_entries} FILE...\n" - " %s [-r] {-b|[-d acl_entries] [-m acl_entries]} FILE...\n" - "\n" - "Modify file and directory access control lists (ACLs)\n" - "\n" - " -b, --remove-all remove all extended ACL entries\n" - " -d, --delete delete one or more specified ACL entries\n" - " -f, --file set ACL entries for FILE to ACL entries read\n" - " from a ACL_FILE\n" - " -k, --remove-default\n" - " remove all default ACL entries\n" - " -m, --modify modify one or more specified ACL entries\n" - " -r, --replace replace mask entry with maximum permissions\n" - " needed for the file group class\n" - " -s, --substitute substitute specified ACL entries for the\n" - " ACL of FILE\n" - " -h, --help output usage information and exit\n" - " -V, --version output version information and exit\n" - "\n" - "At least one of (-b, -d, -f, -k, -m, -s) must be specified\n" - "\n", prog_name, prog_name); - if (stream == stdout) - { - printf("" - " Acl_entries are one or more comma-separated ACL entries \n" - " from the following list:\n" - "\n" - " u[ser]::perm\n" - " u[ser]:uid:perm\n" - " g[roup]::perm\n" - " g[roup]:gid:perm\n" - " m[ask]:perm\n" - " o[ther]:perm\n" - "\n" - " Default entries are like the above with the additional\n" - " default identifier. For example: \n" - "\n" - " d[efault]:u[ser]:uid:perm\n" - "\n" - " 'perm' is either a 3-char permissions string in the form\n" - " \"rwx\" with the character - for no permission\n" - " or it is the octal representation of the permissions, a\n" - " value from 0 (equivalent to \"---\") to 7 (\"rwx\").\n" - " 'uid' is a user name or a numerical uid.\n" - " 'gid' is a group name or a numerical gid.\n" - "\n" - "\n" - "For each file given as parameter, %s will either replace its\n" - "complete ACL (-s, -f), or it will add, modify, or delete ACL\n" - "entries.\n" - "\n" - "The following options are supported:\n" - "\n" - "-b Remove all extended ACL entries. The base ACL entries of the\n" - " owner, group and others are retained.\n" - "\n" - "-d Delete one or more specified entries from the file's ACL.\n" - " The owner, group and others entries must not be deleted.\n" - " Acl_entries to be deleted should be specified without\n" - " permissions, as in the following list:\n" - "\n" - " u[ser]:uid[:]\n" - " g[roup]:gid[:]\n" - " m[ask][:]\n" - " d[efault]:u[ser][:uid]\n" - " d[efault]:g[roup][:gid]\n" - " d[efault]:m[ask][:]\n" - " d[efault]:o[ther][:]\n" - "\n" - "-f Take the Acl_entries from ACL_FILE one per line. Whitespace\n" - " characters are ignored, and the character \"#\" may be used\n" - " to start a comment. The special filename \"-\" indicates\n" - " reading from stdin.\n" - " Required entries are\n" - " - One user entry for the owner of the file.\n" - " - One group entry for the group of the file.\n" - " - One other entry.\n" - " If additional user and group entries are given:\n" - " - A mask entry for the file group class of the file.\n" - " - No duplicate user or group entries with the same uid/gid.\n" - " If it is a directory:\n" - " - One default user entry for the owner of the file.\n" - " - One default group entry for the group of the file.\n" - " - One default mask entry for the file group class.\n" - " - One default other entry.\n" - "\n" - "-k Remove all default ACL entries. If no default ACL entries\n" - " exist, no warnings are issued.\n" - "\n" - "-m Add or modify one or more specified ACL entries.\n" - " Acl_entries is a comma-separated list of entries from the \n" - " same list as above.\n" - "\n" - "-r Causes the permissions specified in the mask entry to be\n" - " ignored and replaced by the maximum permissions needed for\n" - " the file group class.\n" - "\n" - "-s Like -f, but substitute the file's ACL with Acl_entries\n" - " specified in a comma-separated list on the command line.\n" - "\n" - "While the -d and -m options may be used in the same command, the\n" - "-f and -s options may be used only exclusively.\n" - "\n" - "Directories may contain default ACL entries. Files created\n" - "in a directory that contains default ACL entries will have\n" - "permissions according to the combination of the current umask,\n" - "the explicit permissions requested and the default ACL entries\n" - "\n", prog_name); + "Usage: %s {-f ACL_FILE | -s acl_entries} FILE...\n" + " %s {-b|[-x acl_entries] [-m acl_entries]} FILE...\n" + "\n" + "Modify file and directory access control lists (ACLs)\n" + "\n" + " -b, --remove-all remove all extended ACL entries\n" + " -x, --delete delete one or more specified ACL entries\n" + " -f, --file set ACL entries for FILE to ACL entries read\n" + " from ACL_FILE\n" + " -k, --remove-default remove all default ACL entries\n" + " -m, --modify modify one or more specified ACL entries\n" + " -n, --no-mask don't recalculate the effective rights mask\n" + " --mask do recalculate the effective rights mask\n" + " -s, --substitute substitute specified ACL entries on FILE\n" + " -V, --version print version and exit\n" + " -h, --help this help text\n" + "\n" + "At least one of (-b, -x, -f, -k, -m, -s) must be specified\n" + "\n", prog_name, prog_name); + if (stream == stdout) + { + printf("" + " Acl_entries are one or more comma-separated ACL entries \n" + " from the following list:\n" + "\n" + " u[ser]::perm\n" + " u[ser]:uid:perm\n" + " g[roup]::perm\n" + " g[roup]:gid:perm\n" + " m[ask]:perm\n" + " o[ther]:perm\n" + "\n" + " Default entries are like the above with the additional\n" + " default identifier. For example: \n" + "\n" + " d[efault]:u[ser]:uid:perm\n" + "\n" + " 'perm' is either a 3-char permissions string in the form\n" + " \"rwx\" with the character - for no permission\n" + " or it is the octal representation of the permissions, a\n" + " value from 0 (equivalent to \"---\") to 7 (\"rwx\").\n" + " 'uid' is a user name or a numerical uid.\n" + " 'gid' is a group name or a numerical gid.\n" + "\n" + "\n" + "For each file given as parameter, %s will either replace its\n" + "complete ACL (-s, -f), or it will add, modify, or delete ACL\n" + "entries.\n" + "\n" + "The following options are supported:\n" + "\n" + "-b, --remove-all\n" + " Remove all extended ACL entries. The base ACL entries of the\n" + " owner, group and others are retained.\n" + "\n" + "-x, --delete\n" + " Delete one or more specified entries from the file's ACL.\n" + " The owner, group and others entries must not be deleted.\n" + " Acl_entries to be deleted should be specified without\n" + " permissions, as in the following list:\n" + "\n" + " u[ser]:uid[:]\n" + " g[roup]:gid[:]\n" + " m[ask][:]\n" + " d[efault]:u[ser][:uid]\n" + " d[efault]:g[roup][:gid]\n" + " d[efault]:m[ask][:]\n" + " d[efault]:o[ther][:]\n" + "\n" + "-f, --file\n" + " Take the Acl_entries from ACL_FILE one per line. Whitespace\n" + " characters are ignored, and the character \"#\" may be used\n" + " to start a comment. The special filename \"-\" indicates\n" + " reading from stdin.\n" + " Required entries are\n" + " - One user entry for the owner of the file.\n" + " - One group entry for the group of the file.\n" + " - One other entry.\n" + " If additional user and group entries are given:\n" + " - A mask entry for the file group class of the file.\n" + " - No duplicate user or group entries with the same uid/gid.\n" + " If it is a directory:\n" + " - One default user entry for the owner of the file.\n" + " - One default group entry for the group of the file.\n" + " - One default mask entry for the file group class.\n" + " - One default other entry.\n" + "\n" + "-k, --remove-default\n" + " Remove all default ACL entries. If no default ACL entries exist,\n" + " no warnings are issued.\n" + "\n" + "-m, --modify\n" + " Add or modify one or more specified ACL entries. Acl_entries is\n" + " a comma-separated list of entries from the same list as above.\n" + "\n" + "-n, --no-mask\n" + " Valid in conjunction with -m. Do not recalculate the effective\n" + " rights mask. The default behavior of setfacl is to recalculate the\n" + " ACL mask entry, unless a mask entry was explicitly given. The\n" + " mask entry is set to the union of all permissions of the owning\n" + " group, and all named user and group entries. (These are exactly\n" + " the entries affected by the mask entry).\n" + "\n" + "--mask\n" + " Valid in conjunction with -m. Do recalculate the effective rights\n" + " mask, even if an ACL mask entry was explicitly given. (See the\n" + " -n option.)\n" + "\n" + "-s, --substitute\n" + " Like -f, but substitute the file's ACL with ACL entries\n" + " specified in a comma-separated list on the command line.\n" + "\n" + "While the -x and -m options may be used in the same command, the\n" + "-f and -s options may be used only exclusively.\n" + "\n" + "Directories may contain default ACL entries. Files created\n" + "in a directory that contains default ACL entries will have\n" + "permissions according to the combination of the current umask,\n" + "the explicit permissions requested and the default ACL entries\n" + "\n", prog_name); } else fprintf(stream, "Try '%s --help' for more information.\n", prog_name); @@ -519,17 +623,19 @@ usage (FILE *stream) struct option longopts[] = { {"remove-all", no_argument, NULL, 'b'}, - {"delete", required_argument, NULL, 'd'}, + {"delete", required_argument, NULL, 'x'}, {"file", required_argument, NULL, 'f'}, {"remove-default", no_argument, NULL, 'k'}, {"modify", required_argument, NULL, 'm'}, + {"no-mask", required_argument, NULL, 'n'}, + {"mask", required_argument, NULL, '\n'}, {"replace", no_argument, NULL, 'r'}, {"substitute", required_argument, NULL, 's'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, {0, no_argument, NULL, 0} }; -const char *opts = "bd:f:hkm:rs:V"; +const char *opts = "bd:f:hkm:nrs:Vx"; static void print_version () @@ -550,7 +656,6 @@ main (int argc, char **argv) { int c; action_t action = NoAction; - int ropt = 0; aclent_t acls[MAX_ACL_ENTRIES]; int aclidx = 0; int ret = 0; @@ -570,7 +675,8 @@ main (int argc, char **argv) return 1; } break; - case 'd': + case 'd': /* Backward compat */ + case 'x': if (action == NoAction) action = Delete; else if (action == Modify) @@ -628,14 +734,13 @@ main (int argc, char **argv) return 2; } break; + case 'n': + mask_opt = -1; + break; + case '\n': + mask_opt = 1; + break; case 'r': - if (!ropt) - ropt = 1; - else - { - usage (stderr); - return 1; - } break; case 's': if (action == NoAction)