Teach md(4) and mdconfig(8) how to understand XML. Right now there won't be

a problem with listing large number of md(4) devices. Either 'list' or
'query' mode uses XML.

Additionally, new functionality was introduced. It's possible to pass
multiple devices to -u:

	# ./mdconfig -l -u md0,md1

Approved by:	cognet (mentor)
This commit is contained in:
Wojciech A. Koszek 2006-03-26 23:21:11 +00:00
parent 4bfd989f3e
commit c27a895433
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157160
3 changed files with 221 additions and 66 deletions

View File

@ -4,7 +4,7 @@ PROG= mdconfig
MAN= mdconfig.8
MLINKS= mdconfig.8 vnconfig.8
DPADD= ${LIBUTIL}
LDADD= -lutil
DPADD= ${LIBUTIL} ${LIBGEOM}
LDADD= -lutil -lgeom
.include <bsd.prog.mk>

View File

@ -10,31 +10,48 @@
*
*/
#include <sys/param.h>
#include <sys/devicestat.h>
#include <sys/ioctl.h>
#include <sys/linker.h>
#include <sys/mdioctl.h>
#include <sys/module.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <assert.h>
#include <devstat.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libgeom.h>
#include <libutil.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int list(const int);
static int query(const int, const int);
static void usage(void);
static struct md_ioctl mdio;
static enum {UNSET, ATTACH, DETACH, LIST} action = UNSET;
static int nflag;
static void usage(void);
static int md_find(char *, const char *);
static int md_query(char *name);
static int md_list(char *units, int opt);
static char *geom_config_get(struct gconf *g, char *name);
static void geom_config_dump(struct gconf *g);
static void md_prthumanval(char *length);
#define OPT_VERBOSE 0x01
#define OPT_UNIT 0x02
#define OPT_DONE 0x04
#define OPT_LIST 0x10
#define CLASS_NAME_MD "MD"
static void
usage()
{
@ -58,6 +75,7 @@ main(int argc, char **argv)
int ch, fd, i;
char *p;
int cmdline = 0;
char *mdunit;
bzero(&mdio, sizeof(mdio));
mdio.md_file = malloc(PATH_MAX);
@ -195,13 +213,7 @@ main(int argc, char **argv)
case 'u':
if (cmdline != 2 && cmdline != 3)
usage();
if (!strncmp(optarg, "/dev/", 5))
optarg += 5;
if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1))
optarg += sizeof(MD_NAME) - 1;
mdio.md_unit = strtoul(optarg, &p, 0);
if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0')
errx(1, "bad unit: %s", optarg);
mdunit = optarg;
mdio.md_options &= ~MD_AUTOUNIT;
break;
case 'x':
@ -244,10 +256,15 @@ main(int argc, char **argv)
}
}
if (action == LIST) {
if (mdio.md_options & MD_AUTOUNIT)
list(fd);
else
query(fd, mdio.md_unit);
if (mdio.md_options & MD_AUTOUNIT) {
/*
* Listing all devices. This is why we pass NULL
* together with OPT_LIST.
*/
md_list(NULL, OPT_LIST);
} else {
md_query(mdunit);
}
} else if (action == ATTACH) {
if (cmdline < 2)
usage();
@ -268,73 +285,149 @@ main(int argc, char **argv)
return (0);
}
/*
* Lists md(4) disks. Is used also as a query routine, since it handles XML
* interface. 'units' can be NULL for listing memory disks. It might be
* coma-separated string containing md(4) disk names. 'opt' distinguished
* between list and query mode.
*/
static int
mdunitcmp(const void *a, const void *b)
md_list(char *units, int opt)
{
return (*(int *)a - *(int *)b);
struct gmesh gm;
struct gprovider *pp;
struct gconsumer *cp;
struct gconf *gc;
struct gconfig *gce;
struct gident *gid;
struct devstat *gsp, *gsq;
struct ggeom *gg;
struct gclass *gcl;
void *sq;
int retcode;
signed int ch;
int nl;
char *type, *file, *length;
type = file = length = NULL;
retcode = geom_gettree(&gm);
if (retcode != 0)
return (-1);
retcode = geom_stats_open();
if (retcode != 0)
return (-1);
sq = geom_stats_snapshot_get();
if (sq == NULL)
return (-1);
while ((gsp = geom_stats_snapshot_next(sq)) != NULL) {
gid = geom_lookupid(&gm, gsp->id);
if (gid == NULL)
continue;
if (gid->lg_what == ISPROVIDER) {
pp = gid->lg_ptr;
gg = pp->lg_geom;
gcl = gg->lg_class;
if (strcmp(gcl->lg_name, CLASS_NAME_MD) != 0)
continue;
if ((opt & OPT_UNIT) && (units != NULL)) {
retcode = md_find(units, pp->lg_name);
if (retcode != 1)
continue;
}
gc = &pp->lg_config;
printf("%s", pp->lg_name);
if (opt & OPT_VERBOSE || opt & OPT_UNIT) {
type = geom_config_get(gc, "type");
if (strcmp(type, "vnode") == 0)
file = geom_config_get(gc, "file");
length = geom_config_get(gc, "length");
if (length == NULL)
length = "<a>";
printf("\t%s\t", type);
md_prthumanval(length);
if (file != NULL) {
printf("\t%s", file);
file = NULL;
}
}
opt |= OPT_DONE;
if (opt & OPT_LIST)
printf(" ");
else
printf("\n");
}
}
if ((opt & OPT_LIST) && (opt & OPT_DONE))
printf("\n");
/* XXX: Check if it's enough to clean everything. */
geom_stats_snapshot_free(sq);
return (-1);
}
static int
list(const int fd)
/*
* Returns value of 'name' from gconfig structure.
*/
static char *
geom_config_get(struct gconf *g, char *name)
{
int unit;
int mdcount;
struct gconfig *gce;
if (ioctl(fd, MDIOCLIST, &mdio) < 0)
err(1, "ioctl(/dev/%s)", MDCTL_NAME);
mdcount = mdio.md_pad[0];
assert(mdcount < MDNPAD - 1);
if (mdcount > 0)
qsort(&mdio.md_pad[1], mdcount, sizeof(mdio.md_pad[0]), mdunitcmp);
for (unit = 0; unit < mdcount; unit++) {
printf("%s%s%d", unit > 0 ? " " : "",
nflag ? "" : MD_NAME, mdio.md_pad[unit + 1]);
LIST_FOREACH(gce, g, lg_config) {
if (strcmp(gce->lg_name, name) == 0)
return (gce->lg_val);
}
if (unit > 0)
printf("\n");
return (0);
return (NULL);
}
/*
* List is comma separated list of MD disks. name is a
* device name we look for. Returns 1 if found and 0
* otherwise.
*/
static int
md_find(char *list, const char *name)
{
int ret;
char num[16];
char *ptr, *p, *u;
ret = 0;
ptr = strdup(list);
if (ptr == NULL)
return (-1);
for (p = ptr; (u = strsep(&p, ",")) != NULL;) {
if (strncmp(u, "/dev/", 5) == 0)
u += 5;
/* Just in case user specified number instead of full name */
snprintf(num, sizeof(num), "md%s", u);
if (strcmp(u, name) == 0 || strcmp(num, name) == 0) {
ret = 1;
break;
}
}
free(ptr);
return (ret);
}
static void
prthumanval(int64_t bytes)
md_prthumanval(char *length)
{
char buf[6];
uint64_t bytes;
char *endptr;
bytes = strtoul(length, &endptr, 10);
if (bytes == (unsigned)ULONG_MAX || *endptr != '\0')
return;
humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
bytes, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
(void)printf("%6s", buf);
}
static int
query(const int fd, const int unit)
int
md_query(char *name)
{
mdio.md_version = MDIOVERSION;
mdio.md_unit = unit;
if (ioctl(fd, MDIOCQUERY, &mdio) < 0)
err(1, "ioctl(/dev/%s)", MDCTL_NAME);
(void)printf("%s%d\t", MD_NAME, mdio.md_unit);
switch (mdio.md_type) {
case MD_MALLOC:
(void)printf("malloc");
break;
case MD_PRELOAD:
(void)printf("preload");
break;
case MD_SWAP:
(void)printf("swap");
break;
case MD_VNODE:
(void)printf("vnode");
break;
}
printf("\t");
prthumanval(mdio.md_mediasize);
if (mdio.md_type == MD_VNODE)
printf("\t%s", mdio.md_file);
printf("\n");
return (0);
return (md_list(name, OPT_UNIT));
}

View File

@ -120,6 +120,8 @@ static g_init_t g_md_init;
static g_fini_t g_md_fini;
static g_start_t g_md_start;
static g_access_t g_md_access;
static void g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
struct g_consumer *cp __unused, struct g_provider *pp);
static int mdunits;
static struct cdev *status_dev = 0;
@ -140,6 +142,7 @@ struct g_class g_md_class = {
.fini = g_md_fini,
.start = g_md_start,
.access = g_md_access,
.dumpconf = g_md_dumpconf,
};
DECLARE_GEOM_CLASS(g_md_class, g_md);
@ -1177,6 +1180,65 @@ g_md_init(struct g_class *mp __unused)
g_topology_lock();
}
static void
g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
struct g_consumer *cp __unused, struct g_provider *pp)
{
struct md_s *mp;
char *type;
mp = gp->softc;
if (mp == NULL)
return;
switch (mp->type) {
case MD_MALLOC:
type = "malloc";
break;
case MD_PRELOAD:
type = "preload";
break;
case MD_VNODE:
type = "vnode";
break;
case MD_SWAP:
type = "swap";
break;
default:
type = "unknown";
break;
}
if (pp != NULL) {
if (indent == NULL) {
sbuf_printf(sb, " u %d", mp->unit);
sbuf_printf(sb, " s %ju", (uintmax_t) mp->sectorsize);
sbuf_printf(sb, " f %ju", (uintmax_t) mp->fwheads);
sbuf_printf(sb, " fs %ju", (uintmax_t) mp->fwsectors);
sbuf_printf(sb, " l %ju", (uintmax_t) mp->mediasize);
sbuf_printf(sb, " t %s", type);
if (mp->type == MD_VNODE && mp->vnode != NULL)
sbuf_printf(sb, " file %s", mp->file);
} else {
sbuf_printf(sb, "%s<unit>%d</unit>\n", indent,
mp->unit);
sbuf_printf(sb, "%s<sectorsize>%ju</sectorsize>\n",
indent, (uintmax_t) mp->sectorsize);
sbuf_printf(sb, "%s<fwheads>%ju</fwheads>\n",
indent, (uintmax_t) mp->fwheads);
sbuf_printf(sb, "%s<fwsectors>%ju</fwsectors>\n",
indent, (uintmax_t) mp->fwsectors);
sbuf_printf(sb, "%s<length>%ju</length>\n",
indent, (uintmax_t) mp->mediasize);
sbuf_printf(sb, "%s<type>%s</type>\n", indent,
type);
if (mp->type == MD_VNODE && mp->vnode != NULL)
sbuf_printf(sb, "%s<file>%s</file>\n",
indent, mp->file);
}
}
}
static void
g_md_fini(struct g_class *mp __unused)
{