Add mask recomputation as on Linux

* 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.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2015-04-16 17:57:53 +02:00
parent bd57946148
commit baacff7c79
4 changed files with 314 additions and 181 deletions

View File

@ -1,3 +1,7 @@
2015-04-16 Corinna Vinschen <corinna@vinschen.de>
* utils.xml (setfacl): Show new option output.
2015-04-16 Corinna Vinschen <corinna@vinschen.de>
* utils.xml (getfacl): Show new option output.

View File

@ -1698,34 +1698,31 @@ Example: regtool.exe get '\user\software\Microsoft\Clock\iFormat'
<title>setfacl</title>
<screen>
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"
</screen>
<para> For each file given as parameter, <command>setfacl</command> will
either replace its complete ACL (<literal>-s</literal>,
<literal>-f</literal>), or it will add, modify, or delete ACL entries.
For more information on Cygwin and Windows ACLs, see see <xref
linkend="ntsec"/> in the Cygwin User's Guide. </para>
For more information on Cygwin and Windows ACLs, see
<xref linkend="ntsec"/> in the Cygwin User's Guide. </para>
<para> 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
<para> The following options are supported: </para>
<para> <literal>-b</literal> Remove all extended ACL entries. The base
ACL entries of the owner, group and others are retained.</para>
<para> <literal>-b</literal>,<literal>--remove-all</literal> Remove all
extended ACL entries. The base ACL entries of the owner, group and
others are retained.</para>
<para> <literal>-d</literal> 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:
<para> <literal>-x</literal>,<literal>--delete</literal> 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:
<screen>
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][:]
</screen> </para>
<para> <literal>-f</literal> 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 <command>getfacl</command> and
<command>setfacl</command> to copy ACLs from one file to another:
<para> <literal>-f</literal>,<literal>--file</literal> 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
<command>getfacl</command> and <command>setfacl</command> to copy ACLs
from one file to another:
<screen>
$ getfacl source_file | setfacl -f - target_file
</screen> </para>
@ -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. </para>
<para> <literal>-k</literal> Remove all default ACL entries. If no default
ACL entries exist, no warnings are issued. </para>
<para> <literal>-k</literal>,<literal>--remove-default</literal> Remove all
default ACL entries. If no default ACL entries exist, no warnings are
issued. </para>
<para> <literal>-m</literal> Add or modify one or more specified ACL
entries. Acl_entries is a comma-separated list of entries from the same
list as above. </para>
<para> <literal>-m</literal>,<literal>--modify</literal> Add or modify one
or more specified ACL entries. Acl_entries is a comma-separated list of
entries from the same list as above. </para>
<para> <literal>-r</literal> Causes the permissions specified in the mask
entry to be ignored and replaced by the maximum permissions needed for
the file group class. </para>
<para> <literal>-n</literal>,<literal>--no-mask</literal> 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). </para>
<para> <literal>-s</literal> Like <literal>-f</literal>, but substitute the
file's ACL with Acl_entries specified in a comma-separated list on the
command line. </para>
<para> <literal>--mask</literal> Valid in conjunction with -m. Do
recalculate the effective rights mask, even if an ACL mask entry was
explicitly given. (See the -n option.) </para>
<para> While the <literal>-d</literal> and <literal>-m</literal> options
<para> <literal>-s</literal>,<literal>--substitute</literal> Like
<literal>-f</literal>, but substitute the file's ACL with Acl_entries
specified in a comma-separated list on the command line. </para>
<para> While the <literal>-x</literal> and <literal>-m</literal> options
may be used in the same command, the <literal>-f</literal> and
<literal>-s</literal> options may be used only exclusively. </para>

View File

@ -1,3 +1,19 @@
2015-04-16 Corinna Vinschen <corinna@vinschen.de>
* 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 <corinna@vinschen.de>
* getfacl.c (usage): Align more closely to Linux version. Add new

View File

@ -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,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)