2 * Copyright (c) 1995 Jason R. Thorpe.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed for the NetBSD Project
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $NetBSD: ccdconfig.c,v 1.2.2.1 1995/11/11 02:43:35 thorpej Exp $
33 * $FreeBSD: src/sbin/ccdconfig/ccdconfig.c,v 1.16.2.2 2000/12/11 01:03:25 obrien Exp $
36 #define _KERNEL_STRUCTURES
37 #include <sys/param.h>
38 #include <sys/linker.h>
40 #include <sys/module.h>
53 #include <sys/devicestat.h>
54 #include <sys/ccdvar.h>
56 #include "pathnames.h"
58 static int lineno
= 0;
59 static int verbose
= 0;
60 static const char *ccdconf
= _PATH_CCDCONF
;
62 static char *core
= NULL
;
63 static char *kernel
= NULL
;
69 { "CCDF_SWAP", CCDF_SWAP
},
70 { "CCDF_UNIFORM", CCDF_UNIFORM
},
71 { "CCDF_MIRROR", CCDF_MIRROR
},
72 { "CCDF_PARITY", CCDF_PARITY
},
76 static struct nlist nl
[] = {
77 { "_ccd_softc", 0, 0, 0, 0 },
78 #define SYM_CCDSOFTC 0
79 { "_numccd", 0, 0, 0, 0 },
81 { NULL
, 0, 0, 0, 0 },
84 #define CCD_CONFIG 0 /* configure a device */
85 #define CCD_CONFIGALL 1 /* configure all devices */
86 #define CCD_UNCONFIG 2 /* unconfigure a device */
87 #define CCD_UNCONFIGALL 3 /* unconfigure all devices */
88 #define CCD_DUMP 4 /* dump a ccd's configuration */
90 static int checkdev(char *);
91 static int do_io(char *, u_long
, struct ccd_ioctl
*);
92 static int do_single(int, char **, int);
93 static int do_all(int);
94 static int dump_ccd(int, char **);
95 static int getmaxpartitions(void);
96 static int flags_to_val(char *);
97 static void print_ccd_info(struct ccd_softc
*, kvm_t
*);
98 static char *resolve_ccdname(char *);
99 static void usage(void);
102 main(int argc
, char **argv
)
104 int ch
, options
= 0, action
= CCD_CONFIG
;
106 while ((ch
= getopt(argc
, argv
, "cCf:gM:N:uUv")) != -1) {
114 action
= CCD_CONFIGALL
;
135 action
= CCD_UNCONFIG
;
140 action
= CCD_UNCONFIGALL
;
159 * Discard setgid privileges if not the running kernel so that bad
160 * guys can't print interesting stuff from kernel memory.
162 if (core
!= NULL
|| kernel
!= NULL
|| action
!= CCD_DUMP
) {
167 if (modfind("ccd") < 0) {
168 /* Not present in kernel, try loading it */
169 if (kldload("ccd") < 0 || modfind("ccd") < 0) {
170 warn("ccd module not available!\n"
171 "NOTE: Systems which don't have /boot as part of"
172 " the root partition\n"
173 " (as is the case with the default HAMMER"
174 " install) need to load ccd(4)\n"
175 " via /boot/loader.conf or compile it into"
183 exit(do_single(argc
, argv
, action
));
187 case CCD_UNCONFIGALL
:
188 exit(do_all(action
));
192 exit(dump_ccd(argc
, argv
));
200 do_single(int argc
, char **argv
, int action
)
202 struct ccd_ioctl ccio
;
203 char *ccd
, *cp
, *cp2
, **disks
;
204 int noflags
= 0, ileave
, flags
= 0, j
;
207 bzero(&ccio
, sizeof(ccio
));
210 * If unconfiguring, all arguments are treated as ccds.
212 if (action
== CCD_UNCONFIG
|| action
== CCD_UNCONFIGALL
) {
213 for (i
= 0; argc
!= 0; ) {
214 cp
= *argv
++; --argc
;
215 if ((ccd
= resolve_ccdname(cp
)) == NULL
) {
216 warnx("invalid ccd name: %s", cp
);
220 if (do_io(ccd
, CCDIOCCLR
, &ccio
))
224 printf("%s unconfigured\n", cp
);
229 /* Make sure there are enough arguments. */
232 /* Assume that no flags are specified. */
235 if (action
== CCD_CONFIGALL
) {
236 warnx("%s: bad line: %d", ccdconf
, lineno
);
243 /* First argument is the ccd to configure. */
244 cp
= *argv
++; --argc
;
245 if ((ccd
= resolve_ccdname(cp
)) == NULL
) {
246 warnx("invalid ccd name: %s", cp
);
250 /* Next argument is the interleave factor. */
251 cp
= *argv
++; --argc
;
252 errno
= 0; /* to check for ERANGE */
253 ileave
= (int)strtol(cp
, &cp2
, 10);
254 if ((errno
== ERANGE
) || (ileave
< 0) || (*cp2
!= '\0')) {
255 warnx("invalid interleave factor: %s", cp
);
260 /* Next argument is the ccd configuration flags. */
261 cp
= *argv
++; --argc
;
262 if ((flags
= flags_to_val(cp
)) < 0) {
263 warnx("invalid flags argument: %s", cp
);
268 /* Next is the list of disks to make the ccd from. */
269 disks
= malloc(argc
* sizeof(char *));
271 warnx("no memory to configure ccd");
274 for (i
= 0; argc
!= 0; ) {
275 cp
= *argv
++; --argc
;
276 if ((j
= checkdev(cp
)) == 0)
279 warnx("%s: %s", cp
, strerror(j
));
284 /* Fill in the ccio. */
285 ccio
.ccio_disks
= disks
;
286 ccio
.ccio_ndisks
= i
;
287 ccio
.ccio_ileave
= ileave
;
288 ccio
.ccio_flags
= flags
;
290 if (do_io(ccd
, CCDIOCSET
, &ccio
)) {
296 printf("ccd%d: %d components ", ccio
.ccio_unit
,
298 for (i
= 0; i
< ccio
.ccio_ndisks
; ++i
) {
299 if ((cp2
= strrchr(disks
[i
], '/')) != NULL
)
304 i
== 0 ? '(' : ' ', cp2
,
305 i
== ccio
.ccio_ndisks
- 1 ? ')' : ',');
307 printf(", %ju blocks ", (uintmax_t)ccio
.ccio_size
);
308 if (ccio
.ccio_ileave
!= 0)
309 printf("interleaved at %d blocks\n", ccio
.ccio_ileave
);
311 printf("concatenated\n");
322 char line
[_POSIX2_LINE_MAX
];
330 if ((f
= fopen(ccdconf
, "r")) == NULL
) {
332 warn("fopen: %s", ccdconf
);
337 while (fgets(line
, sizeof(line
), f
) != NULL
) {
341 if ((cp
= strrchr(line
, '\n')) != NULL
)
344 /* Break up the line and pass it's contents to do_single(). */
347 for (cp
= line
; (cp
= strtok(cp
, " \t")) != NULL
; cp
= NULL
) {
350 if ((argv
= realloc(argv
,
351 sizeof(char *) * ++argc
)) == NULL
) {
352 warnx("no memory to configure ccds");
357 * If our action is to unconfigure all, then pass
358 * just the first token to do_single() and ignore
359 * the rest. Since this will be encountered on
360 * our first pass through the line, the Right
363 if (action
== CCD_UNCONFIGALL
) {
364 if (do_single(argc
, argv
, action
))
370 if (do_single(argc
, argv
, action
))
387 if (stat(path
, &st
) != 0)
390 if (!S_ISBLK(st
.st_mode
) && !S_ISCHR(st
.st_mode
))
397 pathtounit(char *path
, int *unitp
)
402 if (stat(path
, &st
) != 0)
405 if (!S_ISBLK(st
.st_mode
) && !S_ISCHR(st
.st_mode
))
408 if ((maxpartitions
= getmaxpartitions()) < 0)
411 *unitp
= minor(st
.st_rdev
) / maxpartitions
;
417 resolve_ccdname(char *name
)
421 if (name
[0] == '/' || name
[0] == '.') {
422 /* Assume they gave the correct pathname. */
423 return (strdup(name
));
426 asprintf(&path
, "%s%s", _PATH_DEV
, name
);
432 do_io(char *path
, u_long cmd
, struct ccd_ioctl
*cciop
)
437 if ((fd
= open(path
, O_RDWR
, 0640)) < 0) {
438 warn("open: %s", path
);
442 if (ioctl(fd
, cmd
, cciop
) < 0) {
455 warn("ioctl (%s): %s", cp
, path
);
462 #define KVM_ABORT(kd, str) { \
464 warnx("%s", (str)); \
465 warnx("%s", kvm_geterr((kd))); \
470 dump_ccd(int argc
, char **argv
)
472 char errbuf
[_POSIX2_LINE_MAX
], *ccd
, *cp
;
473 struct ccd_softc
*cs
, *kcs
;
475 int i
= 0, error
, numccd
, numconfiged
= 0;
478 bzero(errbuf
, sizeof(errbuf
));
480 if ((kd
= kvm_openfiles(kernel
, core
, NULL
, O_RDONLY
,
482 warnx("can't open kvm: %s", errbuf
);
486 if (kvm_nlist(kd
, nl
))
487 KVM_ABORT(kd
, "ccd-related symbols not available");
489 /* Check to see how many ccds are currently configured. */
490 if (kvm_read(kd
, nl
[SYM_NUMCCD
].n_value
, (char *)&numccd
,
491 sizeof(numccd
)) != sizeof(numccd
))
492 KVM_ABORT(kd
, "can't determine number of configured ccds");
495 printf("ccd driver in kernel, but is uninitialized\n");
499 /* Allocate space for the configuration data. */
500 readsize
= numccd
* sizeof(struct ccd_softc
);
501 if ((cs
= malloc(readsize
)) == NULL
) {
502 warnx("no memory for configuration data");
508 * Read the ccd configuration data from the kernel and dump
511 if (kvm_read(kd
, nl
[SYM_CCDSOFTC
].n_value
, (char *)&kcs
,
512 sizeof(kcs
)) != sizeof(kcs
)) {
514 KVM_ABORT(kd
, "can't find pointer to configuration data");
516 if (kvm_read(kd
, (u_long
)kcs
, (char *)cs
, readsize
) != readsize
) {
518 KVM_ABORT(kd
, "can't read configuration data");
522 for (i
= 0; i
< numccd
; ++i
)
523 if (cs
[i
].sc_flags
& CCDF_INITED
) {
525 print_ccd_info(&cs
[i
], kd
);
528 if (numconfiged
== 0)
529 printf("no concatenated disks configured\n");
532 cp
= *argv
++; --argc
;
533 if ((ccd
= resolve_ccdname(cp
)) == NULL
) {
534 warnx("invalid ccd name: %s", cp
);
537 if ((error
= pathtounit(ccd
, &i
)) != 0) {
538 warnx("%s: %s", ccd
, strerror(error
));
542 warnx("ccd%d not configured", i
);
545 if (cs
[i
].sc_flags
& CCDF_INITED
)
546 print_ccd_info(&cs
[i
], kd
);
548 printf("ccd%d not configured\n", i
);
564 print_ccd_info(struct ccd_softc
*cs
, kvm_t
*kd
)
566 static int header_printed
= 0;
567 struct ccdcinfo
*cip
;
569 char path
[MAXPATHLEN
];
572 if (header_printed
== 0 && verbose
) {
573 printf("# ccd\t\tileave\tflags\tcompnent devices\n");
577 readsize
= cs
->sc_nccdisks
* sizeof(struct ccdcinfo
);
578 if ((cip
= malloc(readsize
)) == NULL
) {
579 warn("ccd%d: can't allocate memory for component info",
583 bzero(cip
, readsize
);
585 /* Dump out softc information. */
586 printf("ccd%d\t\t%d\t%d\t", cs
->sc_unit
, cs
->sc_ileave
,
587 cs
->sc_cflags
& CCDF_USERMASK
);
590 /* Read in the component info. */
591 if (kvm_read(kd
, (u_long
)cs
->sc_cinfo
, (char *)cip
,
592 readsize
) != readsize
) {
594 warnx("can't read component info");
595 warnx("%s", kvm_geterr(kd
));
599 /* Read component pathname and display component info. */
600 for (i
= 0; i
< cs
->sc_nccdisks
; ++i
) {
601 if ((unsigned)kvm_read(kd
, (u_long
)cip
[i
].ci_path
, (char *)path
,
602 cip
[i
].ci_pathlen
) != cip
[i
].ci_pathlen
) {
604 warnx("can't read component pathname");
605 warnx("%s", kvm_geterr(kd
));
608 printf((i
+ 1 < cs
->sc_nccdisks
) ? "%s " : "%s\n", path
);
617 getmaxpartitions(void)
619 return (MAXPARTITIONS
);
623 flags_to_val(char *flags
)
626 int i
, tmp
, val
= ~CCDF_USERMASK
;
630 * The most common case is that of NIL flags, so check for
633 if (strcmp("none", flags
) == 0 || strcmp("0x0", flags
) == 0 ||
634 strcmp("0", flags
) == 0)
637 flagslen
= strlen(flags
);
639 /* Check for values represented by strings. */
640 if ((cp
= strdup(flags
)) == NULL
)
641 err(1, "no memory to parse flags");
643 for (tok
= cp
; (tok
= strtok(tok
, ",")) != NULL
; tok
= NULL
) {
644 for (i
= 0; flagvaltab
[i
].fv_flag
!= NULL
; ++i
)
645 if (strcmp(tok
, flagvaltab
[i
].fv_flag
) == 0)
647 if (flagvaltab
[i
].fv_flag
== NULL
) {
651 tmp
|= flagvaltab
[i
].fv_val
;
654 /* If we get here, the string was ok. */
661 /* Check for values represented in hex. */
662 if (flagslen
> 2 && flags
[0] == '0' && flags
[1] == 'x') {
663 errno
= 0; /* to check for ERANGE */
664 val
= (int)strtol(&flags
[2], &cp
, 16);
665 if ((errno
== ERANGE
) || (*cp
!= '\0'))
670 /* Check for values represented in decimal. */
671 errno
= 0; /* to check for ERANGE */
672 val
= (int)strtol(flags
, &cp
, 10);
673 if ((errno
== ERANGE
) || (*cp
!= '\0'))
677 return (((val
& ~CCDF_USERMASK
) == 0) ? val
: -1);
683 fprintf(stderr
, "%s\n%s\n%s\n%s\n%s\n",
684 "usage: ccdconfig [-cv] ccd ileave [flags] dev ...",
685 " ccdconfig -C [-v] [-f config_file]",
686 " ccdconfig -u [-v] ccd ...",
687 " ccdconfig -U [-v] [-f config_file]",
688 " ccdconfig -g [-M core] [-N system] [ccd ...]");