Home | History | Annotate | Line # | Download | only in cgdconfig
cgdconfig.c revision 1.46
      1 /* $NetBSD: cgdconfig.c,v 1.46 2018/05/09 18:11:56 alnsn Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Roland C. Dowdeswell.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 __COPYRIGHT("@(#) Copyright (c) 2002, 2003\
     35  The NetBSD Foundation, Inc.  All rights reserved.");
     36 __RCSID("$NetBSD: cgdconfig.c,v 1.46 2018/05/09 18:11:56 alnsn Exp $");
     37 #endif
     38 
     39 #include <err.h>
     40 #include <errno.h>
     41 #include <fcntl.h>
     42 #include <libgen.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <string.h>
     46 #include <unistd.h>
     47 #include <util.h>
     48 #include <paths.h>
     49 #include <dirent.h>
     50 
     51 #include <sys/ioctl.h>
     52 #include <sys/stat.h>
     53 #include <sys/bootblock.h>
     54 #include <sys/disklabel.h>
     55 #include <sys/disklabel_gpt.h>
     56 #include <sys/mman.h>
     57 #include <sys/param.h>
     58 #include <sys/resource.h>
     59 #include <sys/statvfs.h>
     60 #include <sys/bitops.h>
     61 
     62 #include <dev/cgdvar.h>
     63 
     64 #include <ufs/ffs/fs.h>
     65 
     66 #include "params.h"
     67 #include "pkcs5_pbkdf2.h"
     68 #include "utils.h"
     69 #include "cgdconfig.h"
     70 #include "prog_ops.h"
     71 
     72 #define CGDCONFIG_CFILE		CGDCONFIG_DIR "/cgd.conf"
     73 
     74 enum action {
     75 	 ACTION_DEFAULT,		/* default -> configure */
     76 	 ACTION_CONFIGURE,		/* configure, with paramsfile */
     77 	 ACTION_UNCONFIGURE,		/* unconfigure */
     78 	 ACTION_GENERATE,		/* generate a paramsfile */
     79 	 ACTION_GENERATE_CONVERT,	/* generate a ``dup'' paramsfile */
     80 	 ACTION_CONFIGALL,		/* configure all from config file */
     81 	 ACTION_UNCONFIGALL,		/* unconfigure all from config file */
     82 	 ACTION_CONFIGSTDIN,		/* configure, key from stdin */
     83 	 ACTION_LIST			/* list configured devices */
     84 };
     85 
     86 /* if nflag is set, do not configure/unconfigure the cgd's */
     87 
     88 int	nflag = 0;
     89 
     90 /* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */
     91 
     92 #define	PFLAG_GETPASS		0x01
     93 #define	PFLAG_GETPASS_ECHO	0x02
     94 #define	PFLAG_GETPASS_MASK	0x03
     95 #define	PFLAG_STDIN		0x04
     96 int	pflag = PFLAG_GETPASS;
     97 
     98 static int	configure(int, char **, struct params *, int);
     99 static int	configure_stdin(struct params *, int argc, char **);
    100 static int	generate(struct params *, int, char **, const char *);
    101 static int	generate_convert(struct params *, int, char **, const char *);
    102 static int	unconfigure(int, char **, struct params *, int);
    103 static int	do_all(const char *, int, char **,
    104 		       int (*)(int, char **, struct params *, int));
    105 static int	do_list(int, char **);
    106 
    107 #define CONFIG_FLAGS_FROMALL	1	/* called from configure_all() */
    108 #define CONFIG_FLAGS_FROMMAIN	2	/* called from main() */
    109 
    110 static int	 configure_params(int, const char *, const char *,
    111 				  struct params *);
    112 static void	 eliminate_cores(void);
    113 static bits_t	*getkey(const char *, struct keygen *, size_t);
    114 static bits_t	*getkey_storedkey(const char *, struct keygen *, size_t);
    115 static bits_t	*getkey_randomkey(const char *, struct keygen *, size_t, int);
    116 static bits_t	*getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t,
    117 				     int);
    118 static bits_t	*getkey_shell_cmd(const char *, struct keygen *, size_t);
    119 static char	*maybe_getpass(char *);
    120 static int	 opendisk_werror(const char *, char *, size_t);
    121 static int	 unconfigure_fd(int);
    122 static int	 verify(struct params *, int);
    123 static int	 verify_disklabel(int);
    124 static int	 verify_ffs(int);
    125 static int	 verify_reenter(struct params *);
    126 static int	 verify_mbr(int);
    127 static int	 verify_gpt(int);
    128 
    129 __dead static void	 usage(void);
    130 
    131 /* Verbose Framework */
    132 unsigned	verbose = 0;
    133 
    134 #define VERBOSE(x,y)	if (verbose >= x) y
    135 #define VPRINTF(x,y)	if (verbose >= x) (void)printf y
    136 
    137 static void
    138 usage(void)
    139 {
    140 
    141 	(void)fprintf(stderr, "usage: %s [-enpv] [-V vmeth] cgd dev "
    142 	    "[paramsfile]\n", getprogname());
    143 	(void)fprintf(stderr, "       %s -C [-enpv] [-f configfile]\n",
    144 	    getprogname());
    145 	(void)fprintf(stderr, "       %s -G [-enpv] [-i ivmeth] [-k kgmeth] "
    146 	    "[-o outfile] paramsfile\n", getprogname());
    147 	(void)fprintf(stderr, "       %s -g [-nv] [-i ivmeth] [-k kgmeth] "
    148 	    "[-o outfile] alg [keylen]\n", getprogname());
    149 	(void)fprintf(stderr, "       %s -l [-v[v]] [cgd]\n", getprogname());
    150 	(void)fprintf(stderr, "       %s -s [-nv] [-i ivmeth] cgd dev alg "
    151 	    "[keylen]\n", getprogname());
    152 	(void)fprintf(stderr, "       %s -U [-nv] [-f configfile]\n",
    153 	    getprogname());
    154 	(void)fprintf(stderr, "       %s -u [-nv] cgd\n", getprogname());
    155 	exit(EXIT_FAILURE);
    156 }
    157 
    158 static int
    159 parse_size_t(const char *s, size_t *l)
    160 {
    161 	char *endptr;
    162 	long v;
    163 
    164 	errno = 0;
    165 	v = strtol(s, &endptr, 10);
    166 	if ((v == LONG_MIN || v == LONG_MAX) && errno)
    167 		return -1;
    168 	if (v < INT_MIN || v > INT_MAX) {
    169 		errno = ERANGE;
    170 		return -1;
    171 	}
    172 	if (endptr == s) {
    173 		errno = EINVAL;
    174 		return -1;
    175 	}
    176 	*l = (size_t)v;
    177 	return 0;
    178 }
    179 
    180 static void
    181 set_action(enum action *action, enum action value)
    182 {
    183 	if (*action != ACTION_DEFAULT)
    184 		usage();
    185 	*action = value;
    186 }
    187 
    188 int
    189 main(int argc, char **argv)
    190 {
    191 	struct params *p;
    192 	struct params *tp;
    193 	struct keygen *kg;
    194 	enum action action = ACTION_DEFAULT;
    195 	int	ch;
    196 	const char	*cfile = NULL;
    197 	const char	*outfile = NULL;
    198 
    199 	setprogname(*argv);
    200 	eliminate_cores();
    201 	if (mlockall(MCL_FUTURE))
    202 		err(EXIT_FAILURE, "Can't lock memory");
    203 	p = params_new();
    204 	kg = NULL;
    205 
    206 	while ((ch = getopt(argc, argv, "CGUV:b:ef:gi:k:lno:spuv")) != -1)
    207 		switch (ch) {
    208 		case 'C':
    209 			set_action(&action, ACTION_CONFIGALL);
    210 			break;
    211 		case 'G':
    212 			set_action(&action, ACTION_GENERATE_CONVERT);
    213 			break;
    214 		case 'U':
    215 			set_action(&action, ACTION_UNCONFIGALL);
    216 			break;
    217 		case 'V':
    218 			tp = params_verify_method(string_fromcharstar(optarg));
    219 			if (!tp)
    220 				usage();
    221 			p = params_combine(p, tp);
    222 			break;
    223 		case 'b':
    224 			{
    225 				size_t size;
    226 
    227 				if (parse_size_t(optarg, &size) == -1)
    228 					usage();
    229 				tp = params_bsize(size);
    230 				if (!tp)
    231 					usage();
    232 				p = params_combine(p, tp);
    233 			}
    234 			break;
    235 		case 'e':
    236 			pflag = PFLAG_GETPASS_ECHO;
    237 			break;
    238 		case 'f':
    239 			if (cfile)
    240 				usage();
    241 			cfile = estrdup(optarg);
    242 			break;
    243 		case 'g':
    244 			set_action(&action, ACTION_GENERATE);
    245 			break;
    246 		case 'i':
    247 			tp = params_ivmeth(string_fromcharstar(optarg));
    248 			p = params_combine(p, tp);
    249 			break;
    250 		case 'k':
    251 			kg = keygen_method(string_fromcharstar(optarg));
    252 			if (!kg)
    253 				usage();
    254 			keygen_addlist(&p->keygen, kg);
    255 			break;
    256 		case 'l':
    257 			set_action(&action, ACTION_LIST);
    258 			break;
    259 		case 'n':
    260 			nflag = 1;
    261 			break;
    262 		case 'o':
    263 			if (outfile)
    264 				usage();
    265 			outfile = estrdup(optarg);
    266 			break;
    267 		case 'p':
    268 			pflag = PFLAG_STDIN;
    269 			break;
    270 		case 's':
    271 			set_action(&action, ACTION_CONFIGSTDIN);
    272 			break;
    273 
    274 		case 'u':
    275 			set_action(&action, ACTION_UNCONFIGURE);
    276 			break;
    277 		case 'v':
    278 			verbose++;
    279 			break;
    280 		default:
    281 			usage();
    282 			/* NOTREACHED */
    283 		}
    284 
    285 	argc -= optind;
    286 	argv += optind;
    287 
    288 	if (!outfile)
    289 		outfile = "";
    290 	if (!cfile)
    291 		cfile = "";
    292 
    293 	if (prog_init && prog_init() == -1)
    294 		err(1, "init failed");
    295 
    296 	/* validate the consistency of the arguments */
    297 
    298 	switch (action) {
    299 	case ACTION_DEFAULT:	/* ACTION_CONFIGURE is the default */
    300 	case ACTION_CONFIGURE:
    301 		return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN);
    302 	case ACTION_UNCONFIGURE:
    303 		return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN);
    304 	case ACTION_GENERATE:
    305 		return generate(p, argc, argv, outfile);
    306 	case ACTION_GENERATE_CONVERT:
    307 		return generate_convert(p, argc, argv, outfile);
    308 	case ACTION_CONFIGALL:
    309 		return do_all(cfile, argc, argv, configure);
    310 	case ACTION_UNCONFIGALL:
    311 		return do_all(cfile, argc, argv, unconfigure);
    312 	case ACTION_CONFIGSTDIN:
    313 		return configure_stdin(p, argc, argv);
    314 	case ACTION_LIST:
    315 		return do_list(argc, argv);
    316 	default:
    317 		errx(EXIT_FAILURE, "undefined action");
    318 		/* NOTREACHED */
    319 	}
    320 }
    321 
    322 static bits_t *
    323 getkey(const char *dev, struct keygen *kg, size_t len)
    324 {
    325 	bits_t	*ret = NULL;
    326 	bits_t	*tmp;
    327 
    328 	VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len));
    329 	for (; kg; kg=kg->next) {
    330 		switch (kg->kg_method) {
    331 		case KEYGEN_STOREDKEY:
    332 			tmp = getkey_storedkey(dev, kg, len);
    333 			break;
    334 		case KEYGEN_RANDOMKEY:
    335 			tmp = getkey_randomkey(dev, kg, len, 1);
    336 			break;
    337 		case KEYGEN_URANDOMKEY:
    338 			tmp = getkey_randomkey(dev, kg, len, 0);
    339 			break;
    340 		case KEYGEN_PKCS5_PBKDF2_SHA1:
    341 			tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
    342 			break;
    343 		/* provide backwards compatibility for old config files */
    344 		case KEYGEN_PKCS5_PBKDF2_OLD:
    345 			tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1);
    346 			break;
    347 		case KEYGEN_SHELL_CMD:
    348 			tmp = getkey_shell_cmd(dev, kg, len);
    349 			break;
    350 		default:
    351 			warnx("unrecognised keygen method %d in getkey()",
    352 			    kg->kg_method);
    353 			if (ret)
    354 				bits_free(ret);
    355 			return NULL;
    356 		}
    357 
    358 		if (ret)
    359 			ret = bits_xor_d(tmp, ret);
    360 		else
    361 			ret = tmp;
    362 	}
    363 
    364 	return ret;
    365 }
    366 
    367 /*ARGSUSED*/
    368 static bits_t *
    369 getkey_storedkey(const char *target, struct keygen *kg, size_t keylen)
    370 {
    371 	return bits_dup(kg->kg_key);
    372 }
    373 
    374 /*ARGSUSED*/
    375 static bits_t *
    376 getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard)
    377 {
    378 	return bits_getrandombits(keylen, hard);
    379 }
    380 
    381 static char *
    382 maybe_getpass(char *prompt)
    383 {
    384 	char	 buf[1024];
    385 	char	*p = NULL;
    386 	char	*tmp, *pass;
    387 
    388 	switch (pflag) {
    389 	case PFLAG_GETPASS:
    390 		p = getpass_r(prompt, buf, sizeof(buf));
    391 		break;
    392 
    393 	case PFLAG_GETPASS_ECHO:
    394 		p = getpassfd(prompt, buf, sizeof(buf), NULL,
    395 		    GETPASS_ECHO|GETPASS_ECHO_NL|GETPASS_NEED_TTY, 0);
    396 		break;
    397 
    398 	case PFLAG_STDIN:
    399 		p = fgets(buf, sizeof(buf), stdin);
    400 		if (p) {
    401 			tmp = strchr(p, '\n');
    402 			if (tmp)
    403 				*tmp = '\0';
    404 		}
    405 		break;
    406 
    407 	default:
    408 		errx(EXIT_FAILURE, "pflag set inappropriately?");
    409 	}
    410 
    411 	if (!p)
    412 		err(EXIT_FAILURE, "failed to read passphrase");
    413 
    414 	pass = estrdup(p);
    415 	memset(buf, 0, sizeof(buf));
    416 
    417 	return pass;
    418 }
    419 
    420 /*ARGSUSED*/
    421 /*
    422  * XXX take, and pass through, a compat flag that indicates whether we
    423  * provide backwards compatibility with a previous bug.  The previous
    424  * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a
    425  * non-zero compat flag. The new default, and correct keygen method is
    426  * called pcks5_pbkdf2/sha1.  When the old method is removed, so will
    427  * be the compat argument.
    428  */
    429 static bits_t *
    430 getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen,
    431     int compat)
    432 {
    433 	bits_t		*ret;
    434 	char		*passp;
    435 	char		 buf[1024];
    436 	u_int8_t	*tmp;
    437 
    438 	snprintf(buf, sizeof(buf), "%s's passphrase%s:", target,
    439 	    pflag & PFLAG_GETPASS_ECHO ? " (echo)" : "");
    440 	passp = maybe_getpass(buf);
    441 	if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp,
    442 	    strlen(passp),
    443 	    bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)),
    444 	    kg->kg_iterations, compat)) {
    445 		warnx("failed to generate PKCS#5 PBKDF2 key");
    446 		return NULL;
    447 	}
    448 
    449 	ret = bits_new(tmp, keylen);
    450 	kg->kg_key = bits_dup(ret);
    451 	memset(passp, 0, strlen(passp));
    452 	free(passp);
    453 	free(tmp);
    454 	return ret;
    455 }
    456 
    457 /*ARGSUSED*/
    458 static bits_t *
    459 getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen)
    460 {
    461 	FILE	*f;
    462 	bits_t	*ret;
    463 
    464 	f = popen(string_tocharstar(kg->kg_cmd), "r");
    465 	ret = bits_fget(f, keylen);
    466 	pclose(f);
    467 
    468 	return ret;
    469 }
    470 
    471 /*ARGSUSED*/
    472 static int
    473 unconfigure(int argc, char **argv, struct params *inparams, int flags)
    474 {
    475 	int	fd;
    476 	int	ret;
    477 	char	buf[MAXPATHLEN] = "";
    478 
    479 	/* only complain about additional arguments, if called from main() */
    480 	if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
    481 		usage();
    482 
    483 	/* if called from do_all(), then ensure that 2 or 3 args exist */
    484 	if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
    485 		return -1;
    486 
    487 	fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, prog_open);
    488 	if (fd == -1) {
    489 		int saved_errno = errno;
    490 
    491 		warn("can't open cgd \"%s\", \"%s\"", *argv, buf);
    492 
    493 		/* this isn't fatal with nflag != 0 */
    494 		if (!nflag)
    495 			return saved_errno;
    496 	}
    497 
    498 	VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
    499 
    500 	if (nflag)
    501 		return 0;
    502 
    503 	ret = unconfigure_fd(fd);
    504 	(void)prog_close(fd);
    505 	return ret;
    506 }
    507 
    508 static int
    509 unconfigure_fd(int fd)
    510 {
    511 	struct	cgd_ioctl ci;
    512 
    513 	if (prog_ioctl(fd, CGDIOCCLR, &ci) == -1) {
    514 		warn("ioctl");
    515 		return -1;
    516 	}
    517 
    518 	return 0;
    519 }
    520 
    521 /*ARGSUSED*/
    522 static int
    523 configure(int argc, char **argv, struct params *inparams, int flags)
    524 {
    525 	struct params	*p;
    526 	struct keygen	*kg;
    527 	int		 fd;
    528 	int		 loop = 0;
    529 	int		 ret;
    530 	char		 cgdname[PATH_MAX];
    531 	char		 devicename[PATH_MAX];
    532 	const char	*dev = NULL;	/* XXX: gcc */
    533 
    534 	if (argc < 2 || argc > 3) {
    535 		/* print usage and exit, only if called from main() */
    536 		if (flags == CONFIG_FLAGS_FROMMAIN) {
    537 			warnx("wrong number of args");
    538 			usage();
    539 		}
    540 		return -1;
    541 	}
    542 
    543 	if ((
    544 	  fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open)
    545 	    ) != -1) {
    546 		struct cgd_user cgu;
    547 
    548 		cgu.cgu_unit = -1;
    549 		if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) {
    550 			warnx("device %s already in use", *argv);
    551 			prog_close(fd);
    552 			return -1;
    553 		}
    554 		prog_close(fd);
    555 	}
    556 
    557 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    558 	if (dev == NULL) {
    559 		warnx("getfsspecname failed: %s", devicename);
    560 		return -1;
    561 	}
    562 
    563 	if (argc == 2) {
    564 		char pfile[MAXPATHLEN];
    565 
    566 		/* make string writable for basename */
    567 		strlcpy(pfile, dev, sizeof(pfile));
    568 		p = params_cget(basename(pfile));
    569 	} else
    570 		p = params_cget(argv[2]);
    571 
    572 	if (!p)
    573 		return -1;
    574 
    575 	/*
    576 	 * over-ride with command line specifications and fill in default
    577 	 * values.
    578 	 */
    579 
    580 	p = params_combine(p, inparams);
    581 	ret = params_filldefaults(p);
    582 	if (ret) {
    583 		params_free(p);
    584 		return ret;
    585 	}
    586 
    587 	if (!params_verify(p)) {
    588 		warnx("params invalid");
    589 		return -1;
    590 	}
    591 
    592 	/*
    593 	 * loop over configuring the disk and checking to see if it
    594 	 * verifies properly.  We open and close the disk device each
    595 	 * time, because if the user passes us the block device we
    596 	 * need to flush the buffer cache.
    597 	 *
    598 	 * We only loop if one of the verification methods prompts for
    599 	 * a password.
    600 	 */
    601 
    602 	for (kg = p->keygen; pflag == PFLAG_GETPASS && kg; kg = kg->next)
    603 		if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) ||
    604 		    (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) {
    605 			loop = 1;
    606 			break;
    607 		}
    608 
    609 	for (;;) {
    610 		fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    611 		if (fd == -1)
    612 			return -1;
    613 
    614 		if (p->key)
    615 			bits_free(p->key);
    616 
    617 		p->key = getkey(argv[1], p->keygen, p->keylen);
    618 		if (!p->key)
    619 			goto bail_err;
    620 
    621 		ret = configure_params(fd, cgdname, dev, p);
    622 		if (ret)
    623 			goto bail_err;
    624 
    625 		ret = verify(p, fd);
    626 		if (ret == -1)
    627 			goto bail_err;
    628 		if (!ret)
    629 			break;
    630 
    631 		(void)unconfigure_fd(fd);
    632 		(void)prog_close(fd);
    633 
    634 		if (!loop) {
    635 			warnx("verification failed permanently");
    636 			goto bail_err;
    637 		}
    638 
    639 		warnx("verification failed, please reenter passphrase");
    640 	}
    641 
    642 	params_free(p);
    643 	(void)prog_close(fd);
    644 	return 0;
    645 bail_err:
    646 	params_free(p);
    647 	(void)prog_close(fd);
    648 	return -1;
    649 }
    650 
    651 static int
    652 configure_stdin(struct params *p, int argc, char **argv)
    653 {
    654 	int		 fd;
    655 	int		 ret;
    656 	char		 cgdname[PATH_MAX];
    657 	char		 devicename[PATH_MAX];
    658 	const char	*dev;
    659 
    660 	if (argc < 3 || argc > 4)
    661 		usage();
    662 
    663 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    664 	if (dev == NULL) {
    665 		warnx("getfsspecname failed: %s", devicename);
    666 		return -1;
    667 	}
    668 
    669 	p->algorithm = string_fromcharstar(argv[2]);
    670 	if (argc > 3) {
    671 		size_t keylen;
    672 
    673 		if (parse_size_t(argv[3], &keylen) == -1) {
    674 			warn("failed to parse key length");
    675 			return -1;
    676 		}
    677 		p->keylen = keylen;
    678 	}
    679 
    680 	ret = params_filldefaults(p);
    681 	if (ret)
    682 		return ret;
    683 
    684 	fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    685 	if (fd == -1)
    686 		return -1;
    687 
    688 	p->key = bits_fget(stdin, p->keylen);
    689 	if (!p->key) {
    690 		warnx("failed to read key from stdin");
    691 		return -1;
    692 	}
    693 
    694 	return configure_params(fd, cgdname, dev, p);
    695 }
    696 
    697 static int
    698 opendisk_werror(const char *cgd, char *buf, size_t buflen)
    699 {
    700 	int	fd;
    701 
    702 	VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd, buf, buflen));
    703 
    704 	/* sanity */
    705 	if (!cgd || !buf)
    706 		return -1;
    707 
    708 	if (nflag) {
    709 		if (strlcpy(buf, cgd, buflen) >= buflen)
    710 			return -1;
    711 		return 0;
    712 	}
    713 
    714 	fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open);
    715 	if (fd == -1)
    716 		warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
    717 
    718 	return fd;
    719 }
    720 
    721 static int
    722 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
    723 {
    724 	struct cgd_ioctl ci;
    725 
    726 	/* sanity */
    727 	if (!cgd || !dev)
    728 		return -1;
    729 
    730 	(void)memset(&ci, 0x0, sizeof(ci));
    731 	ci.ci_disk = dev;
    732 	ci.ci_alg = string_tocharstar(p->algorithm);
    733 	ci.ci_ivmethod = string_tocharstar(p->ivmeth);
    734 	ci.ci_key = bits_getbuf(p->key);
    735 	ci.ci_keylen = p->keylen;
    736 	ci.ci_blocksize = p->bsize;
    737 
    738 	VPRINTF(1, ("    with alg %s keylen %zu blocksize %zu ivmethod %s\n",
    739 	    string_tocharstar(p->algorithm), p->keylen, p->bsize,
    740 	    string_tocharstar(p->ivmeth)));
    741 	VPRINTF(2, ("key: "));
    742 	VERBOSE(2, bits_fprint(stdout, p->key));
    743 	VPRINTF(2, ("\n"));
    744 
    745 	if (nflag)
    746 		return 0;
    747 
    748 	if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) {
    749 		int saved_errno = errno;
    750 		warn("ioctl");
    751 		return saved_errno;
    752 	}
    753 
    754 	return 0;
    755 }
    756 
    757 /*
    758  * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
    759  */
    760 
    761 #define SCANSIZE	8192
    762 
    763 static int
    764 verify(struct params *p, int fd)
    765 {
    766 
    767 	switch (p->verify_method) {
    768 	case VERIFY_NONE:
    769 		return 0;
    770 	case VERIFY_DISKLABEL:
    771 		return verify_disklabel(fd);
    772 	case VERIFY_FFS:
    773 		return verify_ffs(fd);
    774 	case VERIFY_REENTER:
    775 		return verify_reenter(p);
    776 	case VERIFY_MBR:
    777 		return verify_mbr(fd);
    778 	case VERIFY_GPT:
    779 		return verify_gpt(fd);
    780 	default:
    781 		warnx("unimplemented verification method");
    782 		return -1;
    783 	}
    784 }
    785 
    786 static int
    787 verify_disklabel(int fd)
    788 {
    789 	struct	disklabel l;
    790 	ssize_t	ret;
    791 	char	buf[SCANSIZE];
    792 
    793 	/*
    794 	 * we simply scan the first few blocks for a disklabel, ignoring
    795 	 * any MBR/filecore sorts of logic.  MSDOS and RiscOS can't read
    796 	 * a cgd, anyway, so it is unlikely that there will be non-native
    797 	 * partition information.
    798 	 */
    799 
    800 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    801 	if (ret < 0) {
    802 		warn("can't read disklabel area");
    803 		return -1;
    804 	}
    805 
    806 	/* now scan for the disklabel */
    807 
    808 	return disklabel_scan(&l, buf, (size_t)ret);
    809 }
    810 
    811 static int
    812 verify_mbr(int fd)
    813 {
    814 	struct mbr_sector mbr;
    815 	ssize_t	ret;
    816 	char	buf[SCANSIZE];
    817 
    818 	/*
    819 	 * we read the first blocks to avoid sector size issues and
    820 	 * verify the MBR in the beginning
    821 	 */
    822 
    823 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    824 	if (ret < 0) {
    825 		warn("can't read mbr area");
    826 		return -1;
    827 	}
    828 
    829 	memcpy(&mbr, buf, sizeof(mbr));
    830 	if (le16toh(mbr.mbr_magic) != MBR_MAGIC)
    831 		return -1;
    832 
    833 	return 0;
    834 }
    835 
    836 static uint32_t crc32_tab[] = {
    837 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    838 	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    839 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    840 	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    841 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    842 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    843 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    844 	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    845 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    846 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    847 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    848 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    849 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    850 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    851 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    852 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    853 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    854 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    855 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    856 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    857 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    858 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    859 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    860 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    861 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    862 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    863 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    864 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    865 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    866 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    867 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    868 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    869 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    870 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    871 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    872 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    873 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    874 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    875 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    876 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    877 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    878 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    879 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    880 };
    881 
    882 static uint32_t
    883 crc32(const void *buf, size_t size)
    884 {
    885 	const uint8_t *p;
    886 	uint32_t crc;
    887 
    888 	p = buf;
    889 	crc = ~0U;
    890 
    891 	while (size--)
    892 		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
    893 
    894 	return crc ^ ~0U;
    895 }
    896 
    897 static int
    898 verify_gpt(int fd)
    899 {
    900 	struct	 gpt_hdr hdr;
    901 	ssize_t	 ret;
    902 	char	 buf[SCANSIZE];
    903 	unsigned blksize;
    904 	size_t	 off;
    905 
    906 	/*
    907 	 * we read the first blocks to avoid sector size issues and
    908 	 * verify the GPT header.
    909 	 */
    910 
    911 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    912 	if (ret < 0) {
    913 		warn("can't read gpt area");
    914 		return -1;
    915 	}
    916 
    917 	ret = -1;
    918 	for (blksize=DEV_BSIZE;
    919              (off = blksize * GPT_HDR_BLKNO) <= SCANSIZE - sizeof(hdr);
    920              blksize <<= 1) {
    921 
    922 		memcpy(&hdr, &buf[off], sizeof(hdr));
    923 		if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0 &&
    924 		    le32toh(hdr.hdr_revision) == GPT_HDR_REVISION &&
    925 		    le32toh(hdr.hdr_size) == GPT_HDR_SIZE) {
    926 
    927 			hdr.hdr_crc_self = 0;
    928 			if (crc32(&hdr, sizeof(hdr))) {
    929 				ret = 0;
    930 				break;
    931 			}
    932 		}
    933 	}
    934 
    935 	return ret;
    936 }
    937 
    938 static off_t sblock_try[] = SBLOCKSEARCH;
    939 
    940 static int
    941 verify_ffs(int fd)
    942 {
    943 	size_t	i;
    944 
    945 	for (i = 0; sblock_try[i] != -1; i++) {
    946 		union {
    947 		    char	buf[SBLOCKSIZE];
    948 		    struct	fs fs;
    949 		} u;
    950 		ssize_t ret;
    951 
    952 		ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]);
    953 		if (ret < 0) {
    954 			warn("pread");
    955 			break;
    956 		} else if ((size_t)ret < sizeof(u)) {
    957 			warnx("pread: incomplete block");
    958 			break;
    959 		}
    960 		switch (u.fs.fs_magic) {
    961 		case FS_UFS1_MAGIC:
    962 		case FS_UFS2_MAGIC:
    963 		case FS_UFS1_MAGIC_SWAPPED:
    964 		case FS_UFS2_MAGIC_SWAPPED:
    965 			return 0;
    966 		default:
    967 			continue;
    968 		}
    969 	}
    970 
    971 	return 1;	/* failure */
    972 }
    973 
    974 static int
    975 verify_reenter(struct params *p)
    976 {
    977 	struct keygen *kg;
    978 	bits_t *orig_key, *key;
    979 	int ret;
    980 
    981 	ret = 0;
    982 	for (kg = p->keygen; kg && !ret; kg = kg->next) {
    983 		if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
    984 		    (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
    985 			continue;
    986 
    987 		orig_key = kg->kg_key;
    988 		kg->kg_key = NULL;
    989 
    990 		/* add a compat flag till the _OLD method goes away */
    991 		key = getkey_pkcs5_pbkdf2("re-enter device", kg,
    992 			bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
    993 		ret = !bits_match(key, orig_key);
    994 
    995 		bits_free(key);
    996 		bits_free(kg->kg_key);
    997 		kg->kg_key = orig_key;
    998 	}
    999 
   1000 	return ret;
   1001 }
   1002 
   1003 static int
   1004 generate(struct params *p, int argc, char **argv, const char *outfile)
   1005 {
   1006 	int	 ret;
   1007 
   1008 	if (argc < 1 || argc > 2)
   1009 		usage();
   1010 
   1011 	p->algorithm = string_fromcharstar(argv[0]);
   1012 	if (argc > 1) {
   1013 		size_t keylen;
   1014 
   1015 		if (parse_size_t(argv[1], &keylen) == -1) {
   1016 			warn("Failed to parse key length");
   1017 			return -1;
   1018 		}
   1019 		p->keylen = keylen;
   1020 	}
   1021 
   1022 	ret = params_filldefaults(p);
   1023 	if (ret)
   1024 		return ret;
   1025 
   1026 	if (!p->keygen) {
   1027 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1028 		if (!p->keygen)
   1029 			return -1;
   1030 	}
   1031 
   1032 	if (keygen_filldefaults(p->keygen, p->keylen)) {
   1033 		warnx("Failed to generate defaults for keygen");
   1034 		return -1;
   1035 	}
   1036 
   1037 	if (!params_verify(p)) {
   1038 		warnx("invalid parameters generated");
   1039 		return -1;
   1040 	}
   1041 
   1042 	return params_cput(p, outfile);
   1043 }
   1044 
   1045 static int
   1046 generate_convert(struct params *p, int argc, char **argv, const char *outfile)
   1047 {
   1048 	struct params	*oldp;
   1049 	struct keygen	*kg;
   1050 
   1051 	if (argc != 1)
   1052 		usage();
   1053 
   1054 	oldp = params_cget(*argv);
   1055 	if (!oldp)
   1056 		return -1;
   1057 
   1058 	/* for sanity, we ensure that none of the keygens are randomkey */
   1059 	for (kg=p->keygen; kg; kg=kg->next)
   1060 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1061 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1062 			warnx("can't preserve randomly generated key");
   1063 			goto bail;
   1064 		}
   1065 	for (kg=oldp->keygen; kg; kg=kg->next)
   1066 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1067 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1068 			warnx("can't preserve randomly generated key");
   1069 			goto bail;
   1070 		}
   1071 
   1072 	if (!params_verify(oldp)) {
   1073 		warnx("invalid old parameters file \"%s\"", *argv);
   1074 		return -1;
   1075 	}
   1076 
   1077 	oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
   1078 
   1079 	/* we copy across the non-keygen info, here. */
   1080 
   1081 	string_free(p->algorithm);
   1082 	string_free(p->ivmeth);
   1083 
   1084 	p->algorithm = string_dup(oldp->algorithm);
   1085 	p->ivmeth = string_dup(oldp->ivmeth);
   1086 	p->keylen = oldp->keylen;
   1087 	p->bsize = oldp->bsize;
   1088 	if (p->verify_method == VERIFY_UNKNOWN)
   1089 		p->verify_method = oldp->verify_method;
   1090 
   1091 	params_free(oldp);
   1092 
   1093 	if (!p->keygen) {
   1094 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1095 		if (!p->keygen)
   1096 			return -1;
   1097 	}
   1098 	(void)params_filldefaults(p);
   1099 	(void)keygen_filldefaults(p->keygen, p->keylen);
   1100 	p->key = getkey("new file", p->keygen, p->keylen);
   1101 
   1102 	kg = keygen_generate(KEYGEN_STOREDKEY);
   1103 	kg->kg_key = bits_xor(p->key, oldp->key);
   1104 	keygen_addlist(&p->keygen, kg);
   1105 
   1106 	if (!params_verify(p)) {
   1107 		warnx("can't generate new parameters file");
   1108 		return -1;
   1109 	}
   1110 
   1111 	return params_cput(p, outfile);
   1112 bail:
   1113 	params_free(oldp);
   1114 	return -1;
   1115 }
   1116 
   1117 static int
   1118 /*ARGSUSED*/
   1119 do_all(const char *cfile, int argc, char **argv,
   1120        int (*conf)(int, char **, struct params *, int))
   1121 {
   1122 	FILE		 *f;
   1123 	size_t		  len;
   1124 	size_t		  lineno;
   1125 	int		  my_argc;
   1126 	int		  ret;
   1127 	const char	 *fn;
   1128 	char		 *line;
   1129 	char		**my_argv;
   1130 
   1131 	if (argc > 0)
   1132 		usage();
   1133 
   1134 	if (!cfile[0])
   1135 		fn = CGDCONFIG_CFILE;
   1136 	else
   1137 		fn = cfile;
   1138 
   1139 	f = fopen(fn, "r");
   1140 	if (!f) {
   1141 		warn("could not open config file \"%s\"", fn);
   1142 		return -1;
   1143 	}
   1144 
   1145 	ret = 0;
   1146 	lineno = 0;
   1147 	for (;;) {
   1148 		line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
   1149 		if (!line)
   1150 			break;
   1151 		if (!*line)
   1152 			continue;
   1153 
   1154 		my_argv = words(line, &my_argc);
   1155 		ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
   1156 		if (ret) {
   1157 			warnx("action failed on \"%s\" line %lu", fn,
   1158 			    (u_long)lineno);
   1159 			break;
   1160 		}
   1161 		words_free(my_argv, my_argc);
   1162 	}
   1163 	return ret;
   1164 }
   1165 
   1166 static const char *
   1167 iv_method(int mode)
   1168 {
   1169 
   1170 	switch (mode) {
   1171 	case CGD_CIPHER_CBC_ENCBLKNO8:
   1172 		return "encblkno8";
   1173 	case CGD_CIPHER_CBC_ENCBLKNO1:
   1174 		return "encblkno1";
   1175 	default:
   1176 		return "unknown";
   1177 	}
   1178 }
   1179 
   1180 
   1181 static void
   1182 show(const char *dev) {
   1183 	char path[64];
   1184 	struct cgd_user cgu;
   1185 	int fd;
   1186 
   1187 	fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0);
   1188 	if (fd == -1) {
   1189 		warn("open: %s", dev);
   1190 		return;
   1191 	}
   1192 
   1193 	cgu.cgu_unit = -1;
   1194 	if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) {
   1195 		close(fd);
   1196 		err(1, "CGDIOCGET");
   1197 	}
   1198 
   1199 	printf("%s: ", dev);
   1200 
   1201 	if (cgu.cgu_dev == 0) {
   1202 		printf("not in use");
   1203 		goto out;
   1204 	}
   1205 
   1206 	dev = devname(cgu.cgu_dev, S_IFBLK);
   1207 	if (dev != NULL)
   1208 		printf("%s ", dev);
   1209 	else
   1210 		printf("dev %llu,%llu ", (unsigned long long)major(cgu.cgu_dev),
   1211 		    (unsigned long long)minor(cgu.cgu_dev));
   1212 
   1213 	if (verbose)
   1214 		printf("%s ", cgu.cgu_alg);
   1215 	if (verbose > 1) {
   1216 		printf("keylen %d ", cgu.cgu_keylen);
   1217 		printf("blksize %zd ", cgu.cgu_blocksize);
   1218 		printf("%s ", iv_method(cgu.cgu_mode));
   1219 	}
   1220 
   1221 out:
   1222 	putchar('\n');
   1223 	close(fd);
   1224 }
   1225 
   1226 static int
   1227 do_list(int argc, char **argv)
   1228 {
   1229 
   1230 	if (argc != 0 && argc != 1)
   1231 		usage();
   1232 
   1233 	if (argc) {
   1234 		show(argv[0]);
   1235 		return 0;
   1236 	}
   1237 
   1238 	DIR *dirp;
   1239 	struct dirent *dp;
   1240 	__BITMAP_TYPE(, uint32_t, 65536) bm;
   1241 
   1242 	__BITMAP_ZERO(&bm);
   1243 
   1244 	if ((dirp = opendir(_PATH_DEV)) == NULL)
   1245 		err(1, "opendir: %s", _PATH_DEV);
   1246 
   1247 	while ((dp = readdir(dirp)) != NULL) {
   1248 		char *ep;
   1249 		if (strncmp(dp->d_name, "rcgd", 4) != 0)
   1250 			continue;
   1251 		errno = 0;
   1252 		int n = (int)strtol(dp->d_name + 4, &ep, 0);
   1253 		if (ep == dp->d_name + 4 || errno != 0) {
   1254 			warnx("bad name %s", dp->d_name);
   1255 			continue;
   1256 		}
   1257 		*ep = '\0';
   1258 		if (__BITMAP_ISSET(n, &bm))
   1259 			continue;
   1260 		__BITMAP_SET(n, &bm);
   1261 		show(dp->d_name + 1);
   1262 	}
   1263 
   1264 	closedir(dirp);
   1265 	return 0;
   1266 }
   1267 
   1268 static void
   1269 eliminate_cores(void)
   1270 {
   1271 	struct rlimit	rlp;
   1272 
   1273 	rlp.rlim_cur = 0;
   1274 	rlp.rlim_max = 0;
   1275 	if (setrlimit(RLIMIT_CORE, &rlp) == -1)
   1276 		err(EXIT_FAILURE, "Can't disable cores");
   1277 }
   1278