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 }