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