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 }