xref: /haiku/src/bin/pcmcia-cs/cardctl.c (revision bc3955fea5b07e2e94a27fc05e4bb58fe6f0319b)
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