xref: /dragonfly/sbin/tcplay/main.c (revision 7b1e1c8e)
10d9ba1e1SAlex Hornung /*
20d9ba1e1SAlex Hornung  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
30d9ba1e1SAlex Hornung  * All rights reserved.
40d9ba1e1SAlex Hornung  *
50d9ba1e1SAlex Hornung  * Redistribution and use in source and binary forms, with or without
60d9ba1e1SAlex Hornung  * modification, are permitted provided that the following conditions
70d9ba1e1SAlex Hornung  * are met:
80d9ba1e1SAlex Hornung  *
90d9ba1e1SAlex Hornung  * 1. Redistributions of source code must retain the above copyright
100d9ba1e1SAlex Hornung  *    notice, this list of conditions and the following disclaimer.
110d9ba1e1SAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
120d9ba1e1SAlex Hornung  *    notice, this list of conditions and the following disclaimer in
130d9ba1e1SAlex Hornung  *    the documentation and/or other materials provided with the
140d9ba1e1SAlex Hornung  *    distribution.
150d9ba1e1SAlex Hornung  *
160d9ba1e1SAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
170d9ba1e1SAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
180d9ba1e1SAlex Hornung  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
190d9ba1e1SAlex Hornung  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
200d9ba1e1SAlex Hornung  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
210d9ba1e1SAlex Hornung  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
220d9ba1e1SAlex Hornung  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
230d9ba1e1SAlex Hornung  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
240d9ba1e1SAlex Hornung  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
250d9ba1e1SAlex Hornung  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
260d9ba1e1SAlex Hornung  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270d9ba1e1SAlex Hornung  * SUCH DAMAGE.
280d9ba1e1SAlex Hornung  */
2981b79547SAlex Hornung 
300d9ba1e1SAlex Hornung #include <sys/types.h>
310d9ba1e1SAlex Hornung #include <getopt.h>
320d9ba1e1SAlex Hornung #include <stdio.h>
330d9ba1e1SAlex Hornung #include <stdlib.h>
3481b79547SAlex Hornung #include <inttypes.h>
350d9ba1e1SAlex Hornung #include <errno.h>
360d9ba1e1SAlex Hornung #include <string.h>
370d9ba1e1SAlex Hornung #include <signal.h>
380d9ba1e1SAlex Hornung #include <time.h>
390d9ba1e1SAlex Hornung 
400d9ba1e1SAlex Hornung #include "tcplay.h"
410d9ba1e1SAlex Hornung 
4281b79547SAlex Hornung #ifndef SIGINFO
4381b79547SAlex Hornung #define SIGINFO SIGUSR1
4481b79547SAlex Hornung #endif
4581b79547SAlex Hornung 
46c833cfcfSAlex Hornung #define FLAG_LONG_FDE		0xff01
47c833cfcfSAlex Hornung #define FLAG_LONG_USE_BACKUP	0xff02
48c833cfcfSAlex Hornung #define FLAG_LONG_MOD		0xff04
49c833cfcfSAlex Hornung #define FLAG_LONG_MOD_KF	0xff08
50c833cfcfSAlex Hornung #define FLAG_LONG_MOD_PRF	0xff10
51c833cfcfSAlex Hornung #define FLAG_LONG_MOD_NONE	0xff20
52c833cfcfSAlex Hornung #define FLAG_LONG_MOD_TO_FILE	0xff40
53c833cfcfSAlex Hornung #define FLAG_LONG_USE_HDR_FILE	0xfe01
54c833cfcfSAlex Hornung #define FLAG_LONG_USE_HHDR_FILE	0xfe02
55c833cfcfSAlex Hornung #define FLAG_LONG_NO_RETRIES	0xfabc
56c833cfcfSAlex Hornung 
57c833cfcfSAlex Hornung 
580d9ba1e1SAlex Hornung static
590d9ba1e1SAlex Hornung void
sig_handler(int sig)600d9ba1e1SAlex Hornung sig_handler(int sig)
610d9ba1e1SAlex Hornung {
620d9ba1e1SAlex Hornung 	if ((sig == SIGUSR1 || sig == SIGINFO) && (summary_fn != NULL))
630d9ba1e1SAlex Hornung 		summary_fn();
640d9ba1e1SAlex Hornung }
650d9ba1e1SAlex Hornung 
660d9ba1e1SAlex Hornung static
670d9ba1e1SAlex Hornung void
usage(void)680d9ba1e1SAlex Hornung usage(void)
690d9ba1e1SAlex Hornung {
700d9ba1e1SAlex Hornung 	fprintf(stderr,
71c833cfcfSAlex Hornung 	    "usage: tcplay -c -d device [-g] [-z] [-w] [-a pbkdf_hash] [-b cipher]\n"
7289e181b5SThomas Nikolajsen 	    "              [-f keyfile_hidden] [-k keyfile] [-x pbkdf_hash] [-y cipher]\n"
73*7b1e1c8eSDaniel Fojt 	    "       tcplay -i -d device [-e] [-p] [-f keyfile_hidden] [-k keyfile]\n"
74c833cfcfSAlex Hornung 	    "              [-s system_device] [--fde] [--use-backup]\n"
75c833cfcfSAlex Hornung 	    "              [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n"
76*7b1e1c8eSDaniel Fojt 	    "       tcplay -m mapping -d device [-e] [-p] [-f keyfile_hidden] [-k keyfile]\n"
77c833cfcfSAlex Hornung 	    "              [-s system_device] [--fde] [--use-backup] [--allow-trim]\n"
78c833cfcfSAlex Hornung 	    "              [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n"
79c833cfcfSAlex Hornung 	    "       tcplay --modify -d device [-k keyfile] [--new-keyfile=keyfile]\n"
80c833cfcfSAlex Hornung 	    "              [--new-pbkdf-prf=pbkdf_hash] [-s system_device] [--fde]\n"
81c833cfcfSAlex Hornung 	    "              [--use-backup] [--save-hdr-to-file=hdr_file] [-w]\n"
82c833cfcfSAlex Hornung 	    "              [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n"
83c833cfcfSAlex Hornung 	    "       tcplay --modify -d device [-k keyfile] --restore-from-backup-hdr [-w]\n"
84c833cfcfSAlex Hornung 	    "       tcplay -j mapping\n"
85c833cfcfSAlex Hornung 	    "       tcplay -u mapping\n"
8689e181b5SThomas Nikolajsen 	    "       tcplay -h | -v\n"
8789e181b5SThomas Nikolajsen 	    "\n"
8889e181b5SThomas Nikolajsen 	    "Valid commands are:\n"
890d9ba1e1SAlex Hornung 	    " -c, --create\n"
9089e181b5SThomas Nikolajsen 	    "\t Creates a new TC volume on the device specified by -d or --device.\n"
9189e181b5SThomas Nikolajsen 	    " -h, --help\n"
9289e181b5SThomas Nikolajsen 	    "\t Print help message and exit.\n"
930d9ba1e1SAlex Hornung 	    " -i, --info\n"
9489e181b5SThomas Nikolajsen 	    "\t Gives information about the TC volume specified by -d or --device.\n"
95c833cfcfSAlex Hornung 	    " -j <mapping name>, --info-mapped=<mapping name>\n"
96c833cfcfSAlex Hornung 	    "\t Gives information about the mapped TC volume under the given mapping.\n"
970d9ba1e1SAlex Hornung 	    " -m <mapping name>, --map=<mapping name>\n"
980d9ba1e1SAlex Hornung 	    "\t Creates a dm-crypt mapping with the given name for the device\n"
9989e181b5SThomas Nikolajsen 	    "\t specified by -d or --device.\n"
100c833cfcfSAlex Hornung 	    " -u <mapping name>, --unmap=<mapping name>\n"
101c833cfcfSAlex Hornung 	    "\t Removes a dm-crypt mapping with the given name.\n"
102c833cfcfSAlex Hornung 	    " --modify\n"
103c833cfcfSAlex Hornung 	    "\t Changes the volume's passphrase, keyfile and optionally the hashing\n"
104c833cfcfSAlex Hornung 	    "\t function used for the PBKDF password derivation.\n"
10589e181b5SThomas Nikolajsen 	    " -v, --version\n"
10689e181b5SThomas Nikolajsen 	    "\t Print version message and exit.\n"
1070d9ba1e1SAlex Hornung 	    "\n"
10889e181b5SThomas Nikolajsen 	    "Valid options for --create are:\n"
1090d9ba1e1SAlex Hornung 	    " -a <pbkdf prf algorithm>, --pbkdf-prf=<pbkdf prf algorithm>\n"
11089e181b5SThomas Nikolajsen 	    "\t Specifies which hashing function to use for the PBKDF password\n"
11189e181b5SThomas Nikolajsen 	    "\t derivation when creating a new volume.\n"
11289e181b5SThomas Nikolajsen 	    "\t To see valid options, specify '-a help'.\n"
1130d9ba1e1SAlex Hornung 	    " -b <cipher>, --cipher=<cipher>\n"
11489e181b5SThomas Nikolajsen 	    "\t Specifies which cipher to use when creating a new TC volume.\n"
11589e181b5SThomas Nikolajsen 	    "\t To see valid options, specify '-b help'.\n"
1160d9ba1e1SAlex Hornung 	    " -g, --hidden\n"
11789e181b5SThomas Nikolajsen 	    "\t Specifies that the newly created volume will contain a hidden volume.\n"
11889e181b5SThomas Nikolajsen 	    " -x <pbkdf prf algorithm>, --pbkdf-prf=<pbkdf prf algorithm>\n"
11989e181b5SThomas Nikolajsen 	    "\t Specifies which hashing function to use for the PBKDF password\n"
12089e181b5SThomas Nikolajsen 	    "\t derivation when creating a new hidden volume.  By default, the\n"
12189e181b5SThomas Nikolajsen 	    "\t same as for the outer volume will be used.\n"
12289e181b5SThomas Nikolajsen 	    "\t To see valid options, specify '-x help'.\n"
12389e181b5SThomas Nikolajsen 	    " -y <cipher>, --cipher=<cipher>\n"
12489e181b5SThomas Nikolajsen 	    "\t Specifies which cipher to use when creating a new hidden volume.\n"
12589e181b5SThomas Nikolajsen 	    "\t By default, the same as for the outer volume will be used.\n"
12689e181b5SThomas Nikolajsen 	    "\t To see valid options, specify '-y help'.\n"
127c833cfcfSAlex Hornung 	    " -z, --insecure-erase\n"
128c833cfcfSAlex Hornung 	    "\t Skips the erase of the disk. Possible security hazard.\n"
129c833cfcfSAlex Hornung 	    " -w, --weak-keys\n"
130c833cfcfSAlex Hornung 	    "\t Uses a weak source of entropy (urandom) for key material.\n"
131c833cfcfSAlex Hornung 	    "\t WARNING: This is a REALLY REALLY bad idea for anything but\n"
132c833cfcfSAlex Hornung 	    "\t testing.\n"
133c833cfcfSAlex Hornung 	    "\n"
134c833cfcfSAlex Hornung 	    "Valid options for --modify are:\n"
135c833cfcfSAlex Hornung 	    " --new-keyfile=<key file>\n"
136c833cfcfSAlex Hornung 	    "\t Specifies a key file to use for the password derivation, when\n"
137c833cfcfSAlex Hornung 	    "\t re-encrypting the header, can appear multiple times.\n"
138c833cfcfSAlex Hornung 	    " --new-pbkdf-prf=<pbkdf prf algorithm>\n"
139c833cfcfSAlex Hornung 	    "\t Specifies which hashing function to use for the PBKDF password\n"
140c833cfcfSAlex Hornung 	    "\t derivation when re-encrypting the header.\n"
141c833cfcfSAlex Hornung 	    "\t To see valid options, specify '-a help'.\n"
142c833cfcfSAlex Hornung 	    " -s <disk path>, --system-encryption=<disk path>\n"
143c833cfcfSAlex Hornung 	    "\t Specifies that the disk (e.g. /dev/da0) is using system encryption.\n"
144c833cfcfSAlex Hornung 	    " --fde\n"
145c833cfcfSAlex Hornung 	    "\t Specifies that the disk (e.g. /dev/da0) is using full disk encryption.\n"
146c833cfcfSAlex Hornung 	    " --use-backup\n"
147c833cfcfSAlex Hornung 	    "\t Uses the backup headers (at the end of the volume) instead of the\n"
148c833cfcfSAlex Hornung 	    "\t primary headers. Both normal and backup headers will be modified!\n"
149c833cfcfSAlex Hornung 	    "\t This is useful when your primary headers have been corrupted.\n"
150c833cfcfSAlex Hornung 	    " --use-hdr-file=<header file>\n"
151c833cfcfSAlex Hornung 	    "\t Use the header in the specified file instead of the main header on the\n"
152c833cfcfSAlex Hornung 	    "\t disk as source for the modify operation.\n"
153c833cfcfSAlex Hornung 	    " --use-hidden-hdr-file=<header file>\n"
154c833cfcfSAlex Hornung 	    "\t Use the header in the specified file instead of the hidden header on the\n"
155c833cfcfSAlex Hornung 	    "\t disk as source for the modify operation.\n"
156c833cfcfSAlex Hornung 	    " --restore-from-backup-hdr\n"
157c833cfcfSAlex Hornung 	    "\t Implies --use-backup, no new PBKDF hashing function, no new keyfiles\n"
158c833cfcfSAlex Hornung 	    "\t and no new passphrase.\n"
159c833cfcfSAlex Hornung 	    "\t In other words, this will simply restore both headers from the backup\n"
160c833cfcfSAlex Hornung 	    "\t header. This option cannot be used to restore from a backup header file.\n"
161c833cfcfSAlex Hornung 	    " -w, --weak-keys\n"
162c833cfcfSAlex Hornung 	    "\t Uses a weak source of entropy (urandom) for salt material. The\n"
163c833cfcfSAlex Hornung 	    "\t key material is not affected, as the master keys are kept intact.\n"
164c833cfcfSAlex Hornung 	    "\t WARNING: This is a bad idea for anything but testing.\n"
165c833cfcfSAlex Hornung 	    " --save-hdr-backup=<header file>\n"
166c833cfcfSAlex Hornung 	    "\t Saves the modified header in the specified file instead of updating\n"
167c833cfcfSAlex Hornung 	    "\t the header files on disk.\n"
1680d9ba1e1SAlex Hornung 	    "\n"
16989e181b5SThomas Nikolajsen 	    "Valid options for --info and --map are:\n"
1700d9ba1e1SAlex Hornung 	    " -e, --protect-hidden\n"
17189e181b5SThomas Nikolajsen 	    "\t Protect a hidden volume when mounting the outer volume.\n"
172*7b1e1c8eSDaniel Fojt 	    " -p, --prompt-passphrase\n"
173*7b1e1c8eSDaniel Fojt 	    "\t Immediately prompt for a passphrase even if a keyfile is supplied.\n"
1740d9ba1e1SAlex Hornung 	    " -s <disk path>, --system-encryption=<disk path>\n"
17589e181b5SThomas Nikolajsen 	    "\t Specifies that the disk (e.g. /dev/da0) is using system encryption.\n"
176c833cfcfSAlex Hornung 	    " -t, --allow-trim\n"
177c833cfcfSAlex Hornung 	    "\t Allow discards (TRIM command) on mapped volume.\n"
178c833cfcfSAlex Hornung 	    " --fde\n"
179c833cfcfSAlex Hornung 	    "\t Specifies that the disk (e.g. /dev/da0) is using full disk encryption.\n"
180c833cfcfSAlex Hornung 	    " --use-backup\n"
181c833cfcfSAlex Hornung 	    "\t Uses the backup headers (at the end of the volume) instead of the\n"
182c833cfcfSAlex Hornung 	    "\t primary headers.\n"
183c833cfcfSAlex Hornung 	    "\t This is useful when your primary headers have been corrupted.\n"
184c833cfcfSAlex Hornung 	    " --use-hdr-file=<header file>\n"
185c833cfcfSAlex Hornung 	    "\t Use the header in the specified file instead of the main header on the\n"
186c833cfcfSAlex Hornung 	    "\t disk.\n"
187c833cfcfSAlex Hornung 	    " --use-hidden-hdr-file=<header file>\n"
188c833cfcfSAlex Hornung 	    "\t Use the header in the specified file instead of the hidden header on the\n"
189c833cfcfSAlex Hornung 	    "\t disk.\n"
1900d9ba1e1SAlex Hornung 	    "\n"
19189e181b5SThomas Nikolajsen 	    "Valid options common to all commands are:\n"
1920d9ba1e1SAlex Hornung 	    " -d <device path>, --device=<device path>\n"
19389e181b5SThomas Nikolajsen 	    "\t Specifies the path to the volume to operate on (e.g. /dev/da0s1).\n"
1940d9ba1e1SAlex Hornung 	    " -f <key file>, --keyfile-hidden=<key file>\n"
19589e181b5SThomas Nikolajsen 	    "\t Specifies a key file to use for the hidden volume password derivation.\n"
1960d9ba1e1SAlex Hornung 	    "\t This option is only valid in combination with -e, --protect-hidden\n"
19789e181b5SThomas Nikolajsen 	    "\t or -g, --hidden.\n"
19889e181b5SThomas Nikolajsen 	    " -k <key file>, --keyfile=<key file>\n"
19989e181b5SThomas Nikolajsen 	    "\t Specifies a key file to use for the password derivation, can appear\n"
20089e181b5SThomas Nikolajsen 	    "\t multiple times.\n"
2010d9ba1e1SAlex Hornung 	    );
2020d9ba1e1SAlex Hornung 
203c833cfcfSAlex Hornung 	exit(EXIT_FAILURE);
2040d9ba1e1SAlex Hornung }
2050d9ba1e1SAlex Hornung 
2060d9ba1e1SAlex Hornung static struct option longopts[] = {
2070d9ba1e1SAlex Hornung 	{ "create",		no_argument,		NULL, 'c' },
2080d9ba1e1SAlex Hornung 	{ "cipher",		required_argument,	NULL, 'b' },
2090d9ba1e1SAlex Hornung 	{ "cipher-hidden",	required_argument,	NULL, 'y' },
2100d9ba1e1SAlex Hornung 	{ "hidden",		no_argument,		NULL, 'g' },
2110d9ba1e1SAlex Hornung 	{ "pbkdf-prf",		required_argument,	NULL, 'a' },
2120d9ba1e1SAlex Hornung 	{ "pbkdf-prf-hidden",	required_argument,	NULL, 'x' },
2130d9ba1e1SAlex Hornung 	{ "info",		no_argument,		NULL, 'i' },
214c833cfcfSAlex Hornung 	{ "info-mapped",	required_argument,	NULL, 'j' },
2150d9ba1e1SAlex Hornung 	{ "map",		required_argument,	NULL, 'm' },
2160d9ba1e1SAlex Hornung 	{ "keyfile",		required_argument,	NULL, 'k' },
2170d9ba1e1SAlex Hornung 	{ "keyfile-hidden",	required_argument,	NULL, 'f' },
2180d9ba1e1SAlex Hornung 	{ "protect-hidden",	no_argument,		NULL, 'e' },
2190d9ba1e1SAlex Hornung 	{ "device",		required_argument,	NULL, 'd' },
220*7b1e1c8eSDaniel Fojt 	{ "prompt-passphrase",	no_argument,		NULL, 'p' },
2210d9ba1e1SAlex Hornung 	{ "system-encryption",	required_argument,	NULL, 's' },
222c833cfcfSAlex Hornung 	{ "allow-trim",		no_argument,		NULL, 't' },
223c833cfcfSAlex Hornung 	{ "fde",		no_argument,		NULL, FLAG_LONG_FDE },
224c833cfcfSAlex Hornung 	{ "use-backup",		no_argument,		NULL, FLAG_LONG_USE_BACKUP },
225c833cfcfSAlex Hornung 	{ "use-hdr-file",	required_argument,	NULL, FLAG_LONG_USE_HDR_FILE },
226c833cfcfSAlex Hornung 	{ "use-hidden-hdr-file",required_argument,	NULL, FLAG_LONG_USE_HHDR_FILE },
227c833cfcfSAlex Hornung 	{ "modify",		no_argument,		NULL, FLAG_LONG_MOD },
228c833cfcfSAlex Hornung 	{ "new-keyfile",	required_argument,	NULL, FLAG_LONG_MOD_KF },
229c833cfcfSAlex Hornung 	{ "new-pbkdf-prf",	required_argument,	NULL, FLAG_LONG_MOD_PRF },
230c833cfcfSAlex Hornung 	{ "restore-from-backup-hdr", no_argument,	NULL, FLAG_LONG_MOD_NONE },
231c833cfcfSAlex Hornung 	{ "save-hdr-backup",	required_argument,	NULL, FLAG_LONG_MOD_TO_FILE },
232c833cfcfSAlex Hornung 	{ "unmap",		required_argument,	NULL, 'u' },
2330d9ba1e1SAlex Hornung 	{ "version",		no_argument,		NULL, 'v' },
234c833cfcfSAlex Hornung 	{ "weak-keys",		no_argument,		NULL, 'w' },
235c833cfcfSAlex Hornung 	{ "insecure-erase",	no_argument,		NULL, 'z' },
2360d9ba1e1SAlex Hornung 	{ "help",		no_argument,		NULL, 'h' },
237c833cfcfSAlex Hornung 	{ "no-retries",         no_argument,            NULL, FLAG_LONG_NO_RETRIES },
2380d9ba1e1SAlex Hornung 	{ NULL,			0,			NULL, 0   },
2390d9ba1e1SAlex Hornung };
2400d9ba1e1SAlex Hornung 
241c833cfcfSAlex Hornung #define _set_str_opt(opt) \
242c833cfcfSAlex Hornung 	do {									\
243c833cfcfSAlex Hornung 		if ((opts->opt = strdup_safe_mem(optarg)) == NULL) {		\
244c833cfcfSAlex Hornung 			fprintf(stderr, "Could not allocate safe mem.\n");	\
245c833cfcfSAlex Hornung 			exit(EXIT_FAILURE);					\
246c833cfcfSAlex Hornung 		}								\
247c833cfcfSAlex Hornung 	} while(0)
248c833cfcfSAlex Hornung 
2490d9ba1e1SAlex Hornung int
main(int argc,char * argv[])2500d9ba1e1SAlex Hornung main(int argc, char *argv[])
2510d9ba1e1SAlex Hornung {
252c833cfcfSAlex Hornung 	struct tcplay_opts *opts;
2530d9ba1e1SAlex Hornung 	int ch, error;
254c833cfcfSAlex Hornung 	int info_vol = 0, map_vol = 0,
255c833cfcfSAlex Hornung 	    unmap_vol = 0, info_map = 0,
256c833cfcfSAlex Hornung 	    create_vol = 0, modify_vol = 0;
2570d9ba1e1SAlex Hornung 
2580d9ba1e1SAlex Hornung 	if ((error = tc_play_init()) != 0) {
2590d9ba1e1SAlex Hornung 		fprintf(stderr, "Initialization failed, exiting.");
260c833cfcfSAlex Hornung 		exit(EXIT_FAILURE);
2610d9ba1e1SAlex Hornung 	}
2620d9ba1e1SAlex Hornung 
2630d9ba1e1SAlex Hornung 	atexit(check_and_purge_safe_mem);
2640d9ba1e1SAlex Hornung 	signal(SIGUSR1, sig_handler);
2650d9ba1e1SAlex Hornung 	signal(SIGINFO, sig_handler);
2660d9ba1e1SAlex Hornung 
267c833cfcfSAlex Hornung 	if ((opts = opts_init()) == NULL) {
268c833cfcfSAlex Hornung 		fprintf(stderr, "Initialization failed (opts), exiting.");
269c833cfcfSAlex Hornung 		exit(EXIT_FAILURE);
270c833cfcfSAlex Hornung 	}
2710d9ba1e1SAlex Hornung 
272c833cfcfSAlex Hornung 	opts->interactive = 1;
273c833cfcfSAlex Hornung 
274*7b1e1c8eSDaniel Fojt 	while ((ch = getopt_long(argc, argv, "a:b:cd:ef:ghij:k:m:ps:tu:vwx:y:z",
2750d9ba1e1SAlex Hornung 	    longopts, NULL)) != -1) {
2760d9ba1e1SAlex Hornung 		switch(ch) {
2770d9ba1e1SAlex Hornung 		case 'a':
278c833cfcfSAlex Hornung 			if (opts->prf_algo != NULL)
2790d9ba1e1SAlex Hornung 				usage();
280*7b1e1c8eSDaniel Fojt 			if ((opts->prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) {
2810d9ba1e1SAlex Hornung 				if (strcmp(optarg, "help") == 0)
282c833cfcfSAlex Hornung 					exit(EXIT_SUCCESS);
2830d9ba1e1SAlex Hornung 				else
2840d9ba1e1SAlex Hornung 					usage();
2850d9ba1e1SAlex Hornung 				/* NOT REACHED */
2860d9ba1e1SAlex Hornung 			}
2870d9ba1e1SAlex Hornung 			break;
2880d9ba1e1SAlex Hornung 		case 'b':
289c833cfcfSAlex Hornung 			if (opts->cipher_chain != NULL)
2900d9ba1e1SAlex Hornung 				usage();
291c833cfcfSAlex Hornung 			if ((opts->cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
2920d9ba1e1SAlex Hornung 				if (strcmp(optarg, "help") == 0)
293c833cfcfSAlex Hornung 					exit(EXIT_SUCCESS);
2940d9ba1e1SAlex Hornung 				else
2950d9ba1e1SAlex Hornung 					usage();
2960d9ba1e1SAlex Hornung 				/* NOT REACHED */
2970d9ba1e1SAlex Hornung 			}
2980d9ba1e1SAlex Hornung 			break;
2990d9ba1e1SAlex Hornung 		case 'c':
3000d9ba1e1SAlex Hornung 			create_vol = 1;
3010d9ba1e1SAlex Hornung 			break;
3020d9ba1e1SAlex Hornung 		case 'd':
303c833cfcfSAlex Hornung 			_set_str_opt(dev);
3040d9ba1e1SAlex Hornung 			break;
3050d9ba1e1SAlex Hornung 		case 'e':
306c833cfcfSAlex Hornung 			opts->protect_hidden = 1;
3070d9ba1e1SAlex Hornung 			break;
3080d9ba1e1SAlex Hornung 		case 'f':
309c833cfcfSAlex Hornung 			if ((error = opts_add_keyfile_hidden(opts, optarg)) != 0) {
310c833cfcfSAlex Hornung 				fprintf(stderr, "Could not add keyfile: %s\n", optarg);
311c833cfcfSAlex Hornung 				exit(EXIT_FAILURE);
312c833cfcfSAlex Hornung 			}
3130d9ba1e1SAlex Hornung 			break;
3140d9ba1e1SAlex Hornung 		case 'g':
315c833cfcfSAlex Hornung 			opts->hidden = 1;
3160d9ba1e1SAlex Hornung 			break;
3170d9ba1e1SAlex Hornung 		case 'i':
3180d9ba1e1SAlex Hornung 			info_vol = 1;
3190d9ba1e1SAlex Hornung 			break;
320c833cfcfSAlex Hornung 		case 'j':
321c833cfcfSAlex Hornung 			info_map = 1;
322c833cfcfSAlex Hornung 			_set_str_opt(map_name);
323c833cfcfSAlex Hornung 			break;
3240d9ba1e1SAlex Hornung 		case 'k':
325c833cfcfSAlex Hornung 			if ((error = opts_add_keyfile(opts, optarg)) != 0) {
326c833cfcfSAlex Hornung 				fprintf(stderr, "Could not add keyfile: %s\n", optarg);
327c833cfcfSAlex Hornung 				exit(EXIT_FAILURE);
328c833cfcfSAlex Hornung 			}
3290d9ba1e1SAlex Hornung 			break;
3300d9ba1e1SAlex Hornung 		case 'm':
3310d9ba1e1SAlex Hornung 			map_vol = 1;
332c833cfcfSAlex Hornung 			_set_str_opt(map_name);
3330d9ba1e1SAlex Hornung 			break;
334*7b1e1c8eSDaniel Fojt 		case 'p':
335*7b1e1c8eSDaniel Fojt 			opts->prompt_passphrase = 1;
336*7b1e1c8eSDaniel Fojt 			break;
3370d9ba1e1SAlex Hornung 		case 's':
338c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_SYS;
339c833cfcfSAlex Hornung 			_set_str_opt(sys_dev);
340c833cfcfSAlex Hornung 			break;
341c833cfcfSAlex Hornung 		case 't':
342c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_ALLOW_TRIM;
343c833cfcfSAlex Hornung 			break;
344c833cfcfSAlex Hornung 		case 'u':
345c833cfcfSAlex Hornung 			unmap_vol = 1;
346c833cfcfSAlex Hornung 			_set_str_opt(map_name);
3470d9ba1e1SAlex Hornung 			break;
3480d9ba1e1SAlex Hornung 		case 'v':
3490d9ba1e1SAlex Hornung 			printf("tcplay v%d.%d\n", MAJ_VER, MIN_VER);
350c833cfcfSAlex Hornung 			exit(EXIT_SUCCESS);
3510d9ba1e1SAlex Hornung 			/* NOT REACHED */
352c833cfcfSAlex Hornung 		case 'w':
353c833cfcfSAlex Hornung 			fprintf(stderr, "WARNING: Using urandom as source of "
354c833cfcfSAlex Hornung 			    "entropy for key material is a really bad idea.\n");
355c833cfcfSAlex Hornung 			opts->weak_keys_and_salt = 1;
356c833cfcfSAlex Hornung 			break;
3570d9ba1e1SAlex Hornung 		case 'x':
358c833cfcfSAlex Hornung 			if (opts->h_prf_algo != NULL)
3590d9ba1e1SAlex Hornung 				usage();
360*7b1e1c8eSDaniel Fojt 			if ((opts->h_prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) {
3610d9ba1e1SAlex Hornung 				if (strcmp(optarg, "help") == 0)
362c833cfcfSAlex Hornung 					exit(EXIT_SUCCESS);
3630d9ba1e1SAlex Hornung 				else
3640d9ba1e1SAlex Hornung 					usage();
3650d9ba1e1SAlex Hornung 				/* NOT REACHED */
3660d9ba1e1SAlex Hornung 			}
3670d9ba1e1SAlex Hornung 			break;
3680d9ba1e1SAlex Hornung 		case 'y':
369c833cfcfSAlex Hornung 			if (opts->h_cipher_chain != NULL)
3700d9ba1e1SAlex Hornung 				usage();
371c833cfcfSAlex Hornung 			if ((opts->h_cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
3720d9ba1e1SAlex Hornung 				if (strcmp(optarg, "help") == 0)
373c833cfcfSAlex Hornung 					exit(EXIT_SUCCESS);
3740d9ba1e1SAlex Hornung 				else
3750d9ba1e1SAlex Hornung 					usage();
3760d9ba1e1SAlex Hornung 				/* NOT REACHED */
3770d9ba1e1SAlex Hornung 			}
3780d9ba1e1SAlex Hornung 			break;
379c833cfcfSAlex Hornung 		case 'z':
380c833cfcfSAlex Hornung 			opts->secure_erase = 0;
381c833cfcfSAlex Hornung 			break;
382c833cfcfSAlex Hornung 		case FLAG_LONG_FDE:
383c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_FDE;
384c833cfcfSAlex Hornung 			break;
385c833cfcfSAlex Hornung 		case FLAG_LONG_USE_BACKUP:
386c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_BACKUP;
387c833cfcfSAlex Hornung 			break;
388c833cfcfSAlex Hornung 		case FLAG_LONG_USE_HDR_FILE:
389c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_HDR_FROM_FILE;
390c833cfcfSAlex Hornung 			_set_str_opt(hdr_file_in);
391c833cfcfSAlex Hornung 			break;
392c833cfcfSAlex Hornung 		case FLAG_LONG_USE_HHDR_FILE:
393c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_H_HDR_FROM_FILE;
394c833cfcfSAlex Hornung 			_set_str_opt(h_hdr_file_in);
395c833cfcfSAlex Hornung 			break;
396c833cfcfSAlex Hornung 		case FLAG_LONG_MOD:
397c833cfcfSAlex Hornung 			modify_vol = 1;
398c833cfcfSAlex Hornung 			break;
399c833cfcfSAlex Hornung 		case FLAG_LONG_MOD_KF:
400c833cfcfSAlex Hornung 			if ((error = opts_add_keyfile_new(opts, optarg)) != 0) {
401c833cfcfSAlex Hornung 				fprintf(stderr, "Could not add keyfile: %s\n", optarg);
402c833cfcfSAlex Hornung 				exit(EXIT_FAILURE);
403c833cfcfSAlex Hornung 			}
404c833cfcfSAlex Hornung 			break;
405c833cfcfSAlex Hornung 		case FLAG_LONG_MOD_PRF:
406c833cfcfSAlex Hornung 			if (opts->new_prf_algo != NULL)
407c833cfcfSAlex Hornung 				usage();
408*7b1e1c8eSDaniel Fojt 			if ((opts->new_prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) {
409c833cfcfSAlex Hornung 				if (strcmp(optarg, "help") == 0)
410c833cfcfSAlex Hornung 					exit(EXIT_SUCCESS);
411c833cfcfSAlex Hornung 				else
412c833cfcfSAlex Hornung 					usage();
413c833cfcfSAlex Hornung 				/* NOT REACHED */
414c833cfcfSAlex Hornung 			}
415c833cfcfSAlex Hornung 			break;
416c833cfcfSAlex Hornung 		case FLAG_LONG_MOD_NONE:
417c833cfcfSAlex Hornung 			opts->new_prf_algo = NULL;
418c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_ONLY_RESTORE;
419c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_BACKUP;
420c833cfcfSAlex Hornung 			break;
421c833cfcfSAlex Hornung 		case FLAG_LONG_MOD_TO_FILE:
422c833cfcfSAlex Hornung 			opts->flags |= TC_FLAG_SAVE_TO_FILE;
423c833cfcfSAlex Hornung 			_set_str_opt(hdr_file_out);
424c833cfcfSAlex Hornung 			break;
425c833cfcfSAlex Hornung 		case FLAG_LONG_NO_RETRIES:
426c833cfcfSAlex Hornung 			opts->retries = 1;
427c833cfcfSAlex Hornung 			break;
4280d9ba1e1SAlex Hornung 		case 'h':
4290d9ba1e1SAlex Hornung 		case '?':
4300d9ba1e1SAlex Hornung 		default:
4310d9ba1e1SAlex Hornung 			usage();
4320d9ba1e1SAlex Hornung 			/* NOT REACHED */
4330d9ba1e1SAlex Hornung 		}
4340d9ba1e1SAlex Hornung 	}
4350d9ba1e1SAlex Hornung 
4360d9ba1e1SAlex Hornung 	argc -= optind;
4370d9ba1e1SAlex Hornung 	argv += optind;
4380d9ba1e1SAlex Hornung 
4390d9ba1e1SAlex Hornung 	/* Check arguments */
440c833cfcfSAlex Hornung 	if (!(((map_vol || info_vol || create_vol || modify_vol) && opts->dev != NULL) ||
441c833cfcfSAlex Hornung 	    ((unmap_vol || info_map) && opts->map_name != NULL)) ||
442c833cfcfSAlex Hornung 	    (TC_FLAG_SET(opts->flags, SYS) && TC_FLAG_SET(opts->flags, FDE)) ||
443c833cfcfSAlex Hornung 	    (map_vol + info_vol + create_vol + unmap_vol + info_map + modify_vol > 1) ||
444c833cfcfSAlex Hornung 	    (opts->hidden && !create_vol) ||
445c833cfcfSAlex Hornung 	    (TC_FLAG_SET(opts->flags, SYS) && (opts->sys_dev == NULL)) ||
446c833cfcfSAlex Hornung 	    (TC_FLAG_SET(opts->flags, ONLY_RESTORE) && (opts->n_newkeyfiles > 0 || opts->new_prf_algo != NULL)) ||
447c833cfcfSAlex Hornung 	    (TC_FLAG_SET(opts->flags, BACKUP) && (opts->sys_dev != NULL || TC_FLAG_SET(opts->flags, FDE))) ||
448c833cfcfSAlex Hornung 	    (map_vol && (opts->map_name == NULL)) ||
449c833cfcfSAlex Hornung 	    (unmap_vol && (opts->map_name == NULL)) ||
450c833cfcfSAlex Hornung 	    (!modify_vol && opts->n_newkeyfiles > 0) ||
451c833cfcfSAlex Hornung 	    (!modify_vol && opts->new_prf_algo != NULL) ||
452c833cfcfSAlex Hornung 	    (!modify_vol && TC_FLAG_SET(opts->flags, ONLY_RESTORE)) ||
453c833cfcfSAlex Hornung 	    (!modify_vol && TC_FLAG_SET(opts->flags, SAVE_TO_FILE)) ||
454c833cfcfSAlex Hornung 	    (!(opts->protect_hidden || create_vol) && opts->n_hkeyfiles > 0)) {
4550d9ba1e1SAlex Hornung 		usage();
4560d9ba1e1SAlex Hornung 		/* NOT REACHED */
4570d9ba1e1SAlex Hornung 	}
4580d9ba1e1SAlex Hornung 
4590d9ba1e1SAlex Hornung 	/* Create a new volume */
4600d9ba1e1SAlex Hornung 	if (create_vol) {
461c833cfcfSAlex Hornung 		error = create_volume(opts);
4620d9ba1e1SAlex Hornung 		if (error) {
463c833cfcfSAlex Hornung 			tc_log(1, "could not create new volume on %s\n", opts->dev);
4640d9ba1e1SAlex Hornung 		}
465c833cfcfSAlex Hornung 	} else if (info_map) {
466c833cfcfSAlex Hornung 		error = info_mapped_volume(opts);
4670d9ba1e1SAlex Hornung 	} else if (info_vol) {
468c833cfcfSAlex Hornung 		error = info_volume(opts);
4690d9ba1e1SAlex Hornung 	} else if (map_vol) {
470c833cfcfSAlex Hornung 		error = map_volume(opts);
471c833cfcfSAlex Hornung 	} else if (unmap_vol) {
472c833cfcfSAlex Hornung 		error = dm_teardown(opts->map_name, NULL);
473c833cfcfSAlex Hornung 	} else if (modify_vol) {
474c833cfcfSAlex Hornung 		error = modify_volume(opts);
4750d9ba1e1SAlex Hornung 	}
4760d9ba1e1SAlex Hornung 
4770d9ba1e1SAlex Hornung 	return error;
4780d9ba1e1SAlex Hornung }
479c833cfcfSAlex Hornung 
480c833cfcfSAlex Hornung #undef _set_str_opt
481