xref: /freebsd/usr.sbin/mpsutil/mpsutil.c (revision 638e2a132e38b51b385b2731822294c73621aea9)
129b76e53SScott Long /*-
2883bb7e9SScott Long  * Copyright (c) 2015 Netflix, Inc.
3883bb7e9SScott Long  * Written by: Scott Long <scottl@freebsd.org>
4883bb7e9SScott Long  *
529b76e53SScott Long  * Copyright (c) 2008 Yahoo!, Inc.
629b76e53SScott Long  * All rights reserved.
729b76e53SScott Long  * Written by: John Baldwin <jhb@FreeBSD.org>
829b76e53SScott Long  *
929b76e53SScott Long  * Redistribution and use in source and binary forms, with or without
1029b76e53SScott Long  * modification, are permitted provided that the following conditions
1129b76e53SScott Long  * are met:
1229b76e53SScott Long  * 1. Redistributions of source code must retain the above copyright
1329b76e53SScott Long  *    notice, this list of conditions and the following disclaimer.
1429b76e53SScott Long  * 2. Redistributions in binary form must reproduce the above copyright
1529b76e53SScott Long  *    notice, this list of conditions and the following disclaimer in the
1629b76e53SScott Long  *    documentation and/or other materials provided with the distribution.
1729b76e53SScott Long  * 3. Neither the name of the author nor the names of any co-contributors
1829b76e53SScott Long  *    may be used to endorse or promote products derived from this software
1929b76e53SScott Long  *    without specific prior written permission.
2029b76e53SScott Long  *
2129b76e53SScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2229b76e53SScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329b76e53SScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429b76e53SScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2529b76e53SScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629b76e53SScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729b76e53SScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829b76e53SScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929b76e53SScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029b76e53SScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129b76e53SScott Long  * SUCH DAMAGE.
3229b76e53SScott Long  */
3329b76e53SScott Long 
3429b76e53SScott Long #include <sys/cdefs.h>
3529b76e53SScott Long __RCSID("$FreeBSD$");
3629b76e53SScott Long 
3729b76e53SScott Long #include <sys/param.h>
3829b76e53SScott Long #include <sys/errno.h>
3929b76e53SScott Long #include <err.h>
40e9de7669SJuli Mallett #include <inttypes.h>
41e9de7669SJuli Mallett #include <paths.h>
4229b76e53SScott Long #include <stdio.h>
4329b76e53SScott Long #include <stdlib.h>
4429b76e53SScott Long #include <string.h>
4529b76e53SScott Long #include <unistd.h>
4629b76e53SScott Long #include "mpsutil.h"
4729b76e53SScott Long 
4829b76e53SScott Long SET_DECLARE(MPS_DATASET(top), struct mpsutil_command);
4929b76e53SScott Long SET_DECLARE(MPS_DATASET(usage), struct mpsutil_usage);
5029b76e53SScott Long 
5129b76e53SScott Long int mps_unit;
5248f31f4fSBaptiste Daroussin int is_mps;
5329b76e53SScott Long 
5429b76e53SScott Long static void
5529b76e53SScott Long usage(void)
5629b76e53SScott Long {
5729b76e53SScott Long 	struct mpsutil_usage **cmd;
5829b76e53SScott Long 	const char *args, *desc;
5929b76e53SScott Long 
6048f31f4fSBaptiste Daroussin 	fprintf(stderr, "usage: %s [-u unit] <command> ...\n\n", getprogname());
6129b76e53SScott Long 	fprintf(stderr, "Commands include:\n");
6229b76e53SScott Long 	SET_FOREACH(cmd, MPS_DATASET(usage)) {
639059c77eSEitan Adler 		if (*cmd == NULL) {
6429b76e53SScott Long 			fprintf(stderr, "\n");
65c739854cSEitan Adler 		} else {
6629b76e53SScott Long 			(*cmd)->handler(&args, &desc);
6729b76e53SScott Long 			if (strncmp((*cmd)->set, "top", 3) == 0)
68*638e2a13SScott Long 				fprintf(stderr, "%-16s %-28s%s\n",
6929b76e53SScott Long 				    (*cmd)->name, args, desc);
7029b76e53SScott Long 			else
71*638e2a13SScott Long 				fprintf(stderr, "%-5s %-10s %-28s%s\n",
7229b76e53SScott Long 				    (*cmd)->set, (*cmd)->name, args, desc);
7329b76e53SScott Long 		}
749059c77eSEitan Adler 	}
7529b76e53SScott Long 	exit(1);
7629b76e53SScott Long }
7729b76e53SScott Long 
7829b76e53SScott Long static int
7929b76e53SScott Long version(int ac, char **av)
8029b76e53SScott Long {
8129b76e53SScott Long 
8248f31f4fSBaptiste Daroussin 	printf("%s: version %s", MPSUTIL_VERSION, getprogname());
8329b76e53SScott Long #ifdef DEBUG
8429b76e53SScott Long 	printf(" (DEBUG)");
8529b76e53SScott Long #endif
8629b76e53SScott Long 	printf("\n");
8729b76e53SScott Long 	return (0);
8829b76e53SScott Long }
8929b76e53SScott Long 
90*638e2a13SScott Long MPS_COMMAND(top, version, version, "", "Version number")
9129b76e53SScott Long 
9229b76e53SScott Long int
9329b76e53SScott Long main(int ac, char **av)
9429b76e53SScott Long {
9529b76e53SScott Long 	struct mpsutil_command **cmd;
96e9de7669SJuli Mallett 	uintmax_t unit;
97e9de7669SJuli Mallett 	char *end;
9829b76e53SScott Long 	int ch;
9929b76e53SScott Long 
10048f31f4fSBaptiste Daroussin 	is_mps = !strcmp(getprogname(), "mpsutil");
10148f31f4fSBaptiste Daroussin 
10229b76e53SScott Long 	while ((ch = getopt(ac, av, "u:h?")) != -1) {
10329b76e53SScott Long 		switch (ch) {
10429b76e53SScott Long 		case 'u':
105e9de7669SJuli Mallett 			if (strncmp(optarg, _PATH_DEV, strlen(_PATH_DEV)) == 0) {
106e9de7669SJuli Mallett 				optarg += strlen(_PATH_DEV);
107e9de7669SJuli Mallett 				if (strncmp(optarg, is_mps ? "mps" : "mpr", 3) != 0)
108e9de7669SJuli Mallett 					errx(1, "Invalid device: %s", optarg);
109e9de7669SJuli Mallett 			}
110e9de7669SJuli Mallett 			if (strncmp(optarg, is_mps ? "mps" : "mpr", 3) == 0)
111e9de7669SJuli Mallett 				optarg += 3;
112e9de7669SJuli Mallett 			unit = strtoumax(optarg, &end, 10);
113e9de7669SJuli Mallett 			if (*end != '\0' || unit == UINTMAX_MAX || unit > INT_MAX)
114e9de7669SJuli Mallett 				errx(1, "Invalid unit: %s", optarg);
115e9de7669SJuli Mallett 			mps_unit = unit;
11629b76e53SScott Long 			break;
11729b76e53SScott Long 		case 'h':
11829b76e53SScott Long 		case '?':
11929b76e53SScott Long 			usage();
12029b76e53SScott Long 			return (1);
12129b76e53SScott Long 		}
12229b76e53SScott Long 	}
12329b76e53SScott Long 
12429b76e53SScott Long 	av += optind;
12529b76e53SScott Long 	ac -= optind;
12629b76e53SScott Long 
12729b76e53SScott Long 	/* getopt() eats av[0], so we can't use mpt_table_handler() directly. */
12829b76e53SScott Long 	if (ac == 0) {
12929b76e53SScott Long 		usage();
13029b76e53SScott Long 		return (1);
13129b76e53SScott Long 	}
13229b76e53SScott Long 
13329b76e53SScott Long 	SET_FOREACH(cmd, MPS_DATASET(top)) {
13429b76e53SScott Long 		if (strcmp((*cmd)->name, av[0]) == 0) {
13529b76e53SScott Long 			if ((*cmd)->handler(ac, av))
13629b76e53SScott Long 				return (1);
13729b76e53SScott Long 			else
13829b76e53SScott Long 				return (0);
13929b76e53SScott Long 		}
14029b76e53SScott Long 	}
14129b76e53SScott Long 	warnx("Unknown command %s.", av[0]);
14229b76e53SScott Long 	return (1);
14329b76e53SScott Long }
14429b76e53SScott Long 
14529b76e53SScott Long int
14629b76e53SScott Long mps_table_handler(struct mpsutil_command **start, struct mpsutil_command **end,
14729b76e53SScott Long     int ac, char **av)
14829b76e53SScott Long {
14929b76e53SScott Long 	struct mpsutil_command **cmd;
15029b76e53SScott Long 
15129b76e53SScott Long 	if (ac < 2) {
15229b76e53SScott Long 		warnx("The %s command requires a sub-command.", av[0]);
15329b76e53SScott Long 		return (EINVAL);
15429b76e53SScott Long 	}
15529b76e53SScott Long 	for (cmd = start; cmd < end; cmd++) {
15629b76e53SScott Long 		if (strcmp((*cmd)->name, av[1]) == 0)
15729b76e53SScott Long 			return ((*cmd)->handler(ac - 1, av + 1));
15829b76e53SScott Long 	}
15929b76e53SScott Long 
16029b76e53SScott Long 	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
16129b76e53SScott Long 	return (ENOENT);
16229b76e53SScott Long }
16329b76e53SScott Long 
16429b76e53SScott Long void
16529b76e53SScott Long hexdump(const void *ptr, int length, const char *hdr, int flags)
16629b76e53SScott Long {
16729b76e53SScott Long 	int i, j, k;
16829b76e53SScott Long 	int cols;
16929b76e53SScott Long 	const unsigned char *cp;
17029b76e53SScott Long 	char delim;
17129b76e53SScott Long 
17229b76e53SScott Long 	if ((flags & HD_DELIM_MASK) != 0)
17329b76e53SScott Long 		delim = (flags & HD_DELIM_MASK) >> 8;
17429b76e53SScott Long 	else
17529b76e53SScott Long 		delim = ' ';
17629b76e53SScott Long 
17729b76e53SScott Long 	if ((flags & HD_COLUMN_MASK) != 0)
17829b76e53SScott Long 		cols = flags & HD_COLUMN_MASK;
17929b76e53SScott Long 	else
18029b76e53SScott Long 		cols = 16;
18129b76e53SScott Long 
18229b76e53SScott Long 	cp = ptr;
18329b76e53SScott Long 	for (i = 0; i < length; i+= cols) {
18429b76e53SScott Long 		if (hdr != NULL)
18529b76e53SScott Long 			printf("%s", hdr);
18629b76e53SScott Long 
18729b76e53SScott Long 		if ((flags & HD_OMIT_COUNT) == 0)
18829b76e53SScott Long 			printf("%04x  ", i);
18929b76e53SScott Long 
19029b76e53SScott Long 		if ((flags & HD_OMIT_HEX) == 0) {
19129b76e53SScott Long 			for (j = 0; j < cols; j++) {
19229b76e53SScott Long 				if (flags & HD_REVERSED)
19329b76e53SScott Long 					k = i + (cols - 1 - j);
19429b76e53SScott Long 				else
19529b76e53SScott Long 					k = i + j;
19629b76e53SScott Long 				if (k < length)
19729b76e53SScott Long 					printf("%c%02x", delim, cp[k]);
19829b76e53SScott Long 				else
19929b76e53SScott Long 					printf("   ");
20029b76e53SScott Long 			}
20129b76e53SScott Long 		}
20229b76e53SScott Long 
20329b76e53SScott Long 		if ((flags & HD_OMIT_CHARS) == 0) {
20429b76e53SScott Long 			printf("  |");
20529b76e53SScott Long 			for (j = 0; j < cols; j++) {
20629b76e53SScott Long 				if (flags & HD_REVERSED)
20729b76e53SScott Long 					k = i + (cols - 1 - j);
20829b76e53SScott Long 				else
20929b76e53SScott Long 					k = i + j;
21029b76e53SScott Long 				if (k >= length)
21129b76e53SScott Long 					printf(" ");
21229b76e53SScott Long 				else if (cp[k] >= ' ' && cp[k] <= '~')
21329b76e53SScott Long 					printf("%c", cp[k]);
21429b76e53SScott Long 				else
21529b76e53SScott Long 					printf(".");
21629b76e53SScott Long 			}
21729b76e53SScott Long 			printf("|");
21829b76e53SScott Long 		}
21929b76e53SScott Long 		printf("\n");
22029b76e53SScott Long 	}
22129b76e53SScott Long }
222b3995bb8SScott Long 
223b3995bb8SScott Long #define PCHAR(c) { if (retval < tmpsz) { *outbuf++ = (c); retval++; } }
224b3995bb8SScott Long 
225b3995bb8SScott Long int
226b3995bb8SScott Long mps_parse_flags(uintmax_t num, const char *q, char *outbuf, int tmpsz)
227b3995bb8SScott Long {
228b3995bb8SScott Long 	int n, tmp, retval = 0;
229b3995bb8SScott Long 
230b3995bb8SScott Long 	if (num == 0)
231b3995bb8SScott Long 		return (retval);
232b3995bb8SScott Long 
233b3995bb8SScott Long 	/* %b conversion flag format. */
234b3995bb8SScott Long 	tmp = retval;
235b3995bb8SScott Long 	while (*q) {
236b3995bb8SScott Long 		n = *q++;
237b3995bb8SScott Long 		if (num & (1 << (n - 1))) {
238b3995bb8SScott Long 			PCHAR(retval != tmp ?  ',' : '<');
239b3995bb8SScott Long 			for (; (n = *q) > ' '; ++q)
240b3995bb8SScott Long 				PCHAR(n);
241b3995bb8SScott Long 		} else
242b3995bb8SScott Long 			for (; *q > ' '; ++q)
243b3995bb8SScott Long 				continue;
244b3995bb8SScott Long 	}
245b3995bb8SScott Long 	if (retval != tmp)
246b3995bb8SScott Long 		PCHAR('>');
247b3995bb8SScott Long 
248b3995bb8SScott Long 	return (retval);
249b3995bb8SScott Long }
250b3995bb8SScott Long 
251