150488Speter/* $FreeBSD$ */
248730Siwasaki
348730Siwasaki#include <err.h>
448730Siwasaki#include <errno.h>
548730Siwasaki#include <limits.h>
648730Siwasaki#include <stdarg.h>
748730Siwasaki#include <stddef.h>
848730Siwasaki#include <stdio.h>
948730Siwasaki#include <stdlib.h>
1048730Siwasaki#include <string.h>
1148730Siwasaki#include <time.h>
1248730Siwasaki#include <unistd.h>
1348730Siwasaki#include <sys/types.h>
1448730Siwasaki#include <sys/socket.h>
1548730Siwasaki#include <sys/un.h>
1648730Siwasaki
1748730Siwasakiconst char     *const pccardd_file = "/var/tmp/.pccardd";
1848730Siwasakiconst char     *prog = "pccardq";
1948730Siwasakiconst char     *tmp_dir = "/tmp";
2048730Siwasakiunsigned        slot_map = ~0;
2148730Siwasaki
2248730Siwasakivoid
23208075Suqsusage(void)
2448730Siwasaki{
2548730Siwasaki    fprintf(stderr, "usage: %s [-a] [-n] [-s slot]\n", prog);
2648730Siwasaki}
2748730Siwasaki
2848730Siwasakiint
2948730Siwasakiproc_arg(int ac, char **av)
3048730Siwasaki{
3148730Siwasaki    int             rc = -1;
3248730Siwasaki    int             ch;
3348730Siwasaki
3448730Siwasaki    char           *p = strrchr(av[0], '/');
3548730Siwasaki    prog = p ? p + 1 : av[0];
3648730Siwasaki
3748730Siwasaki    tmp_dir = getenv("TMPDIR") ? getenv("TMPDIR") : tmp_dir;
3848730Siwasaki
39166509Skevlo    while ((ch = getopt(ac, av, "ans:")) != -1) {
4048730Siwasaki	switch (ch) {
4148730Siwasaki	case 'a':
4248730Siwasaki	    slot_map = ~0;
4348730Siwasaki	    break;
4448730Siwasaki	case 'n':
4548730Siwasaki	    slot_map = 0;
4648730Siwasaki	    break;
4748730Siwasaki	case 's':
4848730Siwasaki	    {
4948730Siwasaki		int             n = atoi(optarg);
5048730Siwasaki		if (n < 0 || n >= CHAR_BIT * sizeof slot_map) {
5148730Siwasaki		    warnc(0, "Invalid slot number.");
5248730Siwasaki		    usage();
5348730Siwasaki		    goto out;
5448730Siwasaki		}
5548730Siwasaki		if (slot_map == ~0)
5648730Siwasaki		    slot_map = 0;
5748730Siwasaki		slot_map |= 1 << n;
5848730Siwasaki	    }
5948730Siwasaki	    break;
6048730Siwasaki	default:
6148730Siwasaki	    usage();
6248730Siwasaki	    goto out;
6348730Siwasaki	}
6448730Siwasaki    }
6548730Siwasaki
6648730Siwasaki    rc = 0;
6748730Siwasaki  out:
6848730Siwasaki    return rc;
6948730Siwasaki}
7048730Siwasaki
7148730Siwasakiint
7248730Siwasakiconnect_to_pccardd(char **path)
7348730Siwasaki{
7448730Siwasaki    int             so = -1;
7548730Siwasaki    int             pccardd_len;
7648730Siwasaki    struct sockaddr_un pccardq;
7748730Siwasaki    struct sockaddr_un pccardd;
7848730Siwasaki
7948730Siwasaki    if ((so = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
8048730Siwasaki	warn("socket");
8148730Siwasaki	goto err;
8248730Siwasaki    }
8348730Siwasaki
8448730Siwasaki    snprintf(pccardq.sun_path, sizeof pccardq.sun_path,
8548730Siwasaki	     "%s/%s%ld%ld", tmp_dir, prog, (long) getpid(), (long) time(0));
8648730Siwasaki    pccardq.sun_family = AF_UNIX;
8748730Siwasaki    pccardq.sun_len = offsetof(struct sockaddr_un, sun_path) + strlen(pccardq.sun_path);
8848730Siwasaki    if (bind(so, (struct sockaddr *) &pccardq, pccardq.sun_len) < 0) {
8948730Siwasaki	warn("bind: %s", pccardq.sun_path);
9048730Siwasaki	goto err;
9148730Siwasaki    }
9248730Siwasaki    if ((*path = strdup(pccardq.sun_path)) == NULL) {
9348730Siwasaki	warn("strdup");
9448730Siwasaki	goto err;
9548730Siwasaki    }
9648730Siwasaki
9748730Siwasaki    pccardd_len = strlen(pccardd_file) + 1;
9848730Siwasaki    if (pccardd_len > sizeof pccardd.sun_path) {
9948730Siwasaki	warnc(0, "%s: too long", pccardd_file);
10048730Siwasaki	goto err;
10148730Siwasaki    }
10248730Siwasaki    pccardd.sun_len = offsetof(struct sockaddr_un, sun_path) + pccardd_len;
10348730Siwasaki    pccardd.sun_family = AF_UNIX;
10448730Siwasaki    strcpy(pccardd.sun_path, pccardd_file);
10548730Siwasaki    if (connect(so, (struct sockaddr *) &pccardd, pccardd.sun_len) < 0) {
10648730Siwasaki	warn("connect: %s", pccardd_file);
10748730Siwasaki	goto err;
10848730Siwasaki    }
10948730Siwasaki    return so;
11048730Siwasaki  err:
11148730Siwasaki    if (so >= 0)
11248730Siwasaki	close(so);
11348730Siwasaki    return -1;
11448730Siwasaki}
11548730Siwasaki
11648730Siwasakiint
11748730Siwasakiget_slot_number(int so)
11848730Siwasaki{
11948730Siwasaki    char            buf[8];
12048730Siwasaki    int             rv;
12148730Siwasaki    int             nslot;
12248730Siwasaki
12348730Siwasaki    if ((rv = write(so, "S", 1)) < 1) {
12448730Siwasaki	warn("write");
12548730Siwasaki	goto err;
12648730Siwasaki    } else if (rv != 1) {
12748730Siwasaki	warnc(0, "write: fail.");
12848730Siwasaki	goto err;
12948730Siwasaki    }
13048730Siwasaki
13148730Siwasaki    if ((rv = read(so, buf, sizeof buf)) < 0) {
13248730Siwasaki	warn("read");
13348730Siwasaki	goto err;
13448730Siwasaki    }
13548730Siwasaki    buf[sizeof buf - 1] = 0;
13648730Siwasaki    if (sscanf(buf, "%d", &nslot) != 1) {
13748730Siwasaki	warnc(0, "Invalid response.");
13848730Siwasaki	goto err;
13948730Siwasaki    }
14048730Siwasaki    return nslot;
14148730Siwasaki  err:
14248730Siwasaki    return -1;
14348730Siwasaki}
14448730Siwasaki
14548730Siwasakienum {
14648730Siwasaki    SLOT_EMPTY = 0,
14748730Siwasaki    SLOT_FILLED = 1,
14848730Siwasaki    SLOT_INACTIVE = 2,
14948730Siwasaki    SLOT_UNDEFINED = 9
15048730Siwasaki};
15148730Siwasaki
15248730Siwasakiint
15348730Siwasakiget_slot_info(int so, int slot, char **manuf, char **version, char
15448730Siwasaki	      **device, int *state)
15548730Siwasaki{
15648730Siwasaki    int             rc = -1;
15748730Siwasaki    int             rv;
15848730Siwasaki    static char     buf[1024];
15948730Siwasaki    int             slen;
16048730Siwasaki    char           *s;
16148730Siwasaki    char           *sl;
16248730Siwasaki
16348730Siwasaki    char           *_manuf;
16448730Siwasaki    char           *_version;
16548730Siwasaki    char           *_device;
16648730Siwasaki
16781982Sbrian    if ((slen = snprintf(buf, sizeof buf, "N%d", slot)) < 0) {
16881977Sbrian	warnc(0, "write");
16981977Sbrian	goto err;
17081977Sbrian    }
17181977Sbrian
17248730Siwasaki    if ((rv = write(so, buf, slen)) < 0) {
17348730Siwasaki	warn("write");
17448730Siwasaki	goto err;
17548730Siwasaki    } else if (rv != slen) {
17648730Siwasaki	warnc(0, "write");
17748730Siwasaki	goto err;
17848730Siwasaki    }
17948730Siwasaki
18048730Siwasaki    if ((rv = read(so, buf, sizeof buf)) < 0) {
18148730Siwasaki	warn("read");
18248730Siwasaki	goto err;
18348730Siwasaki    }
18448730Siwasaki
18548730Siwasaki    s = buf;
18648730Siwasaki    if ((sl = strsep(&s, "~")) == NULL)
18748730Siwasaki	goto parse_err;
18848730Siwasaki    if (atoi(sl) != slot)
18948730Siwasaki	goto parse_err;
19048730Siwasaki    if ((_manuf = strsep(&s, "~")) == NULL)
19148730Siwasaki	goto parse_err;
19248730Siwasaki    if ((_version = strsep(&s, "~")) == NULL)
19348730Siwasaki	goto parse_err;
19448730Siwasaki    if ((_device = strsep(&s, "~")) == NULL)
19548730Siwasaki	goto parse_err;
19648730Siwasaki    if (sscanf(s, "%1d", state) != 1)
19748730Siwasaki	goto parse_err;
19848730Siwasaki    if (s != NULL && strchr(s, '~') != NULL)
19948730Siwasaki	goto parse_err;
20048730Siwasaki
20171277Sjedgar    if ((*manuf = strdup(_manuf)) == NULL) {
20271277Sjedgar	warn("strdup");
20371277Sjedgar	goto err;
20471277Sjedgar    }
20571277Sjedgar    if ((*version = strdup(_version)) == NULL) {
20671277Sjedgar	warn("strdup");
20771277Sjedgar	goto err;
20871277Sjedgar    }
20971277Sjedgar    if ((*device = strdup(_device)) == NULL) {
21071277Sjedgar	warn("strdup");
21171277Sjedgar	goto err;
21271277Sjedgar    }
21348730Siwasaki    if (*manuf == NULL || *version == NULL || *device == NULL) {
21448730Siwasaki	warn("strdup");
21548730Siwasaki	goto err;
21648730Siwasaki    }
21748730Siwasaki
21848730Siwasaki    rc = 0;
21948730Siwasaki  err:
22048730Siwasaki    return rc;
22148730Siwasaki  parse_err:
22248730Siwasaki    warnc(0, "Invalid response: %*s", rv, buf);
22348730Siwasaki    return rc;
22448730Siwasaki}
22548730Siwasaki
226208075Suqsconst char *
22748730Siwasakistrstate(int state)
22848730Siwasaki{
22948730Siwasaki    switch (state) {
23048730Siwasaki    case 0:
23148730Siwasaki	return "empty";
23248730Siwasaki    case 1:
23348730Siwasaki	return "filled";
23448730Siwasaki    case 2:
23548730Siwasaki	return "inactive";
23648730Siwasaki    default:
23748730Siwasaki	return "unknown";
23848730Siwasaki    }
23948730Siwasaki}
24048730Siwasaki
24148730Siwasakiint
24248730Siwasakimain(int ac, char **av)
24348730Siwasaki{
24448730Siwasaki    char           *path = NULL;
24548730Siwasaki    int             so = -1;
24648730Siwasaki    int             nslot;
24748730Siwasaki    int             i;
24848730Siwasaki
24948730Siwasaki    if (proc_arg(ac, av) < 0)
25048730Siwasaki	goto out;
25148730Siwasaki    if ((so = connect_to_pccardd(&path)) < 0)
25248730Siwasaki	goto out;
25348730Siwasaki    if ((nslot = get_slot_number(so)) < 0)
25448730Siwasaki	goto out;
25548730Siwasaki    if (slot_map == 0) {
25648730Siwasaki	printf("%d\n", nslot);
25748730Siwasaki    } else {
25848730Siwasaki	for (i = 0; i < nslot; i++) {
25948730Siwasaki	    if ((slot_map & (1 << i))) {
26048730Siwasaki		char           *manuf;
26148730Siwasaki		char           *version;
26248730Siwasaki		char           *device;
26348730Siwasaki		int             state;
26448730Siwasaki
26548730Siwasaki		if (get_slot_info(so, i, &manuf, &version, &device,
26648730Siwasaki				  &state) < 0)
26748730Siwasaki		    goto out;
26848730Siwasaki		if (manuf == NULL || version == NULL || device == NULL)
26948730Siwasaki		    goto out;
27048730Siwasaki		printf("%d~%s~%s~%s~%s\n",
27148730Siwasaki		       i, manuf, version, device, strstate(state));
27248730Siwasaki		free(manuf);
27348730Siwasaki		free(version);
27448730Siwasaki		free(device);
27548730Siwasaki	    }
27648730Siwasaki	}
27748730Siwasaki    }
27848730Siwasaki  out:
27948730Siwasaki    if (path) {
28048730Siwasaki	unlink(path);
28148730Siwasaki	free(path);
28248730Siwasaki    }
28348730Siwasaki    if (so >= 0)
28448730Siwasaki	close(so);
28548730Siwasaki    exit(0);
28648730Siwasaki}
287