1/*	$NetBSD: main.c,v 1.13 2011/06/03 16:35:35 pgoyette Exp $	*/
2
3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30#ifndef lint
31__RCSID("$NetBSD: main.c,v 1.13 2011/06/03 16:35:35 pgoyette Exp $");
32#endif /* !lint */
33
34#include <sys/module.h>
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <err.h>
41
42#include "prog_ops.h"
43
44int	main(int, char **);
45static void	usage(void) __dead;
46static int	modstatcmp(const void *, const void *);
47
48static const char *classes[] = {
49	"any",
50	"misc",
51	"vfs",
52	"driver",
53	"exec",
54	"secmodel",
55};
56const unsigned int class_max = __arraycount(classes);
57
58static const char *sources[] = {
59	"builtin",
60	"boot",
61	"filesys",
62};
63const unsigned int source_max = __arraycount(sources);
64
65int
66main(int argc, char **argv)
67{
68	struct iovec iov;
69	modstat_t *ms;
70	size_t len;
71	const char *name;
72	char sbuf[32];
73	int ch;
74	size_t maxnamelen = 16, i;
75
76	name = NULL;
77
78	while ((ch = getopt(argc, argv, "n:")) != -1) {
79		switch (ch) {
80		case 'n':
81			name = optarg;
82			break;
83		default:
84			usage();
85			/* NOTREACHED */
86		}
87	}
88
89	argc -= optind;
90	argv += optind;
91	if (argc == 1 && name == NULL)
92		name = argv[0];
93	else if (argc != 0)
94		usage();
95
96	if (prog_init && prog_init() == -1)
97		err(1, "prog init failed");
98
99	for (len = 8192;;) {
100		iov.iov_base = malloc(len);
101		iov.iov_len = len;
102		if (prog_modctl(MODCTL_STAT, &iov)) {
103			err(EXIT_FAILURE, "modctl(MODCTL_STAT)");
104		}
105		if (len >= iov.iov_len) {
106			break;
107		}
108		free(iov.iov_base);
109		len = iov.iov_len;
110	}
111
112	len = iov.iov_len / sizeof(modstat_t);
113	qsort(iov.iov_base, len, sizeof(modstat_t), modstatcmp);
114	for (i = 0, ms = iov.iov_base; i < len; i++, ms++) {
115		size_t namelen = strlen(ms->ms_name);
116		if (maxnamelen < namelen)
117			maxnamelen = namelen;
118	}
119	printf("%-*s %-10s %-10s %-5s %-8s %s\n",
120	    (int)maxnamelen, "NAME", "CLASS", "SOURCE", "REFS", "SIZE",
121	    "REQUIRES");
122	for (ms = iov.iov_base; len != 0; ms++, len--) {
123		const char *class;
124		const char *source;
125
126		if (name != NULL && strcmp(ms->ms_name, name) != 0) {
127			continue;
128		}
129		if (ms->ms_required[0] == '\0') {
130			ms->ms_required[0] = '-';
131			ms->ms_required[1] = '\0';
132		}
133		if (ms->ms_size == 0) {
134			sbuf[0] = '-';
135			sbuf[1] = '\0';
136		} else {
137			snprintf(sbuf, sizeof(sbuf), "%u", ms->ms_size);
138		}
139		if (ms->ms_class <= class_max)
140			class = classes[ms->ms_class];
141		else
142			class = "UNKNOWN";
143		if (ms->ms_source < source_max)
144			source = sources[ms->ms_source];
145		else
146			source = "UNKNOWN";
147
148		printf("%-*s %-10s %-10s %-5d %-8s %s\n",
149		    (int)maxnamelen, ms->ms_name, class, source, ms->ms_refcnt,
150		    sbuf, ms->ms_required);
151	}
152
153	exit(EXIT_SUCCESS);
154}
155
156static void
157usage(void)
158{
159
160	(void)fprintf(stderr, "Usage: %s [-n] [name]\n", getprogname());
161	exit(EXIT_FAILURE);
162}
163
164static int
165modstatcmp(const void *a, const void *b)
166{
167	const modstat_t *msa, *msb;
168
169	msa = a;
170	msb = b;
171
172	return strcmp(msa->ms_name, msb->ms_name);
173}
174