dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / ipdadm / ipdadm.c
blob4f222be9b08886800763f7f7fc685f1493ffe5a4
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
14 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
15 * Use is subject to license terms.
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <values.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stropts.h>
29 #include <zone.h>
30 #include <libgen.h>
31 #include <assert.h>
33 #include <libipd.h>
35 static char *g_pname;
36 static char g_zonename[ZONENAME_MAX];
37 static zoneid_t g_zid;
39 #define E_SUCCESS 0
40 #define E_ERROR 1
41 #define E_USAGE 2
43 typedef int (*idc_cmd_func_t)(int, char *[]);
44 typedef struct ipdadm_cmd {
45 const char *idc_name; /* subcommand name */
46 idc_cmd_func_t idc_func; /* subcommand function */
47 const char *idc_usage; /* subcommand help */
48 } ipdadm_cmd_t;
50 static int ipdadm_list(int, char *[]);
51 static int ipdadm_info(int, char *[]);
52 static int ipdadm_corrupt(int, char *[]);
53 static int ipdadm_delay(int, char *[]);
54 static int ipdadm_drop(int, char *[]);
55 static int ipdadm_remove(int, char *[]);
57 #define IPDADM_NCMDS 6
58 static ipdadm_cmd_t ipdadm_cmds[] = {
59 { "list", ipdadm_list, "list [-v]" },
60 { "info", ipdadm_info, "info" },
61 { "corrupt", ipdadm_corrupt, "corrupt <percentage>" },
62 { "delay", ipdadm_delay, "delay <microseconds>" },
63 { "drop", ipdadm_drop, "drop <percentage>" },
64 { "remove", ipdadm_remove, "remove [corrupt|delay|drop]" }
67 static int
68 usage(FILE *fp)
70 int ii;
71 ipdadm_cmd_t *cmd;
73 (void) fprintf(fp, "Usage: %s [-z zonename] subcommand "
74 "[subcommand opts]\n\n", g_pname);
75 (void) fprintf(fp, "Subcommands:\n");
76 for (ii = 0; ii < IPDADM_NCMDS; ii++) {
77 cmd = &ipdadm_cmds[ii];
78 (void) fprintf(fp, "\t%s\n", cmd->idc_usage);
81 return (E_USAGE);
84 static void
85 ipdadm_list_one(zoneid_t z, const ipd_config_t *icp, void *arg)
87 char zonename[ZONENAME_MAX];
88 int opt_v = (int)(intptr_t)arg;
90 if (getzonenamebyid(z, zonename, sizeof (zonename)) < 0)
91 (void) printf("%ld", z);
92 else
93 (void) printf("%s", zonename);
95 if (!opt_v) {
96 (void) printf("\n");
97 return;
100 (void) printf("\t%u\t%u\t%u\n", icp->ic_corrupt, icp->ic_drop,
101 icp->ic_delay);
104 static int
105 ipdadm_list(int argc, char *argv[])
107 int opt_v = 0;
108 int fd, rval;
109 ipd_stathdl_t hdl;
111 if (argc > 1)
112 return (usage(stderr));
114 if (argc == 1) {
115 if (strcmp(argv[0], "-v") == 0)
116 ++opt_v;
117 else
118 return (usage(stderr));
121 fd = ipd_open(NULL);
122 if (fd < 0) {
123 (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n",
124 g_pname, ipd_errmsg);
125 return (E_ERROR);
127 rval = ipd_status_read(fd, &hdl);
128 (void) ipd_close(fd);
130 if (rval != 0) {
131 (void) fprintf(stderr, "%s: failed to get list info: %s\n",
132 g_pname, ipd_errmsg);
133 return (E_ERROR);
136 ipd_status_foreach_zone(hdl, ipdadm_list_one, (void *)(intptr_t)opt_v);
137 ipd_status_free(hdl);
139 return (E_SUCCESS);
142 /*ARGSUSED*/
143 static int
144 ipdadm_info(int argc, char *argv[])
146 int rval, fd;
147 ipd_stathdl_t hdl;
148 ipd_config_t *icp;
150 if (argc != 0)
151 return (usage(stderr));
153 fd = ipd_open(NULL);
154 if (fd < 0) {
155 (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n",
156 g_pname, ipd_errmsg);
157 return (E_ERROR);
159 rval = ipd_status_read(fd, &hdl);
160 (void) ipd_close(fd);
161 if (rval != 0) {
162 (void) fprintf(stderr, "%s: failed to get info: %s\n",
163 g_pname, ipd_errmsg);
164 return (E_ERROR);
167 if (ipd_status_get_config(hdl, g_zid, &icp) != 0) {
168 if (ipd_errno == EIPD_ZC_NOENT) {
169 (void) printf("zone %s does not exist or has no "
170 "ipd actions enabled\n", g_zonename);
171 return (E_SUCCESS);
173 (void) fprintf(stderr, "%s: failed to get info: %s\n",
174 g_pname, ipd_errmsg);
175 return (E_ERROR);
178 (void) printf("ipd information for zone %s:\n",
179 g_zonename);
180 (void) printf("\tcorrupt:\t%u%% chance of packet corruption\n",
181 icp->ic_corrupt);
182 (void) printf("\tdrop:\t\t%u%% chance of packet drop\n",
183 icp->ic_drop);
184 (void) printf("\tdelay:\t\t%u microsecond delay per packet\n",
185 icp->ic_delay);
187 ipd_status_free(hdl);
189 return (E_SUCCESS);
192 static long
193 ipdadm_parse_long(const char *str, const char *name, long min, long max)
195 long val;
196 char *end;
198 errno = 0;
199 val = strtol(str, &end, 10);
200 if (errno != 0) {
201 (void) fprintf(stderr, "%s: invalid value for %s: %s\n",
202 g_pname, name, str);
203 exit(E_ERROR);
207 * We want to make sure that we got the whole string. If not that's an
208 * error. e.g. 23.42 should not be valid.
210 if (*end != '\0') {
211 (void) fprintf(stderr, "%s: %s value must be an integer\n",
212 g_pname, name);
213 exit(E_ERROR);
216 if (val < min || val > max) {
217 (void) fprintf(stderr, "%s: %s value must be between %ld and "
218 "%ld inclusive\n", g_pname, name, min, max);
219 exit(E_ERROR);
222 return (val);
225 static int
226 ipdadm_corrupt(int argc, char *argv[])
228 int rval, fd;
229 long val;
230 ipd_config_t ic;
232 if (argc != 1) {
233 (void) fprintf(stderr, "%s: corrupt <percentage>\n",
234 g_pname);
235 return (usage(stderr));
238 val = ipdadm_parse_long(argv[0], "corrupt", 0, 100);
239 bzero(&ic, sizeof (ic));
240 ic.ic_mask = IPDM_CORRUPT;
241 ic.ic_corrupt = val;
243 fd = ipd_open(NULL);
244 if (fd < 0) {
245 (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n",
246 g_pname, ipd_errmsg);
247 return (E_ERROR);
249 rval = ipd_ctl(fd, g_zid, &ic);
250 (void) ipd_close(fd);
252 if (rval != 0) {
253 (void) fprintf(stderr, "%s: failed to change corrupt "
254 "value: %s\n", g_pname, ipd_errmsg);
255 return (E_ERROR);
258 return (E_SUCCESS);
261 static int
262 ipdadm_delay(int argc, char *argv[])
264 long val;
265 int fd, rval;
266 ipd_config_t ic;
268 if (argc != 1) {
269 (void) fprintf(stderr, "%s: delay <microseconds>\n",
270 g_pname);
271 return (usage(stderr));
274 val = ipdadm_parse_long(argv[0], "delay", 0, MAXLONG);
275 bzero(&ic, sizeof (ic));
276 ic.ic_mask = IPDM_DELAY;
277 ic.ic_delay = val;
279 fd = ipd_open(NULL);
280 if (fd < 0) {
281 (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n",
282 g_pname, ipd_errmsg);
283 return (E_ERROR);
285 rval = ipd_ctl(fd, g_zid, &ic);
286 (void) ipd_close(fd);
288 if (rval != 0) {
289 (void) fprintf(stderr, "%s: failed to change delay value: %s\n",
290 g_pname, ipd_errmsg);
291 return (E_ERROR);
294 return (E_SUCCESS);
297 static int
298 ipdadm_drop(int argc, char *argv[])
300 long val;
301 int fd, rval;
302 ipd_config_t ic;
304 if (argc != 1) {
305 (void) fprintf(stderr, "%s: drop <percentage>\n",
306 g_pname);
307 return (usage(stderr));
310 val = ipdadm_parse_long(argv[0], "drop", 0, 100);
311 bzero(&ic, sizeof (ic));
312 ic.ic_mask = IPDM_DROP;
313 ic.ic_drop = val;
315 fd = ipd_open(NULL);
316 if (fd < 0) {
317 (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n",
318 g_pname, ipd_errmsg);
319 return (E_ERROR);
321 rval = ipd_ctl(fd, g_zid, &ic);
322 (void) ipd_close(fd);
324 if (rval != 0) {
325 (void) fprintf(stderr, "%s: failed to change drop value: %s\n",
326 g_pname, ipd_errmsg);
327 return (E_ERROR);
330 return (E_SUCCESS);
333 static int
334 ipdadm_remove_valid(const char *str)
336 if (strcmp(str, "corrupt") == 0) {
337 return (IPDM_CORRUPT);
338 } else if (strcmp(str, "drop") == 0) {
339 return (IPDM_DROP);
340 } else if (strcmp(str, "delay") == 0) {
341 return (IPDM_DELAY);
344 return (0);
347 static int
348 ipdadm_remove(int argc, char *argv[])
350 ipd_config_t ic;
351 char *cur, *res;
352 int rval, fd;
354 if (argc < 1) {
355 (void) fprintf(stderr, "%s: remove <arguments>\n",
356 g_pname);
357 return (usage(stderr));
360 if (argc > 1) {
361 (void) fprintf(stderr, "%s: remove's arguments must be "
362 "comma seperated\n", g_pname);
363 return (E_ERROR);
366 bzero(&ic, sizeof (ic));
368 cur = argv[0];
369 while ((res = strchr(cur, ',')) != NULL) {
370 *res = '\0';
371 if ((rval = ipdadm_remove_valid(cur)) == 0) {
372 (void) fprintf(stderr, "%s: unknown remove "
373 "argument: %s\n", g_pname, cur);
374 return (E_ERROR);
376 ic.ic_mask |= rval;
377 cur = res + 1;
380 if ((rval = ipdadm_remove_valid(cur)) == 0) {
381 (void) fprintf(stderr, "%s: unknown remove argument: %s\n",
382 g_pname, cur);
383 return (E_ERROR);
385 ic.ic_mask |= rval;
387 fd = ipd_open(NULL);
388 if (fd < 0) {
389 (void) fprintf(stderr, "%s: failed to open ipd ctl node: %s\n",
390 g_pname, ipd_errmsg);
391 return (E_ERROR);
393 rval = ipd_ctl(fd, g_zid, &ic);
394 (void) ipd_close(fd);
395 if (rval == -1) {
396 (void) fprintf(stderr, "%s: failed to remove instances: %s\n",
397 g_pname, ipd_errmsg);
398 return (E_ERROR);
401 return (E_SUCCESS);
406 main(int argc, char *argv[])
408 int ii;
409 ipdadm_cmd_t *cmd;
411 g_pname = basename(argv[0]);
413 if (argc < 2)
414 return (usage(stderr));
415 argc--;
416 argv++;
418 g_zid = getzoneid();
419 if (strcmp("-z", argv[0]) == 0) {
420 argc--;
421 argv++;
422 if (argc < 1) {
423 (void) fprintf(stderr, "%s: -z requires an argument\n",
424 g_pname);
425 return (usage(stderr));
428 if (g_zid != GLOBAL_ZONEID) {
429 (void) fprintf(stderr, "%s: -z option only permitted "
430 "in global zone\n", g_pname);
431 return (usage(stderr));
434 g_zid = getzoneidbyname(argv[0]);
435 if (g_zid == -1) {
436 (void) fprintf(stderr, "%s: %s: invalid zone\n",
437 g_pname, argv[0]);
438 return (E_ERROR);
440 argc--;
441 argv++;
444 if (getzonenamebyid(g_zid, g_zonename, sizeof (g_zonename)) < 0) {
445 (void) fprintf(stderr, "%s: failed to get zonename: %s\n",
446 g_pname, strerror(errno));
447 return (E_ERROR);
450 if (argc < 1)
451 return (usage(stderr));
453 for (ii = 0; ii < IPDADM_NCMDS; ii++) {
454 cmd = &ipdadm_cmds[ii];
455 if (strcmp(argv[0], cmd->idc_name) == 0) {
456 argv++;
457 argc--;
458 assert(cmd->idc_func != NULL);
459 return (cmd->idc_func(argc, argv));
463 (void) fprintf(stderr, "%s: %s: unknown command\n", g_pname, argv[0]);
464 return (usage(stderr));