5801 nuke big file scanner (bfs)
[unleashed.git] / usr / src / cmd / wusbadm / wusbadm.c
blob94635e1ab512480608de47015ac7aca4a6027f2a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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"
45 * EXIT STATUS
46 * The following exit values are returned:
47 * 0 Successful operation
48 * 1 Error: the operation failed.
49 * 2 Usage error.
51 #define WUSB_EXIT_SUCCESS 0
52 #define WUSB_EXIT_FAILURE 1
53 #define WUSB_EXIT_USAGE 2
57 #define ASSO_CABLE_NAME "wusb_ca"
59 #define WUSB_MAX_LEN 255
61 #define WUSB_HOSTID_LEN 2
62 #define WUSB_DEVID_LEN 6
64 /* wusba admin list options */
65 #define WUSB_FIELD_WIDTH 20
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)
75 /* cable device list */
76 typedef struct dev_list {
77 char path[MAXPATHLEN];
78 struct dev_list *next;
79 } dev_list_t;
81 static wusb_device_info_t *dev_lists = NULL;
82 static uint32_t cnt = 0;
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);
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 *);
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);
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);
107 /* string translation helpers */
108 static uint32_t str2id(char *);
109 static void usage();
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}
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
125 static void do_list(int, char **);
126 static void do_list_args(int, char **, char *);
128 static void parse_subopts(char *, const char *);
129 static int parse_option(char *, const char *);
131 static void wusb_prt_titles(char);
132 static void wusb_prt_lists(char, wusb_device_info_t *);
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 *);
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}
148 static void do_associate(int, char **);
149 static void do_asso_args(int, char **, wusb_asso_ctrl_t *);
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 *);
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}
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}
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 **);
179 static void do_remove_dev(int, char **);
180 static void do_remove_dev_args(int, char **, wusb_dev_ctrl_t *);
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"}
201 char *
202 wusb_strerror(int err)
204 if (err < 0 || err > WUSBADM_FAILURE) {
206 return (wusb_errors[WUSBADM_FAILURE].errmsg);
209 return (wusb_errors[err].errmsg);
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
226 main(int argc, char **argv)
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}
244 (void) setlocale(LC_ALL, "");
246 #ifndef TEXT_DOMAIN
247 #define TEXT_DOMAIN "SYS_TEST"
248 #endif
249 (void) textdomain(TEXT_DOMAIN);
251 if (argc <= 1) {
252 usage();
253 exit(WUSB_EXIT_USAGE);
256 /* start wusb damemon */
257 if (strcmp(argv[1], "--daemon") == 0) {
258 (void) daemonize();
259 exit(WUSB_EXIT_SUCCESS);
263 /* wusbadm entry */
264 for (i = 0; cmd_list[i].cmd; i++) {
265 if (strcmp(cmd_list[i].cmd, argv[1]) == 0) {
266 break;
269 if (!cmd_list[i].cmd) {
270 wusb_usage("unknown option %s", argv[1]);
272 wusb_check_auth(cmd_list[i].auth);
274 wusb_load_list(&dev_lists, &cnt);
276 cmd_list[i].func(argc - 1, &argv[1]);
278 wusb_free_list(dev_lists);
279 return (WUSB_EXIT_SUCCESS);
282 static void
283 usage()
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");
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
303 static void
304 do_list(int argc, char **argv)
306 char fields = 0x0;
307 int i;
309 /* parse the list options */
310 do_list_args(argc, argv, &fields);
313 /* print list title */
314 wusb_prt_titles(fields);
316 /* print out the result */
317 for (i = 0; i < cnt; i++) {
318 wusb_prt_lists(fields, &dev_lists[i]);
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
330 static void
331 do_associate(int argc, char **argv)
333 door_arg_t da;
334 wusb_asso_ctrl_t asso_ctrl;
335 uint16_t rval = 0;
337 /* Get association options */
338 bzero(&asso_ctrl, sizeof (wusb_asso_ctrl_t));
339 do_asso_args(argc, argv, &asso_ctrl);
341 /* open door file */
342 (void) wusb_door_req(WUSB_DCMD_ASSOCIATE, &da,
343 (char *)&asso_ctrl, sizeof (wusb_asso_ctrl_t));
345 /* association result */
346 rval = wusb_door_result(&da);
348 wusb_door_free(&da);
350 if (rval != WUSBADM_OK) {
351 wusb_fail("%s", wusb_strerror(rval));
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
363 static void
364 do_remove_dev(int argc, char **argv)
366 wusb_dev_ctrl_t devctrl;
367 door_arg_t da;
369 uint16_t rval = WUSBADM_OK;
371 /* parse options */
372 bzero(&devctrl, sizeof (wusb_dev_ctrl_t));
373 do_remove_dev_args(argc, argv, &devctrl);
375 /* send command to daemon */
376 (void) wusb_door_req(WUSB_DCMD_REMOVE_DEV, &da,
377 (char *)&devctrl, sizeof (wusb_dev_ctrl_t));
380 rval = wusb_door_result(&da);
382 wusb_door_free(&da);
384 if (rval != WUSBADM_OK) {
385 wusb_fail("%s", wusb_strerror(rval));
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.
396 static void
397 wusb_load_list(wusb_device_info_t **cc_list, uint32_t *cnt)
399 door_arg_t da;
401 size_t buflen = 0;
402 uint32_t num = 0;
403 uint16_t rval = WUSBADM_OK;
405 /* send command to daemon */
406 (void) wusb_door_req(WUSB_DCMD_LIST_DATA, &da, 0, 0);
408 rval = wusb_door_result(&da);
409 if (rval != WUSBADM_OK) {
410 wusb_door_free(&da);
412 wusb_fail("%s", wusb_strerror(rval));
415 /* number of the devinfo list */
416 (void) memcpy(&num, da.data_ptr+sizeof (uint16_t), sizeof (uint32_t));
418 if (num) {
420 buflen = (num) * sizeof (wusb_device_info_t);
421 if ((*cc_list = malloc(buflen)) == NULL) {
422 wusb_door_free(&da);
424 wusb_fail("list: malloc buffer failed");
427 (void) memcpy(*cc_list,
428 da.data_ptr + sizeof (uint32_t) + sizeof (uint16_t),
429 buflen);
431 *cnt = num;
433 /* unmap the buffer */
434 wusb_door_free(&da);
436 static void
437 wusb_free_list(wusb_device_info_t *cc_list)
439 if (cc_list) {
440 free(cc_list);
442 cnt = 0;
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.
454 static int
455 wusb_door_req(int cmd, door_arg_t *da, char *databuf, int size)
457 wusb_door_call_t dcall;
458 int fd = -1;
460 bzero(&dcall, sizeof (wusb_door_call_t));
461 dcall.cmdss = cmd;
463 /* copy data buffer */
464 if (databuf) {
465 (void) memcpy(dcall.buf, databuf, size);
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;
475 /* open door file */
476 if ((fd = open(DOOR_FILE, O_RDONLY)) < 0) {
478 wusb_fail("daemon not started");
481 /* make door call */
482 if (door_call(fd, da) != 0) {
483 (void) close(fd);
485 wusb_fail("daemon out of service:%s", strerror(errno));
488 (void) close(fd);
490 if (da->data_size == 0) {
492 wusb_fail("no data from daemon");
495 return (WUSBA_SUCCESS);
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
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));
508 return (rval);
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
517 static void
518 wusb_door_free(door_arg_t *da)
520 (void) munmap(da->rbuf, da->rsize);
524 * wusbadmin remove-host routine
525 * remove-host [-h host-id] [-f]
527 static void
528 do_remove_host(int argc, char **argv)
530 do_host(argc, argv, WUSB_DCMD_REMOVE_HOST);
534 * wusbadmin enable-host routine
535 * enable-host [-h host-id]
537 static void
538 do_enable_host(int argc, char **argv)
540 do_host(argc, argv, WUSB_DCMD_ENABLE_HOST);
544 * wusbadmin disable-host routine
545 * disable-host [-h host-id] [-f]
547 static void
548 do_disable_host(int argc, char **argv)
550 do_host(argc, argv, WUSB_DCMD_DISABLE_HOST);
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
559 static void
560 do_host(int argc, char **argv, int cmd)
562 wusb_dev_ctrl_t hostctrl;
563 door_arg_t da;
565 uint16_t rval = 0;
567 /* parse options */
568 bzero(&hostctrl, sizeof (wusb_dev_ctrl_t));
569 do_host_args(argc, argv, cmd, &hostctrl);
571 /* door call to daemon */
572 (void) wusb_door_req(cmd, &da,
573 (char *)&hostctrl, sizeof (wusb_dev_ctrl_t));
575 rval = wusb_door_result(&da);
576 wusb_door_free(&da);
578 if (rval != WUSBADM_OK) {
579 wusb_fail("%s", wusb_strerror(rval));
584 * wusb list option parser
585 * wusbadmin list [-h | -d] [-o field[,...]]
587 static void
588 do_list_args(int argc, char **argv, char *option)
590 char fields = 0x0;
591 int c;
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");
600 if (fields & WUSB_LIST_DEV) {
601 wusb_usage("-h and -d used together");
603 fields |= WUSB_LIST_HOST;
604 break;
605 case 'd':
606 if (fields & WUSB_LIST_HOST) {
607 wusb_usage("-h and -d used together");
609 if (fields & WUSB_LIST_DEV) {
610 wusb_usage("too many -d specified");
612 fields |= WUSB_LIST_DEV;
613 break;
614 case 'o':
615 if (strlen(optarg) > 63) {
616 wusb_usage("options too long");
618 (void) parse_option(&fields, optarg);
619 break;
620 default:
621 wusb_opterr(optopt, c);
622 break;
626 if (optind < argc) {
627 wusb_usage("unrecognized options:%s", argv[optind++]);
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;
634 *option = fields;
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
645 static void
646 wusb_prt_titles(char fields)
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]);
659 (void) putchar('\n');
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
668 static void
669 append_id(char *buf, wusb_device_info_t *devinfo)
671 char tmp[WUSB_MAX_LEN] = {'\0'};
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);
679 (void) snprintf(buf, WUSB_MAX_LEN, "%s%-*s",
680 buf, WUSB_FIELD_WIDTH, tmp);
683 * Append state to the output buf.
684 * host - enabled/disabled
685 * device - connected/disconnected
686 * See wusbadm (1M) for more
688 static void
689 append_state(char *buf, wusb_device_info_t *devinfo)
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
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
709 char tmp[WUSB_MAX_LEN] = {'\0'};
711 if (devinfo->dev) {
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]);
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]);
729 (void) snprintf(buf, WUSB_MAX_LEN, "%s%-*s",
730 buf, WUSB_FIELD_WIDTH, tmp);
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
739 static void
740 append_type(char *buf, wusb_device_info_t *devinfo)
742 (void) snprintf(buf, WUSB_MAX_LEN, "%s%-*s", buf, WUSB_FIELD_WIDTH,
743 devinfo->type);
748 * This is core func to print wireless device list on systems.
749 * Print the devinfo list entry with option field
751 static void
752 wusb_prt_lists(char fields, wusb_device_info_t *devinfo)
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
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;
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);
779 wusb_prt("%s\n", buf);
783 * wusb association option parser
784 * wusbadmin association [-h host-id] [[-c [-f] | -n] [-o]
785 * Note:Only cable association is supported now
787 static void
788 do_asso_args(int argc, char **argv, wusb_asso_ctrl_t *asso_ctrl)
790 int c;
791 int force = 0;
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;
817 if (optind < argc) {
818 wusb_usage("unrecognized options:%s", argv[optind++]);
821 /* TODO: support cable association */
822 if (asso_ctrl->type & ASSO_TYPE_NUMERIC) {
824 wusb_fail("Numeric association not supported");
827 /* get user input host id */
828 if (!asso_ctrl->host) {
829 (void) input_host_id(&asso_ctrl->host);
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 */
837 #ifdef NUMERIC_ENABLED
838 (void) input_asso_type(&asso_ctrl->type);
839 #endif
842 /* get user input cable device to associate */
843 if (asso_ctrl->type == ASSO_TYPE_CABLE) {
844 (void) select_cable_device(asso_ctrl->path);
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 ");
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.
860 static uint32_t
861 str2id(char *arg)
863 uint32_t id = 0;
865 /* check the string and generate int result */
866 while (*arg) {
867 if (*arg < '0' || *arg > '9') {
869 return (0);
871 id = id*10+(*arg-'0');
872 arg++;
875 return (id);
878 static void
879 parse_host_id(char *arg, uint8_t *host) {
880 int len = strlen(arg);
882 if ((len > WUSB_HOSTID_LEN) || (len == 0)) {
883 wusb_fail("host-id should be 2 digits");
885 if ((*host = str2id(arg)) == 0) {
886 wusb_fail("invalid host id:%s", arg);
888 if (find_dev_id(*host, 0) < 0) {
889 wusb_fail("host-id does not exist: %02d ", *host);
892 return;
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
901 static int
902 input_host_id(uint8_t *host)
905 char fields = WUSB_LIST_HOST | WUSB_LIST_ALL;
906 char buf[WUSB_MAX_LEN] = {'\0'};
907 int i = 0;
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]);
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);
921 return (WUSBA_SUCCESS);
923 static void
924 input_dev_id(wusb_dev_ctrl_t *devctrl)
927 char fields = WUSB_LIST_DEV | WUSB_LIST_ALL;
928 char buf[WUSB_MAX_LEN] = {'\0'};
929 int i = 0;
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]);
939 /* get user input of host id */
940 user_input("Please select dev-id:", buf, WUSB_MAX_LEN-1);
942 parse_dev_id(buf, devctrl);
944 static int
945 find_dev_id(uint8_t host, uint16_t dev)
947 int rval = WUSBA_FAILURE;
948 int i;
950 for (i = 0; i < cnt; i++) {
951 if ((dev_lists[i].dev == dev) &&
952 (dev_lists[i].host == host)) {
953 rval = WUSBA_SUCCESS;
955 break;
959 return (rval);
963 * Select assocation type.
964 * - Cable
965 * - Numeric Not supported
967 #ifdef NUMERIC_ENABLED
968 static int
969 input_asso_type(uint8_t *asso_type)
971 char buf[15] = {'\0'};
973 user_input("Select association type (c/n) :", buf, 14);
974 if (strcasecmp(buf, "c") == 0) {
975 *asso_type = ASSO_TYPE_CABLE;
977 } else if (strcasecmp(buf, "n") == 0) {
978 *asso_type = ASSO_TYPE_NUMERIC;
980 } else {
982 wusb_usage("invalid association type");
984 return (WUSBA_SUCCESS);
986 #endif
989 * Create a list contains all the cable devices on the system
991 static void
992 init_cable_devices(dev_list_t **dev_lists, int *num)
994 struct dirent *entry = NULL;
995 dev_list_t *_devlist = NULL;
997 DIR *dirp = opendir(WUSB_HOST_PATH);
998 char filename[MAXPATHLEN] = {'\0'};
1000 *num = 0;
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
1006 if (!dirp) {
1007 wusb_fail("cable device not available");
1009 while ((entry = readdir(dirp)) != NULL) {
1010 /* searching for cable node */
1011 if (strstr(entry->d_name, ASSO_CABLE_NAME) == NULL) {
1012 continue;
1014 (void) snprintf(filename, MAXPATHLEN, "%s/%s",
1015 WUSB_HOST_PATH, entry->d_name);
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;
1025 /* this need to be freed */
1026 (void) snprintf(_devlist->path, MAXPATHLEN,
1027 "%s", filename);
1029 _devlist->next = NULL;
1031 /* increase the list number */
1032 (*num)++;
1034 (void) closedir(dirp);
1036 /* Free the devlist created for cable device */
1037 static void
1038 free_devlist(dev_list_t *dev_list)
1040 dev_list_t *head = dev_list;
1041 while (head) {
1042 head = dev_list->next;
1043 free(dev_list);
1044 dev_list = head;
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)
1052 int i = 1;
1053 while ((i != index) && dev_list) {
1054 dev_list = dev_list->next;
1055 i++;
1058 return (dev_list);
1060 /* print the cable devlist with index */
1061 static void
1062 show_devlist(dev_list_t *dev_list)
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++;
1075 * when doing association, all the cable devices on the system
1076 * should be print out to the user
1078 static int
1079 select_cable_device(char *device)
1081 /* cable association */
1082 char buf[32];
1083 int cableid = 1;
1085 dev_list_t *head = NULL;
1086 dev_list_t *tmp = NULL;
1087 int devnum = 0;
1089 /* get all the cable dev on the system */
1090 init_cable_devices(&head, &devnum);
1092 /* Get the device name as user input */
1093 if (!head) {
1094 wusb_fail("no cable devices found ");
1097 if (devnum != 1) {
1098 show_devlist(head);
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");
1105 cableid = str2id(buf);
1107 /* check user iput */
1108 if ((cableid <= 0) || (cableid > devnum)) {
1109 free_devlist(head);
1111 wusb_fail("invalid cable device ");
1114 } else {
1115 /* if only one dev exist, use it without asking user */
1116 cableid = 1;
1119 /* find the device to associate */
1120 tmp = get_cable_dev(head, cableid);
1121 (void) snprintf(device, MAXPATHLEN, "%s", tmp->path);
1123 /* free the list */
1124 free_devlist(head);
1126 return (WUSBA_SUCCESS);
1130 * Parse the -o option for wusbadm list
1132 static int
1133 parse_option(char *fields, const char *optarg)
1136 char *lasts = NULL, *token = NULL;
1137 char buf[64] = { '\0' };
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);
1147 return (WUSBA_SUCCESS);
1152 * wusbadmin list
1153 * parse the sub option extracted from -o options
1155 static void
1156 parse_subopts(char *fields, const char *str)
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;
1165 opt = opt << 1;
1168 if (opt > WUSB_LIST_STATE) {
1170 wusb_usage("unrecognized options:%s", str);
1176 * Device id parser for remove-dev
1177 * dev id is 5 digits with format XX.XXX
1179 void
1180 parse_dev_id(const char *arg, wusb_dev_ctrl_t *devctrl)
1182 char buf[WUSB_DEVID_LEN+1] = {'\0'};
1183 char *tmp = NULL;
1185 if (strlen(arg) > WUSB_DEVID_LEN) goto fail;
1187 (void) snprintf(buf, WUSB_DEVID_LEN+1, "%s", arg);
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;
1196 /* get device id */
1197 if ((devctrl->dev = str2id(tmp+1)) == 0) {
1198 goto fail;
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);
1206 return;
1207 fail:
1208 wusb_fail("unknown device id:%s", arg);
1212 * remove-dev options parser
1213 * remove-dev [[-d dev-id] | [-h host-id]] [-f]
1215 static void
1216 do_remove_dev_args(int argc, char **argv, wusb_dev_ctrl_t *devctrl)
1218 int c;
1219 int force = 0;
1220 bzero(devctrl, sizeof (wusb_dev_ctrl_t));
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");
1230 if (devctrl->host) {
1231 wusb_usage("multi -h is not allowed");
1234 /* get 2 digit host id */
1235 parse_host_id(optarg, &(devctrl->host));
1237 break;
1239 case 'd':
1240 if (devctrl->dev) {
1241 wusb_usage("multi -d is not allowed");
1243 if (devctrl->host) {
1244 wusb_usage("-h -d can not be"
1245 "used together");
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;
1260 if (optind < argc) {
1261 wusb_usage("unrecognized options:%s", argv[optind++]);
1263 if ((devctrl->host == 0) && (devctrl->dev == 0)) {
1264 input_dev_id(devctrl);
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);
1282 user_confirm("Continue ");
1286 * Confirm with user continue or not
1287 * info: the information shown to user before input
1289 static void
1290 user_confirm(char *info)
1292 char yesorno[20];
1294 wusb_prt(info);
1295 user_input("(yes/no): ", yesorno, 19);
1296 if (strcasecmp(yesorno, "no") == 0) {
1297 wusb_fail("");
1299 if (strcasecmp(yesorno, "n") == 0) {
1300 wusb_fail("");
1302 if (strcasecmp(yesorno, "yes") == 0) {
1303 return;
1305 if (strcasecmp(yesorno, "y") == 0) {
1306 return;
1308 wusb_fail("illegal input: %s", yesorno);
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
1316 static void
1317 user_input(char *msg, char *buf, int length)
1319 int i = 0, b;
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;
1330 if (i < length)
1331 buf[i] = b;
1332 i++;
1334 if (i >= length) {
1335 buf[length] = 0;
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]
1345 static void
1346 do_host_args(int argc, char **argv, int cmd, wusb_dev_ctrl_t *hostctrl)
1348 int c;
1349 int force = 0;
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");
1358 /* 2 digits host id */
1359 parse_host_id(optarg, &(hostctrl->host));
1361 break;
1363 case 'f':
1364 /* enable host does not need -f */
1365 if (cmd == WUSB_DCMD_ENABLE_HOST) {
1366 wusb_opterr(optopt, c);
1368 force = 1;
1369 break;
1370 default:
1371 wusb_opterr(optopt, c);
1372 break;
1376 if (optind < argc) {
1377 wusb_usage("unrecognized options:%s", argv[optind++]);
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
1383 if (hostctrl->host == 0) {
1384 (void) input_host_id(&(hostctrl->host));
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;
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;
1405 user_confirm("Continue");
1410 static void
1411 wusb_check_auth(const char *auth) {
1413 uid_t uid = geteuid();
1414 if (chk_auths(uid, auth) < 0) {
1415 wusb_fail("%s", wusb_strerror(WUSBADM_AUTH_FAILURE));
1420 * wusb exit helper funcstion
1421 * wusb_fail or wusb_usage
1423 static void
1424 wusb_fail(const char *format, ...)
1426 va_list alist;
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");
1435 wusb_free_list(dev_lists);
1436 exit(WUSB_EXIT_FAILURE);
1438 static void
1439 wusb_usage(const char *format, ...)
1441 va_list alist;
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();
1451 wusb_free_list(dev_lists);
1452 exit(WUSB_EXIT_USAGE);
1456 /* wusb print helper func */
1457 static void
1458 wusb_prt(const char *format, ...)
1460 va_list alist;
1462 format = gettext(format);
1463 va_start(alist, format);
1464 (void) vfprintf(stdout, format, alist);
1465 va_end(alist);
1468 /* wusb option failuer func */
1469 static void
1470 wusb_opterr(int opt, int opterr)
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;