Home | History | Annotate | Line # | Download | only in cgdconfig
cgdconfig.c revision 1.44
      1 /* $NetBSD: cgdconfig.c,v 1.44 2018/05/09 13:19:33 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.44 2018/05/09 13:19:33 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 (argc < 2 || argc > 3) {
    519 		/* print usage and exit, only if called from main() */
    520 		if (flags == CONFIG_FLAGS_FROMMAIN) {
    521 			warnx("wrong number of args");
    522 			usage();
    523 		}
    524 		return -1;
    525 	}
    526 
    527 	if ((
    528 	  fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open)
    529 	    ) != -1) {
    530 		struct cgd_user cgu;
    531 
    532 		cgu.cgu_unit = -1;
    533 		if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) {
    534 			warnx("device %s already in use", *argv);
    535 			prog_close(fd);
    536 			return -1;
    537 		}
    538 		prog_close(fd);
    539 	}
    540 
    541 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    542 	if (dev == NULL) {
    543 		warnx("getfsspecname failed: %s", devicename);
    544 		return -1;
    545 	}
    546 
    547 	if (argc == 2) {
    548 		char pfile[MAXPATHLEN];
    549 
    550 		/* make string writable for basename */
    551 		strlcpy(pfile, dev, sizeof(pfile));
    552 		p = params_cget(basename(pfile));
    553 	} else
    554 		p = params_cget(argv[2]);
    555 
    556 	if (!p)
    557 		return -1;
    558 
    559 	/*
    560 	 * over-ride with command line specifications and fill in default
    561 	 * values.
    562 	 */
    563 
    564 	p = params_combine(p, inparams);
    565 	ret = params_filldefaults(p);
    566 	if (ret) {
    567 		params_free(p);
    568 		return ret;
    569 	}
    570 
    571 	if (!params_verify(p)) {
    572 		warnx("params invalid");
    573 		return -1;
    574 	}
    575 
    576 	/*
    577 	 * loop over configuring the disk and checking to see if it
    578 	 * verifies properly.  We open and close the disk device each
    579 	 * time, because if the user passes us the block device we
    580 	 * need to flush the buffer cache.
    581 	 *
    582 	 * We only loop if one of the verification methods prompts for
    583 	 * a password.
    584 	 */
    585 
    586 	for (kg = p->keygen; pflag == PFLAG_GETPASS && kg; kg = kg->next)
    587 		if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) ||
    588 		    (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) {
    589 			loop = 1;
    590 			break;
    591 		}
    592 
    593 	for (;;) {
    594 		fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    595 		if (fd == -1)
    596 			return -1;
    597 
    598 		if (p->key)
    599 			bits_free(p->key);
    600 
    601 		p->key = getkey(argv[1], p->keygen, p->keylen);
    602 		if (!p->key)
    603 			goto bail_err;
    604 
    605 		ret = configure_params(fd, cgdname, dev, p);
    606 		if (ret)
    607 			goto bail_err;
    608 
    609 		ret = verify(p, fd);
    610 		if (ret == -1)
    611 			goto bail_err;
    612 		if (!ret)
    613 			break;
    614 
    615 		(void)unconfigure_fd(fd);
    616 		(void)prog_close(fd);
    617 
    618 		if (!loop) {
    619 			warnx("verification failed permanently");
    620 			goto bail_err;
    621 		}
    622 
    623 		warnx("verification failed, please reenter passphrase");
    624 	}
    625 
    626 	params_free(p);
    627 	(void)prog_close(fd);
    628 	return 0;
    629 bail_err:
    630 	params_free(p);
    631 	(void)prog_close(fd);
    632 	return -1;
    633 }
    634 
    635 static int
    636 configure_stdin(struct params *p, int argc, char **argv)
    637 {
    638 	int		 fd;
    639 	int		 ret;
    640 	char		 cgdname[PATH_MAX];
    641 	char		 devicename[PATH_MAX];
    642 	const char	*dev;
    643 
    644 	if (argc < 3 || argc > 4)
    645 		usage();
    646 
    647 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    648 	if (dev == NULL) {
    649 		warnx("getfsspecname failed: %s", devicename);
    650 		return -1;
    651 	}
    652 
    653 	p->algorithm = string_fromcharstar(argv[2]);
    654 	if (argc > 3) {
    655 		size_t keylen;
    656 
    657 		if (parse_size_t(argv[3], &keylen) == -1) {
    658 			warn("failed to parse key length");
    659 			return -1;
    660 		}
    661 		p->keylen = keylen;
    662 	}
    663 
    664 	ret = params_filldefaults(p);
    665 	if (ret)
    666 		return ret;
    667 
    668 	fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    669 	if (fd == -1)
    670 		return -1;
    671 
    672 	p->key = bits_fget(stdin, p->keylen);
    673 	if (!p->key) {
    674 		warnx("failed to read key from stdin");
    675 		return -1;
    676 	}
    677 
    678 	return configure_params(fd, cgdname, dev, p);
    679 }
    680 
    681 static int
    682 opendisk_werror(const char *cgd, char *buf, size_t buflen)
    683 {
    684 	int	fd;
    685 
    686 	VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd, buf, buflen));
    687 
    688 	/* sanity */
    689 	if (!cgd || !buf)
    690 		return -1;
    691 
    692 	if (nflag) {
    693 		if (strlcpy(buf, cgd, buflen) >= buflen)
    694 			return -1;
    695 		return 0;
    696 	}
    697 
    698 	fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open);
    699 	if (fd == -1)
    700 		warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
    701 
    702 	return fd;
    703 }
    704 
    705 static int
    706 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
    707 {
    708 	struct cgd_ioctl ci;
    709 
    710 	/* sanity */
    711 	if (!cgd || !dev)
    712 		return -1;
    713 
    714 	(void)memset(&ci, 0x0, sizeof(ci));
    715 	ci.ci_disk = dev;
    716 	ci.ci_alg = string_tocharstar(p->algorithm);
    717 	ci.ci_ivmethod = string_tocharstar(p->ivmeth);
    718 	ci.ci_key = bits_getbuf(p->key);
    719 	ci.ci_keylen = p->keylen;
    720 	ci.ci_blocksize = p->bsize;
    721 
    722 	VPRINTF(1, ("    with alg %s keylen %zu blocksize %zu ivmethod %s\n",
    723 	    string_tocharstar(p->algorithm), p->keylen, p->bsize,
    724 	    string_tocharstar(p->ivmeth)));
    725 	VPRINTF(2, ("key: "));
    726 	VERBOSE(2, bits_fprint(stdout, p->key));
    727 	VPRINTF(2, ("\n"));
    728 
    729 	if (nflag)
    730 		return 0;
    731 
    732 	if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) {
    733 		int saved_errno = errno;
    734 		warn("ioctl");
    735 		return saved_errno;
    736 	}
    737 
    738 	return 0;
    739 }
    740 
    741 /*
    742  * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
    743  */
    744 
    745 #define SCANSIZE	8192
    746 
    747 static int
    748 verify(struct params *p, int fd)
    749 {
    750 
    751 	switch (p->verify_method) {
    752 	case VERIFY_NONE:
    753 		return 0;
    754 	case VERIFY_DISKLABEL:
    755 		return verify_disklabel(fd);
    756 	case VERIFY_FFS:
    757 		return verify_ffs(fd);
    758 	case VERIFY_REENTER:
    759 		return verify_reenter(p);
    760 	case VERIFY_MBR:
    761 		return verify_mbr(fd);
    762 	case VERIFY_GPT:
    763 		return verify_gpt(fd);
    764 	default:
    765 		warnx("unimplemented verification method");
    766 		return -1;
    767 	}
    768 }
    769 
    770 static int
    771 verify_disklabel(int fd)
    772 {
    773 	struct	disklabel l;
    774 	ssize_t	ret;
    775 	char	buf[SCANSIZE];
    776 
    777 	/*
    778 	 * we simply scan the first few blocks for a disklabel, ignoring
    779 	 * any MBR/filecore sorts of logic.  MSDOS and RiscOS can't read
    780 	 * a cgd, anyway, so it is unlikely that there will be non-native
    781 	 * partition information.
    782 	 */
    783 
    784 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    785 	if (ret < 0) {
    786 		warn("can't read disklabel area");
    787 		return -1;
    788 	}
    789 
    790 	/* now scan for the disklabel */
    791 
    792 	return disklabel_scan(&l, buf, (size_t)ret);
    793 }
    794 
    795 static int
    796 verify_mbr(int fd)
    797 {
    798 	struct mbr_sector mbr;
    799 	ssize_t	ret;
    800 	char	buf[SCANSIZE];
    801 
    802 	/*
    803 	 * we read the first blocks to avoid sector size issues and
    804 	 * verify the MBR in the beginning
    805 	 */
    806 
    807 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    808 	if (ret < 0) {
    809 		warn("can't read mbr area");
    810 		return -1;
    811 	}
    812 
    813 	memcpy(&mbr, buf, sizeof(mbr));
    814 	if (le16toh(mbr.mbr_magic) != MBR_MAGIC)
    815 		return -1;
    816 
    817 	return 0;
    818 }
    819 
    820 static uint32_t crc32_tab[] = {
    821 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    822 	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    823 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    824 	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    825 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    826 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    827 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    828 	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    829 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    830 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    831 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    832 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    833 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    834 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    835 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    836 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    837 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    838 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    839 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    840 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    841 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    842 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    843 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    844 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    845 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    846 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    847 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    848 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    849 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    850 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    851 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    852 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    853 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    854 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    855 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    856 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    857 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    858 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    859 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    860 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    861 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    862 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    863 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    864 };
    865 
    866 static uint32_t
    867 crc32(const void *buf, size_t size)
    868 {
    869 	const uint8_t *p;
    870 	uint32_t crc;
    871 
    872 	p = buf;
    873 	crc = ~0U;
    874 
    875 	while (size--)
    876 		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
    877 
    878 	return crc ^ ~0U;
    879 }
    880 
    881 static int
    882 verify_gpt(int fd)
    883 {
    884 	struct	 gpt_hdr hdr;
    885 	ssize_t	 ret;
    886 	char	 buf[SCANSIZE];
    887 	unsigned blksize;
    888 	size_t	 off;
    889 
    890 	/*
    891 	 * we read the first blocks to avoid sector size issues and
    892 	 * verify the GPT header.
    893 	 */
    894 
    895 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    896 	if (ret < 0) {
    897 		warn("can't read gpt area");
    898 		return -1;
    899 	}
    900 
    901 	ret = -1;
    902 	for (blksize=DEV_BSIZE;
    903              (off = blksize * GPT_HDR_BLKNO) <= SCANSIZE - sizeof(hdr);
    904              blksize <<= 1) {
    905 
    906 		memcpy(&hdr, &buf[off], sizeof(hdr));
    907 		if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0 &&
    908 		    le32toh(hdr.hdr_revision) == GPT_HDR_REVISION &&
    909 		    le32toh(hdr.hdr_size) == GPT_HDR_SIZE) {
    910 
    911 			hdr.hdr_crc_self = 0;
    912 			if (crc32(&hdr, sizeof(hdr))) {
    913 				ret = 0;
    914 				break;
    915 			}
    916 		}
    917 	}
    918 
    919 	return ret;
    920 }
    921 
    922 static off_t sblock_try[] = SBLOCKSEARCH;
    923 
    924 static int
    925 verify_ffs(int fd)
    926 {
    927 	size_t	i;
    928 
    929 	for (i = 0; sblock_try[i] != -1; i++) {
    930 		union {
    931 		    char	buf[SBLOCKSIZE];
    932 		    struct	fs fs;
    933 		} u;
    934 		ssize_t ret;
    935 
    936 		ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]);
    937 		if (ret < 0) {
    938 			warn("pread");
    939 			break;
    940 		} else if ((size_t)ret < sizeof(u)) {
    941 			warnx("pread: incomplete block");
    942 			break;
    943 		}
    944 		switch (u.fs.fs_magic) {
    945 		case FS_UFS1_MAGIC:
    946 		case FS_UFS2_MAGIC:
    947 		case FS_UFS1_MAGIC_SWAPPED:
    948 		case FS_UFS2_MAGIC_SWAPPED:
    949 			return 0;
    950 		default:
    951 			continue;
    952 		}
    953 	}
    954 
    955 	return 1;	/* failure */
    956 }
    957 
    958 static int
    959 verify_reenter(struct params *p)
    960 {
    961 	struct keygen *kg;
    962 	bits_t *orig_key, *key;
    963 	int ret;
    964 
    965 	ret = 0;
    966 	for (kg = p->keygen; kg && !ret; kg = kg->next) {
    967 		if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
    968 		    (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
    969 			continue;
    970 
    971 		orig_key = kg->kg_key;
    972 		kg->kg_key = NULL;
    973 
    974 		/* add a compat flag till the _OLD method goes away */
    975 		key = getkey_pkcs5_pbkdf2("re-enter device", kg,
    976 			bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
    977 		ret = !bits_match(key, orig_key);
    978 
    979 		bits_free(key);
    980 		bits_free(kg->kg_key);
    981 		kg->kg_key = orig_key;
    982 	}
    983 
    984 	return ret;
    985 }
    986 
    987 static int
    988 generate(struct params *p, int argc, char **argv, const char *outfile)
    989 {
    990 	int	 ret;
    991 
    992 	if (argc < 1 || argc > 2)
    993 		usage();
    994 
    995 	p->algorithm = string_fromcharstar(argv[0]);
    996 	if (argc > 1) {
    997 		size_t keylen;
    998 
    999 		if (parse_size_t(argv[1], &keylen) == -1) {
   1000 			warn("Failed to parse key length");
   1001 			return -1;
   1002 		}
   1003 		p->keylen = keylen;
   1004 	}
   1005 
   1006 	ret = params_filldefaults(p);
   1007 	if (ret)
   1008 		return ret;
   1009 
   1010 	if (!p->keygen) {
   1011 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1012 		if (!p->keygen)
   1013 			return -1;
   1014 	}
   1015 
   1016 	if (keygen_filldefaults(p->keygen, p->keylen)) {
   1017 		warnx("Failed to generate defaults for keygen");
   1018 		return -1;
   1019 	}
   1020 
   1021 	if (!params_verify(p)) {
   1022 		warnx("invalid parameters generated");
   1023 		return -1;
   1024 	}
   1025 
   1026 	return params_cput(p, outfile);
   1027 }
   1028 
   1029 static int
   1030 generate_convert(struct params *p, int argc, char **argv, const char *outfile)
   1031 {
   1032 	struct params	*oldp;
   1033 	struct keygen	*kg;
   1034 
   1035 	if (argc != 1)
   1036 		usage();
   1037 
   1038 	oldp = params_cget(*argv);
   1039 	if (!oldp)
   1040 		return -1;
   1041 
   1042 	/* for sanity, we ensure that none of the keygens are randomkey */
   1043 	for (kg=p->keygen; kg; kg=kg->next)
   1044 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1045 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1046 			warnx("can't preserve randomly generated key");
   1047 			goto bail;
   1048 		}
   1049 	for (kg=oldp->keygen; kg; kg=kg->next)
   1050 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1051 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1052 			warnx("can't preserve randomly generated key");
   1053 			goto bail;
   1054 		}
   1055 
   1056 	if (!params_verify(oldp)) {
   1057 		warnx("invalid old parameters file \"%s\"", *argv);
   1058 		return -1;
   1059 	}
   1060 
   1061 	oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
   1062 
   1063 	/* we copy across the non-keygen info, here. */
   1064 
   1065 	string_free(p->algorithm);
   1066 	string_free(p->ivmeth);
   1067 
   1068 	p->algorithm = string_dup(oldp->algorithm);
   1069 	p->ivmeth = string_dup(oldp->ivmeth);
   1070 	p->keylen = oldp->keylen;
   1071 	p->bsize = oldp->bsize;
   1072 	if (p->verify_method == VERIFY_UNKNOWN)
   1073 		p->verify_method = oldp->verify_method;
   1074 
   1075 	params_free(oldp);
   1076 
   1077 	if (!p->keygen) {
   1078 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1079 		if (!p->keygen)
   1080 			return -1;
   1081 	}
   1082 	(void)params_filldefaults(p);
   1083 	(void)keygen_filldefaults(p->keygen, p->keylen);
   1084 	p->key = getkey("new file", p->keygen, p->keylen);
   1085 
   1086 	kg = keygen_generate(KEYGEN_STOREDKEY);
   1087 	kg->kg_key = bits_xor(p->key, oldp->key);
   1088 	keygen_addlist(&p->keygen, kg);
   1089 
   1090 	if (!params_verify(p)) {
   1091 		warnx("can't generate new parameters file");
   1092 		return -1;
   1093 	}
   1094 
   1095 	return params_cput(p, outfile);
   1096 bail:
   1097 	params_free(oldp);
   1098 	return -1;
   1099 }
   1100 
   1101 static int
   1102 /*ARGSUSED*/
   1103 do_all(const char *cfile, int argc, char **argv,
   1104        int (*conf)(int, char **, struct params *, int))
   1105 {
   1106 	FILE		 *f;
   1107 	size_t		  len;
   1108 	size_t		  lineno;
   1109 	int		  my_argc;
   1110 	int		  ret;
   1111 	const char	 *fn;
   1112 	char		 *line;
   1113 	char		**my_argv;
   1114 
   1115 	if (argc > 0)
   1116 		usage();
   1117 
   1118 	if (!cfile[0])
   1119 		fn = CGDCONFIG_CFILE;
   1120 	else
   1121 		fn = cfile;
   1122 
   1123 	f = fopen(fn, "r");
   1124 	if (!f) {
   1125 		warn("could not open config file \"%s\"", fn);
   1126 		return -1;
   1127 	}
   1128 
   1129 	ret = 0;
   1130 	lineno = 0;
   1131 	for (;;) {
   1132 		line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
   1133 		if (!line)
   1134 			break;
   1135 		if (!*line)
   1136 			continue;
   1137 
   1138 		my_argv = words(line, &my_argc);
   1139 		ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
   1140 		if (ret) {
   1141 			warnx("action failed on \"%s\" line %lu", fn,
   1142 			    (u_long)lineno);
   1143 			break;
   1144 		}
   1145 		words_free(my_argv, my_argc);
   1146 	}
   1147 	return ret;
   1148 }
   1149 
   1150 static const char *
   1151 iv_method(int mode)
   1152 {
   1153 
   1154 	switch (mode) {
   1155 	case CGD_CIPHER_CBC_ENCBLKNO8:
   1156 		return "encblkno8";
   1157 	case CGD_CIPHER_CBC_ENCBLKNO1:
   1158 		return "encblkno1";
   1159 	default:
   1160 		return "unknown";
   1161 	}
   1162 }
   1163 
   1164 
   1165 static void
   1166 show(const char *dev) {
   1167 	char path[64];
   1168 	struct cgd_user cgu;
   1169 	int fd;
   1170 
   1171 	fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0);
   1172 	if (fd == -1) {
   1173 		warn("open: %s", dev);
   1174 		return;
   1175 	}
   1176 
   1177 	cgu.cgu_unit = -1;
   1178 	if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) {
   1179 		close(fd);
   1180 		err(1, "CGDIOCGET");
   1181 	}
   1182 
   1183 	printf("%s: ", dev);
   1184 
   1185 	if (cgu.cgu_dev == 0) {
   1186 		printf("not in use");
   1187 		goto out;
   1188 	}
   1189 
   1190 	dev = devname(cgu.cgu_dev, S_IFBLK);
   1191 	if (dev != NULL)
   1192 		printf("%s ", dev);
   1193 	else
   1194 		printf("dev %llu,%llu ", (unsigned long long)major(cgu.cgu_dev),
   1195 		    (unsigned long long)minor(cgu.cgu_dev));
   1196 
   1197 	if (verbose)
   1198 		printf("%s ", cgu.cgu_alg);
   1199 	if (verbose > 1) {
   1200 		printf("keylen %d ", cgu.cgu_keylen);
   1201 		printf("blksize %zd ", cgu.cgu_blocksize);
   1202 		printf("%s ", iv_method(cgu.cgu_mode));
   1203 	}
   1204 
   1205 out:
   1206 	putchar('\n');
   1207 	close(fd);
   1208 }
   1209 
   1210 static int
   1211 do_list(int argc, char **argv)
   1212 {
   1213 
   1214 	if (argc != 0 && argc != 1)
   1215 		usage();
   1216 
   1217 	if (argc) {
   1218 		show(argv[0]);
   1219 		return 0;
   1220 	}
   1221 
   1222 	DIR *dirp;
   1223 	struct dirent *dp;
   1224 	__BITMAP_TYPE(, uint32_t, 65536) bm;
   1225 
   1226 	__BITMAP_ZERO(&bm);
   1227 
   1228 	if ((dirp = opendir(_PATH_DEV)) == NULL)
   1229 		err(1, "opendir: %s", _PATH_DEV);
   1230 
   1231 	while ((dp = readdir(dirp)) != NULL) {
   1232 		char *ep;
   1233 		if (strncmp(dp->d_name, "rcgd", 4) != 0)
   1234 			continue;
   1235 		errno = 0;
   1236 		int n = (int)strtol(dp->d_name + 4, &ep, 0);
   1237 		if (ep == dp->d_name + 4 || errno != 0) {
   1238 			warnx("bad name %s", dp->d_name);
   1239 			continue;
   1240 		}
   1241 		*ep = '\0';
   1242 		if (__BITMAP_ISSET(n, &bm))
   1243 			continue;
   1244 		__BITMAP_SET(n, &bm);
   1245 		show(dp->d_name + 1);
   1246 	}
   1247 
   1248 	closedir(dirp);
   1249 	return 0;
   1250 }
   1251 
   1252 static void
   1253 eliminate_cores(void)
   1254 {
   1255 	struct rlimit	rlp;
   1256 
   1257 	rlp.rlim_cur = 0;
   1258 	rlp.rlim_max = 0;
   1259 	if (setrlimit(RLIMIT_CORE, &rlp) == -1)
   1260 		err(EXIT_FAILURE, "Can't disable cores");
   1261 }
   1262