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 $
34 * $DragonFly: src/sbin/ccdconfig/ccdconfig.c,v 1.9 2007/05/20 23:21:33 dillon Exp $
37 #define _KERNEL_STRUCTURES
38 #include <sys/param.h>
39 #include <sys/linker.h>
41 #include <sys/module.h>
54 #include <sys/devicestat.h>
55 #include <sys/ccdvar.h>
57 #include "pathnames.h"
59 static int lineno
= 0;
60 static int verbose
= 0;
61 static const char *ccdconf
= _PATH_CCDCONF
;
63 static char *core
= NULL
;
64 static char *kernel
= NULL
;
70 { "CCDF_SWAP", CCDF_SWAP
},
71 { "CCDF_UNIFORM", CCDF_UNIFORM
},
72 { "CCDF_MIRROR", CCDF_MIRROR
},
73 { "CCDF_PARITY", CCDF_PARITY
},
77 static struct nlist nl
[] = {
78 { "_ccd_softc", 0, 0, 0, 0 },
79 #define SYM_CCDSOFTC 0
80 { "_numccd", 0, 0, 0, 0 },
82 { NULL
, 0, 0, 0, 0 },
85 #define CCD_CONFIG 0 /* configure a device */
86 #define CCD_CONFIGALL 1 /* configure all devices */
87 #define CCD_UNCONFIG 2 /* unconfigure a device */
88 #define CCD_UNCONFIGALL 3 /* unconfigure all devices */
89 #define CCD_DUMP 4 /* dump a ccd's configuration */
91 static int checkdev(char *);
92 static int do_io(char *, u_long
, struct ccd_ioctl
*);
93 static int do_single(int, char **, int);
94 static int do_all(int);
95 static int dump_ccd(int, char **);
96 static int getmaxpartitions(void);
97 static int flags_to_val(char *);
98 static void print_ccd_info(struct ccd_softc
*, kvm_t
*);
99 static char *resolve_ccdname(char *);
100 static void usage(void);
103 main(int argc
, char **argv
)
105 int ch
, options
= 0, action
= CCD_CONFIG
;
107 while ((ch
= getopt(argc
, argv
, "cCf:gM:N:uUv")) != -1) {
115 action
= CCD_CONFIGALL
;
136 action
= CCD_UNCONFIG
;
141 action
= CCD_UNCONFIGALL
;
160 * Discard setgid privileges if not the running kernel so that bad
161 * guys can't print interesting stuff from kernel memory.
163 if (core
!= NULL
|| kernel
!= NULL
|| action
!= CCD_DUMP
) {
168 if (modfind("ccd") < 0) {
169 /* Not present in kernel, try loading it */
170 if (kldload("ccd") < 0 || modfind("ccd") < 0)
171 warn("ccd module not available!");
177 exit(do_single(argc
, argv
, action
));
181 case CCD_UNCONFIGALL
:
182 exit(do_all(action
));
186 exit(dump_ccd(argc
, argv
));
194 do_single(int argc
, char **argv
, int action
)
196 struct ccd_ioctl ccio
;
197 char *ccd
, *cp
, *cp2
, **disks
;
198 int noflags
= 0, ileave
, flags
= 0, j
;
201 bzero(&ccio
, sizeof(ccio
));
204 * If unconfiguring, all arguments are treated as ccds.
206 if (action
== CCD_UNCONFIG
|| action
== CCD_UNCONFIGALL
) {
207 for (i
= 0; argc
!= 0; ) {
208 cp
= *argv
++; --argc
;
209 if ((ccd
= resolve_ccdname(cp
)) == NULL
) {
210 warnx("invalid ccd name: %s", cp
);
214 if (do_io(ccd
, CCDIOCCLR
, &ccio
))
218 printf("%s unconfigured\n", cp
);
223 /* Make sure there are enough arguments. */
226 /* Assume that no flags are specified. */
229 if (action
== CCD_CONFIGALL
) {
230 warnx("%s: bad line: %d", ccdconf
, lineno
);
237 /* First argument is the ccd to configure. */
238 cp
= *argv
++; --argc
;
239 if ((ccd
= resolve_ccdname(cp
)) == NULL
) {
240 warnx("invalid ccd name: %s", cp
);
244 /* Next argument is the interleave factor. */
245 cp
= *argv
++; --argc
;
246 errno
= 0; /* to check for ERANGE */
247 ileave
= (int)strtol(cp
, &cp2
, 10);
248 if ((errno
== ERANGE
) || (ileave
< 0) || (*cp2
!= '\0')) {
249 warnx("invalid interleave factor: %s", cp
);
254 /* Next argument is the ccd configuration flags. */
255 cp
= *argv
++; --argc
;
256 if ((flags
= flags_to_val(cp
)) < 0) {
257 warnx("invalid flags argument: %s", cp
);
262 /* Next is the list of disks to make the ccd from. */
263 disks
= malloc(argc
* sizeof(char *));
265 warnx("no memory to configure ccd");
268 for (i
= 0; argc
!= 0; ) {
269 cp
= *argv
++; --argc
;
270 if ((j
= checkdev(cp
)) == 0)
273 warnx("%s: %s", cp
, strerror(j
));
278 /* Fill in the ccio. */
279 ccio
.ccio_disks
= disks
;
280 ccio
.ccio_ndisks
= i
;
281 ccio
.ccio_ileave
= ileave
;
282 ccio
.ccio_flags
= flags
;
284 if (do_io(ccd
, CCDIOCSET
, &ccio
)) {
290 printf("ccd%d: %d components ", ccio
.ccio_unit
,
292 for (i
= 0; i
< ccio
.ccio_ndisks
; ++i
) {
293 if ((cp2
= strrchr(disks
[i
], '/')) != NULL
)
298 i
== 0 ? '(' : ' ', cp2
,
299 i
== ccio
.ccio_ndisks
- 1 ? ')' : ',');
301 printf(", %llu blocks ", ccio
.ccio_size
);
302 if (ccio
.ccio_ileave
!= 0)
303 printf("interleaved at %d blocks\n", ccio
.ccio_ileave
);
305 printf("concatenated\n");
316 char line
[_POSIX2_LINE_MAX
];
324 if ((f
= fopen(ccdconf
, "r")) == NULL
) {
326 warn("fopen: %s", ccdconf
);
331 while (fgets(line
, sizeof(line
), f
) != NULL
) {
335 if ((cp
= strrchr(line
, '\n')) != NULL
)
338 /* Break up the line and pass it's contents to do_single(). */
341 for (cp
= line
; (cp
= strtok(cp
, " \t")) != NULL
; cp
= NULL
) {
344 if ((argv
= realloc(argv
,
345 sizeof(char *) * ++argc
)) == NULL
) {
346 warnx("no memory to configure ccds");
351 * If our action is to unconfigure all, then pass
352 * just the first token to do_single() and ignore
353 * the rest. Since this will be encountered on
354 * our first pass through the line, the Right
357 if (action
== CCD_UNCONFIGALL
) {
358 if (do_single(argc
, argv
, action
))
364 if (do_single(argc
, argv
, action
))
381 if (stat(path
, &st
) != 0)
384 if (!S_ISBLK(st
.st_mode
) && !S_ISCHR(st
.st_mode
))
391 pathtounit(char *path
, int *unitp
)
396 if (stat(path
, &st
) != 0)
399 if (!S_ISBLK(st
.st_mode
) && !S_ISCHR(st
.st_mode
))
402 if ((maxpartitions
= getmaxpartitions()) < 0)
405 *unitp
= minor(st
.st_rdev
) / maxpartitions
;
411 resolve_ccdname(char *name
)
416 if (name
[0] == '/' || name
[0] == '.') {
417 /* Assume they gave the correct pathname. */
418 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
, 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 [...]]");
693 /* Local Variables: */
694 /* c-argdecl-indent: 8 */
695 /* c-indent-level: 8 */