xref: /freebsd/usr.sbin/mpsutil/mpsutil.c (revision 9059c77ef20b0a8371a14be3fd067f77d8de488a)
129b76e53SScott Long /*-
2883bb7e9SScott Long  * Copyright (c) 2015 Netflix, Inc.
3883bb7e9SScott Long  * All rights reserved.
4883bb7e9SScott Long  * Written by: Scott Long <scottl@freebsd.org>
5883bb7e9SScott Long  *
629b76e53SScott Long  * Copyright (c) 2008 Yahoo!, Inc.
729b76e53SScott Long  * All rights reserved.
829b76e53SScott Long  * Written by: John Baldwin <jhb@FreeBSD.org>
929b76e53SScott Long  *
1029b76e53SScott Long  * Redistribution and use in source and binary forms, with or without
1129b76e53SScott Long  * modification, are permitted provided that the following conditions
1229b76e53SScott Long  * are met:
1329b76e53SScott Long  * 1. Redistributions of source code must retain the above copyright
1429b76e53SScott Long  *    notice, this list of conditions and the following disclaimer.
1529b76e53SScott Long  * 2. Redistributions in binary form must reproduce the above copyright
1629b76e53SScott Long  *    notice, this list of conditions and the following disclaimer in the
1729b76e53SScott Long  *    documentation and/or other materials provided with the distribution.
1829b76e53SScott Long  * 3. Neither the name of the author nor the names of any co-contributors
1929b76e53SScott Long  *    may be used to endorse or promote products derived from this software
2029b76e53SScott Long  *    without specific prior written permission.
2129b76e53SScott Long  *
2229b76e53SScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2329b76e53SScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2429b76e53SScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2529b76e53SScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2629b76e53SScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2729b76e53SScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2829b76e53SScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2929b76e53SScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3029b76e53SScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3129b76e53SScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3229b76e53SScott Long  * SUCH DAMAGE.
3329b76e53SScott Long  */
3429b76e53SScott Long 
3529b76e53SScott Long #include <sys/cdefs.h>
3629b76e53SScott Long __RCSID("$FreeBSD$");
3729b76e53SScott Long 
3829b76e53SScott Long #include <sys/param.h>
3929b76e53SScott Long #include <sys/errno.h>
4029b76e53SScott Long #include <err.h>
4129b76e53SScott Long #include <stdio.h>
4229b76e53SScott Long #include <stdlib.h>
4329b76e53SScott Long #include <string.h>
4429b76e53SScott Long #include <unistd.h>
4529b76e53SScott Long #include "mpsutil.h"
4629b76e53SScott Long 
4729b76e53SScott Long SET_DECLARE(MPS_DATASET(top), struct mpsutil_command);
4829b76e53SScott Long SET_DECLARE(MPS_DATASET(usage), struct mpsutil_usage);
4929b76e53SScott Long 
5029b76e53SScott Long int mps_unit;
5148f31f4fSBaptiste Daroussin int is_mps;
5229b76e53SScott Long 
5329b76e53SScott Long static void
5429b76e53SScott Long usage(void)
5529b76e53SScott Long {
5629b76e53SScott Long 	struct mpsutil_usage **cmd;
5729b76e53SScott Long 	const char *args, *desc;
5829b76e53SScott Long 
5948f31f4fSBaptiste Daroussin 	fprintf(stderr, "usage: %s [-u unit] <command> ...\n\n", getprogname());
6029b76e53SScott Long 	fprintf(stderr, "Commands include:\n");
6129b76e53SScott Long 	SET_FOREACH(cmd, MPS_DATASET(usage)) {
62*9059c77eSEitan Adler 		if (*cmd == NULL) {
6329b76e53SScott Long 			fprintf(stderr, "\n");
64*9059c77eSEitan Adler 		}
65*9059c77eSEitan Adler 		else {
6629b76e53SScott Long 			(*cmd)->handler(&args, &desc);
6729b76e53SScott Long 			if (strncmp((*cmd)->set, "top", 3) == 0)
6829b76e53SScott Long 				fprintf(stderr, "%s %-30s\t%s\n",
6929b76e53SScott Long 				    (*cmd)->name, args, desc);
7029b76e53SScott Long 			else
7129b76e53SScott Long 				fprintf(stderr, "%s %s %-30s\t%s\n",
7229b76e53SScott Long 				    (*cmd)->set, (*cmd)->name, args, desc);
7329b76e53SScott Long 		}
74*9059c77eSEitan 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 
9029b76e53SScott Long MPS_COMMAND(top, version, version, "", "version")
9129b76e53SScott Long 
9229b76e53SScott Long int
9329b76e53SScott Long main(int ac, char **av)
9429b76e53SScott Long {
9529b76e53SScott Long 	struct mpsutil_command **cmd;
9629b76e53SScott Long 	int ch;
9729b76e53SScott Long 
9848f31f4fSBaptiste Daroussin 	is_mps = !strcmp(getprogname(), "mpsutil");
9948f31f4fSBaptiste Daroussin 
10029b76e53SScott Long 	while ((ch = getopt(ac, av, "u:h?")) != -1) {
10129b76e53SScott Long 		switch (ch) {
10229b76e53SScott Long 		case 'u':
10329b76e53SScott Long 			mps_unit = atoi(optarg);
10429b76e53SScott Long 			break;
10529b76e53SScott Long 		case 'h':
10629b76e53SScott Long 		case '?':
10729b76e53SScott Long 			usage();
10829b76e53SScott Long 			return (1);
10929b76e53SScott Long 		}
11029b76e53SScott Long 	}
11129b76e53SScott Long 
11229b76e53SScott Long 	av += optind;
11329b76e53SScott Long 	ac -= optind;
11429b76e53SScott Long 
11529b76e53SScott Long 	/* getopt() eats av[0], so we can't use mpt_table_handler() directly. */
11629b76e53SScott Long 	if (ac == 0) {
11729b76e53SScott Long 		usage();
11829b76e53SScott Long 		return (1);
11929b76e53SScott Long 	}
12029b76e53SScott Long 
12129b76e53SScott Long 	SET_FOREACH(cmd, MPS_DATASET(top)) {
12229b76e53SScott Long 		if (strcmp((*cmd)->name, av[0]) == 0) {
12329b76e53SScott Long 			if ((*cmd)->handler(ac, av))
12429b76e53SScott Long 				return (1);
12529b76e53SScott Long 			else
12629b76e53SScott Long 				return (0);
12729b76e53SScott Long 		}
12829b76e53SScott Long 	}
12929b76e53SScott Long 	warnx("Unknown command %s.", av[0]);
13029b76e53SScott Long 	return (1);
13129b76e53SScott Long }
13229b76e53SScott Long 
13329b76e53SScott Long int
13429b76e53SScott Long mps_table_handler(struct mpsutil_command **start, struct mpsutil_command **end,
13529b76e53SScott Long     int ac, char **av)
13629b76e53SScott Long {
13729b76e53SScott Long 	struct mpsutil_command **cmd;
13829b76e53SScott Long 
13929b76e53SScott Long 	if (ac < 2) {
14029b76e53SScott Long 		warnx("The %s command requires a sub-command.", av[0]);
14129b76e53SScott Long 		return (EINVAL);
14229b76e53SScott Long 	}
14329b76e53SScott Long 	for (cmd = start; cmd < end; cmd++) {
14429b76e53SScott Long 		if (strcmp((*cmd)->name, av[1]) == 0)
14529b76e53SScott Long 			return ((*cmd)->handler(ac - 1, av + 1));
14629b76e53SScott Long 	}
14729b76e53SScott Long 
14829b76e53SScott Long 	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
14929b76e53SScott Long 	return (ENOENT);
15029b76e53SScott Long }
15129b76e53SScott Long 
15229b76e53SScott Long void
15329b76e53SScott Long hexdump(const void *ptr, int length, const char *hdr, int flags)
15429b76e53SScott Long {
15529b76e53SScott Long 	int i, j, k;
15629b76e53SScott Long 	int cols;
15729b76e53SScott Long 	const unsigned char *cp;
15829b76e53SScott Long 	char delim;
15929b76e53SScott Long 
16029b76e53SScott Long 	if ((flags & HD_DELIM_MASK) != 0)
16129b76e53SScott Long 		delim = (flags & HD_DELIM_MASK) >> 8;
16229b76e53SScott Long 	else
16329b76e53SScott Long 		delim = ' ';
16429b76e53SScott Long 
16529b76e53SScott Long 	if ((flags & HD_COLUMN_MASK) != 0)
16629b76e53SScott Long 		cols = flags & HD_COLUMN_MASK;
16729b76e53SScott Long 	else
16829b76e53SScott Long 		cols = 16;
16929b76e53SScott Long 
17029b76e53SScott Long 	cp = ptr;
17129b76e53SScott Long 	for (i = 0; i < length; i+= cols) {
17229b76e53SScott Long 		if (hdr != NULL)
17329b76e53SScott Long 			printf("%s", hdr);
17429b76e53SScott Long 
17529b76e53SScott Long 		if ((flags & HD_OMIT_COUNT) == 0)
17629b76e53SScott Long 			printf("%04x  ", i);
17729b76e53SScott Long 
17829b76e53SScott Long 		if ((flags & HD_OMIT_HEX) == 0) {
17929b76e53SScott Long 			for (j = 0; j < cols; j++) {
18029b76e53SScott Long 				if (flags & HD_REVERSED)
18129b76e53SScott Long 					k = i + (cols - 1 - j);
18229b76e53SScott Long 				else
18329b76e53SScott Long 					k = i + j;
18429b76e53SScott Long 				if (k < length)
18529b76e53SScott Long 					printf("%c%02x", delim, cp[k]);
18629b76e53SScott Long 				else
18729b76e53SScott Long 					printf("   ");
18829b76e53SScott Long 			}
18929b76e53SScott Long 		}
19029b76e53SScott Long 
19129b76e53SScott Long 		if ((flags & HD_OMIT_CHARS) == 0) {
19229b76e53SScott Long 			printf("  |");
19329b76e53SScott Long 			for (j = 0; j < cols; j++) {
19429b76e53SScott Long 				if (flags & HD_REVERSED)
19529b76e53SScott Long 					k = i + (cols - 1 - j);
19629b76e53SScott Long 				else
19729b76e53SScott Long 					k = i + j;
19829b76e53SScott Long 				if (k >= length)
19929b76e53SScott Long 					printf(" ");
20029b76e53SScott Long 				else if (cp[k] >= ' ' && cp[k] <= '~')
20129b76e53SScott Long 					printf("%c", cp[k]);
20229b76e53SScott Long 				else
20329b76e53SScott Long 					printf(".");
20429b76e53SScott Long 			}
20529b76e53SScott Long 			printf("|");
20629b76e53SScott Long 		}
20729b76e53SScott Long 		printf("\n");
20829b76e53SScott Long 	}
20929b76e53SScott Long }
210b3995bb8SScott Long 
211b3995bb8SScott Long #define PCHAR(c) { if (retval < tmpsz) { *outbuf++ = (c); retval++; } }
212b3995bb8SScott Long 
213b3995bb8SScott Long int
214b3995bb8SScott Long mps_parse_flags(uintmax_t num, const char *q, char *outbuf, int tmpsz)
215b3995bb8SScott Long {
216b3995bb8SScott Long 	int n, tmp, retval = 0;
217b3995bb8SScott Long 
218b3995bb8SScott Long 	if (num == 0)
219b3995bb8SScott Long 		return (retval);
220b3995bb8SScott Long 
221b3995bb8SScott Long 	/* %b conversion flag format. */
222b3995bb8SScott Long 	tmp = retval;
223b3995bb8SScott Long 	while (*q) {
224b3995bb8SScott Long 		n = *q++;
225b3995bb8SScott Long 		if (num & (1 << (n - 1))) {
226b3995bb8SScott Long 			PCHAR(retval != tmp ?  ',' : '<');
227b3995bb8SScott Long 			for (; (n = *q) > ' '; ++q)
228b3995bb8SScott Long 				PCHAR(n);
229b3995bb8SScott Long 		} else
230b3995bb8SScott Long 			for (; *q > ' '; ++q)
231b3995bb8SScott Long 				continue;
232b3995bb8SScott Long 	}
233b3995bb8SScott Long 	if (retval != tmp)
234b3995bb8SScott Long 		PCHAR('>');
235b3995bb8SScott Long 
236b3995bb8SScott Long 	return (retval);
237b3995bb8SScott Long }
238b3995bb8SScott Long 
239