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