1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/varargs.h> 29 #include <getopt.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <strings.h> 33 #include <errno.h> 34 #include <locale.h> 35 #include <libintl.h> 36 #include <libvrrpadm.h> 37 #include <ofmt.h> 38 39 static vrrp_handle_t vrrp_vh = NULL; 40 typedef void cmd_func_t(int, char *[], const char *); 41 42 static cmd_func_t do_create, do_delete, do_enable, do_disable, 43 do_modify, do_show; 44 45 typedef struct { 46 char *c_name; 47 cmd_func_t *c_fn; 48 const char *c_usage; 49 } cmd_t; 50 51 static cmd_t cmds[] = { 52 { "create-router", do_create, 53 "-V <vrid> -l <link> -A {inet | inet6} [-p <priority>] " 54 "[-i <adv_interval>] [-o <flags>] <router_name>" }, 55 { "delete-router", do_delete, "<router_name>" }, 56 { "enable-router", do_enable, "<router_name>" }, 57 { "disable-router", do_disable, "<router_name>" }, 58 { "modify-router", do_modify, 59 "[-p <priority>] [-i <adv_interval>] [-o <flags>] <router_name>" }, 60 { "show-router", do_show, 61 "[-P | -x] [-o field[,...]] [-p] [<router_name>]" } 62 }; 63 64 static const struct option lopts[] = { 65 {"vrid", required_argument, 0, 'V'}, 66 {"link", required_argument, 0, 'l'}, 67 {"address_family", required_argument, 0, 'A'}, 68 {"priority", required_argument, 0, 'p'}, 69 {"adv_interval", required_argument, 0, 'i'}, 70 {"flags", required_argument, 0, 'o'}, 71 { 0, 0, 0, 0 } 72 }; 73 74 static const struct option l_show_opts[] = { 75 {"peer", no_argument, 0, 'P'}, 76 {"parsable", no_argument, 0, 'p'}, 77 {"extended", no_argument, 0, 'x'}, 78 {"output", required_argument, 0, 'o'}, 79 { 0, 0, 0, 0 } 80 }; 81 82 static ofmt_cb_t sfunc_vrrp_conf; 83 84 /* 85 * structures for 'dladm show-link -s' (print statistics) 86 */ 87 enum { 88 ROUTER_NAME, 89 ROUTER_VRID, 90 ROUTER_LINK, 91 ROUTER_VNIC, 92 ROUTER_AF, 93 ROUTER_PRIO, 94 ROUTER_ADV_INTV, 95 ROUTER_MODE, 96 ROUTER_STATE, 97 ROUTER_PRV_STAT, 98 ROUTER_STAT_LAST, 99 ROUTER_PEER, 100 ROUTER_P_PRIO, 101 ROUTER_P_INTV, 102 ROUTER_P_ADV_LAST, 103 ROUTER_M_DOWN_INTV, 104 ROUTER_PRIMARY_IP, 105 ROUTER_VIRTUAL_IPS, 106 ROUTER_VIP_CNT 107 }; 108 109 /* 110 * structures for 'vrrpadm show-router' 111 */ 112 static const ofmt_field_t show_print_fields[] = { 113 /* name, field width, index, callback */ 114 { "NAME", 8, ROUTER_NAME, sfunc_vrrp_conf }, 115 { "VRID", 5, ROUTER_VRID, sfunc_vrrp_conf }, 116 { "LINK", 8, ROUTER_LINK, sfunc_vrrp_conf }, 117 { "VNIC", 8, ROUTER_VNIC, sfunc_vrrp_conf }, 118 { "AF", 5, ROUTER_AF, sfunc_vrrp_conf }, 119 { "PRIO", 5, ROUTER_PRIO, sfunc_vrrp_conf }, 120 { "ADV_INTV", 9, ROUTER_ADV_INTV, sfunc_vrrp_conf }, 121 { "MODE", 6, ROUTER_MODE, sfunc_vrrp_conf }, 122 { "STATE", 6, ROUTER_STATE, sfunc_vrrp_conf }, 123 { "PRV_STAT", 9, ROUTER_PRV_STAT, sfunc_vrrp_conf }, 124 { "STAT_LAST", 10, ROUTER_STAT_LAST, sfunc_vrrp_conf }, 125 { "PEER", 20, ROUTER_PEER, sfunc_vrrp_conf }, 126 { "P_PRIO", 7, ROUTER_P_PRIO, sfunc_vrrp_conf }, 127 { "P_INTV", 9, ROUTER_P_INTV, sfunc_vrrp_conf }, 128 { "P_ADV_LAST", 11, ROUTER_P_ADV_LAST, sfunc_vrrp_conf }, 129 { "M_DOWN_INTV", 12, ROUTER_M_DOWN_INTV, sfunc_vrrp_conf }, 130 { "PRIMARY_IP", 20, ROUTER_PRIMARY_IP, sfunc_vrrp_conf }, 131 { "VIRTUAL_IPS", 40, ROUTER_VIRTUAL_IPS, sfunc_vrrp_conf }, 132 { "VIP_CNT", 7, ROUTER_VIP_CNT, sfunc_vrrp_conf }, 133 { NULL, 0, 0, NULL}} 134 ; 135 136 static vrrp_err_t do_show_router(const char *, ofmt_handle_t); 137 static int str2opt(char *opts, uint32_t *, boolean_t *, boolean_t *); 138 static char *timeval_since_str(int, char *, size_t); 139 140 static void usage(); 141 static void warn(const char *, ...); 142 static void err_exit(const char *, ...); 143 static void opterr_exit(int, int, const char *); 144 145 int 146 main(int argc, char *argv[]) 147 { 148 vrrp_err_t err; 149 int i; 150 cmd_t *cp; 151 152 (void) setlocale(LC_ALL, ""); 153 (void) textdomain(TEXT_DOMAIN); 154 155 if (argv[1] == NULL) 156 usage(); 157 158 if ((err = vrrp_open(&vrrp_vh)) != VRRP_SUCCESS) 159 err_exit("operation failed: %s", vrrp_err2str(err)); 160 161 for (i = 0; i < sizeof (cmds) / sizeof (cmd_t); i++) { 162 cp = &cmds[i]; 163 if (strcmp(argv[1], cp->c_name) == 0) { 164 cp->c_fn(argc - 1, &argv[1], cp->c_usage); 165 vrrp_close(vrrp_vh); 166 return (EXIT_SUCCESS); 167 } 168 } 169 170 usage(); 171 return (EXIT_FAILURE); 172 } 173 174 static void 175 do_create(int argc, char *argv[], const char *usage) 176 { 177 vrrp_vr_conf_t conf; 178 int c; 179 uint32_t create_mask = 0, mask; 180 char *endp; 181 vrrp_err_t err; 182 183 /* 184 * default value 185 */ 186 bzero(&conf, sizeof (vrrp_vr_conf_t)); 187 conf.vvc_vrid = VRRP_VRID_NONE; 188 conf.vvc_af = AF_UNSPEC; 189 conf.vvc_pri = VRRP_PRI_DEFAULT; 190 conf.vvc_adver_int = VRRP_MAX_ADVER_INT_DFLT; 191 conf.vvc_preempt = B_TRUE; 192 conf.vvc_accept = B_TRUE; 193 conf.vvc_enabled = B_TRUE; 194 195 while ((c = getopt_long(argc, argv, ":V:l:p:i:o:A:f", lopts, 196 NULL)) != EOF) { 197 switch (c) { 198 case 'l': 199 if (strlcpy(conf.vvc_link, optarg, 200 sizeof (conf.vvc_link)) >= 201 sizeof (conf.vvc_link)) { 202 err_exit("invalid data-link name %s", optarg); 203 } 204 break; 205 case 'i': 206 if (create_mask & VRRP_CONF_INTERVAL) 207 err_exit("duplicate '-i' option"); 208 209 create_mask |= VRRP_CONF_INTERVAL; 210 conf.vvc_adver_int = (uint32_t)strtol(optarg, &endp, 0); 211 if ((*endp) != '\0' || 212 conf.vvc_adver_int < VRRP_MAX_ADVER_INT_MIN || 213 conf.vvc_adver_int > VRRP_MAX_ADVER_INT_MAX || 214 (conf.vvc_adver_int == 0 && errno != 0)) { 215 err_exit("invalid advertisement interval"); 216 } 217 break; 218 case 'p': 219 if (create_mask & VRRP_CONF_PRIORITY) 220 err_exit("duplicate '-p' option"); 221 222 create_mask |= VRRP_CONF_PRIORITY; 223 conf.vvc_pri = strtol(optarg, &endp, 0); 224 if ((*endp) != '\0' || conf.vvc_pri < VRRP_PRI_MIN || 225 conf.vvc_pri > VRRP_PRI_OWNER || 226 (conf.vvc_pri == 0 && errno != 0)) { 227 err_exit("invalid priority"); 228 } 229 break; 230 case 'o': 231 mask = 0; 232 if (str2opt(optarg, &mask, 233 &conf.vvc_preempt, &conf.vvc_accept) != 0) { 234 err_exit("invalid options: %s", optarg); 235 } 236 if (mask & create_mask & VRRP_CONF_PREEMPT) 237 err_exit("duplicate '-o preempt' option"); 238 else if (mask & create_mask & VRRP_CONF_ACCEPT) 239 err_exit("duplicate '-o accept' option"); 240 create_mask |= mask; 241 break; 242 case 'V': 243 if (conf.vvc_vrid != VRRP_VRID_NONE) 244 err_exit("duplicate '-V' option"); 245 246 conf.vvc_vrid = strtol(optarg, &endp, 0); 247 if ((*endp) != '\0' || conf.vvc_vrid < VRRP_VRID_MIN || 248 conf.vvc_vrid > VRRP_VRID_MAX || 249 (conf.vvc_vrid == 0 && errno != 0)) { 250 err_exit("invalid VRID"); 251 } 252 break; 253 case 'A': 254 if (conf.vvc_af != AF_UNSPEC) 255 err_exit("duplicate '-A' option"); 256 257 if (strcmp(optarg, "inet") == 0) 258 conf.vvc_af = AF_INET; 259 else if (strcmp(optarg, "inet6") == 0) 260 conf.vvc_af = AF_INET6; 261 else 262 err_exit("invalid address family"); 263 break; 264 default: 265 opterr_exit(optopt, c, usage); 266 } 267 } 268 269 if (argc - optind > 1) 270 err_exit("usage: %s", gettext(usage)); 271 272 if (optind != argc - 1) 273 err_exit("VRRP name not specified"); 274 275 if (strlcpy(conf.vvc_name, argv[optind], 276 sizeof (conf.vvc_name)) >= sizeof (conf.vvc_name)) { 277 err_exit("Invalid router name %s", argv[optind]); 278 } 279 280 if (conf.vvc_vrid == VRRP_VRID_NONE) 281 err_exit("VRID not specified"); 282 283 if (conf.vvc_af == AF_UNSPEC) 284 err_exit("address family not specified"); 285 286 if (strlen(conf.vvc_link) == 0) 287 err_exit("link name not specified"); 288 289 if (!conf.vvc_accept && conf.vvc_pri == VRRP_PRI_OWNER) 290 err_exit("accept_mode must be true for virtual IP owner"); 291 292 done: 293 if ((err = vrrp_create(vrrp_vh, &conf)) == VRRP_SUCCESS) 294 return; 295 296 err_exit("create-router failed: %s", vrrp_err2str(err)); 297 } 298 299 static void 300 do_delete(int argc, char *argv[], const char *use) 301 { 302 vrrp_err_t err; 303 304 if (argc != 2) 305 err_exit("usage: %s", gettext(use)); 306 307 if ((err = vrrp_delete(vrrp_vh, argv[1])) != VRRP_SUCCESS) 308 err_exit("delete-router failed: %s", vrrp_err2str(err)); 309 } 310 311 static void 312 do_enable(int argc, char *argv[], const char *use) 313 { 314 vrrp_err_t err; 315 316 if (argc != 2) 317 err_exit("usage: %s", gettext(use)); 318 319 if ((err = vrrp_enable(vrrp_vh, argv[1])) != VRRP_SUCCESS) 320 err_exit("enable-router failed: %s", vrrp_err2str(err)); 321 } 322 323 static void 324 do_disable(int argc, char *argv[], const char *use) 325 { 326 vrrp_err_t err; 327 328 if (argc != 2) 329 err_exit("usage: %s", gettext(use)); 330 331 if ((err = vrrp_disable(vrrp_vh, argv[1])) != VRRP_SUCCESS) 332 err_exit("disable-router failed: %s", vrrp_err2str(err)); 333 } 334 335 static void 336 do_modify(int argc, char *argv[], const char *use) 337 { 338 vrrp_vr_conf_t conf; 339 vrrp_err_t err; 340 uint32_t modify_mask = 0, mask; 341 char *endp; 342 int c; 343 344 while ((c = getopt_long(argc, argv, ":i:p:o:", lopts, NULL)) != EOF) { 345 switch (c) { 346 case 'i': 347 if (modify_mask & VRRP_CONF_INTERVAL) 348 err_exit("duplicate '-i' option"); 349 350 modify_mask |= VRRP_CONF_INTERVAL; 351 conf.vvc_adver_int = (uint32_t)strtol(optarg, &endp, 0); 352 if ((*endp) != '\0' || 353 conf.vvc_adver_int < VRRP_MAX_ADVER_INT_MIN || 354 conf.vvc_adver_int > VRRP_MAX_ADVER_INT_MAX || 355 (conf.vvc_adver_int == 0 && errno != 0)) { 356 err_exit("invalid advertisement interval"); 357 } 358 break; 359 case 'o': 360 mask = 0; 361 if (str2opt(optarg, &mask, &conf.vvc_preempt, 362 &conf.vvc_accept) != 0) { 363 err_exit("Invalid options"); 364 } 365 if (mask & modify_mask & VRRP_CONF_PREEMPT) 366 err_exit("duplicate '-o preempt' option"); 367 else if (mask & modify_mask & VRRP_CONF_ACCEPT) 368 err_exit("duplicate '-o accept' option"); 369 modify_mask |= mask; 370 break; 371 case 'p': 372 if (modify_mask & VRRP_CONF_PRIORITY) 373 err_exit("duplicate '-p' option"); 374 375 modify_mask |= VRRP_CONF_PRIORITY; 376 conf.vvc_pri = strtol(optarg, &endp, 0); 377 if ((*endp) != '\0' || conf.vvc_pri < VRRP_PRI_MIN || 378 conf.vvc_pri > VRRP_PRI_OWNER || 379 (conf.vvc_pri == 0 && errno != 0)) { 380 err_exit("invalid priority"); 381 } 382 break; 383 default: 384 opterr_exit(optopt, c, use); 385 } 386 } 387 388 if (argc - optind > 1) 389 err_exit("usage: %s", gettext(use)); 390 391 if (optind != argc - 1) 392 err_exit("VRRP name not specified."); 393 394 if (strlcpy(conf.vvc_name, argv[optind], sizeof (conf.vvc_name)) >= 395 sizeof (conf.vvc_name)) { 396 err_exit("invalid router name %s", argv[optind]); 397 } 398 399 if ((modify_mask & VRRP_CONF_ACCEPT) && !conf.vvc_accept && 400 (modify_mask & VRRP_CONF_PRIORITY) && 401 conf.vvc_pri == VRRP_PRI_OWNER) { 402 err_exit("accept_mode must be true for virtual IP owner"); 403 } 404 405 if (modify_mask == 0) 406 usage(); 407 408 err = vrrp_modify(vrrp_vh, &conf, modify_mask); 409 if (err != VRRP_SUCCESS) 410 err_exit("modify-router failed: %s", vrrp_err2str(err)); 411 } 412 413 /* 414 * 'show-router' one VRRP router. 415 */ 416 static vrrp_err_t 417 do_show_router(const char *vn, ofmt_handle_t ofmt) 418 { 419 vrrp_queryinfo_t *vq; 420 vrrp_err_t err; 421 422 if ((err = vrrp_query(vrrp_vh, vn, &vq)) != VRRP_SUCCESS) 423 return (err); 424 425 ofmt_print(ofmt, vq); 426 free(vq); 427 return (VRRP_SUCCESS); 428 } 429 430 static void 431 do_show(int argc, char *argv[], const char *use) 432 { 433 int c; 434 char *fields_str = NULL; 435 char *names = NULL, *router; 436 uint32_t i, in_cnt = 0, out_cnt; 437 ofmt_status_t oferr; 438 ofmt_handle_t ofmt; 439 uint_t ofmt_flags = 0; 440 vrrp_err_t err = VRRP_SUCCESS; 441 boolean_t P_opt, x_opt; 442 443 static char *dft_fields_str = 444 "NAME,VRID,LINK,AF,PRIO,ADV_INTV,MODE,STATE,VNIC"; 445 static char *ext_fields_str = 446 "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIRTUAL_IPS"; 447 static char *peer_fields_str = 448 "NAME,PEER,P_PRIO,P_INTV,P_ADV_LAST,M_DOWN_INTV"; 449 /* 450 * If parsable output is requested, add VIP_CNT into the output 451 * for extended output. It is not needed for human-readable 452 * output as it is obvious from the VIRTUAL_IPS list. 453 */ 454 static char *ext_parsable_fields_str = 455 "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIP_CNT," 456 "VIRTUAL_IPS"; 457 458 P_opt = x_opt = B_FALSE; 459 fields_str = dft_fields_str; 460 while ((c = getopt_long(argc, argv, ":Pxpo:", l_show_opts, 461 NULL)) != EOF) { 462 switch (c) { 463 case 'o': 464 fields_str = optarg; 465 break; 466 case 'p': 467 ofmt_flags |= OFMT_PARSABLE; 468 break; 469 case 'P': 470 P_opt = B_TRUE; 471 fields_str = peer_fields_str; 472 break; 473 case 'x': 474 x_opt = B_TRUE; 475 fields_str = ext_fields_str; 476 break; 477 default: 478 opterr_exit(optopt, c, use); 479 } 480 } 481 482 if (x_opt && P_opt) 483 err_exit("incompatible -P and -x options"); 484 485 /* 486 * If parsable output is requested, add VIP_CNT into the output 487 * for extended output. 488 */ 489 if ((ofmt_flags & OFMT_PARSABLE) && (fields_str == ext_fields_str)) 490 fields_str = ext_parsable_fields_str; 491 492 if ((oferr = ofmt_open(fields_str, show_print_fields, ofmt_flags, 493 0, &ofmt)) != OFMT_SUCCESS) { 494 char buf[OFMT_BUFSIZE]; 495 496 /* 497 * If some fields were badly formed in human-friendly mode, we 498 * emit a warning and continue. Otherwise exit immediately. 499 */ 500 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 501 if (oferr != OFMT_EBADFIELDS || (ofmt_flags & OFMT_PARSABLE)) { 502 ofmt_close(ofmt); 503 err_exit(buf); 504 } else { 505 warn(buf); 506 } 507 } 508 509 /* Show one router */ 510 if (optind == argc - 1) { 511 err = do_show_router(argv[optind], ofmt); 512 goto done; 513 } 514 515 /* 516 * Show all routers. First set in_cnt to 0 to find out the number 517 * of vrrp routers. 518 */ 519 again: 520 if ((in_cnt != 0) && (names = malloc(in_cnt * VRRP_NAME_MAX)) == NULL) { 521 err = VRRP_ENOMEM; 522 goto done; 523 } 524 525 out_cnt = in_cnt; 526 if ((err = vrrp_list(vrrp_vh, VRRP_VRID_NONE, NULL, AF_UNSPEC, 527 &out_cnt, names)) != VRRP_SUCCESS) { 528 free(names); 529 goto done; 530 } 531 532 /* 533 * The VRRP routers has been changed between two vrrp_list() 534 * calls, try again. 535 */ 536 if (out_cnt > in_cnt) { 537 in_cnt = out_cnt; 538 free(names); 539 goto again; 540 } 541 542 /* 543 * Each VRRP router name is separated by '\0` 544 */ 545 router = names; 546 for (i = 0; i < in_cnt; i++) { 547 (void) do_show_router(router, ofmt); 548 router += strlen(router) + 1; 549 } 550 551 free(names); 552 553 done: 554 ofmt_close(ofmt); 555 556 if (err != VRRP_SUCCESS) 557 err_exit(vrrp_err2str(err)); 558 } 559 560 /* 561 * Callback function to print fields of the configuration information. 562 */ 563 static boolean_t 564 sfunc_vrrp_conf(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) 565 { 566 vrrp_queryinfo_t *qinfo = ofmtarg->ofmt_cbarg; 567 uint_t ofmtid = ofmtarg->ofmt_id; 568 vrrp_vr_conf_t *conf = &qinfo->show_vi; 569 vrrp_stateinfo_t *sinfo = &qinfo->show_vs; 570 vrrp_peer_t *peer = &qinfo->show_vp; 571 vrrp_timerinfo_t *tinfo = &qinfo->show_vt; 572 vrrp_addrinfo_t *ainfo = &qinfo->show_va; 573 574 switch (ofmtid) { 575 case ROUTER_NAME: 576 (void) snprintf(buf, bufsize, "%s", conf->vvc_name); 577 break; 578 case ROUTER_VRID: 579 (void) snprintf(buf, bufsize, "%d", conf->vvc_vrid); 580 break; 581 case ROUTER_LINK: 582 (void) snprintf(buf, bufsize, "%s", conf->vvc_link); 583 break; 584 case ROUTER_AF: 585 (void) snprintf(buf, bufsize, "IPv%d", 586 conf->vvc_af == AF_INET ? 4 : 6); 587 break; 588 case ROUTER_PRIO: 589 (void) snprintf(buf, bufsize, "%d", conf->vvc_pri); 590 break; 591 case ROUTER_ADV_INTV: 592 (void) snprintf(buf, bufsize, "%d", conf->vvc_adver_int); 593 break; 594 case ROUTER_MODE: 595 (void) strlcpy(buf, "-----", bufsize); 596 if (conf->vvc_enabled) 597 buf[0] = 'e'; 598 if (conf->vvc_pri == VRRP_PRI_OWNER) 599 buf[1] = 'o'; 600 if (conf->vvc_preempt) 601 buf[2] = 'p'; 602 if (conf->vvc_accept) 603 buf[3] = 'a'; 604 break; 605 case ROUTER_STATE: 606 (void) snprintf(buf, bufsize, "%s", 607 vrrp_state2str(sinfo->vs_state)); 608 break; 609 case ROUTER_PRV_STAT: 610 (void) snprintf(buf, bufsize, "%s", 611 vrrp_state2str(sinfo->vs_prev_state)); 612 break; 613 case ROUTER_STAT_LAST: 614 (void) timeval_since_str(tinfo->vt_since_last_tran, buf, 615 bufsize); 616 break; 617 case ROUTER_PEER: 618 /* LINTED E_CONSTANT_CONDITION */ 619 VRRPADDR2STR(conf->vvc_af, &peer->vp_addr, 620 buf, bufsize, B_FALSE); 621 break; 622 case ROUTER_P_PRIO: 623 (void) snprintf(buf, bufsize, "%d", peer->vp_prio); 624 break; 625 case ROUTER_P_INTV: 626 (void) snprintf(buf, bufsize, "%d", peer->vp_adver_int); 627 break; 628 case ROUTER_P_ADV_LAST: 629 (void) timeval_since_str(tinfo->vt_since_last_adv, buf, 630 bufsize); 631 break; 632 case ROUTER_M_DOWN_INTV: 633 (void) snprintf(buf, bufsize, "%d", tinfo->vt_master_down_intv); 634 break; 635 case ROUTER_VNIC: 636 (void) snprintf(buf, bufsize, "%s", 637 strlen(ainfo->va_vnic) == 0 ? "--" : ainfo->va_vnic); 638 break; 639 case ROUTER_PRIMARY_IP: 640 /* LINTED E_CONSTANT_CONDITION */ 641 VRRPADDR2STR(conf->vvc_af, &ainfo->va_primary, 642 buf, bufsize, B_FALSE); 643 break; 644 case ROUTER_VIRTUAL_IPS: { 645 uint32_t i; 646 647 for (i = 0; i < ainfo->va_vipcnt; i++) { 648 /* LINTED E_CONSTANT_CONDITION */ 649 VRRPADDR2STR(conf->vvc_af, &(ainfo->va_vips[i]), 650 buf, bufsize, B_TRUE); 651 if (i != ainfo->va_vipcnt - 1) 652 (void) strlcat(buf, ",", bufsize); 653 } 654 break; 655 } 656 case ROUTER_VIP_CNT: 657 (void) snprintf(buf, bufsize, "%d", ainfo->va_vipcnt); 658 break; 659 default: 660 return (B_FALSE); 661 } 662 663 return (B_TRUE); 664 } 665 666 static void 667 usage() 668 { 669 int i; 670 cmd_t *cp; 671 672 (void) fprintf(stderr, "%s", 673 gettext("usage: vrrpadm <sub-command> <args> ...\n")); 674 675 for (i = 0; i < sizeof (cmds) / sizeof (cmd_t); i++) { 676 cp = &cmds[i]; 677 if (cp->c_usage != NULL) 678 (void) fprintf(stderr, " %-10s %s\n", 679 gettext(cp->c_name), gettext(cp->c_usage)); 680 } 681 682 vrrp_close(vrrp_vh); 683 exit(EXIT_FAILURE); 684 } 685 686 static void 687 warn(const char *format, ...) 688 { 689 va_list alist; 690 691 format = gettext(format); 692 (void) fprintf(stderr, gettext("warning: ")); 693 694 va_start(alist, format); 695 (void) vfprintf(stderr, format, alist); 696 va_end(alist); 697 (void) putc('\n', stderr); 698 } 699 700 static void 701 err_exit(const char *format, ...) 702 { 703 va_list alist; 704 705 format = gettext(format); 706 va_start(alist, format); 707 (void) vfprintf(stderr, format, alist); 708 va_end(alist); 709 (void) putc('\n', stderr); 710 vrrp_close(vrrp_vh); 711 exit(EXIT_FAILURE); 712 } 713 714 static void 715 opterr_exit(int opt, int opterr, const char *use) 716 { 717 switch (opterr) { 718 case ':': 719 err_exit("option '-%c' requires a value\nusage: %s", opt, 720 gettext(use)); 721 break; 722 case '?': 723 default: 724 err_exit("unrecognized option '-%c'\nusage: %s", opt, 725 gettext(use)); 726 break; 727 } 728 } 729 730 static char * 731 timeval_since_str(int mill, char *str, size_t len) 732 { 733 int sec, msec, min; 734 735 msec = mill % 1000; 736 sec = mill / 1000; 737 min = sec > 60 ? sec / 60 : 0; 738 sec %= 60; 739 740 if (min > 0) 741 (void) snprintf(str, len, "%4dm%2ds", min, sec); 742 else 743 (void) snprintf(str, len, "%4d.%03ds", sec, msec); 744 745 return (str); 746 } 747 748 /* 749 * Parses options string. The values of the two options will be returned 750 * by 'preempt' and 'accept', and the mask 'modify_mask' will be updated 751 * accordingly. 752 * 753 * Returns 0 on success, errno on failures. 754 * 755 * Used by do_create() and do_modify(). 756 * 757 * Note that "opts" could be modified internally in this function. 758 */ 759 static int 760 str2opt(char *opts, uint32_t *modify_mask, boolean_t *preempt, 761 boolean_t *accept) 762 { 763 char *value; 764 int opt; 765 uint32_t mask = 0; 766 enum { o_preempt = 0, o_un_preempt, o_accept, o_no_accept }; 767 static char *myopts[] = { 768 "preempt", 769 "un_preempt", 770 "accept", 771 "no_accept", 772 NULL 773 }; 774 775 while (*opts != '\0') { 776 switch ((opt = getsubopt(&opts, myopts, &value))) { 777 case o_preempt: 778 case o_un_preempt: 779 if (mask & VRRP_CONF_PREEMPT) 780 return (EINVAL); 781 782 mask |= VRRP_CONF_PREEMPT; 783 *preempt = (opt == o_preempt); 784 break; 785 case o_accept: 786 case o_no_accept: 787 if (mask & VRRP_CONF_ACCEPT) 788 return (EINVAL); 789 790 mask |= VRRP_CONF_ACCEPT; 791 *accept = (opt == o_accept); 792 break; 793 default: 794 return (EINVAL); 795 } 796 } 797 798 *modify_mask |= mask; 799 return (0); 800 } 801