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
));
285 /* Fill in the ccio. */
286 ccio
.ccio_disks
= disks
;
287 ccio
.ccio_ndisks
= i
;
288 ccio
.ccio_ileave
= ileave
;
289 ccio
.ccio_flags
= flags
;
291 if (do_io(ccd
, CCDIOCSET
, &ccio
)) {
297 printf("ccd%d: %d components ", ccio
.ccio_unit
,
299 for (i
= 0; i
< ccio
.ccio_ndisks
; ++i
) {
300 if ((cp2
= strrchr(disks
[i
], '/')) != NULL
)
305 i
== 0 ? '(' : ' ', cp2
,
306 i
== ccio
.ccio_ndisks
- 1 ? ')' : ',');
308 printf(", %ju blocks ", (uintmax_t)ccio
.ccio_size
);
309 if (ccio
.ccio_ileave
!= 0)
310 printf("interleaved at %d blocks\n", ccio
.ccio_ileave
);
312 printf("concatenated\n");
323 char line
[_POSIX2_LINE_MAX
];
331 if ((f
= fopen(ccdconf
, "r")) == NULL
) {
333 warn("fopen: %s", ccdconf
);
338 while (fgets(line
, sizeof(line
), f
) != NULL
) {
342 if ((cp
= strrchr(line
, '\n')) != NULL
)
345 /* Break up the line and pass it's contents to do_single(). */
348 for (cp
= line
; (cp
= strtok(cp
, " \t")) != NULL
; cp
= NULL
) {
351 if ((argv
= realloc(argv
,
352 sizeof(char *) * ++argc
)) == NULL
) {
353 warnx("no memory to configure ccds");
358 * If our action is to unconfigure all, then pass
359 * just the first token to do_single() and ignore
360 * the rest. Since this will be encountered on
361 * our first pass through the line, the Right
364 if (action
== CCD_UNCONFIGALL
) {
365 if (do_single(argc
, argv
, action
))
371 if (do_single(argc
, argv
, action
))
388 if (stat(path
, &st
) != 0)
391 if (!S_ISBLK(st
.st_mode
) && !S_ISCHR(st
.st_mode
))
398 pathtounit(char *path
, int *unitp
)
403 if (stat(path
, &st
) != 0)
406 if (!S_ISBLK(st
.st_mode
) && !S_ISCHR(st
.st_mode
))
409 if ((maxpartitions
= getmaxpartitions()) < 0)
412 *unitp
= minor(st
.st_rdev
) / maxpartitions
;
418 resolve_ccdname(char *name
)
422 if (name
[0] == '/' || name
[0] == '.') {
423 /* Assume they gave the correct pathname. */
424 return (strdup(name
));
427 asprintf(&path
, "%s%s", _PATH_DEV
, name
);
433 do_io(char *path
, u_long cmd
, struct ccd_ioctl
*cciop
)
438 if ((fd
= open(path
, O_RDWR
, 0640)) < 0) {
439 warn("open: %s", path
);
443 if (ioctl(fd
, cmd
, cciop
) < 0) {
456 warn("ioctl (%s): %s", cp
, path
);
463 #define KVM_ABORT(kd, str) { \
465 warnx("%s", (str)); \
466 warnx("%s", kvm_geterr((kd))); \
471 dump_ccd(int argc
, char **argv
)
473 char errbuf
[_POSIX2_LINE_MAX
], *ccd
, *cp
;
474 struct ccd_softc
*cs
, *kcs
;
476 int i
= 0, error
, numccd
, numconfiged
= 0;
479 bzero(errbuf
, sizeof(errbuf
));
481 if ((kd
= kvm_openfiles(kernel
, core
, NULL
, O_RDONLY
,
483 warnx("can't open kvm: %s", errbuf
);
487 if (kvm_nlist(kd
, nl
))
488 KVM_ABORT(kd
, "ccd-related symbols not available");
490 /* Check to see how many ccds are currently configured. */
491 if (kvm_read(kd
, nl
[SYM_NUMCCD
].n_value
, (char *)&numccd
,
492 sizeof(numccd
)) != sizeof(numccd
))
493 KVM_ABORT(kd
, "can't determine number of configured ccds");
496 printf("ccd driver in kernel, but is uninitialized\n");
500 /* Allocate space for the configuration data. */
501 readsize
= numccd
* sizeof(struct ccd_softc
);
502 if ((cs
= malloc(readsize
)) == NULL
) {
503 warnx("no memory for configuration data");
509 * Read the ccd configuration data from the kernel and dump
512 if (kvm_read(kd
, nl
[SYM_CCDSOFTC
].n_value
, (char *)&kcs
,
513 sizeof(kcs
)) != sizeof(kcs
)) {
515 KVM_ABORT(kd
, "can't find pointer to configuration data");
517 if (kvm_read(kd
, (u_long
)kcs
, (char *)cs
, readsize
) != readsize
) {
519 KVM_ABORT(kd
, "can't read configuration data");
523 for (i
= 0; i
< numccd
; ++i
)
524 if (cs
[i
].sc_flags
& CCDF_INITED
) {
526 print_ccd_info(&cs
[i
], kd
);
529 if (numconfiged
== 0)
530 printf("no concatenated disks configured\n");
533 cp
= *argv
++; --argc
;
534 if ((ccd
= resolve_ccdname(cp
)) == NULL
) {
535 warnx("invalid ccd name: %s", cp
);
538 if ((error
= pathtounit(ccd
, &i
)) != 0) {
539 warnx("%s: %s", ccd
, strerror(error
));
543 warnx("ccd%d not configured", i
);
546 if (cs
[i
].sc_flags
& CCDF_INITED
)
547 print_ccd_info(&cs
[i
], kd
);
549 printf("ccd%d not configured\n", i
);
565 print_ccd_info(struct ccd_softc
*cs
, kvm_t
*kd
)
567 static int header_printed
= 0;
568 struct ccdcinfo
*cip
;
570 char path
[MAXPATHLEN
];
573 if (header_printed
== 0 && verbose
) {
574 printf("# ccd\t\tileave\tflags\tcompnent devices\n");
578 readsize
= cs
->sc_nccdisks
* sizeof(struct ccdcinfo
);
579 if ((cip
= malloc(readsize
)) == NULL
) {
580 warn("ccd%d: can't allocate memory for component info",
584 bzero(cip
, readsize
);
586 /* Dump out softc information. */
587 printf("ccd%d\t\t%d\t%d\t", cs
->sc_unit
, cs
->sc_ileave
,
588 cs
->sc_cflags
& CCDF_USERMASK
);
591 /* Read in the component info. */
592 if (kvm_read(kd
, (u_long
)cs
->sc_cinfo
, (char *)cip
,
593 readsize
) != readsize
) {
595 warnx("can't read component info");
596 warnx("%s", kvm_geterr(kd
));
600 /* Read component pathname and display component info. */
601 for (i
= 0; i
< cs
->sc_nccdisks
; ++i
) {
602 if ((unsigned)kvm_read(kd
, (u_long
)cip
[i
].ci_path
, (char *)path
,
603 cip
[i
].ci_pathlen
) != cip
[i
].ci_pathlen
) {
605 warnx("can't read component pathname");
606 warnx("%s", kvm_geterr(kd
));
609 printf((i
+ 1 < cs
->sc_nccdisks
) ? "%s " : "%s\n", path
);
618 getmaxpartitions(void)
620 return (MAXPARTITIONS
);
624 flags_to_val(char *flags
)
627 int i
, tmp
, val
= ~CCDF_USERMASK
;
631 * The most common case is that of NIL flags, so check for
634 if (strcmp("none", flags
) == 0 || strcmp("0x0", flags
) == 0 ||
635 strcmp("0", flags
) == 0)
638 flagslen
= strlen(flags
);
640 /* Check for values represented by strings. */
641 if ((cp
= strdup(flags
)) == NULL
)
642 err(1, "no memory to parse flags");
644 for (tok
= cp
; (tok
= strtok(tok
, ",")) != NULL
; tok
= NULL
) {
645 for (i
= 0; flagvaltab
[i
].fv_flag
!= NULL
; ++i
)
646 if (strcmp(tok
, flagvaltab
[i
].fv_flag
) == 0)
648 if (flagvaltab
[i
].fv_flag
== NULL
) {
652 tmp
|= flagvaltab
[i
].fv_val
;
655 /* If we get here, the string was ok. */
662 /* Check for values represented in hex. */
663 if (flagslen
> 2 && flags
[0] == '0' && flags
[1] == 'x') {
664 errno
= 0; /* to check for ERANGE */
665 val
= (int)strtol(&flags
[2], &cp
, 16);
666 if ((errno
== ERANGE
) || (*cp
!= '\0'))
671 /* Check for values represented in decimal. */
672 errno
= 0; /* to check for ERANGE */
673 val
= (int)strtol(flags
, &cp
, 10);
674 if ((errno
== ERANGE
) || (*cp
!= '\0'))
678 return (((val
& ~CCDF_USERMASK
) == 0) ? val
: -1);
684 fprintf(stderr
, "%s\n%s\n%s\n%s\n%s\n",
685 "usage: ccdconfig [-cv] ccd ileave [flags] dev ...",
686 " ccdconfig -C [-v] [-f config_file]",
687 " ccdconfig -u [-v] ccd ...",
688 " ccdconfig -U [-v] [-f config_file]",
689 " ccdconfig -g [-M core] [-N system] [ccd ...]");