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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <stdio.h>
  28 #include <stdarg.h>
  29 #include <sys/param.h>
  30 #include <locale.h>
  31 #include <dirent.h>
  32 #include <fcntl.h>
  33 #include <door.h>
  34 #include <errno.h>
  35 #include <sys/mman.h>
  36 #include <getopt.h>
  37 #include <assert.h>
  38 #include <sys/stat.h>
  39 #include <sys/usb/usba/wusba_io.h>
  40 #include <sys/usb/clients/wusb_ca/wusb_ca.h>
  41 #include "crypto_util.h"
  42 #include "wusbd.h"
  43 
  44 /*
  45  * EXIT STATUS
  46  *    The following exit values are returned:
  47  *         0    Successful operation
  48  *         1    Error: the operation failed.
  49  *         2    Usage error.
  50  */
  51 #define WUSB_EXIT_SUCCESS       0
  52 #define WUSB_EXIT_FAILURE       1
  53 #define WUSB_EXIT_USAGE         2
  54 
  55 
  56 
  57 #define ASSO_CABLE_NAME         "wusb_ca"
  58 
  59 #define WUSB_MAX_LEN                            255
  60 
  61 #define WUSB_HOSTID_LEN         2
  62 #define WUSB_DEVID_LEN          6
  63 
  64 /* wusba admin list options */
  65 #define WUSB_FIELD_WIDTH                20
  66 
  67 #define WUSB_LIST_HOST  0x01
  68 #define WUSB_LIST_DEV   0x02
  69 #define WUSB_LIST_HD    (WUSB_LIST_HOST | WUSB_LIST_DEV)
  70 #define WUSB_LIST_ID    0x04
  71 #define WUSB_LIST_TYPE  0x08
  72 #define WUSB_LIST_STATE 0x10
  73 #define WUSB_LIST_ALL   (WUSB_LIST_ID | WUSB_LIST_TYPE | WUSB_LIST_STATE)
  74 
  75 /* cable device list */
  76 typedef struct dev_list {
  77         char                    path[MAXPATHLEN];
  78         struct dev_list         *next;
  79 } dev_list_t;
  80 
  81 static wusb_device_info_t   *dev_lists = NULL;
  82 static uint32_t cnt        = 0;
  83 
  84 /* log and debug helpers */
  85 static  void    wusb_prt(const char *, ...);
  86 static  void    wusb_usage(const char *, ...);
  87 static  void    wusb_fail(const char *, ...);
  88 static  void    wusb_opterr(int, int);
  89 
  90 
  91 
  92 /* load host/dev list helpers */
  93 static void     wusb_load_list(wusb_device_info_t **, uint32_t *cnt);
  94 static void     wusb_free_list(wusb_device_info_t *);
  95 
  96 /* door call helpers */
  97 static int      wusb_door_req(int, door_arg_t *, char *, int);
  98 static void     wusb_door_free(door_arg_t *);
  99 static uint16_t wusb_door_result(door_arg_t *da);
 100 
 101 /* check auths */
 102 static void     wusb_check_auth(const char *);
 103 /* usr input funcs */
 104 static void     user_confirm(char *);
 105 static void     user_input(char *, char *, int);
 106 
 107 /* string translation helpers */
 108 static uint32_t str2id(char *);
 109 static void     usage();
 110 
 111 /* list */
 112 static const struct option wusb_list_opts[] = {
 113         { "host",       no_argument,            NULL, 'h'},
 114         { "device",     no_argument,            NULL, 'd'},
 115         { "output",     required_argument,      NULL, 'o'},
 116         {0, 0, 0, 0}
 117 };
 118 static const char *WUSB_LIST_HEADER[] = {
 119         "ID",                   /* host-id or dev-id            */
 120         "STATE",                /* host or device states        */
 121         "TYPE",                 /* host or deivce types         */
 122         NULL
 123 };
 124 
 125 static void     do_list(int, char **);
 126 static void     do_list_args(int, char **, char *);
 127 
 128 static void     parse_subopts(char *, const char *);
 129 static int      parse_option(char *, const char *);
 130 
 131 static void     wusb_prt_titles(char);
 132 static void     wusb_prt_lists(char, wusb_device_info_t *);
 133 
 134 
 135 static int      find_dev_id(uint8_t, uint16_t);
 136 static void     parse_dev_id(const char *, wusb_dev_ctrl_t *);
 137 static void     parse_host_id(char *, uint8_t  *);
 138 
 139 /* associate */
 140 static struct option wusb_asso_opts[] = {
 141         { "host",               required_argument,      NULL, 'h'},
 142         { "cable",              no_argument,            NULL, 'c'},
 143         { "numeric",            required_argument,      NULL, 'n'},
 144         { "force",              no_argument,            NULL, 'f'},
 145         { "onetime",            no_argument,            NULL, 'o'},
 146         { 0, 0, 0, 0}
 147 };
 148 static void     do_associate(int, char **);
 149 static void     do_asso_args(int, char **, wusb_asso_ctrl_t *);
 150 
 151 static int      input_host_id(uint8_t *);
 152 static void     input_dev_id(wusb_dev_ctrl_t *);
 153 #ifdef NUMERIC_ENABLED
 154 static int      input_asso_type(uint8_t *);
 155 #endif
 156 static int      select_cable_device(char *);
 157 
 158 /* remove dev */
 159 static struct option wusb_rmdev_opts[] = {
 160         { "host",               required_argument,      NULL, 'h'},
 161         { "device",             required_argument,      NULL, 'd'},
 162         { "force",              no_argument,            NULL, 'f'},
 163         { 0, 0, 0, 0}
 164 };
 165 
 166 /* remove/enable/disable host */
 167 static struct option wusb_host_opts[] = {
 168         { "host",               required_argument,      NULL, 'h'},
 169         { "force",              no_argument,            NULL, 'f'},
 170         { 0, 0, 0, 0}
 171 };
 172 
 173 static void     do_host(int, char **, int);
 174 static void     do_host_args(int, char **, int, wusb_dev_ctrl_t *);
 175 static void     do_remove_host(int, char **);
 176 static void     do_enable_host(int, char **);
 177 static void     do_disable_host(int, char **);
 178 
 179 static void     do_remove_dev(int, char **);
 180 static void     do_remove_dev_args(int, char **, wusb_dev_ctrl_t *);
 181 
 182 
 183 
 184 /* error message maps */
 185 struct errormsgs {
 186         int code;
 187         char *errmsg;
 188 } wusb_errors[] = {
 189         { WUSBADM_OK,                   "success" },
 190         { WUSBADM_AUTH_FAILURE,         "permisson denied" },
 191         { WUSBADM_NO_HOST,              "host does not exist" },
 192         { WUSBADM_NO_DEVICE,            "device does not exist" },
 193         { WUSBADM_CCSTORE_ACC,          "fail to access CC store" },
 194         { WUSBADM_NO_SUPPORT,           "command not supported" },
 195         { WUSBADM_INVAL_HOSTID,         "invalid host id" },
 196         { WUSBADM_INVAL_DEVID,          "invalid device id" },
 197         { WUSBADM_HOST_NOT_ATTACH,      "host not attached" },
 198         { WUSBADM_FAILURE,              "unknown error"}
 199 };
 200 
 201 char *
 202 wusb_strerror(int err)
 203 {
 204         if (err < 0 || err > WUSBADM_FAILURE) {
 205 
 206                 return (wusb_errors[WUSBADM_FAILURE].errmsg);
 207         }
 208 
 209         return (wusb_errors[err].errmsg);
 210 }
 211 
 212 
 213 /*
 214  * wusbadm cmd line tool is used for used to administrate the wireless usb
 215  * host and wireless usb devices.
 216  * list         - List the device and host status
 217  * associated   - Setup assocaition between host and devices.
 218  * remove-dev   - Remove the assocation of device
 219  * remove-host  - Remove the host information and all the devices assocaiton to
 220  *                the host
 221  * enable-host  - Enable a host to be ready to accept wireless devices
 222  * disable-host - Disable a host, host will not accpet connections
 223  */
 224 
 225 int
 226 main(int argc, char **argv)
 227 {
 228         int i;
 229         static struct {
 230                 const char *cmd;
 231                 void (*func)(int, char **);
 232                 const char *auth;
 233         } cmd_list[] = {
 234                 { "list",         do_list,              WUSB_AUTH_READ},
 235                 { "associate",    do_associate,         WUSB_AUTH_MODIFY},
 236                 { "remove-dev",   do_remove_dev,        WUSB_AUTH_MODIFY},
 237                 { "remove-host",  do_remove_host,       WUSB_AUTH_HOST},
 238                 { "enable-host",  do_enable_host,       WUSB_AUTH_HOST},
 239                 { "disable-host", do_disable_host,      WUSB_AUTH_HOST},
 240                 { NULL, NULL}
 241         };
 242 
 243 
 244         (void) setlocale(LC_ALL, "");
 245 
 246 #ifndef TEXT_DOMAIN
 247 #define TEXT_DOMAIN     "SYS_TEST"
 248 #endif
 249         (void) textdomain(TEXT_DOMAIN);
 250 
 251         if (argc <= 1) {
 252                 usage();
 253                 exit(WUSB_EXIT_USAGE);
 254         }
 255 
 256         /* start wusb damemon */
 257         if (strcmp(argv[1], "--daemon") == 0) {
 258                 (void) daemonize();
 259                 exit(WUSB_EXIT_SUCCESS);
 260         }
 261 
 262 
 263         /* wusbadm entry */
 264         for (i = 0; cmd_list[i].cmd; i++) {
 265                 if (strcmp(cmd_list[i].cmd, argv[1]) == 0) {
 266                         break;
 267                 }
 268         }
 269         if (!cmd_list[i].cmd) {
 270                 wusb_usage("unknown option %s", argv[1]);
 271         }
 272         wusb_check_auth(cmd_list[i].auth);
 273 
 274         wusb_load_list(&dev_lists, &cnt);
 275 
 276         cmd_list[i].func(argc - 1, &argv[1]);
 277 
 278         wusb_free_list(dev_lists);
 279         return (WUSB_EXIT_SUCCESS);
 280 }
 281 
 282 static void
 283 usage()
 284 {
 285         wusb_prt("\nUsage:\twusbadm sub-command args ...\n\n");
 286         wusb_prt("\tlist         [-h | -d] [-o field[,...]]\n");
 287         wusb_prt("\tassociate    [-h host-id] [[-c [-f]] | -n] [-o]\n");
 288         wusb_prt("\tremove-dev   [[-d dev-id] | [-h host-id]] [-f]\n");
 289         wusb_prt("\tremove-host  [-h host-id] [-f]\n");
 290         wusb_prt("\tenable-host  [-h host-id]\n");
 291         wusb_prt("\tdisable-host [-h host-id] [-f]\n");
 292         wusb_prt("\n");
 293 }
 294 
 295 /*
 296  * list command routine.
 297  *      wusbadmin list [-h | -d] [-o field[,...]]
 298  *      1. parse the options
 299  *      2. load host/deivce info from daemon
 300  *      3. print titles accoding to list  options
 301  *      4. print host/deivce list one by one
 302  */
 303 static void
 304 do_list(int argc, char **argv)
 305 {
 306         char            fields     = 0x0;
 307         int i;
 308 
 309         /* parse the list options */
 310         do_list_args(argc, argv, &fields);
 311 
 312 
 313         /* print list title */
 314         wusb_prt_titles(fields);
 315 
 316         /* print out the result */
 317         for (i = 0; i < cnt; i++) {
 318                 wusb_prt_lists(fields, &dev_lists[i]);
 319         }
 320 
 321 
 322 }
 323 
 324 /*
 325  * associate command routine
 326  *      wusbadmin associate [-h host-id] [[-c [-f] | -n] [-o]
 327  *      1. Parse the options and get user input
 328  *      2. Send the asso infor the daemon
 329  */
 330 static void
 331 do_associate(int argc, char **argv)
 332 {
 333         door_arg_t da;
 334         wusb_asso_ctrl_t  asso_ctrl;
 335         uint16_t rval = 0;
 336 
 337         /* Get association options */
 338         bzero(&asso_ctrl, sizeof (wusb_asso_ctrl_t));
 339         do_asso_args(argc, argv, &asso_ctrl);
 340 
 341         /* open door file */
 342         (void) wusb_door_req(WUSB_DCMD_ASSOCIATE, &da,
 343             (char *)&asso_ctrl, sizeof (wusb_asso_ctrl_t));
 344 
 345         /* association result */
 346         rval = wusb_door_result(&da);
 347 
 348         wusb_door_free(&da);
 349 
 350         if (rval != WUSBADM_OK) {
 351                 wusb_fail("%s", wusb_strerror(rval));
 352         }
 353 
 354 }
 355 /*
 356  * remove-dev command routine
 357  *      remove-dev   [[-d dev-id] | [-h host-id]] [-f]
 358  *      1. parse options/user input
 359  *      2. send message to daemon.
 360  *      dev-id != 0 means remove one dev
 361  *      dev-id == 0 means remove all dev with a host
 362  */
 363 static void
 364 do_remove_dev(int argc, char **argv)
 365 {
 366         wusb_dev_ctrl_t  devctrl;
 367         door_arg_t       da;
 368 
 369         uint16_t rval = WUSBADM_OK;
 370 
 371         /* parse options */
 372         bzero(&devctrl, sizeof (wusb_dev_ctrl_t));
 373         do_remove_dev_args(argc, argv, &devctrl);
 374 
 375         /* send command to daemon */
 376         (void) wusb_door_req(WUSB_DCMD_REMOVE_DEV, &da,
 377             (char *)&devctrl, sizeof (wusb_dev_ctrl_t));
 378 
 379 
 380         rval = wusb_door_result(&da);
 381 
 382         wusb_door_free(&da);
 383 
 384         if (rval != WUSBADM_OK) {
 385                 wusb_fail("%s", wusb_strerror(rval));
 386         }
 387 
 388 
 389 }
 390 
 391 /*
 392  * Send the LOAD_CC request to daemon. Daemon will allocate memory and put
 393  * all CCs in that block of memory. We need to free the memory here.
 394  * CCs are in data array format.
 395  */
 396 static void
 397 wusb_load_list(wusb_device_info_t **cc_list, uint32_t *cnt)
 398 {
 399         door_arg_t da;
 400 
 401         size_t   buflen = 0;
 402         uint32_t num    = 0;
 403         uint16_t rval   = WUSBADM_OK;
 404 
 405         /* send command to daemon */
 406         (void) wusb_door_req(WUSB_DCMD_LIST_DATA, &da, 0, 0);
 407 
 408         rval = wusb_door_result(&da);
 409         if (rval != WUSBADM_OK) {
 410                 wusb_door_free(&da);
 411 
 412                 wusb_fail("%s", wusb_strerror(rval));
 413         }
 414 
 415         /* number of the devinfo list */
 416         (void) memcpy(&num, da.data_ptr+sizeof (uint16_t), sizeof (uint32_t));
 417 
 418         if (num) {
 419 
 420                 buflen = (num) * sizeof (wusb_device_info_t);
 421                 if ((*cc_list = malloc(buflen)) == NULL) {
 422                         wusb_door_free(&da);
 423 
 424                         wusb_fail("list: malloc buffer failed");
 425                 }
 426 
 427                 (void) memcpy(*cc_list,
 428                     da.data_ptr + sizeof (uint32_t) + sizeof (uint16_t),
 429                     buflen);
 430         }
 431         *cnt = num;
 432 
 433         /* unmap the buffer */
 434         wusb_door_free(&da);
 435 }
 436 static void
 437 wusb_free_list(wusb_device_info_t *cc_list)
 438 {
 439         if (cc_list) {
 440                 free(cc_list);
 441         }
 442         cnt = 0;
 443 }
 444 
 445 /*
 446  * This is a wrapper of door call for wusb adm tool.
 447  * Mandatory:
 448  *      cmd     - wusb admin command (WUSB_DCMD_*).
 449  *      da      - door call arg.
 450  * Optional:
 451  *      databuf - data send to daemon.
 452  *      size    - data buf size.
 453  */
 454 static int
 455 wusb_door_req(int cmd, door_arg_t *da, char *databuf, int size)
 456 {
 457         wusb_door_call_t dcall;
 458         int fd = -1;
 459 
 460         bzero(&dcall, sizeof (wusb_door_call_t));
 461         dcall.cmdss = cmd;
 462 
 463         /* copy data buffer */
 464         if (databuf) {
 465                 (void) memcpy(dcall.buf, databuf, size);
 466         }
 467 
 468         /* set rbuf to 0, unmap the data buf later */
 469         bzero(da, sizeof (door_arg_t));
 470         da->data_ptr = (char *)&dcall;
 471         da->data_size        = sizeof (wusb_door_call_t);
 472         da->rbuf     = 0;
 473         da->rsize    = 0;
 474 
 475         /* open door file */
 476         if ((fd = open(DOOR_FILE, O_RDONLY)) < 0) {
 477 
 478                 wusb_fail("daemon not started");
 479         }
 480 
 481         /* make door call */
 482         if (door_call(fd, da) != 0) {
 483                 (void) close(fd);
 484 
 485                 wusb_fail("daemon out of service:%s", strerror(errno));
 486         }
 487 
 488         (void) close(fd);
 489 
 490         if (da->data_size == 0) {
 491 
 492                 wusb_fail("no data from daemon");
 493         }
 494 
 495         return (WUSBA_SUCCESS);
 496 }
 497 
 498 /*
 499  * After each door call return, the first 2 bytes of the data
 500  * returned is encoded as the door call result from daemon.
 501  * This is a wrapper to get the door call result
 502  */
 503 uint16_t
 504 wusb_door_result(door_arg_t *da) {
 505         uint16_t rval = 0;
 506         (void) memcpy(&rval, da->data_ptr, sizeof (uint16_t));
 507 
 508         return (rval);
 509 }
 510 
 511 /*
 512  * Unmap the buffer after door call.
 513  * It is mandatory after any wusb_door_call since we set the rbuf to NULL
 514  * in the wusb_door_call. So any buffer returned is from the client proces.
 515  * See  door_call(3C) for more infor
 516  */
 517 static void
 518 wusb_door_free(door_arg_t *da)
 519 {
 520         (void) munmap(da->rbuf, da->rsize);
 521 }
 522 
 523 /*
 524  * wusbadmin remove-host routine
 525  *    remove-host  [-h host-id] [-f]
 526  */
 527 static void
 528 do_remove_host(int argc, char **argv)
 529 {
 530         do_host(argc, argv, WUSB_DCMD_REMOVE_HOST);
 531 }
 532 
 533 /*
 534  *  wusbadmin enable-host routine
 535  *      enable-host  [-h host-id]
 536  */
 537 static void
 538 do_enable_host(int argc, char **argv)
 539 {
 540         do_host(argc, argv, WUSB_DCMD_ENABLE_HOST);
 541 }
 542 
 543 /*
 544  *  wusbadmin disable-host routine
 545  *      disable-host [-h host-id] [-f]
 546  */
 547 static void
 548 do_disable_host(int argc, char **argv)
 549 {
 550         do_host(argc, argv, WUSB_DCMD_DISABLE_HOST);
 551 }
 552 
 553 /*
 554  * wusb do host routine. The wrapper for all host related
 555  * subcommand (enable-host, disable-host, remove-host).
 556  *      1. parser options/user input
 557  *      2. send wusb command to daemon
 558  */
 559 static void
 560 do_host(int argc, char **argv, int cmd)
 561 {
 562         wusb_dev_ctrl_t         hostctrl;
 563         door_arg_t              da;
 564 
 565         uint16_t rval = 0;
 566 
 567         /* parse options */
 568         bzero(&hostctrl, sizeof (wusb_dev_ctrl_t));
 569         do_host_args(argc, argv, cmd, &hostctrl);
 570 
 571         /* door call to daemon */
 572         (void) wusb_door_req(cmd, &da,
 573             (char *)&hostctrl, sizeof (wusb_dev_ctrl_t));
 574 
 575         rval = wusb_door_result(&da);
 576         wusb_door_free(&da);
 577 
 578         if (rval != WUSBADM_OK) {
 579                 wusb_fail("%s", wusb_strerror(rval));
 580         }
 581 }
 582 
 583 /*
 584  * wusb list option parser
 585  *      wusbadmin list [-h | -d] [-o field[,...]]
 586  */
 587 static void
 588 do_list_args(int argc, char **argv, char *option)
 589 {
 590         char fields = 0x0;
 591         int c;
 592 
 593         while ((c = getopt_long(argc, argv, ":hdo:",
 594             wusb_list_opts, NULL)) != -1) {
 595                 switch (c) {
 596                         case 'h':
 597                                 if (fields & WUSB_LIST_HOST) {
 598                                         wusb_usage("too many -h specified");
 599                                 }
 600                                 if (fields & WUSB_LIST_DEV) {
 601                                         wusb_usage("-h and -d used together");
 602                                 }
 603                                 fields |= WUSB_LIST_HOST;
 604                                 break;
 605                         case 'd':
 606                                 if (fields & WUSB_LIST_HOST) {
 607                                         wusb_usage("-h and -d used together");
 608                                 }
 609                                 if (fields & WUSB_LIST_DEV) {
 610                                         wusb_usage("too many -d specified");
 611                                 }
 612                                 fields |= WUSB_LIST_DEV;
 613                                 break;
 614                         case 'o':
 615                                 if (strlen(optarg) > 63) {
 616                                         wusb_usage("options too long");
 617                                 }
 618                                 (void) parse_option(&fields, optarg);
 619                                 break;
 620                         default:
 621                                 wusb_opterr(optopt, c);
 622                                 break;
 623                 }
 624         }
 625 
 626         if (optind < argc) {
 627                 wusb_usage("unrecognized options:%s", argv[optind++]);
 628         }
 629 
 630         /* if no option specified,print out all fields */
 631         fields |= (fields & WUSB_LIST_HD)? 0x00:WUSB_LIST_HD;
 632         fields |= (fields & WUSB_LIST_ALL)? 0x00:WUSB_LIST_ALL;
 633 
 634         *option = fields;
 635 
 636 
 637 }
 638 /*
 639  * Print the header for list subcommand.
 640  * Each title is right aligned with length of WUSB_FIELD_WIDTH
 641  * The following titles will be printed if the relative tags
 642  * marked in the fields option.
 643  *      ID      STATE           TYPE
 644  */
 645 static void
 646 wusb_prt_titles(char fields)
 647 {
 648         int i = 0;
 649         char option;
 650         for (option = WUSB_LIST_ID;
 651             option <= WUSB_LIST_STATE;
 652             option <<= 1, i++) {
 653                 if (fields & option) {
 654                         wusb_prt("%-*s", WUSB_FIELD_WIDTH,
 655                             WUSB_LIST_HEADER[i]);
 656                 }
 657         }
 658 
 659         (void) putchar('\n');
 660 
 661 }
 662 /*
 663  * Append the host-id / dev-id to the output buf.
 664  *   host-id  - 2 digits number (XX)
 665  *   dev-id   - 5 digits number (XX.XXX)
 666  *   See wusbadm (1M) for more
 667  */
 668 static void
 669 append_id(char *buf, wusb_device_info_t *devinfo)
 670 {
 671         char tmp[WUSB_MAX_LEN] = {'\0'};
 672 
 673         if (devinfo->dev) {
 674                 (void) snprintf(tmp, WUSB_MAX_LEN, "%02d.%03d",
 675                     devinfo->host, devinfo->dev);
 676         } else {
 677                 (void) snprintf(tmp, WUSB_MAX_LEN, "%02d", devinfo->host);
 678         }
 679         (void) snprintf(buf, WUSB_MAX_LEN, "%s%-*s",
 680             buf, WUSB_FIELD_WIDTH, tmp);
 681 }
 682 /*
 683  * Append state to the output buf.
 684  *   host       -  enabled/disabled
 685  *   device     -  connected/disconnected
 686  *   See wusbadm (1M) for more
 687  */
 688 static void
 689 append_state(char *buf, wusb_device_info_t *devinfo)
 690 {
 691         const char *WUSB_DEV_STATE_MSG[] = {
 692                 "disconnected",         /* WUSB_STATE_UNCONNTED         */
 693                 "connected",            /* WUSB_STATE_CONNTING          */
 694                 "connected",            /* WUSB_STATE_UNAUTHENTICATED   */
 695                 "connected",            /* WUSB_STATE_DEFAULT           */
 696                 "connected",            /* WUSB_STATE_ADDRESSED         */
 697                 "connected",            /* WUSB_STATE_CONFIGURED        */
 698                 "connected",            /* WUSB_STATE_SLEEPING          */
 699                 "connected",            /* WUSB_STATE_RECONNTING        */
 700                 NULL
 701         };
 702         const char *WUSB_HOST_STATE_MSG[] = {
 703                 "disconnected",         /* WUSB_HC_DISCONNTED           */
 704                 "disabled",             /* WUSB_HC_STOPPED              */
 705                 "enabled",              /* WUSB_HC_STARTED              */
 706                 "disabled",             /* WUSB_HC_CH_STOPPED           */
 707                 NULL
 708         };
 709         char tmp[WUSB_MAX_LEN] = {'\0'};
 710 
 711         if (devinfo->dev) {
 712 
 713                 /* append the state for device */
 714                 if (devinfo->stat > WUSB_STATE_RECONNTING) {
 715                         (void) snprintf(tmp, WUSB_MAX_LEN, "%s", "unknown");
 716                 } else {
 717                         (void) snprintf(tmp, WUSB_MAX_LEN, "%s",
 718                             WUSB_DEV_STATE_MSG[devinfo->stat]);
 719                 }
 720         } else {
 721                 /* append the state for host */
 722                 if (devinfo->stat > WUSB_HC_CH_STOPPED) {
 723                         (void) snprintf(tmp, WUSB_MAX_LEN, "%s", "unknown");
 724                 } else {
 725                         (void) snprintf(tmp, WUSB_MAX_LEN, "%s",
 726                             WUSB_HOST_STATE_MSG[devinfo->stat]);
 727                 }
 728         }
 729         (void) snprintf(buf, WUSB_MAX_LEN, "%s%-*s",
 730             buf, WUSB_FIELD_WIDTH, tmp);
 731 }
 732 
 733 
 734 /*
 735  * Appenend host/dev type to the ouput buf string
 736  * Currently map the file name to specific types
 737  * TODO: how to define the type
 738  */
 739 static void
 740 append_type(char *buf, wusb_device_info_t *devinfo)
 741 {
 742         (void) snprintf(buf, WUSB_MAX_LEN, "%s%-*s", buf, WUSB_FIELD_WIDTH,
 743             devinfo->type);
 744 }
 745 
 746 
 747 /*
 748  * This is core func to print wireless device list on systems.
 749  * Print the devinfo list entry with  option field
 750  */
 751 static void
 752 wusb_prt_lists(char fields, wusb_device_info_t *devinfo)
 753 {
 754         char buf[WUSB_MAX_LEN+1] = {'\0'};
 755         int i = 0;
 756         char opt = 0;
 757         void (*append_funcs[])(char *, wusb_device_info_t *) = {
 758                 append_id,
 759                 append_state,
 760                 append_type,
 761                 NULL
 762         };
 763 
 764         /* check if dev or host need to be print out */
 765         if ((devinfo->dev && !(fields & WUSB_LIST_DEV)) ||
 766             (!devinfo->dev && !(fields & WUSB_LIST_HOST))) {
 767                 return;
 768         }
 769 
 770         /* Append all the enabled fields to the output buf */
 771         for (i = 0, opt = WUSB_LIST_ID;
 772             opt <= WUSB_LIST_STATE;
 773             opt <<= 1, i++) {
 774                 if (fields & opt) {
 775                         append_funcs[i](buf, devinfo);
 776                 }
 777         }
 778 
 779         wusb_prt("%s\n", buf);
 780 }
 781 
 782 /*
 783  * wusb association option parser
 784  *      wusbadmin association [-h host-id] [[-c [-f] | -n] [-o]
 785  *      Note:Only cable association is supported now
 786  */
 787 static void
 788 do_asso_args(int argc, char **argv, wusb_asso_ctrl_t *asso_ctrl)
 789 {
 790         int c;
 791         int force = 0;
 792 
 793         while ((c = getopt_long(argc, argv, ":h:cfno", wusb_asso_opts, 0))
 794             != -1) {
 795                 switch (c) {
 796                         case 'h':
 797                                 parse_host_id(optarg, &(asso_ctrl->host));
 798                                 break;
 799                         case 'c':
 800                                 asso_ctrl->type |= ASSO_TYPE_CABLE;
 801                                 break;
 802                         case 'n':
 803                                 asso_ctrl->type |= ASSO_TYPE_NUMERIC;
 804                                 break;
 805                         case 'f':
 806                                 force = 1;
 807                                 break;
 808                         case 'o':
 809                                 asso_ctrl->onetime = 1;
 810                                 break;
 811                         default:
 812                                 wusb_opterr(optopt, c);
 813                                 break;
 814                 }
 815         }
 816 
 817         if (optind < argc) {
 818                 wusb_usage("unrecognized options:%s", argv[optind++]);
 819         }
 820 
 821         /* TODO: support cable association */
 822         if (asso_ctrl->type & ASSO_TYPE_NUMERIC) {
 823 
 824                 wusb_fail("Numeric association not supported");
 825         }
 826 
 827         /* get user input host id */
 828         if (!asso_ctrl->host) {
 829                 (void) input_host_id(&asso_ctrl->host);
 830         }
 831 
 832         /* get user input association type */
 833         if (!asso_ctrl->type) {
 834                 asso_ctrl->type |= ASSO_TYPE_CABLE;
 835                 /* Todo: Will be enabled after Numberic Assocation support */
 836 
 837 #ifdef NUMERIC_ENABLED
 838                 (void) input_asso_type(&asso_ctrl->type);
 839 #endif
 840         }
 841 
 842         /* get user input cable device to associate */
 843         if (asso_ctrl->type == ASSO_TYPE_CABLE) {
 844                 (void) select_cable_device(asso_ctrl->path);
 845         }
 846 
 847         /* confirm with user to continue or not */
 848         if (!force) {
 849                 wusb_prt("Associate device (%s) with host (%02d) via cable\n",
 850                     asso_ctrl->path, asso_ctrl->host);
 851                 user_confirm("Continue ");
 852         }
 853 
 854 }
 855 /*
 856  * Convert a string to an id (host-id/dev-id/cable-dev-id)
 857  * Fail if 0 returned, since each id is indexed from 1.
 858  * Widely used to handle user input ids.
 859  */
 860 static uint32_t
 861 str2id(char *arg)
 862 {
 863         uint32_t id = 0;
 864 
 865         /* check the string and generate int result */
 866         while (*arg) {
 867                 if (*arg < '0' || *arg > '9') {
 868 
 869                         return (0);
 870                 }
 871                 id = id*10+(*arg-'0');
 872                 arg++;
 873         }
 874 
 875         return (id);
 876 }
 877 
 878 static void
 879 parse_host_id(char *arg, uint8_t *host) {
 880         int len = strlen(arg);
 881 
 882         if ((len > WUSB_HOSTID_LEN) || (len == 0)) {
 883                 wusb_fail("host-id should be 2 digits");
 884         }
 885         if ((*host = str2id(arg)) == 0) {
 886                 wusb_fail("invalid host id:%s", arg);
 887         }
 888         if (find_dev_id(*host, 0) < 0) {
 889                 wusb_fail("host-id does not exist: %02d ", *host);
 890         }
 891 
 892         return;
 893 
 894 }
 895 /*
 896  * Get the host from user input.
 897  *      1. list all the host id from the daemon
 898  *      2. Ask user to input the host id
 899  *      3. Check host id and return
 900  */
 901 static int
 902 input_host_id(uint8_t *host)
 903 {
 904 
 905         char fields  = WUSB_LIST_HOST | WUSB_LIST_ALL;
 906         char buf[WUSB_MAX_LEN] = {'\0'};
 907         int i = 0;
 908 
 909 
 910 
 911         /* show avaialbe host id to usr */
 912         wusb_prt_titles(fields);
 913         for (i = 0; i < cnt; i++) {
 914                 wusb_prt_lists(fields, &dev_lists[i]);
 915         }
 916 
 917         /* get user input of host id */
 918         user_input("Please select 2 digits host-id:", buf, WUSB_MAX_LEN-1);
 919         parse_host_id(buf, host);
 920 
 921         return (WUSBA_SUCCESS);
 922 }
 923 static void
 924 input_dev_id(wusb_dev_ctrl_t *devctrl)
 925 {
 926 
 927         char fields  = WUSB_LIST_DEV | WUSB_LIST_ALL;
 928         char buf[WUSB_MAX_LEN] = {'\0'};
 929         int i = 0;
 930 
 931 
 932 
 933         /* show avaialbe host id to usr */
 934         wusb_prt_titles(fields);
 935         for (i = 0; i < cnt; i++) {
 936                 wusb_prt_lists(fields, &dev_lists[i]);
 937         }
 938 
 939         /* get user input of host id */
 940         user_input("Please select dev-id:", buf, WUSB_MAX_LEN-1);
 941 
 942         parse_dev_id(buf, devctrl);
 943 }
 944 static int
 945 find_dev_id(uint8_t host, uint16_t dev)
 946 {
 947         int rval = WUSBA_FAILURE;
 948         int i;
 949 
 950         for (i = 0; i < cnt; i++) {
 951                 if ((dev_lists[i].dev == dev) &&
 952                     (dev_lists[i].host == host)) {
 953                         rval = WUSBA_SUCCESS;
 954 
 955                         break;
 956                 }
 957         }
 958 
 959         return (rval);
 960 }
 961 
 962 /*
 963  * Select assocation type.
 964  *     - Cable
 965  *     - Numeric Not supported
 966  */
 967 #ifdef NUMERIC_ENABLED
 968 static int
 969 input_asso_type(uint8_t *asso_type)
 970 {
 971         char buf[15] = {'\0'};
 972 
 973         user_input("Select association type (c/n) :", buf, 14);
 974         if (strcasecmp(buf, "c") == 0) {
 975                 *asso_type = ASSO_TYPE_CABLE;
 976 
 977         } else if (strcasecmp(buf, "n") == 0) {
 978                 *asso_type = ASSO_TYPE_NUMERIC;
 979 
 980         } else {
 981 
 982                 wusb_usage("invalid association type");
 983         }
 984         return (WUSBA_SUCCESS);
 985 }
 986 #endif
 987 
 988 /*
 989  * Create a list contains all the cable devices on the system
 990  */
 991 static void
 992 init_cable_devices(dev_list_t **dev_lists, int *num)
 993 {
 994         struct dirent *entry = NULL;
 995         dev_list_t *_devlist = NULL;
 996 
 997         DIR *dirp = opendir(WUSB_HOST_PATH);
 998         char filename[MAXPATHLEN] = {'\0'};
 999 
1000         *num = 0;
1001         /*
1002          * walk on all the filename in the /dev/usb, check the filename
1003          * to see if it is a cable asso filename and add it to the devinfo
1004          * list if so
1005          */
1006         if (!dirp) {
1007                 wusb_fail("cable device not available");
1008         }
1009         while ((entry = readdir(dirp)) != NULL) {
1010                 /* searching for cable node */
1011                 if (strstr(entry->d_name, ASSO_CABLE_NAME) == NULL) {
1012                         continue;
1013                 }
1014                 (void) snprintf(filename, MAXPATHLEN, "%s/%s",
1015                     WUSB_HOST_PATH, entry->d_name);
1016 
1017                 /* add the filename to the dev list */
1018                 if (_devlist == NULL) {
1019                         _devlist = malloc(sizeof (dev_list_t));
1020                         *dev_lists = _devlist;
1021                 } else {
1022                         _devlist->next = malloc(sizeof (dev_list_t));
1023                         _devlist = _devlist->next;
1024                 }
1025                 /* this need to be freed */
1026                 (void) snprintf(_devlist->path, MAXPATHLEN,
1027                     "%s", filename);
1028 
1029                 _devlist->next = NULL;
1030 
1031                 /* increase the list number */
1032                 (*num)++;
1033         }
1034         (void) closedir(dirp);
1035 }
1036 /* Free the devlist created for cable device */
1037 static void
1038 free_devlist(dev_list_t *dev_list)
1039 {
1040         dev_list_t *head = dev_list;
1041         while (head) {
1042                 head = dev_list->next;
1043                 free(dev_list);
1044                 dev_list = head;
1045         }
1046 }
1047 
1048 /* find the cable dev with the user-inputed index */
1049 static dev_list_t *
1050 get_cable_dev(dev_list_t *dev_list, int index)
1051 {
1052         int i = 1;
1053         while ((i != index) && dev_list) {
1054                 dev_list = dev_list->next;
1055                 i++;
1056         }
1057 
1058         return (dev_list);
1059 }
1060 /* print the cable devlist with index */
1061 static void
1062 show_devlist(dev_list_t *dev_list)
1063 {
1064         /* show all the cable devices to user */
1065         int index = 1;
1066         wusb_prt("Cable devices on the system:\n");
1067         while (dev_list) {
1068                 wusb_prt("%03d. %s\n", index, dev_list->path);
1069                 dev_list = dev_list->next;
1070                 index++;
1071         }
1072 
1073 }
1074 /*
1075  * when doing association, all the cable devices on the system
1076  * should be print out to the user
1077  */
1078 static int
1079 select_cable_device(char *device)
1080 {
1081         /* cable association */
1082         char buf[32];
1083         int cableid = 1;
1084 
1085         dev_list_t *head = NULL;
1086         dev_list_t *tmp  = NULL;
1087         int devnum = 0;
1088 
1089         /* get all the cable dev on the system */
1090         init_cable_devices(&head, &devnum);
1091 
1092         /* Get the device name as user input */
1093         if (!head) {
1094                 wusb_fail("no cable devices found ");
1095         }
1096 
1097         if (devnum != 1) {
1098                 show_devlist(head);
1099 
1100                 /* get the user input of the cable dev index */
1101                 user_input("Select cable device to associate:", buf, 19);
1102                 if (strlen(buf) != 3) {
1103                         wusb_fail("cable device id should be 3 digits");
1104                 }
1105                 cableid = str2id(buf);
1106 
1107                 /* check user iput */
1108                 if ((cableid <= 0) || (cableid > devnum)) {
1109                         free_devlist(head);
1110 
1111                         wusb_fail("invalid cable device ");
1112                 }
1113 
1114         } else {
1115                 /* if only one dev exist, use it without asking user */
1116                 cableid = 1;
1117         }
1118 
1119         /* find the device to associate */
1120         tmp = get_cable_dev(head, cableid);
1121         (void) snprintf(device, MAXPATHLEN, "%s", tmp->path);
1122 
1123         /* free the list */
1124         free_devlist(head);
1125 
1126         return (WUSBA_SUCCESS);
1127 
1128 }
1129 /*
1130  * Parse the -o option for wusbadm list
1131  */
1132 static int
1133 parse_option(char *fields, const char *optarg)
1134 {
1135 
1136         char *lasts = NULL, *token = NULL;
1137         char buf[64] = { '\0' };
1138 
1139         (void) snprintf(buf, 64, "%s", optarg);
1140         if ((token = strtok_r(buf, ",", &lasts)) != 0) {
1141                 parse_subopts(fields, token);
1142                 while ((token = strtok_r(NULL, ",", &lasts))) {
1143                         parse_subopts(fields, token);
1144                 }
1145         }
1146 
1147         return (WUSBA_SUCCESS);
1148 
1149 }
1150 
1151 /*
1152  * wusbadmin list
1153  * parse the sub option extracted from -o options
1154  */
1155 static void
1156 parse_subopts(char *fields, const char *str)
1157 {
1158         int i;
1159         char opt;
1160         for (i = 0, opt = WUSB_LIST_ID; opt <= WUSB_LIST_STATE; i++) {
1161                 if (strcasecmp(str, WUSB_LIST_HEADER[i]) == 0) {
1162                         *fields |= opt;
1163                         break;
1164                 }
1165                 opt = opt << 1;
1166         }
1167 
1168         if (opt > WUSB_LIST_STATE) {
1169 
1170                 wusb_usage("unrecognized options:%s", str);
1171         }
1172 
1173 }
1174 
1175 /*
1176  * Device id parser for remove-dev
1177  * dev id is 5 digits with format XX.XXX
1178  */
1179 void
1180 parse_dev_id(const char *arg, wusb_dev_ctrl_t *devctrl)
1181 {
1182         char buf[WUSB_DEVID_LEN+1] = {'\0'};
1183         char *tmp = NULL;
1184 
1185         if (strlen(arg) > WUSB_DEVID_LEN) goto fail;
1186 
1187         (void) snprintf(buf, WUSB_DEVID_LEN+1, "%s", arg);
1188 
1189         if ((tmp = strchr(buf, '.')) == NULL) goto fail;
1190         /* get host id */
1191         *tmp = '\0';
1192         if ((devctrl->host = str2id(buf)) == 0) {
1193                 goto fail;
1194         }
1195 
1196         /* get device id */
1197         if ((devctrl->dev = str2id(tmp+1)) == 0) {
1198                 goto fail;
1199         }
1200 
1201         if (find_dev_id(devctrl->host, devctrl->dev) < 0) {
1202                 wusb_fail("dev-id does not exist: %02d.%03d ",
1203                     devctrl->host, devctrl->dev);
1204         }
1205 
1206         return;
1207 fail:
1208         wusb_fail("unknown device id:%s", arg);
1209 
1210 }
1211 /*
1212  * remove-dev options parser
1213  *      remove-dev   [[-d dev-id] | [-h host-id]] [-f]
1214  */
1215 static void
1216 do_remove_dev_args(int argc, char **argv, wusb_dev_ctrl_t *devctrl)
1217 {
1218         int c;
1219         int force = 0;
1220         bzero(devctrl, sizeof (wusb_dev_ctrl_t));
1221 
1222         while ((c = getopt_long(argc, argv, ":h:d:f",
1223             wusb_rmdev_opts, NULL)) != -1) {
1224                 switch (c) {
1225                         case 'h':
1226                                 if (devctrl->dev) {
1227                                         wusb_usage("-h -d can not be"
1228                                             "used together");
1229                                 }
1230                                 if (devctrl->host) {
1231                                         wusb_usage("multi -h is not allowed");
1232                                 }
1233 
1234                                 /* get 2 digit host id */
1235                                 parse_host_id(optarg, &(devctrl->host));
1236 
1237                                 break;
1238 
1239                         case 'd':
1240                                 if (devctrl->dev) {
1241                                         wusb_usage("multi -d is not allowed");
1242                                 }
1243                                 if (devctrl->host) {
1244                                         wusb_usage("-h -d can not be"
1245                                             "used together");
1246                                 }
1247                                 /* parse devid */
1248                                 (void) parse_dev_id(optarg, devctrl);
1249                                 break;
1250                         case 'f':
1251                                 force = 1;
1252                                 break;
1253                         default:
1254                                 wusb_opterr(optopt, c);
1255                                 break;
1256 
1257                 }
1258         }
1259 
1260         if (optind < argc) {
1261                 wusb_usage("unrecognized options:%s", argv[optind++]);
1262         }
1263         if ((devctrl->host == 0) && (devctrl->dev == 0)) {
1264                 input_dev_id(devctrl);
1265         }
1266 
1267         /* confirm with user to continue or not */
1268         if (!force) {
1269                 if (devctrl->dev) {
1270                         wusb_prt("Remove the device's association information"
1271                             " of device (%02d.%03d) from system.\nThis device"
1272                             " can not be connected with the host until it is"
1273                             " associated again.\n",
1274                             devctrl->host, devctrl->dev);
1275                 } else {
1276                         wusb_prt("Remove the information of all the devices "
1277                             "associated with host (%02d) from the system\n"
1278                             "All the devices asociated with the host can not"
1279                             " be connected with it until they are associated"
1280                             " again.\n", devctrl->host);
1281                 }
1282                 user_confirm("Continue ");
1283         }
1284 }
1285 /*
1286  * Confirm with user continue or not
1287  *    info: the information shown to user before input
1288  */
1289 static void
1290 user_confirm(char *info)
1291 {
1292         char yesorno[20];
1293 
1294         wusb_prt(info);
1295         user_input("(yes/no): ", yesorno, 19);
1296         if (strcasecmp(yesorno, "no") == 0) {
1297                 wusb_fail("");
1298         }
1299         if (strcasecmp(yesorno, "n") == 0) {
1300                 wusb_fail("");
1301         }
1302         if (strcasecmp(yesorno, "yes") == 0) {
1303                 return;
1304         }
1305         if (strcasecmp(yesorno, "y") == 0) {
1306                 return;
1307         }
1308         wusb_fail("illegal input: %s", yesorno);
1309 }
1310 /*
1311  * Get user input
1312  *   msg(in): infor shown to user before input
1313  *   length(in): buf size to save uer input
1314  *   buf(out): user input saved in buffer
1315  */
1316 static void
1317 user_input(char *msg, char *buf, int length)
1318 {
1319         int i = 0, b;
1320 
1321         wusb_prt(msg);
1322         /*CONSTCOND*/
1323         while (1) {
1324                 b = getc(stdin);
1325                 if (b == '\n' || b == '\0' || b == EOF) {
1326                         if (i < length)
1327                                 buf[i] = 0;
1328                         break;
1329                 }
1330                 if (i < length)
1331                         buf[i] = b;
1332                 i++;
1333         }
1334         if (i >= length) {
1335                 buf[length] = 0;
1336         }
1337 
1338 }
1339 /*
1340  * do host options parser
1341  *      remove-host  [-h host-id] [-f]
1342  *      enable-host  [-h host-id]
1343  *      disable-host [-h host-id] [-f]
1344  */
1345 static void
1346 do_host_args(int argc, char **argv, int cmd, wusb_dev_ctrl_t *hostctrl)
1347 {
1348         int c;
1349         int force = 0;
1350 
1351         while ((c = getopt_long(argc, argv, ":h:f",
1352             wusb_host_opts, NULL)) != -1) {
1353                 switch (c) {
1354                         case 'h':
1355                                 if (hostctrl->host) {
1356                                         wusb_usage("multi -h is not allowed");
1357                                 }
1358                                 /* 2 digits host id */
1359                                 parse_host_id(optarg, &(hostctrl->host));
1360 
1361                                 break;
1362 
1363                         case 'f':
1364                                 /* enable host does not need -f */
1365                                 if (cmd == WUSB_DCMD_ENABLE_HOST) {
1366                                         wusb_opterr(optopt, c);
1367                                 }
1368                                 force = 1;
1369                                 break;
1370                         default:
1371                                 wusb_opterr(optopt, c);
1372                                 break;
1373 
1374                 }
1375         }
1376         if (optind < argc) {
1377                 wusb_usage("unrecognized options:%s", argv[optind++]);
1378         }
1379         /*
1380          * all the host related command can be used without a specific
1381          * host-id, so list all the hosts avalable to users for selection
1382          */
1383         if (hostctrl->host == 0) {
1384                 (void) input_host_id(&(hostctrl->host));
1385         }
1386 
1387 
1388         /* confirm with user to continue or not */
1389         if (!force && (cmd != WUSB_DCMD_ENABLE_HOST)) {
1390                 switch (cmd) {
1391                         case WUSB_DCMD_DISABLE_HOST:
1392                                 wusb_prt("Disable host (%02d).\nAll the"
1393                                     " devices connected with the host will be"
1394                                     " disconnected\n", hostctrl->host);
1395                                 break;
1396 
1397                         case WUSB_DCMD_REMOVE_HOST:
1398                                 wusb_prt("Remove host (%02d).\nAll the"
1399                                     " association with the host will be"
1400                                     " removed\n", hostctrl->host);
1401                                 break;
1402                         default:
1403                                 break;
1404                 }
1405                 user_confirm("Continue");
1406         }
1407 
1408 }
1409 
1410 static void
1411 wusb_check_auth(const char *auth) {
1412 
1413         uid_t   uid = geteuid();
1414         if (chk_auths(uid, auth) < 0) {
1415                 wusb_fail("%s", wusb_strerror(WUSBADM_AUTH_FAILURE));
1416         }
1417 
1418 }
1419 /*
1420  * wusb exit helper funcstion
1421  *     wusb_fail or wusb_usage
1422  */
1423 static void
1424 wusb_fail(const char *format, ...)
1425 {
1426         va_list alist;
1427 
1428         format = gettext(format);
1429         (void) fprintf(stderr, gettext("wusbadm: "));
1430         va_start(alist, format);
1431         (void) vfprintf(stderr, format, alist);
1432         va_end(alist);
1433         (void) fprintf(stderr, "\n");
1434 
1435         wusb_free_list(dev_lists);
1436         exit(WUSB_EXIT_FAILURE);
1437 }
1438 static void
1439 wusb_usage(const char *format, ...)
1440 {
1441         va_list alist;
1442 
1443         format = gettext(format);
1444         (void) fprintf(stderr, gettext("wusbadm: "));
1445         va_start(alist, format);
1446         (void) vfprintf(stderr, format, alist);
1447         va_end(alist);
1448         (void) fprintf(stderr, "\n");
1449         usage();
1450 
1451         wusb_free_list(dev_lists);
1452         exit(WUSB_EXIT_USAGE);
1453 }
1454 
1455 
1456 /* wusb print helper func */
1457 static void
1458 wusb_prt(const char *format, ...)
1459 {
1460         va_list alist;
1461 
1462         format = gettext(format);
1463         va_start(alist, format);
1464         (void) vfprintf(stdout, format, alist);
1465         va_end(alist);
1466 }
1467 
1468 /* wusb option failuer func */
1469 static void
1470 wusb_opterr(int opt, int opterr)
1471 {
1472         switch (opterr) {
1473                 case ':':
1474                         wusb_usage("option '-%c' requires a value", opt);
1475                         break;
1476                 case '?':
1477                 default:
1478                         wusb_usage("unrecognized option '-%c'", opt);
1479                         break;
1480         }
1481 }