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 #if (defined(__BEOS__) || defined(__HAIKU__))
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 #if (!defined(__BEOS__) && !defined(__HAIKU__))
71 static int major = 0;
72
lookup_dev(char * name)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
open_sock(int sock)97 static int open_sock(int sock)
98 {
99 #if (defined(__BEOS__) || defined(__HAIKU__))
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
print_status(cs_status_t * status)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
print_config(config_info_t * config)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
print_windows(int fd)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
get_tuple(int fd,cisdata_t code,ds_ioctl_arg_t * arg)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
print_ident(int fd)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
print_info(int fd)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
do_cmd(int fd,int cmd)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
fetch_stab(void)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 #if (!defined(__BEOS__) && !defined(__HAIKU__))
eprintf(char * name,char * fmt,...)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
execute(stab_t * s,char * action,char * scheme)508 static int execute(stab_t *s, char *action, char *scheme)
509 {
510 int ret;
511 char cmd[133];
512
513 #if (!defined(__BEOS__) && !defined(__HAIKU__))
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
stop_scheme(char * new)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
start_scheme(void)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
do_scheme(char * new)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
usage(char * name)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
main(int argc,char * argv[])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 #if (!defined(__BEOS__) && !defined(__HAIKU__))
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