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