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