-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Another pass at the patch.
This time -Z is not optional, only --context is.
- -Z or --context indicates use default label.
- --context=CTX uses previous behavior.
You can now do
cp -aZ and cp -Za and the right thing will happen.
I have turned off the warning SELinux is disabled if you specify -Z or
- --context. Now it will quietly ignore. I can add a comment to the usage if
you think it is worth while. The reason I want to do this, is to allow
people to do "mkdir -Z /var/run/XYZ" in a script and not worry about whether
or not SELinux is enabled. Currently we have lots of init script that do
things like
mkdir -Z /var/run/XYZ
restorecon /var/run/XYZ
Where restorecon quietly exits if SELinux is disabled.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iEYEARECAAYFAlCcMEsACgkQrlYvE4MpobMtdgCfduYKrGB3Igb4XJyi6AcPW/MV
pqIAoNXqgO4Sw0lbUt6xpWOacpG2dj2N
=3JB1
-----END PGP SIGNATURE-----
diff --git a/gnulib b/gnulib
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit d245e6ddd6ab2624d0d83acd8f111454f984f50f
+Subproject commit d245e6ddd6ab2624d0d83acd8f111454f984f50f-dirty
diff --git a/src/chcon.c b/src/chcon.c
index 34e92e4..0cf8fa6 100644
--- a/src/chcon.c
+++ b/src/chcon.c
@@ -355,7 +355,7 @@ Usage: %s [OPTION]... CONTEXT FILE...\n\
"),
program_name, program_name, program_name);
fputs (_("\
-Change the security context of each FILE to CONTEXT.\n\
+Change the SELinux security context of each FILE to CONTEXT.\n\
With --reference, change the security context of each FILE to that of RFILE.\n\
\n\
"), stdout);
diff --git a/src/copy.c b/src/copy.c
index 16aed03..c91a756 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -60,6 +60,7 @@
#include "write-any-file.h"
#include "areadlink.h"
#include "yesno.h"
+#include "selinux.h"
#if USE_XATTR
# include <attr/error_context.h>
@@ -837,41 +838,18 @@ copy_reg (char const *src_name, char const *dst_name,
1) the src context may prohibit writing, and
2) because it's more consistent to use the same context
that is used when the destination file doesn't already exist. */
- if (x->preserve_security_context && 0 <= dest_desc)
+ if ((x->set_security_context || x->preserve_security_context) && 0 <= dest_desc)
{
bool all_errors = (!x->data_copy_required
|| x->require_preserve_context);
bool some_errors = !all_errors && !x->reduce_diagnostics;
- security_context_t con = NULL;
- if (getfscreatecon (&con) < 0)
- {
- if (all_errors || (some_errors && !errno_unsupported (errno)))
- error (0, errno, _("failed to get file system create context"));
- if (x->require_preserve_context)
- {
- return_val = false;
- goto close_src_and_dst_desc;
- }
- }
-
- if (con)
- {
- if (fsetfilecon (dest_desc, con) < 0)
- {
- if (all_errors || (some_errors && !errno_unsupported (errno)))
- error (0, errno,
- _("failed to set the security context of %s to %s"),
- quote_n (0, dst_name), quote_n (1, con));
- if (x->require_preserve_context)
- {
- return_val = false;
- freecon (con);
- goto close_src_and_dst_desc;
- }
- }
- freecon (con);
- }
+ if (restorecon(dst_name, 0, x->preserve_security_context) < 0) {
+ if (all_errors || (some_errors && !errno_unsupported (errno)))
+ error (0, errno, _("failed to set file system context on %s"), quote_n (0, dst_name));
+ return_val = false;
+ goto close_src_and_dst_desc;
+ }
}
if (dest_desc < 0 && x->unlink_dest_after_failed_open)
@@ -892,6 +870,9 @@ copy_reg (char const *src_name, char const *dst_name,
if (*new_dst)
{
+ if (x->set_security_context && (! x->require_preserve_context))
+ defaultcon(dst_name, dst_mode);
+
open_with_O_CREAT:;
int open_flags = O_WRONLY | O_CREAT | O_BINARY;
@@ -974,6 +955,9 @@ copy_reg (char const *src_name, char const *dst_name,
goto close_src_and_dst_desc;
}
+ if (x->set_security_context && ! x->preserve_security_context)
+ restorecon(dst_name, 1, false);
+
/* --attributes-only overrides --reflink. */
if (data_copy_required && x->reflink_mode)
{
@@ -2092,6 +2076,9 @@ copy_internal (char const *src_name, char const *dst_name,
emit_verbose (src_name, dst_name,
backup_succeeded ? dst_backup : NULL);
+ if (x->set_security_context)
+ restorecon(dst_name, 1, false);
+
if (rename_succeeded)
*rename_succeeded = true;
@@ -2231,6 +2218,11 @@ copy_internal (char const *src_name, char const *dst_name,
return false;
}
}
+ else
+ {
+ if (x->set_security_context)
+ restorecon(dst_name, 1, false);
+ }
if (S_ISDIR (src_mode))
{
diff --git a/src/copy.h b/src/copy.h
index 440d3bb..d6044aa 100644
--- a/src/copy.h
+++ b/src/copy.h
@@ -159,6 +159,9 @@ struct cp_options
bool preserve_timestamps;
bool explicit_no_preserve_mode;
+ /* If true, attempt to set specified security context */
+ bool set_security_context;
+
/* Enabled for mv, and for cp by the --preserve=links option.
If true, attempt to preserve in the destination files any
logical hard links between the source files. If used with cp's
diff --git a/src/cp.c b/src/cp.c
index 61b31af..2bf6a7b 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -141,6 +141,7 @@ static struct option const long_opts[] =
{"target-directory", required_argument, NULL, 't'},
{"update", no_argument, NULL, 'u'},
{"verbose", no_argument, NULL, 'v'},
+ {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@@ -229,6 +230,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
destination file is missing\n\
-v, --verbose explain what is being done\n\
-x, --one-file-system stay on this file system\n\
+ -Z, --context[=CTX] set security context of destination file to default type or to CTX if specified\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -786,6 +788,7 @@ cp_option_init (struct cp_options *x)
x->explicit_no_preserve_mode = false;
x->preserve_security_context = false;
x->require_preserve_context = false;
+ x->set_security_context = false;
x->preserve_xattr = false;
x->reduce_diagnostics = false;
x->require_preserve_xattr = false;
@@ -877,8 +880,10 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
break;
case PRESERVE_CONTEXT:
- x->preserve_security_context = on_off;
- x->require_preserve_context = on_off;
+ if (! x->set_security_context) {
+ x->preserve_security_context = on_off;
+ x->require_preserve_context = on_off;
+ }
break;
case PRESERVE_XATTR:
@@ -892,7 +897,7 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
x->preserve_ownership = on_off;
x->preserve_links = on_off;
x->explicit_no_preserve_mode = !on_off;
- if (selinux_enabled)
+ if (selinux_enabled && (! x->set_security_context))
x->preserve_security_context = on_off;
x->preserve_xattr = on_off;
break;
@@ -935,7 +940,7 @@ main (int argc, char **argv)
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:T",
+ while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
long_opts, NULL))
!= -1)
{
@@ -962,7 +967,7 @@ main (int argc, char **argv)
x.preserve_mode = true;
x.preserve_timestamps = true;
x.require_preserve = true;
- if (selinux_enabled)
+ if (selinux_enabled && (! x.set_security_context))
x.preserve_security_context = true;
x.preserve_xattr = true;
x.reduce_diagnostics = true;
@@ -1092,6 +1097,23 @@ main (int argc, char **argv)
x.one_file_system = true;
break;
+
+ case 'Z':
+ /* politely decline if we're not on a selinux-enabled kernel. */
+ if( selinux_enabled ) {
+ if (optarg) {
+ /* if there's a security_context given set new path
+ components to that context, too */
+ if ( setfscreatecon(optarg) < 0 ) {
+ (void) fprintf(stderr, _("cannot set default security context %s\n"), optarg);
+ exit( 1 );
+ }
+ }
+ x.set_security_context = true;
+ x.preserve_security_context = false;
+ }
+ break;
+
case 'S':
make_backups = true;
backup_suffix_string = optarg;
diff --git a/src/install.c b/src/install.c
index 8ea5491..0b9b317 100644
--- a/src/install.c
+++ b/src/install.c
@@ -280,6 +280,7 @@ cp_option_init (struct cp_options *x)
x->data_copy_required = true;
x->require_preserve = false;
x->require_preserve_context = false;
+ x->set_security_context = false;
x->require_preserve_xattr = false;
x->recursive = false;
x->sparse_mode = SPARSE_AUTO;
@@ -641,8 +642,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
--preserve-context preserve SELinux security context\n\
- -Z, --context=CONTEXT set SELinux security context of files and directories\
-\n\
+ -Z, --context[=CTX] set security context of destination file to default type or to CTX if specified\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
@@ -783,7 +783,7 @@ main (int argc, char **argv)
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
- while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z:", long_options,
+ while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options,
NULL)) != -1)
{
switch (optc)
@@ -860,18 +860,20 @@ main (int argc, char **argv)
"this kernel is not SELinux-enabled"));
break;
}
+ if ( x.set_security_context || scontext ) {
+ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]);
+ exit( 1 );
+ }
x.preserve_security_context = true;
- use_default_selinux_context = false;
break;
case 'Z':
- if ( ! selinux_enabled)
- {
- error (0, 0, _("WARNING: ignoring --context (-Z); "
- "this kernel is not SELinux-enabled"));
- break;
- }
- scontext = optarg;
- use_default_selinux_context = false;
+ if ( selinux_enabled )
+ {
+ if (optarg)
+ scontext = optarg;
+ else
+ x.set_security_context = true;
+ }
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
diff --git a/src/local.mk b/src/local.mk
index f40f681..113544a 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -306,6 +306,10 @@ RELEASE_YEAR = \
`sed -n '/.*COPYRIGHT_YEAR = \([0-9][0-9][0-9][0-9]\) };/s//\1/p' \
$(top_srcdir)/lib/version-etc.c`
+selinux_sources = \
+ src/selinux.c \
+ src/selinux.h
+
copy_sources = \
src/copy.c \
src/cp-hash.c \
@@ -317,12 +321,12 @@ copy_sources = \
# to install before applying any user-specified name transformations.
transform = s/ginstall/install/; $(program_transform_name)
-src_ginstall_SOURCES = src/install.c src/prog-fprintf.c $(copy_sources)
+src_ginstall_SOURCES = src/install.c src/prog-fprintf.c $(copy_sources) $(selinux_sources)
# This is for the '[' program. Automake transliterates '[' and '/' to '_'.
src___SOURCES = src/lbracket.c
-src_cp_SOURCES = src/cp.c $(copy_sources)
+src_cp_SOURCES = src/cp.c $(copy_sources) $(selinux_sources)
src_dir_SOURCES = src/ls.c src/ls-dir.c
src_vdir_SOURCES = src/ls.c src/ls-vdir.c
src_id_SOURCES = src/id.c src/group-list.c
@@ -335,12 +339,15 @@ src_kill_SOURCES = src/kill.c src/operand2sig.c
src_realpath_SOURCES = src/realpath.c src/relpath.c src/relpath.h
src_timeout_SOURCES = src/timeout.c src/operand2sig.c
-src_mv_SOURCES = src/mv.c src/remove.c $(copy_sources)
+src_mv_SOURCES = src/mv.c src/remove.c $(copy_sources) $(selinux_sources)
src_rm_SOURCES = src/rm.c src/remove.c
-src_mkdir_SOURCES = src/mkdir.c src/prog-fprintf.c
+src_mkdir_SOURCES = src/mkdir.c src/prog-fprintf.c $(selinux_sources)
src_rmdir_SOURCES = src/rmdir.c src/prog-fprintf.c
+src_mkfifo_SOURCES = src/mkfifo.c $(selinux_sources)
+src_mknod_SOURCES = src/mknod.c $(selinux_sources)
+
src_df_SOURCES = src/df.c src/find-mount-point.c
src_stat_SOURCES = src/stat.c src/find-mount-point.c
diff --git a/src/mkdir.c b/src/mkdir.c
index 32f79d4..548030c 100644
--- a/src/mkdir.c
+++ b/src/mkdir.c
@@ -29,6 +29,7 @@
#include "prog-fprintf.h"
#include "quote.h"
#include "savewd.h"
+#include "selinux.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "mkdir"
@@ -65,8 +66,8 @@ Mandatory arguments to long options are mandatory for short options too.\n\
-m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\
-p, --parents no error if existing, make parent directories as needed\n\
-v, --verbose print a message for each created directory\n\
- -Z, --context=CTX set the SELinux security context of each created\n\
- directory to CTX\n\
+ -Z, --context[=CTX] set the SELinux security context of each created\n\
+ directory to default type or to CTX if specified\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -91,6 +92,9 @@ struct mkdir_options
/* File mode bits affected by MODE. */
mode_t mode_bits;
+ /* Set the SELinux File Context. */
+ int set_security_context;
+
/* If not null, format to use when reporting newly made directories. */
char const *created_directory_format;
};
@@ -113,6 +117,9 @@ static int
make_ancestor (char const *dir, char const *component, void *options)
{
struct mkdir_options const *o = options;
+
+ if (o->set_security_context)
+ defaultcon(dir, S_IFDIR);
int r = mkdir (component, o->ancestor_mode);
if (r == 0)
{
@@ -146,6 +153,7 @@ main (int argc, char **argv)
options.mode = S_IRWXUGO;
options.mode_bits = 0;
options.created_directory_format = NULL;
+ options.set_security_context = false;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
@@ -155,7 +163,7 @@ main (int argc, char **argv)
atexit (close_stdout);
- while ((optc = getopt_long (argc, argv, "pm:vZ:", longopts, NULL)) != -1)
+ while ((optc = getopt_long (argc, argv, "pm:vZ", longopts, NULL)) != -1)
{
switch (optc)
{
@@ -169,7 +177,13 @@ main (int argc, char **argv)
options.created_directory_format = _("created directory %s");
break;
case 'Z':
- scontext = optarg;
+ if ( is_selinux_enabled() > 0 )
+ {
+ if (optarg)
+ scontext = optarg;
+ else
+ options.set_security_context = true;
+ }
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
diff --git a/src/mkfifo.c b/src/mkfifo.c
index e524c44..3253640 100644
--- a/src/mkfifo.c
+++ b/src/mkfifo.c
@@ -26,6 +26,7 @@
#include "error.h"
#include "modechange.h"
#include "quote.h"
+#include "selinux.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "mkfifo"
@@ -60,7 +61,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
-m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\
"), stdout);
fputs (_("\
- -Z, --context=CTX set the SELinux security context of each NAME to CTX\n\
+ -Z, --context[=CTX] set the SELinux security context of each NAME to default type or CTX if specified\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -74,6 +75,7 @@ main (int argc, char **argv)
{
mode_t newmode;
char const *specified_mode = NULL;
+ int set_security_context = false;
int exit_status = EXIT_SUCCESS;
int optc;
security_context_t scontext = NULL;
@@ -86,7 +88,7 @@ main (int argc, char **argv)
atexit (close_stdout);
- while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
+ while ((optc = getopt_long (argc, argv, "m:Z", longopts, NULL)) != -1)
{
switch (optc)
{
@@ -94,7 +96,13 @@ main (int argc, char **argv)
specified_mode = optarg;
break;
case 'Z':
- scontext = optarg;
+ if ( is_selinux_enabled() > 0 )
+ {
+ if (optarg)
+ scontext = optarg;
+ else
+ set_security_context = true;
+ }
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -128,6 +136,8 @@ main (int argc, char **argv)
}
for (; optind < argc; ++optind)
+ if (set_security_context)
+ defaultcon(argv[optind], S_IFIFO);
if (mkfifo (argv[optind], newmode) != 0)
{
error (0, errno, _("cannot create fifo %s"), quote (argv[optind]));
diff --git a/src/mknod.c b/src/mknod.c
index dc158b4..6977ba8 100644
--- a/src/mknod.c
+++ b/src/mknod.c
@@ -27,6 +27,7 @@
#include "modechange.h"
#include "quote.h"
#include "xstrtol.h"
+#include "selinux.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "mknod"
@@ -62,7 +63,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
-m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\
"), stdout);
fputs (_("\
- -Z, --context=CTX set the SELinux security context of NAME to CTX\n\
+ -Z, --context[=CTX] set the SELinux security context of NAME to default type or to CTX if specified\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -94,6 +95,7 @@ main (int argc, char **argv)
int expected_operands;
mode_t node_type;
security_context_t scontext = NULL;
+ int set_security_context = false;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
@@ -103,7 +105,7 @@ main (int argc, char **argv)
atexit (close_stdout);
- while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
+ while ((optc = getopt_long (argc, argv, "m:Z", longopts, NULL)) != -1)
{
switch (optc)
{
@@ -111,7 +113,13 @@ main (int argc, char **argv)
specified_mode = optarg;
break;
case 'Z':
- scontext = optarg;
+ if ( is_selinux_enabled() > 0 )
+ {
+ if (optarg)
+ scontext = optarg;
+ else
+ set_security_context = true;
+ }
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -212,6 +220,9 @@ main (int argc, char **argv)
error (EXIT_FAILURE, 0, _("invalid device %s %s"), s_major, s_minor);
#endif
+ if (set_security_context)
+ defaultcon(argv[optind], node_type);
+
if (mknod (argv[optind], newmode | node_type, device) != 0)
error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
}
diff --git a/src/mv.c b/src/mv.c
index 5b08fdd..683c649 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -55,6 +55,7 @@ static bool remove_trailing_slashes;
static struct option const long_options[] =
{
{"backup", optional_argument, NULL, 'b'},
+ {"context", no_argument, NULL, 'Z'},
{"force", no_argument, NULL, 'f'},
{"interactive", no_argument, NULL, 'i'},
{"no-clobber", no_argument, NULL, 'n'},
@@ -120,6 +121,7 @@ cp_option_init (struct cp_options *x)
x->preserve_timestamps = true;
x->explicit_no_preserve_mode= false;
x->preserve_security_context = selinux_enabled;
+ x->set_security_context = false;
x->reduce_diagnostics = false;
x->data_copy_required = true;
x->require_preserve = false; /* FIXME: maybe make this an option */
@@ -317,6 +319,7 @@ If you specify more than one of -i, -f, -n, only the final one takes effect.\n\
than the destination file or when the\n\
destination file is missing\n\
-v, --verbose explain what is being done\n\
+ -Z, --context set security context of destination file to default type\n \
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -351,6 +354,7 @@ main (int argc, char **argv)
bool no_target_directory = false;
int n_files;
char **file;
+ bool selinux_enabled = (0 < is_selinux_enabled ());
initialize_main (&argc, &argv);
set_program_name (argv[0]);
@@ -369,7 +373,7 @@ main (int argc, char **argv)
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
- while ((c = getopt_long (argc, argv, "bfint:uvS:T", long_options, NULL))
+ while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL))
!= -1)
{
switch (c)
@@ -418,6 +422,13 @@ main (int argc, char **argv)
make_backups = true;
backup_suffix_string = optarg;
break;
+ case 'Z':
+ /* politely decline if we're not on a selinux-enabled kernel. */
+ if( selinux_enabled ) {
+ x.preserve_security_context = false;
+ x.set_security_context = true;
+ }
+ break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
diff --git a/src/runcon.c b/src/runcon.c
index 875441f..7162f65 100644
--- a/src/runcon.c
+++ b/src/runcon.c
@@ -85,7 +85,7 @@ Usage: %s CONTEXT COMMAND [args]\n\
or: %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
"), program_name, program_name);
fputs (_("\
-Run a program in a different security context.\n\
+Run a program in a different SELinux security context.\n\
With neither CONTEXT nor COMMAND, print the current security context.\n\
\n\
CONTEXT Complete security context\n\
diff --git a/src/system.h b/src/system.h
index 06cc803..b5d750c 100644
--- a/src/system.h
+++ b/src/system.h
@@ -330,7 +330,7 @@ enum
#define GETOPT_VERSION_OPTION_DECL \
"version", no_argument, NULL, GETOPT_VERSION_CHAR
#define GETOPT_SELINUX_CONTEXT_OPTION_DECL \
- "context", required_argument, NULL, 'Z'
+ "context", optional_argument, NULL, 'Z'
#define case_GETOPT_HELP_CHAR \
case GETOPT_HELP_CHAR: \