189ef44efSEdward Tomasz Napierala /*- 289ef44efSEdward Tomasz Napierala * Copyright (c) 2000-2004 Poul-Henning Kamp <phk@FreeBSD.org> 377c43773SEdward Tomasz Napierala * Copyright (c) 2012 The FreeBSD Foundation 489ef44efSEdward Tomasz Napierala * All rights reserved. 589ef44efSEdward Tomasz Napierala * 677c43773SEdward Tomasz Napierala * Portions of this software were developed by Edward Tomasz Napierala 777c43773SEdward Tomasz Napierala * under sponsorship from the FreeBSD Foundation. 877c43773SEdward Tomasz Napierala * 989ef44efSEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 1089ef44efSEdward Tomasz Napierala * modification, are permitted provided that the following conditions 1189ef44efSEdward Tomasz Napierala * are met: 1289ef44efSEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 1389ef44efSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 1489ef44efSEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 1589ef44efSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 1689ef44efSEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 1789ef44efSEdward Tomasz Napierala * 1889ef44efSEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1989ef44efSEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2089ef44efSEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2189ef44efSEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2289ef44efSEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2389ef44efSEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2489ef44efSEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2589ef44efSEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2689ef44efSEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2789ef44efSEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2889ef44efSEdward Tomasz Napierala * SUCH DAMAGE. 2970d586c0SPoul-Henning Kamp * 3070d586c0SPoul-Henning Kamp * $FreeBSD$ 3170d586c0SPoul-Henning Kamp */ 3289ef44efSEdward Tomasz Napierala 3370d586c0SPoul-Henning Kamp #include <sys/param.h> 34c27a8954SWojciech A. Koszek #include <sys/devicestat.h> 354bfd989fSWojciech A. Koszek #include <sys/ioctl.h> 3657e9624eSPoul-Henning Kamp #include <sys/linker.h> 3770d586c0SPoul-Henning Kamp #include <sys/mdioctl.h> 384bfd989fSWojciech A. Koszek #include <sys/module.h> 39c27a8954SWojciech A. Koszek #include <sys/resource.h> 40b830359bSPawel Jakub Dawidek #include <sys/stat.h> 41174b5e9aSPoul-Henning Kamp 424bfd989fSWojciech A. Koszek #include <assert.h> 43c27a8954SWojciech A. Koszek #include <devstat.h> 444bfd989fSWojciech A. Koszek #include <err.h> 454bfd989fSWojciech A. Koszek #include <errno.h> 464bfd989fSWojciech A. Koszek #include <fcntl.h> 474bfd989fSWojciech A. Koszek #include <inttypes.h> 48c27a8954SWojciech A. Koszek #include <libgeom.h> 494bfd989fSWojciech A. Koszek #include <libutil.h> 50c27a8954SWojciech A. Koszek #include <stdarg.h> 514bfd989fSWojciech A. Koszek #include <stdio.h> 524bfd989fSWojciech A. Koszek #include <stdlib.h> 534bfd989fSWojciech A. Koszek #include <string.h> 544bfd989fSWojciech A. Koszek #include <unistd.h> 5570d586c0SPoul-Henning Kamp 564bfd989fSWojciech A. Koszek static struct md_ioctl mdio; 574bfd989fSWojciech A. Koszek static enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; 584bfd989fSWojciech A. Koszek static int nflag; 5970d586c0SPoul-Henning Kamp 60c27a8954SWojciech A. Koszek static void usage(void); 616c49c6cfSDag-Erling Smørgrav static void md_set_file(const char *); 62c27a8954SWojciech A. Koszek static int md_find(char *, const char *); 63c27a8954SWojciech A. Koszek static int md_query(char *name); 64c27a8954SWojciech A. Koszek static int md_list(char *units, int opt); 65a4ca6a49SJaakko Heinonen static char *geom_config_get(struct gconf *g, const char *name); 66c27a8954SWojciech A. Koszek static void md_prthumanval(char *length); 67c27a8954SWojciech A. Koszek 68c27a8954SWojciech A. Koszek #define OPT_VERBOSE 0x01 69c27a8954SWojciech A. Koszek #define OPT_UNIT 0x02 70c27a8954SWojciech A. Koszek #define OPT_DONE 0x04 71c27a8954SWojciech A. Koszek #define OPT_LIST 0x10 72c27a8954SWojciech A. Koszek 73c27a8954SWojciech A. Koszek #define CLASS_NAME_MD "MD" 74c27a8954SWojciech A. Koszek 754bfd989fSWojciech A. Koszek static void 76a4ca6a49SJaakko Heinonen usage(void) 77c2ef0b73SPoul-Henning Kamp { 7877c43773SEdward Tomasz Napierala 7978bb1162SRuslan Ermilov fprintf(stderr, 8078bb1162SRuslan Ermilov "usage: mdconfig -a -t type [-n] [-o [no]option] ... [-f file]\n" 8178bb1162SRuslan Ermilov " [-s size] [-S sectorsize] [-u unit]\n" 82db280204SJoel Dahl " [-x sectors/track] [-y heads/cylinder]\n" 83a9ebb311SEdward Tomasz Napierala " mdconfig -d -u unit [-o [no]force]\n" 846c49c6cfSDag-Erling Smørgrav " mdconfig -l [-v] [-n] [-u unit]\n" 856c49c6cfSDag-Erling Smørgrav " mdconfig file\n"); 86c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n"); 873f6f9216SPoul-Henning Kamp fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n"); 885d19b2f9SPawel Jakub Dawidek fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n"); 895d19b2f9SPawel Jakub Dawidek fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB) or\n"); 905d19b2f9SPawel Jakub Dawidek fprintf(stderr, "\t\t %%dt (TB)\n"); 91c2ef0b73SPoul-Henning Kamp exit(1); 92c2ef0b73SPoul-Henning Kamp } 93c2ef0b73SPoul-Henning Kamp 9470d586c0SPoul-Henning Kamp int 9570d586c0SPoul-Henning Kamp main(int argc, char **argv) 9670d586c0SPoul-Henning Kamp { 97c94b8307SDmitry Morozovsky int ch, fd, i, vflag; 98c2ef0b73SPoul-Henning Kamp char *p; 9977c43773SEdward Tomasz Napierala char *fflag = NULL, *tflag = NULL, *uflag = NULL; 10070d586c0SPoul-Henning Kamp 101b830359bSPawel Jakub Dawidek bzero(&mdio, sizeof(mdio)); 10288b5b78dSPawel Jakub Dawidek mdio.md_file = malloc(PATH_MAX); 10388b5b78dSPawel Jakub Dawidek if (mdio.md_file == NULL) 10488b5b78dSPawel Jakub Dawidek err(1, "could not allocate memory"); 105c94b8307SDmitry Morozovsky vflag = 0; 10688b5b78dSPawel Jakub Dawidek bzero(mdio.md_file, PATH_MAX); 10777c43773SEdward Tomasz Napierala 10877c43773SEdward Tomasz Napierala if (argc == 1) 10977c43773SEdward Tomasz Napierala usage(); 11077c43773SEdward Tomasz Napierala 1116c49c6cfSDag-Erling Smørgrav while ((ch = getopt(argc, argv, "ab:df:lno:s:S:t:u:vx:y:")) != -1) { 11270d586c0SPoul-Henning Kamp switch (ch) { 11370d586c0SPoul-Henning Kamp case 'a': 11477c43773SEdward Tomasz Napierala if (action != UNSET && action != ATTACH) 11577c43773SEdward Tomasz Napierala errx(1, 11677c43773SEdward Tomasz Napierala "-a is mutually exclusive with -d and -l"); 11770d586c0SPoul-Henning Kamp action = ATTACH; 11870d586c0SPoul-Henning Kamp break; 11970d586c0SPoul-Henning Kamp case 'd': 12077c43773SEdward Tomasz Napierala if (action != UNSET && action != DETACH) 12177c43773SEdward Tomasz Napierala errx(1, 12277c43773SEdward Tomasz Napierala "-d is mutually exclusive with -a and -l"); 12370d586c0SPoul-Henning Kamp action = DETACH; 12477c43773SEdward Tomasz Napierala mdio.md_options |= MD_AUTOUNIT; 125c2ef0b73SPoul-Henning Kamp break; 126174b5e9aSPoul-Henning Kamp case 'l': 12777c43773SEdward Tomasz Napierala if (action != UNSET && action != LIST) 12877c43773SEdward Tomasz Napierala errx(1, 12977c43773SEdward Tomasz Napierala "-l is mutually exclusive with -a and -d"); 130174b5e9aSPoul-Henning Kamp action = LIST; 13177c43773SEdward Tomasz Napierala mdio.md_options |= MD_AUTOUNIT; 132174b5e9aSPoul-Henning Kamp break; 133f79c46d3SRobert Watson case 'n': 134f79c46d3SRobert Watson nflag = 1; 135f79c46d3SRobert Watson break; 136c2ef0b73SPoul-Henning Kamp case 't': 13777c43773SEdward Tomasz Napierala if (tflag != NULL) 13877c43773SEdward Tomasz Napierala errx(1, "-t can be passed only once"); 13977c43773SEdward Tomasz Napierala tflag = optarg; 140c2ef0b73SPoul-Henning Kamp if (!strcmp(optarg, "malloc")) { 141c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_MALLOC; 14277c43773SEdward Tomasz Napierala mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS; 143c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "preload")) { 144c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_PRELOAD; 145c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "vnode")) { 146c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_VNODE; 14777c43773SEdward Tomasz Napierala mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 148c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "swap")) { 149c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_SWAP; 15077c43773SEdward Tomasz Napierala mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 15177c43773SEdward Tomasz Napierala } else 15277c43773SEdward Tomasz Napierala errx(1, "unknown type: %s", optarg); 15370d586c0SPoul-Henning Kamp break; 15470d586c0SPoul-Henning Kamp case 'f': 15577c43773SEdward Tomasz Napierala if (fflag != NULL) 15677c43773SEdward Tomasz Napierala errx(1, "-f can be passed only once"); 15777c43773SEdward Tomasz Napierala fflag = optarg; 15870d586c0SPoul-Henning Kamp break; 15970d586c0SPoul-Henning Kamp case 'o': 1607a6b2b64SPoul-Henning Kamp if (!strcmp(optarg, "async")) 1617a6b2b64SPoul-Henning Kamp mdio.md_options |= MD_ASYNC; 1627a6b2b64SPoul-Henning Kamp else if (!strcmp(optarg, "noasync")) 1637a6b2b64SPoul-Henning Kamp mdio.md_options &= ~MD_ASYNC; 1647a6b2b64SPoul-Henning Kamp else if (!strcmp(optarg, "cluster")) 16570d586c0SPoul-Henning Kamp mdio.md_options |= MD_CLUSTER; 16670d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "nocluster")) 16770d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_CLUSTER; 168c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "compress")) 169c2ef0b73SPoul-Henning Kamp mdio.md_options |= MD_COMPRESS; 170c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "nocompress")) 171c2ef0b73SPoul-Henning Kamp mdio.md_options &= ~MD_COMPRESS; 17226a0ee75SDima Dorfman else if (!strcmp(optarg, "force")) 17326a0ee75SDima Dorfman mdio.md_options |= MD_FORCE; 17426a0ee75SDima Dorfman else if (!strcmp(optarg, "noforce")) 17526a0ee75SDima Dorfman mdio.md_options &= ~MD_FORCE; 176d31ba625SJohn-Mark Gurney else if (!strcmp(optarg, "readonly")) 177d31ba625SJohn-Mark Gurney mdio.md_options |= MD_READONLY; 178d31ba625SJohn-Mark Gurney else if (!strcmp(optarg, "noreadonly")) 179d31ba625SJohn-Mark Gurney mdio.md_options &= ~MD_READONLY; 18070d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "reserve")) 18170d586c0SPoul-Henning Kamp mdio.md_options |= MD_RESERVE; 18270d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "noreserve")) 18370d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_RESERVE; 18470d586c0SPoul-Henning Kamp else 18577c43773SEdward Tomasz Napierala errx(1, "unknown option: %s", optarg); 18670d586c0SPoul-Henning Kamp break; 187ebe789d6SPoul-Henning Kamp case 'S': 188b830359bSPawel Jakub Dawidek mdio.md_sectorsize = strtoul(optarg, &p, 0); 189ebe789d6SPoul-Henning Kamp break; 19070d586c0SPoul-Henning Kamp case 's': 191b830359bSPawel Jakub Dawidek mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0); 192c2ef0b73SPoul-Henning Kamp if (p == NULL || *p == '\0') 193b830359bSPawel Jakub Dawidek mdio.md_mediasize *= DEV_BSIZE; 1940d79319aSPawel Jakub Dawidek else if (*p == 'b' || *p == 'B') 1950d79319aSPawel Jakub Dawidek ; /* do nothing */ 196c2ef0b73SPoul-Henning Kamp else if (*p == 'k' || *p == 'K') 197b830359bSPawel Jakub Dawidek mdio.md_mediasize <<= 10; 198c2ef0b73SPoul-Henning Kamp else if (*p == 'm' || *p == 'M') 199b830359bSPawel Jakub Dawidek mdio.md_mediasize <<= 20; 200c2ef0b73SPoul-Henning Kamp else if (*p == 'g' || *p == 'G') 201b830359bSPawel Jakub Dawidek mdio.md_mediasize <<= 30; 202b830359bSPawel Jakub Dawidek else if (*p == 't' || *p == 'T') { 203b830359bSPawel Jakub Dawidek mdio.md_mediasize <<= 30; 204b830359bSPawel Jakub Dawidek mdio.md_mediasize <<= 10; 205b830359bSPawel Jakub Dawidek } else 20677c43773SEdward Tomasz Napierala errx(1, "unknown suffix on -s argument"); 20770d586c0SPoul-Henning Kamp break; 20870d586c0SPoul-Henning Kamp case 'u': 209ea3d97aeSWojciech A. Koszek if (!strncmp(optarg, "/dev/", 5)) 210ea3d97aeSWojciech A. Koszek optarg += 5; 211ea3d97aeSWojciech A. Koszek if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) 212ea3d97aeSWojciech A. Koszek optarg += sizeof(MD_NAME) - 1; 21377c43773SEdward Tomasz Napierala uflag = optarg; 21470d586c0SPoul-Henning Kamp break; 215c94b8307SDmitry Morozovsky case 'v': 216c94b8307SDmitry Morozovsky vflag = OPT_VERBOSE; 217c94b8307SDmitry Morozovsky break; 2184e8bfe14SPoul-Henning Kamp case 'x': 2194e8bfe14SPoul-Henning Kamp mdio.md_fwsectors = strtoul(optarg, &p, 0); 2204e8bfe14SPoul-Henning Kamp break; 2214e8bfe14SPoul-Henning Kamp case 'y': 2224e8bfe14SPoul-Henning Kamp mdio.md_fwheads = strtoul(optarg, &p, 0); 2234e8bfe14SPoul-Henning Kamp break; 22470d586c0SPoul-Henning Kamp default: 225c2ef0b73SPoul-Henning Kamp usage(); 22670d586c0SPoul-Henning Kamp } 22770d586c0SPoul-Henning Kamp } 2286c49c6cfSDag-Erling Smørgrav 2296c49c6cfSDag-Erling Smørgrav argc -= optind; 2306c49c6cfSDag-Erling Smørgrav argv += optind; 23177c43773SEdward Tomasz Napierala 23277c43773SEdward Tomasz Napierala if (action == UNSET) 23377c43773SEdward Tomasz Napierala action = ATTACH; 23477c43773SEdward Tomasz Napierala 23577c43773SEdward Tomasz Napierala if (action == ATTACH) { 23677c43773SEdward Tomasz Napierala if (tflag == NULL) { 23777c43773SEdward Tomasz Napierala /* 23877c43773SEdward Tomasz Napierala * Try to infer the type based on other arguments. 23977c43773SEdward Tomasz Napierala */ 24077c43773SEdward Tomasz Napierala if (fflag != NULL || argc > 0) { 24177c43773SEdward Tomasz Napierala /* Imply ``-t vnode'' */ 24277c43773SEdward Tomasz Napierala mdio.md_type = MD_VNODE; 24377c43773SEdward Tomasz Napierala mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | 24477c43773SEdward Tomasz Napierala MD_COMPRESS; 24577c43773SEdward Tomasz Napierala } else if (mdio.md_mediasize != 0) { 24677c43773SEdward Tomasz Napierala /* Imply ``-t swap'' */ 24777c43773SEdward Tomasz Napierala mdio.md_type = MD_SWAP; 24877c43773SEdward Tomasz Napierala mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | 24977c43773SEdward Tomasz Napierala MD_COMPRESS; 25077c43773SEdward Tomasz Napierala } else 25177c43773SEdward Tomasz Napierala errx(1, "unable to determine type"); 25277c43773SEdward Tomasz Napierala } 25377c43773SEdward Tomasz Napierala 25477c43773SEdward Tomasz Napierala if ((fflag != NULL || argc > 0) && mdio.md_type != MD_VNODE) 25577c43773SEdward Tomasz Napierala errx(1, "only -t vnode can be used with file name"); 25677c43773SEdward Tomasz Napierala 25777c43773SEdward Tomasz Napierala if (mdio.md_type == MD_VNODE) { 25877c43773SEdward Tomasz Napierala if (fflag != NULL) { 25977c43773SEdward Tomasz Napierala if (argc != 0) 26077c43773SEdward Tomasz Napierala usage(); 26177c43773SEdward Tomasz Napierala md_set_file(fflag); 26277c43773SEdward Tomasz Napierala } else { 2636c49c6cfSDag-Erling Smørgrav if (argc != 1) 2646c49c6cfSDag-Erling Smørgrav usage(); 2656c49c6cfSDag-Erling Smørgrav md_set_file(*argv); 2666c49c6cfSDag-Erling Smørgrav } 2676c49c6cfSDag-Erling Smørgrav 26877c43773SEdward Tomasz Napierala if ((mdio.md_options & MD_READONLY) == 0 && 26977c43773SEdward Tomasz Napierala access(mdio.md_file, W_OK) < 0 && 27077c43773SEdward Tomasz Napierala (errno == EACCES || errno == EPERM || 27177c43773SEdward Tomasz Napierala errno == EROFS)) { 27277c43773SEdward Tomasz Napierala warnx("WARNING: opening backing store: %s " 27377c43773SEdward Tomasz Napierala "readonly", mdio.md_file); 27477c43773SEdward Tomasz Napierala mdio.md_options |= MD_READONLY; 27577c43773SEdward Tomasz Napierala } 27677c43773SEdward Tomasz Napierala } 27777c43773SEdward Tomasz Napierala 27877c43773SEdward Tomasz Napierala if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP) && 27977c43773SEdward Tomasz Napierala mdio.md_mediasize == 0) 28077c43773SEdward Tomasz Napierala errx(1, "must specify -s for -t malloc or -t swap"); 28177c43773SEdward Tomasz Napierala if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0') 28277c43773SEdward Tomasz Napierala errx(1, "must specify -f for -t vnode"); 28377c43773SEdward Tomasz Napierala } else { 28477c43773SEdward Tomasz Napierala if (mdio.md_sectorsize != 0) 28577c43773SEdward Tomasz Napierala errx(1, "-S can only be used with -a"); 28677c43773SEdward Tomasz Napierala if (mdio.md_mediasize != 0) 28777c43773SEdward Tomasz Napierala errx(1, "-s can only be used with -a"); 28877c43773SEdward Tomasz Napierala if (mdio.md_fwsectors != 0) 28977c43773SEdward Tomasz Napierala errx(1, "-x can only be used with -a"); 29077c43773SEdward Tomasz Napierala if (mdio.md_fwheads != 0) 29177c43773SEdward Tomasz Napierala errx(1, "-y can only be used with -a"); 29277c43773SEdward Tomasz Napierala if (fflag != NULL) 29377c43773SEdward Tomasz Napierala errx(1, "-f can only be used with -a"); 29477c43773SEdward Tomasz Napierala if (tflag != NULL) 29577c43773SEdward Tomasz Napierala errx(1, "-t can only be used with -a"); 29677c43773SEdward Tomasz Napierala if (argc > 0) 29777c43773SEdward Tomasz Napierala errx(1, "file can only be used with -a"); 29877c43773SEdward Tomasz Napierala if (action != DETACH && (mdio.md_options & ~MD_AUTOUNIT) != 0) 29977c43773SEdward Tomasz Napierala errx(1, "-o can only be used with -a and -d"); 30077c43773SEdward Tomasz Napierala if (action == DETACH && 30177c43773SEdward Tomasz Napierala (mdio.md_options & ~(MD_FORCE | MD_AUTOUNIT)) != 0) 30277c43773SEdward Tomasz Napierala errx(1, "only -o [no]force can be used with -d"); 30377c43773SEdward Tomasz Napierala } 30477c43773SEdward Tomasz Napierala 30577c43773SEdward Tomasz Napierala if (action != LIST && vflag == OPT_VERBOSE) 30677c43773SEdward Tomasz Napierala errx(1, "-v can only be used with -l"); 30777c43773SEdward Tomasz Napierala 30877c43773SEdward Tomasz Napierala if (uflag != NULL) { 30977c43773SEdward Tomasz Napierala mdio.md_unit = strtoul(uflag, &p, 0); 31077c43773SEdward Tomasz Napierala if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0') 31177c43773SEdward Tomasz Napierala errx(1, "bad unit: %s", uflag); 31277c43773SEdward Tomasz Napierala mdio.md_options &= ~MD_AUTOUNIT; 31377c43773SEdward Tomasz Napierala } 31477c43773SEdward Tomasz Napierala 31553d745bcSDima Dorfman mdio.md_version = MDIOVERSION; 31670d586c0SPoul-Henning Kamp 317a921cb31SPawel Jakub Dawidek if (!kld_isloaded("g_md") && kld_load("geom_md") == -1) 318a921cb31SPawel Jakub Dawidek err(1, "failed to load geom_md module"); 319a921cb31SPawel Jakub Dawidek 320174b5e9aSPoul-Henning Kamp fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 32170d586c0SPoul-Henning Kamp if (fd < 0) 322174b5e9aSPoul-Henning Kamp err(1, "open(/dev/%s)", MDCTL_NAME); 32377c43773SEdward Tomasz Napierala 32477c43773SEdward Tomasz Napierala if (action == ATTACH) { 32570d586c0SPoul-Henning Kamp i = ioctl(fd, MDIOCATTACH, &mdio); 326174b5e9aSPoul-Henning Kamp if (i < 0) 327174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 32883da2a90SPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 329f79c46d3SRobert Watson printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit); 33083da2a90SPoul-Henning Kamp } else if (action == DETACH) { 3318f8def9eSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 33277c43773SEdward Tomasz Napierala errx(1, "-d requires -u"); 333c2ef0b73SPoul-Henning Kamp i = ioctl(fd, MDIOCDETACH, &mdio); 33470d586c0SPoul-Henning Kamp if (i < 0) 335174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 33677c43773SEdward Tomasz Napierala } else if (action == LIST) { 33777c43773SEdward Tomasz Napierala if (mdio.md_options & MD_AUTOUNIT) { 33877c43773SEdward Tomasz Napierala /* 33977c43773SEdward Tomasz Napierala * Listing all devices. This is why we pass NULL 34077c43773SEdward Tomasz Napierala * together with OPT_LIST. 34177c43773SEdward Tomasz Napierala */ 34277c43773SEdward Tomasz Napierala md_list(NULL, OPT_LIST | vflag); 34377c43773SEdward Tomasz Napierala } else 34477c43773SEdward Tomasz Napierala return (md_query(uflag)); 34577c43773SEdward Tomasz Napierala 34683da2a90SPoul-Henning Kamp } else 34783da2a90SPoul-Henning Kamp usage(); 348174b5e9aSPoul-Henning Kamp close(fd); 349174b5e9aSPoul-Henning Kamp return (0); 350174b5e9aSPoul-Henning Kamp } 351174b5e9aSPoul-Henning Kamp 3526c49c6cfSDag-Erling Smørgrav static void 3536c49c6cfSDag-Erling Smørgrav md_set_file(const char *fn) 3546c49c6cfSDag-Erling Smørgrav { 3556c49c6cfSDag-Erling Smørgrav struct stat sb; 3566c49c6cfSDag-Erling Smørgrav int fd; 3576c49c6cfSDag-Erling Smørgrav 3586c49c6cfSDag-Erling Smørgrav if (realpath(fn, mdio.md_file) == NULL) 3596c49c6cfSDag-Erling Smørgrav err(1, "could not find full path for %s", fn); 3606c49c6cfSDag-Erling Smørgrav fd = open(mdio.md_file, O_RDONLY); 3616c49c6cfSDag-Erling Smørgrav if (fd < 0) 3626c49c6cfSDag-Erling Smørgrav err(1, "could not open %s", fn); 3636c49c6cfSDag-Erling Smørgrav if (fstat(fd, &sb) == -1) 3646c49c6cfSDag-Erling Smørgrav err(1, "could not stat %s", fn); 3656c49c6cfSDag-Erling Smørgrav if (!S_ISREG(sb.st_mode)) 3666c49c6cfSDag-Erling Smørgrav errx(1, "%s is not a regular file", fn); 3676c49c6cfSDag-Erling Smørgrav if (mdio.md_mediasize == 0) 3686c49c6cfSDag-Erling Smørgrav mdio.md_mediasize = sb.st_size; 3696c49c6cfSDag-Erling Smørgrav close(fd); 3706c49c6cfSDag-Erling Smørgrav } 3716c49c6cfSDag-Erling Smørgrav 372c27a8954SWojciech A. Koszek /* 373c27a8954SWojciech A. Koszek * Lists md(4) disks. Is used also as a query routine, since it handles XML 374c27a8954SWojciech A. Koszek * interface. 'units' can be NULL for listing memory disks. It might be 375c27a8954SWojciech A. Koszek * coma-separated string containing md(4) disk names. 'opt' distinguished 376c27a8954SWojciech A. Koszek * between list and query mode. 377c27a8954SWojciech A. Koszek */ 3787e06d7bcSDima Dorfman static int 379c27a8954SWojciech A. Koszek md_list(char *units, int opt) 3807e06d7bcSDima Dorfman { 381c27a8954SWojciech A. Koszek struct gmesh gm; 382c27a8954SWojciech A. Koszek struct gprovider *pp; 383c27a8954SWojciech A. Koszek struct gconf *gc; 384c27a8954SWojciech A. Koszek struct gident *gid; 385c3345c66SJason Evans struct devstat *gsp; 386c27a8954SWojciech A. Koszek struct ggeom *gg; 387c27a8954SWojciech A. Koszek struct gclass *gcl; 388c27a8954SWojciech A. Koszek void *sq; 38969fcb537SFlorent Thoumie int retcode, found; 390c27a8954SWojciech A. Koszek char *type, *file, *length; 3917e06d7bcSDima Dorfman 392c27a8954SWojciech A. Koszek type = file = length = NULL; 393174b5e9aSPoul-Henning Kamp 394c27a8954SWojciech A. Koszek retcode = geom_gettree(&gm); 395c27a8954SWojciech A. Koszek if (retcode != 0) 396c27a8954SWojciech A. Koszek return (-1); 397c27a8954SWojciech A. Koszek retcode = geom_stats_open(); 398c27a8954SWojciech A. Koszek if (retcode != 0) 399c27a8954SWojciech A. Koszek return (-1); 400c27a8954SWojciech A. Koszek sq = geom_stats_snapshot_get(); 401c27a8954SWojciech A. Koszek if (sq == NULL) 402c27a8954SWojciech A. Koszek return (-1); 403c27a8954SWojciech A. Koszek 40469fcb537SFlorent Thoumie found = 0; 405c27a8954SWojciech A. Koszek while ((gsp = geom_stats_snapshot_next(sq)) != NULL) { 406c27a8954SWojciech A. Koszek gid = geom_lookupid(&gm, gsp->id); 407c27a8954SWojciech A. Koszek if (gid == NULL) 408c27a8954SWojciech A. Koszek continue; 409c27a8954SWojciech A. Koszek if (gid->lg_what == ISPROVIDER) { 410c27a8954SWojciech A. Koszek pp = gid->lg_ptr; 411c27a8954SWojciech A. Koszek gg = pp->lg_geom; 412c27a8954SWojciech A. Koszek gcl = gg->lg_class; 413c27a8954SWojciech A. Koszek if (strcmp(gcl->lg_name, CLASS_NAME_MD) != 0) 414c27a8954SWojciech A. Koszek continue; 415c27a8954SWojciech A. Koszek if ((opt & OPT_UNIT) && (units != NULL)) { 416c27a8954SWojciech A. Koszek retcode = md_find(units, pp->lg_name); 417c27a8954SWojciech A. Koszek if (retcode != 1) 418c27a8954SWojciech A. Koszek continue; 41969fcb537SFlorent Thoumie else 42069fcb537SFlorent Thoumie found = 1; 421174b5e9aSPoul-Henning Kamp } 422c27a8954SWojciech A. Koszek gc = &pp->lg_config; 423c3e257a9SRebecca Cran if (nflag && strncmp(pp->lg_name, "md", 2) == 0) 424c3e257a9SRebecca Cran printf("%s", pp->lg_name + 2); 425c3e257a9SRebecca Cran else 426c3e257a9SRebecca Cran printf("%s", pp->lg_name); 427c3e257a9SRebecca Cran 428c27a8954SWojciech A. Koszek if (opt & OPT_VERBOSE || opt & OPT_UNIT) { 429c27a8954SWojciech A. Koszek type = geom_config_get(gc, "type"); 430c27a8954SWojciech A. Koszek if (strcmp(type, "vnode") == 0) 431c27a8954SWojciech A. Koszek file = geom_config_get(gc, "file"); 432c27a8954SWojciech A. Koszek length = geom_config_get(gc, "length"); 433c27a8954SWojciech A. Koszek printf("\t%s\t", type); 434a4ca6a49SJaakko Heinonen if (length != NULL) 435c27a8954SWojciech A. Koszek md_prthumanval(length); 436c27a8954SWojciech A. Koszek if (file != NULL) { 437c27a8954SWojciech A. Koszek printf("\t%s", file); 438c27a8954SWojciech A. Koszek file = NULL; 439c27a8954SWojciech A. Koszek } 440c27a8954SWojciech A. Koszek } 441c27a8954SWojciech A. Koszek opt |= OPT_DONE; 442c94b8307SDmitry Morozovsky if ((opt & OPT_LIST) && !(opt & OPT_VERBOSE)) 443c27a8954SWojciech A. Koszek printf(" "); 444c27a8954SWojciech A. Koszek else 445e39eff98SPoul-Henning Kamp printf("\n"); 446c27a8954SWojciech A. Koszek } 447c27a8954SWojciech A. Koszek } 448c94b8307SDmitry Morozovsky if ((opt & OPT_LIST) && (opt & OPT_DONE) && !(opt & OPT_VERBOSE)) 449c27a8954SWojciech A. Koszek printf("\n"); 450c27a8954SWojciech A. Koszek /* XXX: Check if it's enough to clean everything. */ 451c27a8954SWojciech A. Koszek geom_stats_snapshot_free(sq); 45269fcb537SFlorent Thoumie if ((opt & OPT_UNIT) && found) 45369fcb537SFlorent Thoumie return (0); 45469fcb537SFlorent Thoumie else 455c27a8954SWojciech A. Koszek return (-1); 456c27a8954SWojciech A. Koszek } 457c27a8954SWojciech A. Koszek 458c27a8954SWojciech A. Koszek /* 459c27a8954SWojciech A. Koszek * Returns value of 'name' from gconfig structure. 460c27a8954SWojciech A. Koszek */ 461c27a8954SWojciech A. Koszek static char * 462a4ca6a49SJaakko Heinonen geom_config_get(struct gconf *g, const char *name) 463c27a8954SWojciech A. Koszek { 464c27a8954SWojciech A. Koszek struct gconfig *gce; 465c27a8954SWojciech A. Koszek 466c27a8954SWojciech A. Koszek LIST_FOREACH(gce, g, lg_config) { 467c27a8954SWojciech A. Koszek if (strcmp(gce->lg_name, name) == 0) 468c27a8954SWojciech A. Koszek return (gce->lg_val); 469c27a8954SWojciech A. Koszek } 470c27a8954SWojciech A. Koszek return (NULL); 471c27a8954SWojciech A. Koszek } 472c27a8954SWojciech A. Koszek 473c27a8954SWojciech A. Koszek /* 474c27a8954SWojciech A. Koszek * List is comma separated list of MD disks. name is a 475c27a8954SWojciech A. Koszek * device name we look for. Returns 1 if found and 0 476c27a8954SWojciech A. Koszek * otherwise. 477c27a8954SWojciech A. Koszek */ 478c27a8954SWojciech A. Koszek static int 479c27a8954SWojciech A. Koszek md_find(char *list, const char *name) 480c27a8954SWojciech A. Koszek { 481c27a8954SWojciech A. Koszek int ret; 482c27a8954SWojciech A. Koszek char num[16]; 483c27a8954SWojciech A. Koszek char *ptr, *p, *u; 484c27a8954SWojciech A. Koszek 485c27a8954SWojciech A. Koszek ret = 0; 486c27a8954SWojciech A. Koszek ptr = strdup(list); 487c27a8954SWojciech A. Koszek if (ptr == NULL) 488c27a8954SWojciech A. Koszek return (-1); 489c27a8954SWojciech A. Koszek for (p = ptr; (u = strsep(&p, ",")) != NULL;) { 490c27a8954SWojciech A. Koszek if (strncmp(u, "/dev/", 5) == 0) 491c27a8954SWojciech A. Koszek u += 5; 492c27a8954SWojciech A. Koszek /* Just in case user specified number instead of full name */ 493c27a8954SWojciech A. Koszek snprintf(num, sizeof(num), "md%s", u); 494c27a8954SWojciech A. Koszek if (strcmp(u, name) == 0 || strcmp(num, name) == 0) { 495c27a8954SWojciech A. Koszek ret = 1; 496c27a8954SWojciech A. Koszek break; 497c27a8954SWojciech A. Koszek } 498c27a8954SWojciech A. Koszek } 499c27a8954SWojciech A. Koszek free(ptr); 500c27a8954SWojciech A. Koszek return (ret); 501174b5e9aSPoul-Henning Kamp } 502174b5e9aSPoul-Henning Kamp 503b830359bSPawel Jakub Dawidek static void 504c27a8954SWojciech A. Koszek md_prthumanval(char *length) 505b830359bSPawel Jakub Dawidek { 506b830359bSPawel Jakub Dawidek char buf[6]; 5070e3ebc63SJaakko Heinonen uintmax_t bytes; 508c27a8954SWojciech A. Koszek char *endptr; 509b830359bSPawel Jakub Dawidek 5100e3ebc63SJaakko Heinonen errno = 0; 5110e3ebc63SJaakko Heinonen bytes = strtoumax(length, &endptr, 10); 5120e3ebc63SJaakko Heinonen if (errno != 0 || *endptr != '\0' || bytes > INT64_MAX) 513c27a8954SWojciech A. Koszek return; 5140e3ebc63SJaakko Heinonen humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 5150e3ebc63SJaakko Heinonen HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 516b830359bSPawel Jakub Dawidek (void)printf("%6s", buf); 517b830359bSPawel Jakub Dawidek } 518b830359bSPawel Jakub Dawidek 519*cff3dc08SEdward Tomasz Napierala static int 520c27a8954SWojciech A. Koszek md_query(char *name) 521174b5e9aSPoul-Henning Kamp { 52277c43773SEdward Tomasz Napierala 523c27a8954SWojciech A. Koszek return (md_list(name, OPT_UNIT)); 52470d586c0SPoul-Henning Kamp } 525