xref: /freebsd/usr.sbin/mpsutil/mpsutil.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
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/param.h>
3529b76e53SScott Long #include <sys/errno.h>
3629b76e53SScott Long #include <err.h>
37e9de7669SJuli Mallett #include <inttypes.h>
38e9de7669SJuli Mallett #include <paths.h>
3929b76e53SScott Long #include <stdio.h>
4029b76e53SScott Long #include <stdlib.h>
4129b76e53SScott Long #include <string.h>
4229b76e53SScott Long #include <unistd.h>
4329b76e53SScott Long #include "mpsutil.h"
4429b76e53SScott Long 
4529b76e53SScott Long SET_DECLARE(MPS_DATASET(top), struct mpsutil_command);
4629b76e53SScott Long SET_DECLARE(MPS_DATASET(usage), struct mpsutil_usage);
4729b76e53SScott Long 
4829b76e53SScott Long int mps_unit;
4948f31f4fSBaptiste Daroussin int is_mps;
5029b76e53SScott Long 
5129b76e53SScott Long static void
usage(void)5229b76e53SScott Long usage(void)
5329b76e53SScott Long {
5429b76e53SScott Long 	struct mpsutil_usage **cmd;
5529b76e53SScott Long 	const char *args, *desc;
5629b76e53SScott Long 
5748f31f4fSBaptiste Daroussin 	fprintf(stderr, "usage: %s [-u unit] <command> ...\n\n", getprogname());
5829b76e53SScott Long 	fprintf(stderr, "Commands include:\n");
5929b76e53SScott Long 	SET_FOREACH(cmd, MPS_DATASET(usage)) {
609059c77eSEitan Adler 		if (*cmd == NULL) {
6129b76e53SScott Long 			fprintf(stderr, "\n");
62c739854cSEitan Adler 		} else {
6329b76e53SScott Long 			(*cmd)->handler(&args, &desc);
6429b76e53SScott Long 			if (strncmp((*cmd)->set, "top", 3) == 0)
65*638e2a13SScott Long 				fprintf(stderr, "%-16s %-28s%s\n",
6629b76e53SScott Long 				    (*cmd)->name, args, desc);
6729b76e53SScott Long 			else
68*638e2a13SScott Long 				fprintf(stderr, "%-5s %-10s %-28s%s\n",
6929b76e53SScott Long 				    (*cmd)->set, (*cmd)->name, args, desc);
7029b76e53SScott Long 		}
719059c77eSEitan Adler 	}
7229b76e53SScott Long 	exit(1);
7329b76e53SScott Long }
7429b76e53SScott Long 
7529b76e53SScott Long static int
version(int ac,char ** av)7629b76e53SScott Long version(int ac, char **av)
7729b76e53SScott Long {
7829b76e53SScott Long 
7948f31f4fSBaptiste Daroussin 	printf("%s: version %s", MPSUTIL_VERSION, getprogname());
8029b76e53SScott Long #ifdef DEBUG
8129b76e53SScott Long 	printf(" (DEBUG)");
8229b76e53SScott Long #endif
8329b76e53SScott Long 	printf("\n");
8429b76e53SScott Long 	return (0);
8529b76e53SScott Long }
8629b76e53SScott Long 
87*638e2a13SScott Long MPS_COMMAND(top, version, version, "", "Version number")
8829b76e53SScott Long 
8929b76e53SScott Long int
main(int ac,char ** av)9029b76e53SScott Long main(int ac, char **av)
9129b76e53SScott Long {
9229b76e53SScott Long 	struct mpsutil_command **cmd;
93e9de7669SJuli Mallett 	uintmax_t unit;
94e9de7669SJuli Mallett 	char *end;
9529b76e53SScott Long 	int ch;
9629b76e53SScott Long 
9748f31f4fSBaptiste Daroussin 	is_mps = !strcmp(getprogname(), "mpsutil");
9848f31f4fSBaptiste Daroussin 
9929b76e53SScott Long 	while ((ch = getopt(ac, av, "u:h?")) != -1) {
10029b76e53SScott Long 		switch (ch) {
10129b76e53SScott Long 		case 'u':
102e9de7669SJuli Mallett 			if (strncmp(optarg, _PATH_DEV, strlen(_PATH_DEV)) == 0) {
103e9de7669SJuli Mallett 				optarg += strlen(_PATH_DEV);
104e9de7669SJuli Mallett 				if (strncmp(optarg, is_mps ? "mps" : "mpr", 3) != 0)
105e9de7669SJuli Mallett 					errx(1, "Invalid device: %s", optarg);
106e9de7669SJuli Mallett 			}
107e9de7669SJuli Mallett 			if (strncmp(optarg, is_mps ? "mps" : "mpr", 3) == 0)
108e9de7669SJuli Mallett 				optarg += 3;
109e9de7669SJuli Mallett 			unit = strtoumax(optarg, &end, 10);
110e9de7669SJuli Mallett 			if (*end != '\0' || unit == UINTMAX_MAX || unit > INT_MAX)
111e9de7669SJuli Mallett 				errx(1, "Invalid unit: %s", optarg);
112e9de7669SJuli Mallett 			mps_unit = unit;
11329b76e53SScott Long 			break;
11429b76e53SScott Long 		case 'h':
11529b76e53SScott Long 		case '?':
11629b76e53SScott Long 			usage();
11729b76e53SScott Long 			return (1);
11829b76e53SScott Long 		}
11929b76e53SScott Long 	}
12029b76e53SScott Long 
12129b76e53SScott Long 	av += optind;
12229b76e53SScott Long 	ac -= optind;
12329b76e53SScott Long 
12429b76e53SScott Long 	/* getopt() eats av[0], so we can't use mpt_table_handler() directly. */
12529b76e53SScott Long 	if (ac == 0) {
12629b76e53SScott Long 		usage();
12729b76e53SScott Long 		return (1);
12829b76e53SScott Long 	}
12929b76e53SScott Long 
13029b76e53SScott Long 	SET_FOREACH(cmd, MPS_DATASET(top)) {
13129b76e53SScott Long 		if (strcmp((*cmd)->name, av[0]) == 0) {
13229b76e53SScott Long 			if ((*cmd)->handler(ac, av))
13329b76e53SScott Long 				return (1);
13429b76e53SScott Long 			else
13529b76e53SScott Long 				return (0);
13629b76e53SScott Long 		}
13729b76e53SScott Long 	}
13829b76e53SScott Long 	warnx("Unknown command %s.", av[0]);
13929b76e53SScott Long 	return (1);
14029b76e53SScott Long }
14129b76e53SScott Long 
14229b76e53SScott Long int
mps_table_handler(struct mpsutil_command ** start,struct mpsutil_command ** end,int ac,char ** av)14329b76e53SScott Long mps_table_handler(struct mpsutil_command **start, struct mpsutil_command **end,
14429b76e53SScott Long     int ac, char **av)
14529b76e53SScott Long {
14629b76e53SScott Long 	struct mpsutil_command **cmd;
14729b76e53SScott Long 
14829b76e53SScott Long 	if (ac < 2) {
14929b76e53SScott Long 		warnx("The %s command requires a sub-command.", av[0]);
15029b76e53SScott Long 		return (EINVAL);
15129b76e53SScott Long 	}
15229b76e53SScott Long 	for (cmd = start; cmd < end; cmd++) {
15329b76e53SScott Long 		if (strcmp((*cmd)->name, av[1]) == 0)
15429b76e53SScott Long 			return ((*cmd)->handler(ac - 1, av + 1));
15529b76e53SScott Long 	}
15629b76e53SScott Long 
15729b76e53SScott Long 	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
15829b76e53SScott Long 	return (ENOENT);
15929b76e53SScott Long }
16029b76e53SScott Long 
16129b76e53SScott Long void
hexdump(const void * ptr,int length,const char * hdr,int flags)16229b76e53SScott Long hexdump(const void *ptr, int length, const char *hdr, int flags)
16329b76e53SScott Long {
16429b76e53SScott Long 	int i, j, k;
16529b76e53SScott Long 	int cols;
16629b76e53SScott Long 	const unsigned char *cp;
16729b76e53SScott Long 	char delim;
16829b76e53SScott Long 
16929b76e53SScott Long 	if ((flags & HD_DELIM_MASK) != 0)
17029b76e53SScott Long 		delim = (flags & HD_DELIM_MASK) >> 8;
17129b76e53SScott Long 	else
17229b76e53SScott Long 		delim = ' ';
17329b76e53SScott Long 
17429b76e53SScott Long 	if ((flags & HD_COLUMN_MASK) != 0)
17529b76e53SScott Long 		cols = flags & HD_COLUMN_MASK;
17629b76e53SScott Long 	else
17729b76e53SScott Long 		cols = 16;
17829b76e53SScott Long 
17929b76e53SScott Long 	cp = ptr;
18029b76e53SScott Long 	for (i = 0; i < length; i+= cols) {
18129b76e53SScott Long 		if (hdr != NULL)
18229b76e53SScott Long 			printf("%s", hdr);
18329b76e53SScott Long 
18429b76e53SScott Long 		if ((flags & HD_OMIT_COUNT) == 0)
18529b76e53SScott Long 			printf("%04x  ", i);
18629b76e53SScott Long 
18729b76e53SScott Long 		if ((flags & HD_OMIT_HEX) == 0) {
18829b76e53SScott Long 			for (j = 0; j < cols; j++) {
18929b76e53SScott Long 				if (flags & HD_REVERSED)
19029b76e53SScott Long 					k = i + (cols - 1 - j);
19129b76e53SScott Long 				else
19229b76e53SScott Long 					k = i + j;
19329b76e53SScott Long 				if (k < length)
19429b76e53SScott Long 					printf("%c%02x", delim, cp[k]);
19529b76e53SScott Long 				else
19629b76e53SScott Long 					printf("   ");
19729b76e53SScott Long 			}
19829b76e53SScott Long 		}
19929b76e53SScott Long 
20029b76e53SScott Long 		if ((flags & HD_OMIT_CHARS) == 0) {
20129b76e53SScott Long 			printf("  |");
20229b76e53SScott Long 			for (j = 0; j < cols; j++) {
20329b76e53SScott Long 				if (flags & HD_REVERSED)
20429b76e53SScott Long 					k = i + (cols - 1 - j);
20529b76e53SScott Long 				else
20629b76e53SScott Long 					k = i + j;
20729b76e53SScott Long 				if (k >= length)
20829b76e53SScott Long 					printf(" ");
20929b76e53SScott Long 				else if (cp[k] >= ' ' && cp[k] <= '~')
21029b76e53SScott Long 					printf("%c", cp[k]);
21129b76e53SScott Long 				else
21229b76e53SScott Long 					printf(".");
21329b76e53SScott Long 			}
21429b76e53SScott Long 			printf("|");
21529b76e53SScott Long 		}
21629b76e53SScott Long 		printf("\n");
21729b76e53SScott Long 	}
21829b76e53SScott Long }
219b3995bb8SScott Long 
220b3995bb8SScott Long #define PCHAR(c) { if (retval < tmpsz) { *outbuf++ = (c); retval++; } }
221b3995bb8SScott Long 
222b3995bb8SScott Long int
mps_parse_flags(uintmax_t num,const char * q,char * outbuf,int tmpsz)223b3995bb8SScott Long mps_parse_flags(uintmax_t num, const char *q, char *outbuf, int tmpsz)
224b3995bb8SScott Long {
225b3995bb8SScott Long 	int n, tmp, retval = 0;
226b3995bb8SScott Long 
227b3995bb8SScott Long 	if (num == 0)
228b3995bb8SScott Long 		return (retval);
229b3995bb8SScott Long 
230b3995bb8SScott Long 	/* %b conversion flag format. */
231b3995bb8SScott Long 	tmp = retval;
232b3995bb8SScott Long 	while (*q) {
233b3995bb8SScott Long 		n = *q++;
234b3995bb8SScott Long 		if (num & (1 << (n - 1))) {
235b3995bb8SScott Long 			PCHAR(retval != tmp ?  ',' : '<');
236b3995bb8SScott Long 			for (; (n = *q) > ' '; ++q)
237b3995bb8SScott Long 				PCHAR(n);
238b3995bb8SScott Long 		} else
239b3995bb8SScott Long 			for (; *q > ' '; ++q)
240b3995bb8SScott Long 				continue;
241b3995bb8SScott Long 	}
242b3995bb8SScott Long 	if (retval != tmp)
243b3995bb8SScott Long 		PCHAR('>');
244b3995bb8SScott Long 
245b3995bb8SScott Long 	return (retval);
246b3995bb8SScott Long }
247b3995bb8SScott Long 
248