From b142eaa27cf8fb959f35dd514719741e1284e912 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Jun 01 2017 17:44:42 +0000 Subject: Clean up error message and return codes Update documentation to match the new behavior. --- diff --git a/luksmeta.8 b/luksmeta.8 index 32f0355..7ef9cd7 100644 --- a/luksmeta.8 +++ b/luksmeta.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "LUKSMETA" "1" "May 2017" "" "" +.TH "LUKSMETA" "1" "June 2017" "" "" . .SH "NAME" \fBluksmeta\fR \- Utility for storing metadata in a LUKSv1 header @@ -25,10 +25,10 @@ \fBluksmeta wipe\fR \-d DEVICE \-s SLOT [\-u UUID] [\-f] . .SH "OVERVIEW" -The \fBluksmeta\fR utility enables an administrator to store metadata in the gap between the end of the LUKSv1 header and the start of the encrypted data\. +The \fBluksmeta\fR utility enables an administrator to store metadata in the gap between the end of the LUKSv1 header and the start of the encrypted data\. This is useful for storing data that is available before the volume is unlocked, usually for use during the volume unlock process\. . .P -The metadata is stored in a series of UUID\-typed slots, allowing multiple blocks of metadata\. Although the \fBluksmeta\fR slots are inspired by the LUKS slots, they are functionally independent and share only a casual relationship\. +The metadata is stored in a series of UUID\-typed slots, allowing multiple blocks of metadata\. Although the \fBluksmeta\fR slots are inspired by the LUKS slots, they are functionally independent and share only a casual relationship\. Slots merely provide a hint that a given chunk of metadata is associated with a specific LUKSv1 password (in a slot with the same number)\. However, \fBluksmeta\fR itself is indifferent to the relationship between a LUKSv1 slot and the correspondly numbered \fBluksmeta\fR slot, with one exception (detailed below)\. . .P After a LUKSv1 volume is initialized using \fBcryptsetup\fR(8), it must also be initialized for metadata storage by \fBluksmeta init\fR\. Once this is complete, the device is ready to store medata\. @@ -37,16 +37,25 @@ After a LUKSv1 volume is initialized using \fBcryptsetup\fR(8), it must also be Data can be written to a slot using \fBluksmeta save\fR or read from a slot using \fBluksmeta load\fR\. You can also erase the data in an existing slot using \fBluksmeta wipe\fR or query the slots using \fBluksmeta show\fR\. . .SH "UUID GENERATION" -It is often presumed that saving metadata to a slot requires a specific UUID\. This is incorrect\. The UUID is not in any way special, it simply identifies the type of data you store in the slot\. If you are defining a new type of metadata, simply generate a random UUID and use it to identify your metadata\. The easiest way to generate a UUID is to use \fBuuidgen\fR(1)\. +It is often presumed that saving metadata to a slot requires a specific UUID or that there is an official registry of UUID types\. This is incorrect\. +. +.P +UUID stands for Universally Unique IDentifier\. UUIDs are a standardized, widely\-used data type used for identification without a central registry\. For the relevant standards, see ISO 9834\-8:2005 and RFC 4122\. +. +.P +UUIDs are large enough that collision is practically impossible\. So if your application wants to store data in a \fBluksmeta\fR slot, just generate your own UUID and use it consistently to refer to your type of data\. If you have multiple types of data, feel free to generate multiple UUIDs\. +. +.P +The easiest way to generate a UUID is to use \fBuuidgen\fR(1)\. However, any compliant UUID generator will suffice\. . .SH "INITIALIZATION" Before reading or writing metadata, the LUKSv1 block device must be initialized for metadata storage\. Two commands help with this process: \fBluksmeta test\fR and \fBluksmeta init\fR\. . .P -The \fBluksmeta test\fR command simply checks an existing block device to see if it is initialized for metadata storage\. It returns zero if the device is already initialized\. Otherwise, it returns non\-zero\. +The \fBluksmeta test\fR command simply checks an existing block device to see if it is initialized for metadata storage\. This command does not provide any output, so be sure to check its return code (see below)\. . .P -The \fBluksmeta init\fR command initializes the LUKSv1 block device for metadata storage\. This process will wipe out any data in the LUKSv1 header gap\. For this reason, you should use great care with this command\. However, if the block device already contains a \fBluksmeta\fR header, no modifications will be performed\. Because initialization is a destructive operation, this command will require user confirmation before any data is written, unless the \fB\-f\fR option is supplied\. +The \fBluksmeta init\fR command initializes the LUKSv1 block device for metadata storage\. This process will wipe out any data in the LUKSv1 header gap\. For this reason, this command will require user confirmation before any data is written, unless the \fB\-f\fR option is supplied\. Note that this command succeeds if the device is already initialized\. . .SH "METADATA STATE" The \fBluksmeta show\fR command displays the current state of slots on the LUKSv1 block device\. If no slot is specified, it prints a table consisting of the slot number, the corresponding LUKSv1 slot state and the UUID of the data stored in the \fBluksmeta\fR slot (or "empty" if no data is stored)\. If a slot is specified, this command simply prints out the UUID of the data in the slot\. If the slot does not contain data, it prints nothing\. @@ -55,41 +64,135 @@ The \fBluksmeta show\fR command displays the current state of slots on the LUKSv Managing the metadata in the slots is performed with three commands: \fBluksmeta save\fR, \fBluksmeta load\fR and \fBluksmeta wipe\fR\. These commands write metadata to a slot, read metadata from a slot and erase metadata in a slot, respectively\. . .P -The \fBluksmeta save\fR command reads metadata on standard input and writes it to the specified slot using the specified UUID\. If no slot is specified, the metadata is written to the first empty slot using the specified UUID\. In this case, the slot written to is printed to standard output\. This command will never overwrite existing data\. To replace data in a slot you will need to execute \fBluksmeta wipe\fR before \fBluksmeta save\fR\. +The \fBluksmeta save\fR command reads metadata on standard input and writes it to the specified slot using the specified UUID\. If no slot is specified, \fBluksmeta\fR will search for the first slot number for which the LUKSv1 slot is inactive and the \fBluksmeta\fR slot is empty\. This represents the only official correlation between LUKSv1 slots and \fBluksmeta\fR slots\. In this case, the metadata is written to the first applicable slot using the specified UUID and the slot number is printed to standard output\. In either case, this command will never overwrite existing data\. To replace data in a slot you will need to execute \fBluksmeta wipe\fR before \fBluksmeta save\fR\. . .P The \fBluksmeta load\fR command reads data from the specified slot and writes it to standard output\. If a UUID is specified, the command will verify that the UUID associated with the metadata in the slot matches the specified UUID\. This type check helps to ensure that you always receive the type of data you are expecting as output\. If the UUIDs do not match, the command will fail\. . .P -The \fBluksmeta wipe\fR command erases the data from the given slot\. If a UUID is specified, the command will verify that the UUID associated with the metadata in the slot matches the specified UUID\. This type check helps to ensure that you only erase the data you intended to erase\. Because this is a destructive operation, this command will require user confirmation before any data is erased, unless the \fB\-f\fR option is supplied\. +The \fBluksmeta wipe\fR command erases the data from the given slot\. If a UUID is specified, the command will verify that the UUID associated with the metadata in the slot matches the specified UUID\. This type check helps to ensure that you only erase the data you intended to erase\. Because this is a destructive operation, this command will require user confirmation before any data is erased, unless the \fB\-f\fR option is supplied\. Note that this command succeeds if you attempt to wipe a slot that is already empty\. . .SH "CAVEATS" -The ammount of storage in the LUKSv1 header gap is extremely limited\. It also varies based upon the configuration used by LUKSv1 at device initialization time\. In some LUKSv1 configurations, there is not even enough space for all the metadata slots even at the smallest possible slot size\. +The amount of storage in the LUKSv1 header gap is extremely limited\. It also varies based upon the configuration used by LUKSv1 at device initialization time\. In some LUKSv1 configurations, there is not even enough space for all the metadata slots even at the smallest possible slot size\. . .P -During the design of this utility, we considered it likely that users would want to reduce the number of available slots in exchange for more storage space in the remaining slots\. In order to provide this flexibility, the amount of storage available per\-slot is dynamic\. Put simply, slots are not a fixed size\. This means that it is possible (and even somewhat likely) to encounter an error during \fBluksmeta save\fR indicating that there is insufficient space\. +During the design of this utility, we considered it likely that users would want to reduce the number of usable slots in exchange for more storage space in the slots used\. In order to provide this flexibility, the amount of storage available per\-slot is dynamic\. Put simply, slots are not a fixed size\. This means that it is possible (and even somewhat likely) to encounter an error during \fBluksmeta save\fR indicating that there is insufficient space\. . .P This error is not a programming bug\. If you encounter this error it likely means that either all space is being consumed by the already\-written slots or that the metadata you are attempting to write simply does not fit\. . +.P +You can attempt to resolve this problem by calling \fBluksmeta wipe\fR on slots that are no longer in use\. This will release the storage space for use by other slots\. Note that \fBluksmeta\fR does not, however, currently perform defragmentation since the number of usable blocks is rather limited\. You can attempt to manually get around this by extracting all slot data, wiping the slots and reloading them in order\. However, this operation is potentially dangerous and should be undertaken with great care\. +. .SH "OPTIONS" . .TP -\fB\-d\fR \fIDEVICE\fR +\fB\-d\fR \fIDEVICE\fR, \fB\-\-device\fR=\fIDEVICE\fR The device on which to perform the operation\. . .TP -\fB\-s\fR \fISLOT\fR -The slot on which to perform the operation\. +\fB\-s\fR \fISLOT\fR, \fB\-\-slot\fR=\fISLOT\fR +The slot number on which to perform the operation\. . .TP -\fB\-u\fR \fIUUID\fR +\fB\-u\fR \fIUUID\fR, \fB\-\-uuid\fR=\fIUUID\fR The UUID to associate with the operation\. . .TP -\fB\-f\fR +\fB\-f\fR, \fB\-\-force\fR Forcibly suppress all user prompting\. . +.SH "RETURN VALUES" +This command uses the return values as defined by \fBsysexit\.h\fR\. The following are general errors whose meaning is shared by all \fBluksmeta\fR commands: +. +.IP "\(bu" 4 +\fBEX_OK\fR : The operation was successful\. +. +.IP "\(bu" 4 +\fBEX_OSERR\fR : An undefined operating system error occurred\. +. +.IP "\(bu" 4 +\fBEX_USAGE\fR : The program was called with invalid parameters\. +. +.IP "\(bu" 4 +\fBEX_IOERR\fR : An IO error occurred when writing to the device\. +. +.IP "\(bu" 4 +\fBEX_OSFILE\fR : The device is not initialized or is corrupted\. +. +.IP "\(bu" 4 +\fBEX_NOPERM\fR : The user did not grant permission during confirmation\. +. +.IP "\(bu" 4 +\fBEX_NOINPUT\fR : An error occured while reading from standard input\. +. +.IP "\(bu" 4 +\fBEX_DATAERR\fR : The specified UUID does not match the slot UUID\. +. +.IP "\(bu" 4 +\fBEX_CANTCREAT\fR : There is insufficient space in LUKSv1 header\. +. +.IP "" 0 +. +.P +Additionally, \fBluksmeta save\fR will return \fBEX_UNAVAILABLE\fR when you attempt to save data into a slot that is already used\. Likewise, \fBluksmeta load\fR will return \fBEX_UNAVAILABLE\fR when you attempt to read from an empty slot\. +. +.SH "EXAMPLES" +Ensure that a device is initialized: +. +.IP "" 4 +. +.nf + +$ luksmeta test \-d /dev/sdz || luksmeta init \-f \-d /dev/sdz +. +.fi +. +.IP "" 0 +. +.P +Write some data to a slot: +. +.IP "" 4 +. +.nf + +$ UUID=`uuidgen` +$ echo $UUID +31c25e3b\-b8e2\-4eaa\-a427\-23aa882feef2 +$ echo "Hello, World" | luksmeta save \-d /dev/sdz \-s 0 \-u $UUID +. +.fi +. +.IP "" 0 +. +.P +Read the data back: +. +.IP "" 4 +. +.nf + +$ luksmeta load \-d /dev/sdz \-s 0 \-u $UUID +Hello, World +. +.fi +. +.IP "" 0 +. +.P +Wipe the data from the slot: +. +.IP "" 4 +. +.nf + +$ luksmeta wipe \-d /dev/sdz \-s 0 \-u $UUID +. +.fi +. +.IP "" 0 +. .SH "AUTHOR" Nathaniel McCallum . diff --git a/luksmeta.8.md b/luksmeta.8.md index 2981365..2008f45 100644 --- a/luksmeta.8.md +++ b/luksmeta.8.md @@ -18,11 +18,18 @@ luksmeta(1) -- Utility for storing metadata in a LUKSv1 header ## OVERVIEW The `luksmeta` utility enables an administrator to store metadata in the gap -between the end of the LUKSv1 header and the start of the encrypted data. +between the end of the LUKSv1 header and the start of the encrypted data. This +is useful for storing data that is available before the volume is unlocked, +usually for use during the volume unlock process. The metadata is stored in a series of UUID-typed slots, allowing multiple blocks of metadata. Although the `luksmeta` slots are inspired by the LUKS slots, they are functionally independent and share only a casual relationship. +Slots merely provide a hint that a given chunk of metadata is associated with +a specific LUKSv1 password (in a slot with the same number). However, +`luksmeta` itself is indifferent to the relationship between a LUKSv1 slot +and the correspondly numbered `luksmeta` slot, with one exception (detailed +below). After a LUKSv1 volume is initialized using `cryptsetup`(8), it must also be initialized for metadata storage by `luksmeta init`. Once this is complete, @@ -34,11 +41,20 @@ using `luksmeta load`. You can also erase the data in an existing slot using ## UUID GENERATION -It is often presumed that saving metadata to a slot requires a specific UUID. -This is incorrect. The UUID is not in any way special, it simply identifies -the type of data you store in the slot. If you are defining a new type of -metadata, simply generate a random UUID and use it to identify your metadata. -The easiest way to generate a UUID is to use `uuidgen`(1). +It is often presumed that saving metadata to a slot requires a specific UUID +or that there is an official registry of UUID types. This is incorrect. + +UUID stands for Universally Unique IDentifier. UUIDs are a standardized, +widely-used data type used for identification without a central registry. For +the relevant standards, see ISO 9834-8:2005 and RFC 4122. + +UUIDs are large enough that collision is practically impossible. So if your +application wants to store data in a `luksmeta` slot, just generate your own +UUID and use it consistently to refer to your type of data. If you have +multiple types of data, feel free to generate multiple UUIDs. + +The easiest way to generate a UUID is to use `uuidgen`(1). However, any +compliant UUID generator will suffice. ## INITIALIZATION @@ -47,16 +63,14 @@ initialized for metadata storage. Two commands help with this process: `luksmeta test` and `luksmeta init`. The `luksmeta test` command simply checks an existing block device to see -if it is initialized for metadata storage. It returns zero if the device -is already initialized. Otherwise, it returns non-zero. +if it is initialized for metadata storage. This command does not provide any +output, so be sure to check its return code (see below). The `luksmeta init` command initializes the LUKSv1 block device for metadata storage. This process will wipe out any data in the LUKSv1 header gap. For -this reason, you should use great care with this command. However, if the -block device already contains a `luksmeta` header, no modifications will be -performed. Because initialization is a destructive operation, this command -will require user confirmation before any data is written, unless the `-f` -option is supplied. +this reason, this command will require user confirmation before any data is +written, unless the `-f` option is supplied. Note that this command succeeds +if the device is already initialized. ## METADATA STATE @@ -75,11 +89,14 @@ metadata to a slot, read metadata from a slot and erase metadata in a slot, respectively. The `luksmeta save` command reads metadata on standard input and writes it to -the specified slot using the specified UUID. If no slot is specified, the -metadata is written to the first empty slot using the specified UUID. In this -case, the slot written to is printed to standard output. This command will -never overwrite existing data. To replace data in a slot you will need to -execute `luksmeta wipe` before `luksmeta save`. +the specified slot using the specified UUID. If no slot is specified, +`luksmeta` will search for the first slot number for which the LUKSv1 slot +is inactive and the `luksmeta` slot is empty. This represents the only +official correlation between LUKSv1 slots and `luksmeta` slots. In this case, +the metadata is written to the first applicable slot using the specified UUID +and the slot number is printed to standard output. In either case, this +command will never overwrite existing data. To replace data in a slot you will +need to execute `luksmeta wipe` before `luksmeta save`. The `luksmeta load` command reads data from the specified slot and writes it to standard output. If a UUID is specified, the command will verify that the @@ -92,40 +109,90 @@ specified, the command will verify that the UUID associated with the metadata in the slot matches the specified UUID. This type check helps to ensure that you only erase the data you intended to erase. Because this is a destructive operation, this command will require user confirmation before any data is -erased, unless the `-f` option is supplied. +erased, unless the `-f` option is supplied. Note that this command succeeds +if you attempt to wipe a slot that is already empty. ## CAVEATS -The ammount of storage in the LUKSv1 header gap is extremely limited. It also +The amount of storage in the LUKSv1 header gap is extremely limited. It also varies based upon the configuration used by LUKSv1 at device initialization time. In some LUKSv1 configurations, there is not even enough space for all the metadata slots even at the smallest possible slot size. During the design of this utility, we considered it likely that users would -want to reduce the number of available slots in exchange for more storage -space in the remaining slots. In order to provide this flexibility, the amount -of storage available per-slot is dynamic. Put simply, slots are not a fixed -size. This means that it is possible (and even somewhat likely) to encounter -an error during `luksmeta save` indicating that there is insufficient space. +want to reduce the number of usable slots in exchange for more storage space +in the slots used. In order to provide this flexibility, the amount of storage +available per-slot is dynamic. Put simply, slots are not a fixed size. This +means that it is possible (and even somewhat likely) to encounter an error +during `luksmeta save` indicating that there is insufficient space. This error is not a programming bug. If you encounter this error it likely means that either all space is being consumed by the already-written slots or that the metadata you are attempting to write simply does not fit. +You can attempt to resolve this problem by calling `luksmeta wipe` on slots +that are no longer in use. This will release the storage space for use by +other slots. Note that `luksmeta` does not, however, currently perform +defragmentation since the number of usable blocks is rather limited. You can +attempt to manually get around this by extracting all slot data, wiping the +slots and reloading them in order. However, this operation is potentially +dangerous and should be undertaken with great care. + ## OPTIONS -* `-d` _DEVICE_ : +* `-d` _DEVICE_, `--device`=_DEVICE_ : The device on which to perform the operation. -* `-s` _SLOT_ : - The slot on which to perform the operation. +* `-s` _SLOT_, `--slot`=_SLOT_ : + The slot number on which to perform the operation. -* `-u` _UUID_ : +* `-u` _UUID_, `--uuid`=_UUID_ : The UUID to associate with the operation. -* `-f` : +* `-f`, `--force` : Forcibly suppress all user prompting. +## RETURN VALUES + +This command uses the return values as defined by `sysexit.h`. The following +are general errors whose meaning is shared by all `luksmeta` commands: + +* `EX_OK` : The operation was successful. +* `EX_OSERR` : An undefined operating system error occurred. +* `EX_USAGE` : The program was called with invalid parameters. +* `EX_IOERR` : An IO error occurred when writing to the device. +* `EX_OSFILE` : The device is not initialized or is corrupted. +* `EX_NOPERM` : The user did not grant permission during confirmation. +* `EX_NOINPUT` : An error occured while reading from standard input. +* `EX_DATAERR` : The specified UUID does not match the slot UUID. +* `EX_CANTCREAT` : There is insufficient space in LUKSv1 header. + +Additionally, `luksmeta save` will return `EX_UNAVAILABLE` when you attempt +to save data into a slot that is already used. Likewise, `luksmeta load` will +return `EX_UNAVAILABLE` when you attempt to read from an empty slot. + +## EXAMPLES + +Ensure that a device is initialized: + + $ luksmeta test -d /dev/sdz || luksmeta init -f -d /dev/sdz + +Write some data to a slot: + + $ UUID=`uuidgen` + $ echo $UUID + 31c25e3b-b8e2-4eaa-a427-23aa882feef2 + $ echo "Hello, World" | luksmeta save -d /dev/sdz -s 0 -u $UUID + +Read the data back: + + $ luksmeta load -d /dev/sdz -s 0 -u $UUID + Hello, World + +Wipe the data from the slot: + + $ luksmeta wipe -d /dev/sdz -s 0 -u $UUID + ## AUTHOR Nathaniel McCallum <npmccallum@redhat.com> diff --git a/luksmeta.c b/luksmeta.c index 65f4c7a..ed5f2b9 100644 --- a/luksmeta.c +++ b/luksmeta.c @@ -27,11 +27,15 @@ #include #include -#define UUID_TEMPLATE \ +#define UUID_TMPL \ "%02hhx%02hhx%02hhx%02hhx-" \ "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-" \ "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" +#define UUID_ARGS(u) \ + u[0x0], u[0x1], u[0x2], u[0x3], u[0x4], u[0x5], u[0x6], u[0x7], \ + u[0x8], u[0x9], u[0xa], u[0xb], u[0xc], u[0xd], u[0xe], u[0xf] + struct options { const char *device; luksmeta_uuid_t uuid; @@ -43,7 +47,7 @@ struct options { static int cmd_test(const struct options *opts, struct crypt_device *cd) { - return luksmeta_test(cd) == 0 ? EX_OK : EX_DATAERR; + return luksmeta_test(cd) == 0 ? EX_OK : EX_OSFILE; } static int @@ -71,10 +75,21 @@ cmd_init(const struct options *opts, struct crypt_device *cd) } r = luksmeta_init(cd); - if (r < 0 && r != -EALREADY) { + fprintf(stderr, "rc: %d\n", r); + switch (r) { + case 0: /* fallthrough */ + case -EALREADY: + return EX_OK; + + case -ENOSPC: + fprintf(stderr, "Insufficient space in the LUKS header (%s)\n", + opts->device); + return EX_CANTCREAT; + + default: fprintf(stderr, "Error while initializing device (%s): %s\n", opts->device, strerror(-r)); - return EX_IOERR; + return EX_OSERR; } return EX_OK; @@ -105,17 +120,17 @@ cmd_show(const struct options *opts, struct crypt_device *cd) switch (r) { case -EBADSLT: fprintf(stderr, "Invalid slot (%d)\n", opts->slot); - return EX_DATAERR; + return EX_USAGE; case -ENOENT: fprintf(stderr, "Device is not initialized (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -EINVAL: fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -ENODATA: if (opts->slot < 0) @@ -130,11 +145,7 @@ cmd_show(const struct options *opts, struct crypt_device *cd) if (opts->slot < 0) fprintf(stdout, "%d %8s ", i, status(cd, i)); - fprintf(stdout, UUID_TEMPLATE "\n", - uuid[0x0], uuid[0x1], uuid[0x2], uuid[0x3], - uuid[0x4], uuid[0x5], uuid[0x6], uuid[0x7], - uuid[0x8], uuid[0x9], uuid[0xa], uuid[0xb], - uuid[0xc], uuid[0xd], uuid[0xe], uuid[0xf]); + fprintf(stdout, UUID_TMPL "\n", UUID_ARGS(uuid)); } break; } @@ -152,7 +163,7 @@ cmd_save(const struct options *opts, struct crypt_device *cd) if (!opts->have_uuid) { fprintf(stderr, "UUID required\n"); - return EX_DATAERR; + return EX_USAGE; } while (!feof(stdin)) { @@ -171,13 +182,13 @@ cmd_save(const struct options *opts, struct crypt_device *cd) if (r < 4096 && (ferror(stdin) || inl == 0)) { fprintf(stderr, "Error reading from standard input\n"); free(in); - return EX_IOERR; + return EX_NOINPUT; } } if (!in) { fprintf(stderr, "No data on standard input\n"); - return EX_IOERR; + return EX_NOINPUT; } r = luksmeta_save(cd, opts->slot, opts->uuid, in, inl); @@ -186,33 +197,29 @@ cmd_save(const struct options *opts, struct crypt_device *cd) switch (r) { case -ENOENT: fprintf(stderr, "Device is not initialized (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -EINVAL: fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -EBADSLT: fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot); - return EX_DATAERR; + return EX_USAGE; case -EKEYREJECTED: - fprintf(stderr, - "The specified UUID is reserved (" UUID_TEMPLATE ")\n", - opts->uuid[0x0], opts->uuid[0x1], opts->uuid[0x2], opts->uuid[0x3], - opts->uuid[0x4], opts->uuid[0x5], opts->uuid[0x6], opts->uuid[0x7], - opts->uuid[0x8], opts->uuid[0x9], opts->uuid[0xa], opts->uuid[0xb], - opts->uuid[0xc], opts->uuid[0xd], opts->uuid[0xe], opts->uuid[0xf] - ); - return EX_DATAERR; + fprintf(stderr, "The specified UUID is reserved (" UUID_TMPL ")\n", + UUID_ARGS(opts->uuid)); + return EX_USAGE; case -EALREADY: fprintf(stderr, "Will not overwrite existing slot (%d)\n", opts->slot); - return EX_DATAERR; + return EX_UNAVAILABLE; case -ENOSPC: - fprintf(stderr, "Insufficient space in the LUKS header\n"); - return EX_IOERR; + fprintf(stderr, "Insufficient space in the LUKS header (%s)\n", + opts->device); + return EX_CANTCREAT; default: if (r < 0) @@ -232,7 +239,7 @@ cmd_load(const struct options *opts, struct crypt_device *cd) if (opts->slot < 0) { fprintf(stderr, "Slot required\n"); - return EX_DATAERR; + return EX_USAGE; } r = luksmeta_load(cd, opts->slot, uuid, NULL, 0); @@ -240,7 +247,12 @@ cmd_load(const struct options *opts, struct crypt_device *cd) uint8_t *out = NULL; if (opts->have_uuid && memcmp(opts->uuid, uuid, sizeof(uuid)) != 0) { - fprintf(stderr, "Slot contains different UUID\n"); + fprintf(stderr, + "The given UUID does not match the slot UUID:\n" + "UUID: " UUID_TMPL "\n" + "SLOT: " UUID_TMPL "\n", + UUID_ARGS(opts->uuid), + UUID_ARGS(uuid)); return EX_DATAERR; } @@ -262,19 +274,19 @@ cmd_load(const struct options *opts, struct crypt_device *cd) switch (r) { case -ENOENT: fprintf(stderr, "Device is not initialized (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -EINVAL: fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -EBADSLT: fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot); - return EX_DATAERR; + return EX_USAGE; case -ENODATA: fprintf(stderr, "The specified slot is empty (%d)\n", opts->slot); - return EX_DATAERR; + return EX_UNAVAILABLE; default: if (r < 0) @@ -287,11 +299,12 @@ cmd_load(const struct options *opts, struct crypt_device *cd) static int cmd_wipe(const struct options *opts, struct crypt_device *cd) { + luksmeta_uuid_t uuid = {}; int r = 0; if (opts->slot < 0) { fprintf(stderr, "Slot required\n"); - return EX_DATAERR; + return EX_USAGE; } if (!opts->force) { @@ -313,30 +326,37 @@ cmd_wipe(const struct options *opts, struct crypt_device *cd) r = luksmeta_wipe(cd, opts->slot, opts->have_uuid ? opts->uuid : NULL); switch (r) { + case -EALREADY: + return EX_OK; + case -ENOENT: fprintf(stderr, "Device is not initialized (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -EINVAL: fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device); - return EX_DATAERR; + return EX_OSFILE; case -EBADSLT: fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot); - return EX_DATAERR; + return EX_USAGE; case -EKEYREJECTED: - fprintf(stderr, - "The UUID does not match the slot UUID (" UUID_TEMPLATE ")\n", - opts->uuid[0x0], opts->uuid[0x1], opts->uuid[0x2], opts->uuid[0x3], - opts->uuid[0x4], opts->uuid[0x5], opts->uuid[0x6], opts->uuid[0x7], - opts->uuid[0x8], opts->uuid[0x9], opts->uuid[0xa], opts->uuid[0xb], - opts->uuid[0xc], opts->uuid[0xd], opts->uuid[0xe], opts->uuid[0xf] - ); - return EX_DATAERR; - - case -EALREADY: - fprintf(stderr, "Slot is already empty (%d)\n", opts->slot); + r = luksmeta_load(cd, opts->slot, uuid, NULL, 0); + if (r >= 0) { + fprintf(stderr, + "The given UUID does not match the slot UUID:\n" + "UUID: " UUID_TMPL "\n" + "SLOT: " UUID_TMPL "\n", + UUID_ARGS(opts->uuid), + UUID_ARGS(uuid)); + } else { + fprintf(stderr, + "The given UUID does not match the slot UUID:\n" + "UUID: " UUID_TMPL "\n" + "SLOT: UNKNOWN\n", + UUID_ARGS(opts->uuid)); + } return EX_DATAERR; default: @@ -380,14 +400,9 @@ main(int argc, char *argv[]) case 'd': o.device = optarg; break; case 'f': o.force = true; break; case 'u': - if (sscanf(optarg, UUID_TEMPLATE, - &o.uuid[0x0], &o.uuid[0x1], &o.uuid[0x2], &o.uuid[0x3], - &o.uuid[0x4], &o.uuid[0x5], &o.uuid[0x6], &o.uuid[0x7], - &o.uuid[0x8], &o.uuid[0x9], &o.uuid[0xa], &o.uuid[0xb], - &o.uuid[0xc], &o.uuid[0xd], &o.uuid[0xe], &o.uuid[0xf]) - != 16) { + if (sscanf(optarg, UUID_TMPL, UUID_ARGS(&o.uuid)) != 16) { fprintf(stderr, "Invalid UUID (%s)\n", optarg); - return EX_DATAERR; + return EX_USAGE; } o.have_uuid = true; @@ -396,7 +411,7 @@ main(int argc, char *argv[]) if (sscanf(optarg, "%d", &o.slot) != 1 || o.slot < 0 || o.slot >= crypt_keyslot_max(CRYPT_LUKS1)) { fprintf(stderr, "Invalid slot (%s)\n", optarg); - return EX_DATAERR; + return EX_USAGE; } break; } @@ -438,13 +453,13 @@ main(int argc, char *argv[]) fprintf(stderr, "Unable to determine device type for %s\n", o.device); crypt_free(cd); - return EX_DATAERR; + return EX_OSFILE; } if (strcmp(type, CRYPT_LUKS1) != 0) { fprintf(stderr, "%s (%s) is not a LUKS device\n", o.device, type); crypt_free(cd); - return EX_DATAERR; + return EX_OSFILE; } r = commands[i].func(&o, cd);