summaryrefslogtreecommitdiffstats
path: root/winsup/utils
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/utils')
-rw-r--r--winsup/utils/ChangeLog28
-rw-r--r--winsup/utils/getfacl.c197
-rw-r--r--winsup/utils/setfacl.c375
3 files changed, 407 insertions, 193 deletions
diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog
index ac6eb98eb..104aae244 100644
--- a/winsup/utils/ChangeLog
+++ b/winsup/utils/ChangeLog
@@ -1,3 +1,31 @@
+2015-11-18 Corinna Vinschen <corinna@vinschen.de>
+
+ Reapply POSIX ACL changes.
+
+ * getfacl.c (main): Special-case SYSTEM and Admins group. Add comments.
+
+ * 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.
+
+ * getfacl.c (usage): Align more closely to Linux version. Add new
+ options -c, -e, -E. Change formatting to accommodate longer options.
+ (longopts): Rename --noname to --numeric. Keep --noname for backward
+ compatibility. Add --omit-header, --all-effective and --no-effective
+ options.
+ (opts): Add -c, -e and -E option.
+ (main): Handle new -c, -e, and -E options.
+
2015-10-22 Yaakov Selkowitz <yselkowi@redhat.com>
* getconf.c (conf_table): Add LEVEL*_CACHE_* variables.
diff --git a/winsup/utils/getfacl.c b/winsup/utils/getfacl.c
index 0bc484877..45e5e2090 100644
--- a/winsup/utils/getfacl.c
+++ b/winsup/utils/getfacl.c
@@ -66,61 +66,68 @@ static void
usage (FILE * stream)
{
fprintf (stream, "Usage: %s [-adn] FILE [FILE2...]\n"
- "\n"
- "Display file and directory access control lists (ACLs).\n"
- "\n"
- " -a, --access display the file access control list\n"
- " -d, --default display the default access control list\n"
- " -h, --help print help explaining the command line options\n"
- " -n, --noname display user and group IDs instead of names\n"
- " -V, --version output version information and exit\n"
- "\n"
- "When multiple files are specified on the command line, a blank\n"
- "line separates the ACLs for each file.\n", prog_name);
+ "\n"
+ "Display file and directory access control lists (ACLs).\n"
+ "\n"
+ " -a, --access display the file access control list only\n"
+ " -d, --default display the default access control list only\n"
+ " -c, --omit-header do not display the comment header\n"
+ " -e, --all-effective print all effective rights\n"
+ " -E, --no-effective print no effective rights\n"
+ " -n, --numeric print numeric user/group identifiers\n"
+ " -V, --version print version and exit\n"
+ " -h, --help this help text\n"
+ "\n"
+ "When multiple files are specified on the command line, a blank\n"
+ "line separates the ACLs for each file.\n", prog_name);
if (stream == stdout)
{
fprintf (stream, ""
- "For each argument that is a regular file, special file or\n"
- "directory, getfacl displays the owner, the group, and the ACL.\n"
- "For directories getfacl displays additionally the default ACL.\n"
- "\n"
- "With no options specified, getfacl displays the filename, the\n"
- "owner, the group, the setuid (s), setgid (s), and sticky (t)\n"
- "bits if available, and both the ACL and the default ACL, if it\n"
- "exists.\n"
- "\n"
- "The format for ACL output is as follows:\n"
- " # file: filename\n"
- " # owner: name or uid\n"
- " # group: name or uid\n"
- " # flags: sst\n"
- " user::perm\n"
- " user:name or uid:perm\n"
- " group::perm\n"
- " group:name or gid:perm\n"
- " mask:perm\n"
- " other:perm\n"
- " default:user::perm\n"
- " default:user:name or uid:perm\n"
- " default:group::perm\n"
- " default:group:name or gid:perm\n"
- " default:mask:perm\n"
- " default:other:perm\n"
- "\n");
+ "For each argument that is a regular file, special file or\n"
+ "directory, getfacl displays the owner, the group, and the ACL.\n"
+ "For directories getfacl displays additionally the default ACL.\n"
+ "\n"
+ "With no options specified, getfacl displays the filename, the\n"
+ "owner, the group, the setuid (s), setgid (s), and sticky (t)\n"
+ "bits if available, and both the ACL and the default ACL, if it\n"
+ "exists.\n"
+ "\n"
+ "The format for ACL output is as follows:\n"
+ " # file: filename\n"
+ " # owner: name or uid\n"
+ " # group: name or uid\n"
+ " # flags: sst\n"
+ " user::perm\n"
+ " user:name or uid:perm\n"
+ " group::perm\n"
+ " group:name or gid:perm\n"
+ " mask:perm\n"
+ " other:perm\n"
+ " default:user::perm\n"
+ " default:user:name or uid:perm\n"
+ " default:group::perm\n"
+ " default:group:name or gid:perm\n"
+ " default:mask:perm\n"
+ " default:other:perm\n"
+ "\n");
}
}
struct option longopts[] = {
{"access", no_argument, NULL, 'a'},
{"all", no_argument, NULL, 'a'},
+ {"omit-header", no_argument, NULL, 'c'},
+ {"all-effective", no_argument, NULL, 'e'},
+ {"no-effective", no_argument, NULL, 'E'},
{"default", no_argument, NULL, 'd'},
{"dir", no_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
- {"noname", no_argument, NULL, 'n'},
+ {"noname", no_argument, NULL, 'n'}, /* Backward compat */
+ {"numeric", no_argument, NULL, 'n'},
{"version", no_argument, NULL, 'V'},
{0, no_argument, NULL, 0}
};
-const char *opts = "adhnV";
+const char *opts = "acdeEhnV";
static void
print_version ()
@@ -142,8 +149,11 @@ main (int argc, char **argv)
int c;
int ret = 0;
int aopt = 0;
+ int copt = 0;
+ int eopt = 0;
int dopt = 0;
int nopt = 0;
+ int istty = isatty (fileno (stdout));
struct stat st;
aclent_t acls[MAX_ACL_ENTRIES];
@@ -155,9 +165,18 @@ main (int argc, char **argv)
case 'a':
aopt = 1;
break;
+ case 'c':
+ copt = 1;
+ break;
case 'd':
dopt = 1;
break;
+ case 'e':
+ eopt = 1;
+ break;
+ case 'E':
+ eopt = -1;
+ break;
case 'h':
usage (stdout);
return 0;
@@ -179,6 +198,8 @@ main (int argc, char **argv)
for (; optind < argc; ++optind)
{
int i, num_acls;
+ mode_t mask = S_IRWXO, def_mask = S_IRWXO;
+
if (stat (argv[optind], &st)
|| (num_acls = acl (argv[optind], GETACL, MAX_ACL_ENTRIES, acls)) < 0)
{
@@ -187,28 +208,42 @@ main (int argc, char **argv)
ret = 2;
continue;
}
- printf ("# file: %s\n", argv[optind]);
- if (nopt)
+ if (!copt)
{
- printf ("# owner: %lu\n", (unsigned long)st.st_uid);
- printf ("# group: %lu\n", (unsigned long)st.st_gid);
+ printf ("# file: %s\n", argv[optind]);
+ if (nopt)
+ {
+ printf ("# owner: %lu\n", (unsigned long)st.st_uid);
+ printf ("# group: %lu\n", (unsigned long)st.st_gid);
+ }
+ else
+ {
+ printf ("# owner: %s\n", username (st.st_uid));
+ printf ("# group: %s\n", groupname (st.st_gid));
+ }
+ if (st.st_mode & (S_ISUID | S_ISGID | S_ISVTX))
+ printf ("# flags: %c%c%c\n", (st.st_mode & S_ISUID) ? 's' : '-',
+ (st.st_mode & S_ISGID) ? 's' : '-',
+ (st.st_mode & S_ISVTX) ? 't' : '-');
}
- else
+ for (i = 0; i < num_acls; ++i)
{
- printf ("# owner: %s\n", username (st.st_uid));
- printf ("# group: %s\n", groupname (st.st_gid));
+ if (acls[i].a_type == CLASS_OBJ)
+ mask = acls[i].a_perm;
+ else if (acls[i].a_type == DEF_CLASS_OBJ)
+ def_mask = acls[i].a_perm;
}
- if (st.st_mode & (S_ISUID | S_ISGID | S_ISVTX))
- printf ("# flags: %c%c%c\n", (st.st_mode & S_ISUID) ? 's' : '-',
- (st.st_mode & S_ISGID) ? 's' : '-',
- (st.st_mode & S_ISVTX) ? 't' : '-');
for (i = 0; i < num_acls; ++i)
{
+ int n = 0;
+ int print_effective = 0;
+ mode_t effective = acls[i].a_perm;
+
if (acls[i].a_type & ACL_DEFAULT)
{
if (aopt)
continue;
- printf ("default:");
+ n += printf ("default:");
}
else if (dopt)
continue;
@@ -219,18 +254,18 @@ main (int argc, char **argv)
break;
case USER:
if (nopt)
- printf ("user:%lu:", (unsigned long)acls[i].a_id);
+ n += printf ("user:%lu:", (unsigned long)acls[i].a_id);
else
- printf ("user:%s:", username (acls[i].a_id));
+ n += printf ("user:%s:", username (acls[i].a_id));
break;
case GROUP_OBJ:
- printf ("group::");
+ n += printf ("group::");
break;
case GROUP:
if (nopt)
- printf ("group:%lu:", (unsigned long)acls[i].a_id);
+ n += printf ("group:%lu:", (unsigned long)acls[i].a_id);
else
- printf ("group:%s:", groupname (acls[i].a_id));
+ n += printf ("group:%s:", groupname (acls[i].a_id));
break;
case CLASS_OBJ:
printf ("mask:");
@@ -239,7 +274,53 @@ main (int argc, char **argv)
printf ("other:");
break;
}
- printf ("%s\n", permstr (acls[i].a_perm));
+ n += printf ("%s", permstr (acls[i].a_perm));
+ switch (acls[i].a_type)
+ {
+ case USER:
+ case GROUP_OBJ:
+ effective = acls[i].a_perm & mask;
+ print_effective = 1;
+ break;
+ case GROUP:
+ /* Special case SYSTEM and Admins group: The mask only
+ applies to them as far as the execute bit is concerned. */
+ if (acls[i].a_id == 18 || acls[i].a_id == 544)
+ effective = acls[i].a_perm & (mask | S_IROTH | S_IWOTH);
+ else
+ effective = acls[i].a_perm & mask;
+ print_effective = 1;
+ break;
+ case DEF_USER:
+ case DEF_GROUP_OBJ:
+ effective = acls[i].a_perm & def_mask;
+ print_effective = 1;
+ break;
+ case DEF_GROUP:
+ /* Special case SYSTEM and Admins group: The mask only
+ applies to them as far as the execute bit is concerned. */
+ if (acls[i].a_id == 18 || acls[i].a_id == 544)
+ effective = acls[i].a_perm & (def_mask | S_IROTH | S_IWOTH);
+ else
+ effective = acls[i].a_perm & def_mask;
+ print_effective = 1;
+ break;
+ }
+ if (print_effective && eopt >= 0
+ && (eopt > 0 || effective != acls[i].a_perm))
+ {
+ if (istty)
+ {
+ n = 40 - n;
+ if (n <= 0)
+ n = 1;
+ printf ("%*s", n, " ");
+ }
+ else
+ putchar ('\t');
+ printf ("#effective:%s", permstr (effective));
+ }
+ putchar ('\n');
}
putchar ('\n');
}
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 <vinschen@redhat.com>
@@ -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,22 +251,112 @@ 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;
- }
+ 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)
{
- tgt[t] = src[s];
- if (t >= tcnt)
- ++tcnt;
+ 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;
}
@@ -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)