1 /*====================================================================== 2 3 PCMCIA device control program 4 5 cardctl.c 1.70 2004/04/09 03:54:53 6 7 The contents of this file are subject to the Mozilla Public 8 License Version 1.1 (the "License"); you may not use this file 9 except in compliance with the License. You may obtain a copy of 10 the License at http://www.mozilla.org/MPL/ 11 12 Software distributed under the License is distributed on an "AS 13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 14 implied. See the License for the specific language governing 15 rights and limitations under the License. 16 17 The initial developer of the original code is David A. Hinds 18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 20 21 Alternatively, the contents of this file may be used under the 22 terms of the GNU General Public License version 2 (the "GPL"), in 23 which case the provisions of the GPL are applicable instead of the 24 above. If you wish to allow the use of your version of this file 25 only under the terms of the GPL and not to allow others to use 26 your version of this file under the MPL, indicate your decision 27 by deleting the provisions above and replace them with the notice 28 and other provisions required by the GPL. If you do not delete 29 the provisions above, a recipient may use your version of this 30 file under either the MPL or the GPL. 31 32 ======================================================================*/ 33 #ifdef __BEOS__ 34 #include <OS.h> 35 #endif 36 37 #include <sys/types.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <fcntl.h> 43 #include <errno.h> 44 #include <ctype.h> 45 #include <stdarg.h> 46 #include <sys/time.h> 47 #include <sys/ioctl.h> 48 #include <sys/stat.h> 49 #include <sys/wait.h> 50 #include <sys/stat.h> 51 52 #include <pcmcia/version.h> 53 #include <pcmcia/config.h> 54 #include <pcmcia/cs_types.h> 55 #include <pcmcia/cs.h> 56 #include <pcmcia/cistpl.h> 57 #include <pcmcia/ds.h> 58 59 /*====================================================================*/ 60 61 #ifdef ETC 62 static char *configpath = ETC; 63 #else 64 static char *configpath = "/etc/pcmcia"; 65 #endif 66 67 static char *scheme, *stabfile; 68 69 /*====================================================================*/ 70 #ifndef __BEOS__ 71 static int major = 0; 72 73 static int lookup_dev(char *name) 74 { 75 FILE *f; 76 int n; 77 char s[32], t[32]; 78 79 f = fopen("/proc/devices", "r"); 80 if (f == NULL) 81 return -errno; 82 while (fgets(s, 32, f) != NULL) { 83 if (sscanf(s, "%d %s", &n, t) == 2) 84 if (strcmp(name, t) == 0) 85 break; 86 } 87 fclose(f); 88 if (strcmp(name, t) == 0) 89 return n; 90 else 91 return -ENODEV; 92 } /* lookup_dev */ 93 #endif 94 95 /*====================================================================*/ 96 97 static int open_sock(int sock) 98 { 99 #ifdef __BEOS__ 100 char fn[B_OS_NAME_LENGTH]; 101 sprintf(fn, "/dev/bus/pcmcia/sock/%d", sock); 102 return open(fn, O_RDONLY); 103 #else 104 static char *paths[] = { 105 "/var/lib/pcmcia", "/var/run", "/dev", "/tmp", NULL 106 }; 107 int fd; 108 char **p, fn[64]; 109 dev_t dev = makedev(major, sock); 110 111 for (p = paths; *p; p++) { 112 sprintf(fn, "%s/cc-%d", *p, getpid()); 113 if (mknod(fn, (S_IFCHR|S_IREAD|S_IWRITE), dev) == 0) { 114 fd = open(fn, O_RDONLY); 115 unlink(fn); 116 if (fd >= 0) 117 return fd; 118 if (errno == ENODEV) 119 break; 120 } 121 } 122 return -1; 123 #endif 124 } /* open_sock */ 125 126 /*====================================================================*/ 127 128 static void print_status(cs_status_t *status) 129 { 130 char *v = "5"; 131 if (status->Function == 0) { 132 printf(" "); 133 if (status->CardState & CS_EVENT_3VCARD) 134 v = "3.3"; 135 else if (status->CardState & CS_EVENT_XVCARD) 136 v = "X.X"; 137 if (status->CardState & CS_EVENT_CB_DETECT) 138 printf("%sV CardBus card", v); 139 else if (status->CardState & CS_EVENT_CARD_DETECT) 140 printf("%sV 16-bit PC Card", v); 141 else 142 printf("no card"); 143 if (status->CardState & CS_EVENT_PM_SUSPEND) 144 printf(" [suspended]"); 145 printf("\n"); 146 } 147 if ((status->CardState & CS_EVENT_PM_SUSPEND) || 148 !(status->CardState & CS_EVENT_CARD_DETECT)) 149 return; 150 printf(" function %d: ", status->Function); 151 printf("%s", (status->CardState & CS_EVENT_READY_CHANGE) 152 ? "[ready]" : "[busy]"); 153 if (status->CardState & CS_EVENT_WRITE_PROTECT) 154 printf(", [wp]"); 155 if (status->CardState & CS_EVENT_BATTERY_DEAD) 156 printf(", [bat dead]"); 157 if (status->CardState & CS_EVENT_BATTERY_LOW) 158 printf(", [bat low]"); 159 if (status->CardState & CS_EVENT_REQUEST_ATTENTION) 160 printf(", [req attn]"); 161 printf("\n"); 162 } /* print_status */ 163 164 /*====================================================================*/ 165 166 static void print_config(config_info_t *config) 167 { 168 if (config->Function == 0) { 169 printf(" Vcc %.1fV Vpp1 %.1fV Vpp2 %.1fV\n", 170 config->Vcc/10.0, config->Vpp1/10.0, config->Vpp2/10.0); 171 if (!(config->Attributes & CONF_VALID_CLIENT)) 172 return; 173 printf(" interface type is "); 174 switch (config->IntType) { 175 case INT_MEMORY: 176 printf("\"memory-only\"\n"); break; 177 case INT_MEMORY_AND_IO: 178 printf("\"memory and I/O\"\n"); break; 179 case INT_CARDBUS: 180 printf("\"cardbus\"\n"); break; 181 } 182 if (config->AssignedIRQ != 0) { 183 printf(" irq %d", config->AssignedIRQ); 184 switch (config->IRQAttributes & IRQ_TYPE) { 185 case IRQ_TYPE_EXCLUSIVE: 186 printf(" [exclusive]"); break; 187 case IRQ_TYPE_TIME: 188 printf(" [multiplexed]"); break; 189 case IRQ_TYPE_DYNAMIC_SHARING: 190 printf(" [shared]"); break; 191 } 192 if (config->IRQAttributes & IRQ_PULSE_ALLOCATED) 193 printf(" [pulse]"); 194 else 195 printf(" [level]"); 196 if (!(config->Attributes & CONF_ENABLE_IRQ)) 197 printf(" [disabled]"); 198 printf("\n"); 199 } 200 if (config->Attributes & CONF_ENABLE_DMA) 201 printf(" DMA mode is enabled\n"); 202 if (config->Attributes & CONF_ENABLE_SPKR) 203 printf(" speaker output is enabled\n"); 204 205 } 206 207 if (!(config->Attributes & CONF_VALID_CLIENT)) 208 return; 209 210 printf(" function %d:\n", config->Function); 211 212 if (config->CardValues) { 213 printf(" config base %#06x\n", config->ConfigBase); 214 printf(" "); 215 if (config->CardValues & CV_OPTION_VALUE) 216 printf(" option 0x%02x", config->Option); 217 if (config->CardValues & CV_STATUS_VALUE) 218 printf(" status 0x%02x", config->Status); 219 if (config->CardValues & CV_PIN_REPLACEMENT) 220 printf(" pin 0x%02x", config->Pin); 221 if (config->CardValues & CV_COPY_VALUE) 222 printf(" copy 0x%02x", config->Copy); 223 if (config->CardValues & CV_EXT_STATUS) 224 printf(" ext 0x%02x", config->ExtStatus); 225 printf("\n"); 226 } 227 228 if (config->NumPorts1 > 0) { 229 printf(" io %#06x-%#06x", config->BasePort1, 230 config->BasePort1 + config->NumPorts1 - 1); 231 if (config->IntType == INT_CARDBUS) { 232 printf(" [32bit]\n"); 233 } else { 234 if (config->Attributes1 & IO_SHARED) 235 printf(" [shared]"); 236 if (config->Attributes1 & IO_FORCE_ALIAS_ACCESS) 237 printf(" [alias]"); 238 switch (config->Attributes1 & IO_DATA_PATH_WIDTH) { 239 case IO_DATA_PATH_WIDTH_8: 240 printf(" [8bit]\n"); break; 241 case IO_DATA_PATH_WIDTH_16: 242 printf(" [16bit]\n"); break; 243 case IO_DATA_PATH_WIDTH_AUTO: 244 printf(" [auto]\n"); break; 245 } 246 } 247 } 248 if (config->NumPorts2 > 0) { 249 printf(" io %#06x-%#06x", config->BasePort2, 250 config->BasePort2 + config->NumPorts2 - 1); 251 if (config->Attributes2 & IO_SHARED) 252 printf(" [shared]"); 253 if (config->Attributes2 & IO_FORCE_ALIAS_ACCESS) 254 printf(" [alias]"); 255 switch (config->Attributes2 & IO_DATA_PATH_WIDTH) { 256 case IO_DATA_PATH_WIDTH_8: 257 printf(" [8bit]\n"); break; 258 case IO_DATA_PATH_WIDTH_16: 259 printf(" [16bit]\n"); break; 260 case IO_DATA_PATH_WIDTH_AUTO: 261 printf(" [auto]\n"); break; 262 } 263 } 264 } /* print_config */ 265 266 /*====================================================================*/ 267 268 static void print_windows(int fd) 269 { 270 ds_ioctl_arg_t arg1, arg2; 271 int ret; 272 win_req_t *win = &arg1.win_info.window; 273 memreq_t *req = &arg2.win_info.map; 274 275 ret = ioctl(fd, DS_GET_FIRST_WINDOW, &arg1); 276 while (ret == 0) { 277 arg2.win_info.handle = arg1.win_info.handle; 278 ioctl(fd, DS_GET_MEM_PAGE, &arg2); 279 printf(" memory 0x%04x-0x%04x @ 0x%08lx", 280 req->CardOffset, req->CardOffset+win->Size-1, 281 win->Base); 282 if (win->Attributes & WIN_MEMORY_TYPE_AM) 283 printf(" [attr]"); 284 if (!(win->Attributes & WIN_ENABLE)) 285 printf(" [disabled]"); 286 if (win->Attributes & WIN_USE_WAIT) 287 printf(" [wait]"); 288 switch (win->Attributes & WIN_DATA_WIDTH) { 289 case WIN_DATA_WIDTH_8: 290 printf(" [8bit]\n"); break; 291 case WIN_DATA_WIDTH_16: 292 printf(" [16bit]\n"); break; 293 case WIN_DATA_WIDTH_32: 294 printf(" [32bit]\n"); break; 295 } 296 ret = ioctl(fd, DS_GET_NEXT_WINDOW, &arg1); 297 } 298 } 299 300 /*====================================================================*/ 301 302 static int get_tuple(int fd, cisdata_t code, ds_ioctl_arg_t *arg) 303 { 304 arg->tuple.DesiredTuple = code; 305 arg->tuple.Attributes = TUPLE_RETURN_COMMON; 306 arg->tuple.TupleOffset = 0; 307 if ((ioctl(fd, DS_GET_FIRST_TUPLE, arg) == 0) && 308 (ioctl(fd, DS_GET_TUPLE_DATA, arg) == 0) && 309 (ioctl(fd, DS_PARSE_TUPLE, arg) == 0)) 310 return 0; 311 else 312 return -1; 313 } 314 315 static void print_ident(int fd) 316 { 317 ds_ioctl_arg_t arg; 318 cistpl_vers_1_t *vers = &arg.tuple_parse.parse.version_1; 319 cistpl_manfid_t *manfid = &arg.tuple_parse.parse.manfid; 320 cistpl_funcid_t *funcid = &arg.tuple_parse.parse.funcid; 321 config_info_t config; 322 int i; 323 static char *fn[] = { 324 "multifunction", "memory", "serial", "parallel", 325 "fixed disk", "video", "network", "AIMS", "SCSI" 326 }; 327 328 if (get_tuple(fd, CISTPL_VERS_1, &arg) == 0) { 329 printf(" product info: "); 330 for (i = 0; i < vers->ns; i++) 331 printf("%s\"%s\"", (i>0) ? ", " : "", 332 vers->str+vers->ofs[i]); 333 printf("\n"); 334 } else { 335 printf(" no product info available\n"); 336 } 337 if (get_tuple(fd, CISTPL_MANFID, &arg) == 0) 338 printf(" manfid: 0x%04x, 0x%04x\n", 339 manfid->manf, manfid->card); 340 if (get_tuple(fd, CISTPL_FUNCID, &arg) == 0) 341 printf(" function: %d (%s)\n", funcid->func, 342 fn[funcid->func]); 343 config.Function = config.ConfigBase = 0; 344 if ((ioctl(fd, DS_GET_CONFIGURATION_INFO, &config) == 0) && 345 (config.IntType == INT_CARDBUS) && config.ConfigBase) 346 printf(" PCI id: 0x%04x, 0x%04x\n", 347 config.ConfigBase & 0xffff, 348 config.ConfigBase >> 16); 349 } 350 351 static void print_info(int fd) 352 { 353 ds_ioctl_arg_t arg; 354 cistpl_vers_1_t *vers = &arg.tuple_parse.parse.version_1; 355 cistpl_manfid_t *manfid = &arg.tuple_parse.parse.manfid; 356 cistpl_funcid_t *funcid = &arg.tuple_parse.parse.funcid; 357 config_info_t config; 358 int i; 359 360 vers->ns = 0; 361 get_tuple(fd, CISTPL_VERS_1, &arg); 362 for (i = 0; i < 4; i++) 363 printf("PRODID_%d=\"%s\"\n", i+1, 364 (i < vers->ns) ? vers->str+vers->ofs[i] : ""); 365 *manfid = (cistpl_manfid_t) { 0, 0 }; 366 get_tuple(fd, CISTPL_MANFID, &arg); 367 printf("MANFID=%04x,%04x\n", manfid->manf, manfid->card); 368 *funcid = (cistpl_funcid_t) { 0xff, 0xff }; 369 get_tuple(fd, CISTPL_FUNCID, &arg); 370 printf("FUNCID=%d\n", funcid->func); 371 config.Function = config.ConfigBase = 0; 372 } 373 374 /*====================================================================*/ 375 376 typedef enum cmd_t { 377 C_STATUS, C_CONFIG, C_IDENT, C_INFO, C_SUSPEND, 378 C_RESUME, C_RESET, C_EJECT, C_INSERT 379 } cmd_t; 380 381 static char *cmdname[] = { 382 "status", "config", "ident", "info", "suspend", 383 "resume", "reset", "eject", "insert" 384 }; 385 386 #define NCMD (sizeof(cmdname)/sizeof(char *)) 387 388 static int do_cmd(int fd, int cmd) 389 { 390 int i, ret; 391 cs_status_t status; 392 config_info_t config; 393 394 ret = 0; 395 switch (cmd) { 396 397 case C_STATUS: 398 for (i = 0; i < 4; i++) { 399 status.Function = i; 400 if (ioctl(fd, DS_GET_STATUS, &status) == 0) 401 print_status(&status); 402 else { 403 if (i == 0) { 404 if (errno == ENODEV) 405 printf(" no card\n"); 406 else 407 perror("ioctl()"); 408 } 409 break; 410 } 411 } 412 break; 413 414 case C_CONFIG: 415 for (i = 0; i < 4; i++) { 416 config.Function = i; 417 if (ioctl(fd, DS_GET_CONFIGURATION_INFO, &config) == 0) 418 print_config(&config); 419 else { 420 if (i == 0) printf(" not configured\n"); 421 break; 422 } 423 print_windows(fd); 424 } 425 break; 426 427 case C_IDENT: 428 print_ident(fd); 429 break; 430 431 case C_INFO: 432 print_info(fd); 433 break; 434 435 case C_SUSPEND: 436 ret = ioctl(fd, DS_SUSPEND_CARD); 437 break; 438 439 case C_RESUME: 440 ret = ioctl(fd, DS_RESUME_CARD); 441 break; 442 443 case C_RESET: 444 ret = ioctl(fd, DS_RESET_CARD); 445 break; 446 447 case C_EJECT: 448 ret = ioctl(fd, DS_EJECT_CARD); 449 break; 450 451 case C_INSERT: 452 ret = ioctl(fd, DS_INSERT_CARD); 453 break; 454 } 455 return ret; 456 } 457 458 /*====================================================================== 459 460 A utility function to scan /var/run/stab and apply a specified action 461 to each device, in turn. If any command returns a non-zero exit 462 code, execute() returns -1. 463 464 ======================================================================*/ 465 466 typedef struct stab_t { 467 int socket, instance, status; 468 char class[33], driver[33], dev[33]; 469 } stab_t; 470 471 static stab_t stab[256]; 472 static int nstab; 473 474 static int fetch_stab(void) 475 { 476 char s[133]; 477 FILE *f; 478 479 f = fopen(stabfile, "r"); 480 if (f == NULL) 481 return -1; 482 for (nstab = 0; fgets(s, 132, f); ) { 483 if (s[0] != 'S') { 484 sscanf(s, "%d\t%s\t%s\t%d\t%s", 485 &stab[nstab].socket, stab[nstab].class, 486 stab[nstab].driver, &stab[nstab].instance, 487 stab[nstab].dev); 488 stab[nstab].status = 0; 489 nstab++; 490 } 491 } 492 fclose(f); 493 return 0; 494 } 495 496 #ifndef __BEOS__ 497 static void eprintf(char *name, char *fmt, ...) 498 { 499 va_list args; 500 char s[32]; 501 va_start(args, fmt); 502 vsprintf(s, fmt, args); 503 setenv(name, s, 1); 504 va_end(args); 505 } 506 #endif 507 508 static int execute(stab_t *s, char *action, char *scheme) 509 { 510 int ret; 511 char cmd[133]; 512 513 #ifndef __BEOS__ 514 eprintf("SOCKET", "%d", s->socket); 515 eprintf("INSTANCE", "%d", s->instance); 516 #endif 517 if (scheme) 518 sprintf(cmd, "./%s %s %s %s", s->class, action, s->dev, scheme); 519 else 520 sprintf(cmd, "./%s %s %s", s->class, action, s->dev); 521 ret = system(cmd); 522 if (!WIFEXITED(ret) || WEXITSTATUS(ret)) 523 return -1; 524 return 0; 525 } 526 527 static int stop_scheme(char *new) 528 { 529 int i; 530 531 fprintf(stderr, "checking:"); 532 for (i = 0; i < nstab; i++) { 533 fprintf(stderr, " %s", stab[i].dev); 534 stab[i].status = execute(stab+i, "cksum", new); 535 if (stab[i].status && 536 (execute(stab+i, "check", NULL) != 0)) break; 537 } 538 fprintf(stderr, "\n"); 539 if (i < nstab) { 540 fprintf(stderr, "Device '%s' busy: scheme unchanged.\n", 541 stab[i].dev); 542 return -1; 543 } 544 for (i = 0; i < nstab; i++) 545 if (stab[i].status) execute(stab+i, "stop", NULL); 546 return 0; 547 } 548 549 static int start_scheme(void) 550 { 551 int i, j = 0; 552 553 for (i = 0; i < nstab; i++) 554 if (stab[i].status) j |= execute(stab+i, "start", NULL); 555 return j; 556 } 557 558 /*====================================================================== 559 560 do_scheme() is in charge of checking and updating the current 561 PCMCIA configuration scheme. The current scheme is kept in a 562 file, /var/run/pcmcia-scheme. When updating the scheme, we first 563 stop all PCMCIA devices, then update the scheme, then restart. 564 565 ======================================================================*/ 566 567 static int do_scheme(char *new) 568 { 569 FILE *f; 570 char old[33]; 571 int i; 572 573 f = fopen(scheme, "r"); 574 if (f && fgets(old, 32, f)) 575 old[strlen(old)-1] = '\0'; 576 else 577 old[0] = '\0'; 578 if (f) fclose(f); 579 580 if (new) { 581 582 #ifndef UNSAFE_TOOLS 583 if (getuid() != 0) { 584 fprintf(stderr, "Only root can select a new scheme.\n"); 585 return -1; 586 } 587 #else 588 setuid(geteuid()); 589 #endif 590 591 /* Sanity checks... */ 592 for (i = 0; i < strlen(new); i++) 593 if (!isalnum(new[i])) break; 594 if ((i != strlen(new)) || (strlen(new) < 1) || 595 (strlen(new) > 32)) { 596 fprintf(stderr, "Bad scheme name.\n"); 597 return -1; 598 } 599 if (strcmp(old, new) == 0) { 600 fprintf(stderr, "Scheme unchanged.\n"); 601 return 0; 602 } 603 604 if (chdir(configpath) != 0) { 605 fprintf(stderr, "Could not change to %s.\n", configpath); 606 return -1; 607 } 608 609 /* Shut down devices in old scheme */ 610 if ((fetch_stab() == 0) && (stop_scheme(new) != 0)) 611 return -1; 612 613 /* Update scheme state */ 614 if (old[0]) 615 printf("Changing scheme from '%s' to '%s'...\n", old, new); 616 else 617 printf("Changing scheme to '%s'...\n", new); 618 619 umask(022); 620 f = fopen(scheme, "w"); 621 if (f) { 622 fprintf(f, "%s\n", new); 623 fclose(f); 624 } else 625 perror("Could not set scheme."); 626 627 /* Start up devices in new scheme */ 628 if (start_scheme() != 0) 629 fprintf(stderr, "Some devices did not start cleanly.\n"); 630 631 } else { 632 if (old[0]) 633 printf("Current scheme: '%s'.\n", old); 634 else 635 printf("Current scheme: 'default'.\n"); 636 } 637 return 0; 638 } 639 640 /*====================================================================*/ 641 642 static void usage(char *name) 643 { 644 int i; 645 fprintf(stderr, "usage: %s command [socket #]\n", name); 646 fprintf(stderr, " or %s [-c configpath] [-f scheme]" 647 " [-s stab] scheme [name]\n", name); 648 fprintf(stderr, " commands:"); 649 for (i = 0; i < NCMD; i++) 650 fprintf(stderr, " %s", cmdname[i]); 651 fprintf(stderr, "\n"); 652 exit(EXIT_FAILURE); 653 } 654 655 /*====================================================================*/ 656 657 #define MAX_SOCKS 8 658 659 int main(int argc, char *argv[]) 660 { 661 int cmd, fd[MAX_SOCKS], ns, ret, i; 662 int optch, errflg = 0; 663 char *s, *opts = (getuid() == 0) ? "Vc:f:s:" : "V"; 664 665 if (access("/var/lib/pcmcia", R_OK) == 0) { 666 scheme = "/var/lib/pcmcia/scheme"; 667 stabfile = "/var/lib/pcmcia/stab"; 668 } else { 669 scheme = "/var/run/pcmcia-scheme"; 670 stabfile = "/var/run/stab"; 671 } 672 673 while ((optch = getopt(argc, argv, opts)) != -1) { 674 switch (optch) { 675 case 'V': 676 fprintf(stderr, "cardctl version " CS_PKG_RELEASE "\n"); 677 return 0; 678 break; 679 case 'c': 680 configpath = strdup(optarg); break; 681 case 'f': 682 scheme = strdup(optarg); break; 683 case 's': 684 stabfile = strdup(optarg); break; 685 default: 686 errflg = 1; break; 687 } 688 } 689 690 if (errflg || (argc == optind) || (argc > optind+2)) 691 usage(argv[0]); 692 693 if (geteuid() != 0) { 694 fprintf(stderr, "cardctl must be setuid root\n"); 695 exit(EXIT_FAILURE); 696 } 697 698 #ifndef __BEOS__ 699 major = lookup_dev("pcmcia"); 700 if (major < 0) { 701 if (major == -ENODEV) 702 fprintf(stderr, "no pcmcia driver in /proc/devices\n"); 703 else 704 perror("could not open /proc/devices"); 705 exit(EXIT_FAILURE); 706 } 707 #endif 708 709 if (strcmp(argv[optind], "scheme") == 0) { 710 #ifndef UNSAFE_TOOLS 711 setuid(getuid()); 712 #endif 713 if (do_scheme((argc == optind+1) ? NULL : argv[optind+1]) == 0) 714 exit(EXIT_SUCCESS); 715 else 716 exit(EXIT_FAILURE); 717 } 718 719 for (cmd = 0; cmd < NCMD; cmd++) 720 if (strcmp(argv[optind], cmdname[cmd]) == 0) break; 721 if (cmd == NCMD) 722 usage(argv[0]); 723 724 ret = 0; 725 if (argc == optind+2) { 726 ns = strtol(argv[optind+1], &s, 0); 727 if ((*argv[optind+1] == '\0') || (*s != '\0')) 728 usage(argv[0]); 729 fd[0] = open_sock(ns); 730 if (fd[0] < 0) { 731 perror("open_sock()"); 732 exit(EXIT_FAILURE); 733 } 734 #ifndef UNSAFE_TOOLS 735 setuid(getuid()); 736 #endif 737 ret = do_cmd(fd[0], cmd); 738 if (ret != 0) 739 perror("ioctl()"); 740 } else { 741 for (ns = 0; ns < MAX_SOCKS; ns++) { 742 fd[ns] = open_sock(ns); 743 if (fd[ns] < 0) break; 744 } 745 #ifndef UNSAFE_TOOLS 746 setuid(getuid()); 747 #endif 748 if (ns == 0) { 749 perror("open_sock()"); 750 exit(EXIT_FAILURE); 751 } 752 for (ns = 0; (ns < MAX_SOCKS) && (fd[ns] >= 0); ns++) { 753 if (cmd <= C_IDENT) 754 printf("Socket %d:\n", ns); 755 i = do_cmd(fd[ns], cmd); 756 if ((i != 0) && (errno != ENODEV)) { 757 perror("ioctl()"); 758 ret = i; 759 } 760 } 761 } 762 if (ret != 0) 763 exit(EXIT_FAILURE); 764 return 0; 765 } 766