zkey: Allow to associate non-existing APQNs with a key

Add option --no-apqn-check to the generate, import, change, and
validate commands to disable checking of the specified APQNs.

With this option a currently non-existing APQN can be associated
with a key. This is useful to associate APQNs that exist only on
other systems, such as disaster recovery systems, but not on the
current system. When generating keys, at least one of the specified
APQNs must be available to generate the key.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2019-05-15 10:17:16 +02:00
committed by Jan Höppner
parent d8c630e5f4
commit f97d048643
4 changed files with 215 additions and 47 deletions

View File

@@ -1085,6 +1085,11 @@ out:
return rc;
}
struct apqn_check {
bool noonlinecheck;
bool nomsg;
};
/**
* Checks an APQN value for its syntax. This is a callback function for
* function _keystore_change_association().
@@ -1093,13 +1098,14 @@ out:
* @param[in] remove if true the apqn is removed
* @param[in] set if true the apqn is set (not used here)
* @param[out] normalized normalized value on return or NULL if no change
* @param[in] private private data (not used here)
* @param[in] private private data (struct apqn_check)
*
* @returns 0 if successful, a negative errno value otherwise
*/
static int _keystore_apqn_check(const char *apqn, bool remove, bool UNUSED(set),
char **normalized, void *UNUSED(private))
char **normalized, void *private)
{
struct apqn_check *info = (struct apqn_check *)private;
int rc, card, domain;
regmatch_t pmatch[1];
regex_t reg_buf;
@@ -1125,15 +1131,16 @@ static int _keystore_apqn_check(const char *apqn, bool remove, bool UNUSED(set),
util_asprintf(normalized, "%02x.%04x", card, domain);
if (remove) {
if (remove || info->noonlinecheck) {
rc = 0;
goto out;
}
rc = _keystore_is_apqn_online(card, domain);
if (rc != 1) {
warnx("The APQN %02x.%04x is %s", card, domain,
rc == -1 ? "not a CCA card" : "not online");
if (info->nomsg == 0)
warnx("The APQN %02x.%04x is %s", card, domain,
rc == -1 ? "not a CCA card" : "not online");
rc = -EIO;
goto out;
} else {
@@ -1552,6 +1559,8 @@ static int _keystore_set_default_properties(struct properties *key_props)
* key (optional, can be NULL)
* @param[in] apqns a comma separated list of APQNs associated with this
* key (optional, can be NULL)
* @param[in] noapqncheck if true, the specified APQN(s) are not checked for
* existence and type.
* @param[in] sector_size the sector size to use with dm-crypt. It must be power
* of two and in range 512 - 4096 bytes. 0 means that
* the sector size is not specified and the system
@@ -1563,11 +1572,14 @@ static int _keystore_create_info_file(struct keystore *keystore,
const struct key_filenames *filenames,
const char *description,
const char *volumes, const char *apqns,
bool noapqncheck,
size_t sector_size,
const char *volume_type)
{
struct volume_check vol_check = { .keystore = keystore, .name = name,
.set = 0 };
struct apqn_check apqn_check = { .noonlinecheck = noapqncheck,
.nomsg = 0 };
struct properties *key_props;
char temp[10];
int rc;
@@ -1593,7 +1605,8 @@ static int _keystore_create_info_file(struct keystore *keystore,
rc = _keystore_change_association(key_props, PROP_NAME_APQNS,
apqns != NULL ? apqns : "",
"APQN", _keystore_apqn_check, NULL);
"APQN", _keystore_apqn_check,
&apqn_check);
if (rc != 0)
goto out;
@@ -1652,15 +1665,18 @@ out:
}
/**
* Extracts a card/domain pair from the specified APQns, or uses AUTOSELECT
* if no APQNs are specified.
* Extracts an online card/domain pair from the specified APQns. If none of the
* specified APQNs are online, then -ENODEV is returned.
* If no APQNs are specified at all, then it uses AUTOSELECT and returns zero.
*/
static int _keystore_get_card_domain(const char *apqns, unsigned int *card,
unsigned int *domain)
{
struct apqn_check apqn_check = { .noonlinecheck = 0, .nomsg = 1 };
char **apqn_list;
char *normalized = NULL;
int rc = 0;
int i;
*card = AUTOSELECT;
*domain = AUTOSELECT;
@@ -1672,17 +1688,23 @@ static int _keystore_get_card_domain(const char *apqns, unsigned int *card,
if (apqn_list[0] == NULL)
goto out;
rc = _keystore_apqn_check(apqn_list[0], 0, 0, &normalized, NULL);
if (normalized != NULL)
free(normalized);
if (rc != 0)
goto out;
for (i = 0; apqn_list[i] != NULL; i++) {
rc = _keystore_apqn_check(apqn_list[i], 0, 0, &normalized,
&apqn_check);
if (normalized != NULL)
free(normalized);
if (rc == -EINVAL)
goto out;
if (rc != 0)
continue;
if (sscanf(apqn_list[0], "%x.%x", card, domain) != 2) {
rc = -EINVAL;
goto out;
if (sscanf(apqn_list[i], "%x.%x", card, domain) == 2)
goto found;
}
warnx("None of the specified APQNs is online or of type CCA");
rc = -ENODEV;
found:
out:
str_list_free_string_array(apqn_list);
return rc;
@@ -1698,6 +1720,8 @@ out:
* key (optional, can be NULL)
* @param[in] apqns a comma separated list of APQNs associated with this
* key (optional, can be NULL)
* @param[in] noapqncheck if true, the specified APQN(s) are not checked for
* existence and type.
* @param[in] sector_size the sector size to use with dm-crypt. It must be power
* of two and in range 512 - 4096 bytes. 0 means that
* the sector size is not specified and the system
@@ -1714,9 +1738,10 @@ out:
*/
int keystore_generate_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, size_t sector_size,
size_t keybits, bool xts, const char *clear_key_file,
const char *volume_type, int pkey_fd)
const char *apqns, bool noapqncheck,
size_t sector_size, size_t keybits, bool xts,
const char *clear_key_file, const char *volume_type,
int pkey_fd)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct properties *key_props = NULL;
@@ -1758,7 +1783,7 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
rc = _keystore_create_info_file(keystore, name, &file_names,
description, volumes, apqns,
sector_size, volume_type);
noapqncheck, sector_size, volume_type);
if (rc != 0)
goto out_free_props;
@@ -1791,6 +1816,8 @@ out_free_key_filenames:
* key (optional, can be NULL)
* @param[in] apqns a comma separated list of APQNs associated with this
* key (optional, can be NULL)
* @param[in] noapqncheck if true, the specified APQN(s) are not checked for
* existence and type.
* @param[in] sector_size the sector size to use with dm-crypt. It must be power
* of two and in range 512 - 4096 bytes. 0 means that
* the sector size is not specified and the system
@@ -1802,7 +1829,7 @@ out_free_key_filenames:
*/
int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, size_t sector_size,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type)
{
struct key_filenames file_names = { NULL, NULL, NULL };
@@ -1842,7 +1869,7 @@ int keystore_import_key(struct keystore *keystore, const char *name,
rc = _keystore_create_info_file(keystore, name, &file_names,
description, volumes, apqns,
sector_size, volume_type);
noapqncheck, sector_size, volume_type);
if (rc != 0)
goto out_free_props;
@@ -1880,6 +1907,8 @@ out_free_key_filenames:
* key, or an APQN prefixed with '+' or '-' to add or
* remove that APQN respectively. If NULL then the APQNs
* are not changed.
* @param[in] noapqncheck if true, the specified APQN(s) are not checked for
* existence and type.
* @param[in] sector_size the sector size to use with dm-crypt. It must be power
* of two and in range 512 - 4096 bytes. 0 means that
* the sector size is not specified and the system
@@ -1893,11 +1922,13 @@ out_free_key_filenames:
*/
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, long int sector_size,
const char *volume_type)
const char *apqns, bool noapqncheck,
long int sector_size, const char *volume_type)
{
struct volume_check vol_check = { .keystore = keystore, .name = name,
.set = 0 };
struct apqn_check apqn_check = { .noonlinecheck = noapqncheck,
.nomsg = 0 };
struct key_filenames file_names = { NULL, NULL, NULL };
struct properties *key_props = NULL;
char temp[30];
@@ -1942,7 +1973,8 @@ int keystore_change_key(struct keystore *keystore, const char *name,
if (apqns != NULL) {
rc = _keystore_change_association(key_props, PROP_NAME_APQNS,
apqns, "APQN",
_keystore_apqn_check, NULL);
_keystore_apqn_check,
&apqn_check);
if (rc != 0)
goto out;
}
@@ -2276,6 +2308,7 @@ static void _keystore_print_record(struct util_rec *rec,
struct validate_info {
struct util_rec *rec;
int pkey_fd;
bool noapqncheck;
unsigned long int num_valid;
unsigned long int num_invalid;
unsigned long int num_warnings;
@@ -2429,8 +2462,9 @@ static int _keystore_process_validate(struct keystore *keystore,
"master key\n", 0);
info->num_warnings++;
}
if (_keystore_display_apqn_status(properties, name) != 0)
info->num_warnings++;
if (info->noapqncheck == 0)
if (_keystore_display_apqn_status(properties, name) != 0)
info->num_warnings++;
if (_keystore_display_volume_status(properties, name) != 0)
info->num_warnings++;
@@ -2446,11 +2480,16 @@ out:
*
* @param[in] keystore the key store
* @param[in] name_filter the name filter to select the key (can be NULL)
* @param[in] apqn_filter the APQN filter to select the key (can be NULL)
* @param[in] noapqncheck if true, the specified APQN(s) are not checked for
* existence and type.
* @param[in] pkey_fd the file descriptor of /dev/pkey
*
* @returns 0 for success or a negative errno in case of an error
*/
int keystore_validate_key(struct keystore *keystore, const char *name_filter,
const char *apqn_filter, int pkey_fd)
const char *apqn_filter, bool noapqncheck,
int pkey_fd)
{
struct validate_info info;
struct util_rec *rec;
@@ -2461,6 +2500,7 @@ int keystore_validate_key(struct keystore *keystore, const char *name_filter,
rec = _keystore_setup_record(1);
info.pkey_fd = pkey_fd;
info.noapqncheck = noapqncheck;
info.rec = rec;
info.num_valid = 0;
info.num_invalid = 0;

View File

@@ -28,25 +28,27 @@ struct keystore *keystore_new(const char *directory, bool verbose);
int keystore_generate_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, size_t sector_size,
size_t keybits, bool xts, const char *clear_key_file,
const char *volume_type, int pkey_fd);
const char *apqns, bool noapqncheck,
size_t sector_size, size_t keybits, bool xts,
const char *clear_key_file, const char *volume_type,
int pkey_fd);
int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, size_t sector_size,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type);
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, long int sector_size,
const char *volume_type);
const char *apqns, bool noapqncheck,
long int sector_size, const char *volume_type);
int keystore_rename_key(struct keystore *keystore, const char *name,
const char *newname);
int keystore_validate_key(struct keystore *keystore, const char *name_filter,
const char *apqn_filter, int pkey_fd);
const char *apqn_filter, bool noapqncheck,
int pkey_fd);
int keystore_reencipher_key(struct keystore *keystore, const char *name_filter,
const char *apqn_filter,

View File

@@ -92,6 +92,7 @@ key repository.
.IR volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-apqns | \-a
.IR card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-no\-apqn\-check ]
.RB [ \-\-sector-size | \-S
.IR bytes ]
.RB [ \-\-volume-type | \-t
@@ -141,6 +142,9 @@ options.
.BR validate | val
.RB [ \-\-name | \-N
.IR key-name ]
.RB [ \-\-apqns | \-a
.IR card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-no\-apqn\-check ]
.RB [ \-\-verbose | \-V ]
.PP
Use the
@@ -160,8 +164,21 @@ contained in the secure key repository, specify the name of the key
or a pattern containing wildcards using the
.B \-\-name
option. When wildcards are used you must quote the value.
If neither option \fIsecure\-key\-file\fP nor option
You can also specify the
.B \-\-apqns
option to validate those secure keys which are associated with the specified
cryptographic adapters (APQNs). You can use wildcards for the APQN
specification. When wildcards are used you must quote the value.
If both option
.B \-\-name
and option
.B \-\-apqns
are specified then all secure keys contained in the key repository that match
both patterns are validated.
If neither option \fIsecure\-key\-file\fP nor options
.B \-\-name
or
.B \-\-apqns
are specified, then all secure keys contained in the key repository
are validated.
.
@@ -259,7 +276,7 @@ and option
.B \-\-apqns
are specified then all secure keys
contained in the key repository that match both patterns are re-enciphered.
If all both options are omitted, then all secure keys contained in the key
If both options are omitted, then all secure keys contained in the key
repository are re-enciphered.
.PP
Re-enciphering a secure key contained in the secure key repository can be
@@ -298,6 +315,7 @@ to be installed. For the supported environments and downloads, see:
.IR volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-apqns | \-a
.IR card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-no\-apqn\-check ]
.RB [ \-\-sector-size | \-S
.IR bytes ]
.RB [ \-\-volume-type | \-t
@@ -410,6 +428,7 @@ because the secure key is contained in the LUKS2 header.
.IR [+|-]volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-apqns | \-a
.IR [+|-]card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-no\-apqn\-check ]
.RB [ \-\-sector-size | \-S
.IR bytes ]
.RB [ \-\-volume-type | \-t
@@ -685,8 +704,14 @@ Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQN) which are associated with the secure AES key in the
repository. Each APQN association specifies a card and domain number separated
by a period (like lszcrypt displays it). When at least one APQN is specified,
then the first one is used to generate the key. If no APQNs are specified,
then an APQN is selected automatically. All specified APQNs must be online.
then the first online APQN is used to generate the key. If no APQNs are
specified, then an APQN is selected automatically. All specified APQNs must be
online, unless the \fB\-\-no\-apqn\-check\fP option is specified.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-no\-apqn\-check
Do not check if the specified APQNs are available. Use this option to
associate APQNs with a secure AES key that are currently not available.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
@@ -713,6 +738,19 @@ Specifies the name of the secure key in the secure key repository. You can
use wildcards to select multiple secure keys in the secure key repository.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP
Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQNs). You can use wildcards in the APQN specification.
All secure keys contained in the secure key repository
which are associated with the specified APQNs are validated.
Each APQN specifies a card and domain number separated by a period (like
lszcrypt displays it).
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-no\-apqn\-check
Do not check if the associated APQNs are available.
This option is only used for secure keys contained in the secure key repository.
.
.
.
@@ -796,7 +834,13 @@ This option is only used for secure keys contained in the secure key repository.
Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQN) which are associated with the secure AES key in the
repository. Each APQN association specifies a card and domain number separated
by a period (like lszcrypt displays it). All specified APQNs must be online.
by a period (like lszcrypt displays it). All specified APQNs must be online,
unless option \fB\-\-no\-apqn\-check\fP is specified.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-no\-apqn\-check
Do not check if the specified APQNs are available. Use this option to
associate APQNs with a secure AES key that are currently not available.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
@@ -915,7 +959,13 @@ To remove an APQN from the associated APQNs, prefix the APQN with a \fI-\fP.
To set (replace) the APQN association do not specify a prefix.
You cannot mix \fI+\fP and \fI-\fP in one specification. You can either add or
remove (or set) the associations with one command.
All APQNs being added or set (replaced) must be online.
All APQNs being added or set (replaced) must be online, unless option
\fB\-\-no\-apqn\-check\fP is specified.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-no\-apqn\-check
Do not check if the specified APQNs are available. Use this option to
associate APQNs with a secure AES key that are currently not available.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-S ", " \-\-sector-size\~\fIbytes\fP

View File

@@ -67,6 +67,7 @@ static struct zkey_globals {
char *description;
char *volumes;
char *apqns;
bool noapqncheck;
long int sector_size;
char *volume_type;
char *newname;
@@ -115,6 +116,7 @@ static struct zkey_globals {
#define OPT_CRYPTSETUP_TRIES 259
#define OPT_CRYPTSETUP_OPEN 260
#define OPT_CRYPTSETUP_FORMAT 261
#define OPT_NO_APQN_CHECK 262
/*
* Configuration of command line options
@@ -186,6 +188,14 @@ static struct util_opt opt_vec[] = {
"repository",
.command = COMMAND_GENERATE,
},
{
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
.desc = "Do not check if the specified APQN(s) are available. "
"Use this option to associate APQN(s) with a secure "
"AES key that are currently not available.",
.command = COMMAND_GENERATE,
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "sector-size", required_argument, NULL, 'S'},
.argument = "bytes",
@@ -295,6 +305,12 @@ static struct util_opt opt_vec[] = {
"associated with specific crypto cards",
.command = COMMAND_VALIDATE,
},
{
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
.desc = "Do not check if the associated APQN(s) are available",
.command = COMMAND_VALIDATE,
.flags = UTIL_OPT_FLAG_NOSHORT,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -330,6 +346,14 @@ static struct util_opt opt_vec[] = {
"repository",
.command = COMMAND_IMPORT,
},
{
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
.desc = "Do not check if the specified APQN(s) are available. "
"Use this option to associate APQN(s) with a secure "
"AES key that are currently not available.",
.command = COMMAND_IMPORT,
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "sector-size", required_argument, NULL, 'S'},
.argument = "512|4096",
@@ -467,6 +491,14 @@ static struct util_opt opt_vec[] = {
"specify '-CARD.DOMAIN[,...]'",
.command = COMMAND_CHANGE,
},
{
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
.desc = "Do not check if the specified APQN(s) are available. "
"Use this option to associate APQN(s) with a secure "
"AES key that are currently not available.",
.command = COMMAND_CHANGE,
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "sector-size", required_argument, NULL, 'S'},
.argument = "0|512|4096",
@@ -1013,8 +1045,9 @@ static int command_generate_repository(void)
g.sector_size = 0;
rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.sector_size, g.keybits, g.xts,
g.clearkeyfile, g.volume_type, g.pkey_fd);
g.apqns, g.noapqncheck, g.sector_size,
g.keybits, g.xts, g.clearkeyfile,
g.volume_type, g.pkey_fd);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1033,6 +1066,12 @@ static int command_generate(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.apqns == NULL && g.noapqncheck) {
warnx("Option '--noapqncheck' is only valid together with "
"the '--apqns|-a' option");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.name != NULL)
return command_generate_repository();
if (g.pos_arg != NULL) {
@@ -1048,6 +1087,12 @@ static int command_generate(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.noapqncheck) {
warnx("Option '--noapqncheck' is not valid for "
"generating a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.description != NULL) {
warnx("Option '--description|-d' is not valid for "
"generating a key outside of the repository");
@@ -1271,6 +1316,12 @@ static int command_validate_file(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.noapqncheck) {
warnx("Option '--noapqncheck' is not valid for "
"validating a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
/* Read the secure key to be re-enciphered */
secure_key = read_secure_key(g.pos_arg, &secure_key_size, g.verbose);
@@ -1324,7 +1375,15 @@ static int command_validate_repository(void)
{
int rc;
rc = keystore_validate_key(g.keystore, g.name, g.apqns, g.pkey_fd);
if (g.apqns == NULL && g.noapqncheck) {
warnx("Option '--noapqncheck' is only valid together with "
"the '--apqns|-a' option");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = keystore_validate_key(g.keystore, g.name, g.apqns, g.noapqncheck,
g.pkey_fd);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1361,9 +1420,16 @@ static int command_import(void)
if (g.sector_size < 0)
g.sector_size = 0;
if (g.apqns == NULL && g.noapqncheck) {
warnx("Option '--noapqncheck' is only valid together with "
"the '--apqns|-a' option");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.sector_size, g.pos_arg,
g.volume_type);
g.apqns, g.noapqncheck, g.sector_size,
g.pos_arg, g.volume_type);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1434,9 +1500,16 @@ static int command_change(void)
misc_print_required_parm("--name/-N");
return EXIT_FAILURE;
}
if (g.apqns == NULL && g.noapqncheck) {
warnx("Option '--noapqncheck' is only valid together with "
"the '--apqns|-a' option");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.sector_size, g.volume_type);
g.apqns, g.noapqncheck, g.sector_size,
g.volume_type);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1686,6 +1759,9 @@ int main(int argc, char *argv[])
case 'a':
g.apqns = optarg;
break;
case OPT_NO_APQN_CHECK:
g.noapqncheck = 1;
break;
case 'S':
g.sector_size = strtol(optarg, &endp, 0);
if (*optarg == '\0' || *endp != '\0' ||