pccardq.c revision 71277
1/* $FreeBSD: head/usr.sbin/apmd/contrib/pccardq.c 71277 2001-01-20 01:22:31Z jedgar $ */
2
3#include <err.h>
4#include <errno.h>
5#include <limits.h>
6#include <stdarg.h>
7#include <stddef.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <time.h>
12#include <unistd.h>
13#include <sys/types.h>
14#include <sys/socket.h>
15#include <sys/un.h>
16
17const char     *const pccardd_file = "/var/tmp/.pccardd";
18const char     *prog = "pccardq";
19const char     *tmp_dir = "/tmp";
20unsigned        slot_map = ~0;
21
22void
23usage()
24{
25    fprintf(stderr, "usage: %s [-a] [-n] [-s slot]\n", prog);
26}
27
28int
29proc_arg(int ac, char **av)
30{
31    int             rc = -1;
32    int             ch;
33
34    char           *p = strrchr(av[0], '/');
35    prog = p ? p + 1 : av[0];
36
37    tmp_dir = getenv("TMPDIR") ? getenv("TMPDIR") : tmp_dir;
38
39    while ((ch = getopt(ac, av, "ans:")) != EOF) {
40	switch (ch) {
41	case 'a':
42	    slot_map = ~0;
43	    break;
44	case 'n':
45	    slot_map = 0;
46	    break;
47	case 's':
48	    {
49		int             n = atoi(optarg);
50		if (n < 0 || n >= CHAR_BIT * sizeof slot_map) {
51		    warnc(0, "Invalid slot number.");
52		    usage();
53		    goto out;
54		}
55		if (slot_map == ~0)
56		    slot_map = 0;
57		slot_map |= 1 << n;
58	    }
59	    break;
60	default:
61	    usage();
62	    goto out;
63	}
64    }
65
66    rc = 0;
67  out:
68    return rc;
69}
70
71int
72connect_to_pccardd(char **path)
73{
74    int             so = -1;
75    int             pccardd_len;
76    struct sockaddr_un pccardq;
77    struct sockaddr_un pccardd;
78
79    if ((so = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
80	warn("socket");
81	goto err;
82    }
83
84    snprintf(pccardq.sun_path, sizeof pccardq.sun_path,
85	     "%s/%s%ld%ld", tmp_dir, prog, (long) getpid(), (long) time(0));
86    pccardq.sun_family = AF_UNIX;
87    pccardq.sun_len = offsetof(struct sockaddr_un, sun_path) + strlen(pccardq.sun_path);
88    if (bind(so, (struct sockaddr *) &pccardq, pccardq.sun_len) < 0) {
89	warn("bind: %s", pccardq.sun_path);
90	goto err;
91    }
92    if ((*path = strdup(pccardq.sun_path)) == NULL) {
93	warn("strdup");
94	goto err;
95    }
96
97    pccardd_len = strlen(pccardd_file) + 1;
98    if (pccardd_len > sizeof pccardd.sun_path) {
99	warnc(0, "%s: too long", pccardd_file);
100	goto err;
101    }
102    pccardd.sun_len = offsetof(struct sockaddr_un, sun_path) + pccardd_len;
103    pccardd.sun_family = AF_UNIX;
104    strcpy(pccardd.sun_path, pccardd_file);
105    if (connect(so, (struct sockaddr *) &pccardd, pccardd.sun_len) < 0) {
106	warn("connect: %s", pccardd_file);
107	goto err;
108    }
109    return so;
110  err:
111    if (so >= 0)
112	close(so);
113    return -1;
114}
115
116int
117get_slot_number(int so)
118{
119    char            buf[8];
120    int             rv;
121    int             nslot;
122
123    if ((rv = write(so, "S", 1)) < 1) {
124	warn("write");
125	goto err;
126    } else if (rv != 1) {
127	warnc(0, "write: fail.");
128	goto err;
129    }
130
131    if ((rv = read(so, buf, sizeof buf)) < 0) {
132	warn("read");
133	goto err;
134    }
135    buf[sizeof buf - 1] = 0;
136    if (sscanf(buf, "%d", &nslot) != 1) {
137	warnc(0, "Invalid response.");
138	goto err;
139    }
140    return nslot;
141  err:
142    return -1;
143}
144
145enum {
146    SLOT_EMPTY = 0,
147    SLOT_FILLED = 1,
148    SLOT_INACTIVE = 2,
149    SLOT_UNDEFINED = 9
150};
151
152int
153get_slot_info(int so, int slot, char **manuf, char **version, char
154	      **device, int *state)
155{
156    int             rc = -1;
157    int             rv;
158    static char     buf[1024];
159    int             slen;
160    char           *s;
161    char           *sl;
162
163    char           *_manuf;
164    char           *_version;
165    char           *_device;
166
167    slen = snprintf(buf, sizeof buf, "N%d", slot);
168    if ((rv = write(so, buf, slen)) < 0) {
169	warn("write");
170	goto err;
171    } else if (rv != slen) {
172	warnc(0, "write");
173	goto err;
174    }
175
176    if ((rv = read(so, buf, sizeof buf)) < 0) {
177	warn("read");
178	goto err;
179    }
180
181    s = buf;
182    if ((sl = strsep(&s, "~")) == NULL)
183	goto parse_err;
184    if (atoi(sl) != slot)
185	goto parse_err;
186    if ((_manuf = strsep(&s, "~")) == NULL)
187	goto parse_err;
188    if ((_version = strsep(&s, "~")) == NULL)
189	goto parse_err;
190    if ((_device = strsep(&s, "~")) == NULL)
191	goto parse_err;
192    if (sscanf(s, "%1d", state) != 1)
193	goto parse_err;
194    if (s != NULL && strchr(s, '~') != NULL)
195	goto parse_err;
196
197    if ((*manuf = strdup(_manuf)) == NULL) {
198	warn("strdup");
199	goto err;
200    }
201    if ((*version = strdup(_version)) == NULL) {
202	warn("strdup");
203	goto err;
204    }
205    if ((*device = strdup(_device)) == NULL) {
206	warn("strdup");
207	goto err;
208    }
209    if (*manuf == NULL || *version == NULL || *device == NULL) {
210	warn("strdup");
211	goto err;
212    }
213
214    rc = 0;
215  err:
216    return rc;
217  parse_err:
218    warnc(0, "Invalid response: %*s", rv, buf);
219    return rc;
220}
221
222const char     *
223strstate(int state)
224{
225    switch (state) {
226    case 0:
227	return "empty";
228    case 1:
229	return "filled";
230    case 2:
231	return "inactive";
232    default:
233	return "unknown";
234    }
235}
236
237int
238main(int ac, char **av)
239{
240    char           *path = NULL;
241    int             so = -1;
242    int             nslot;
243    int             i;
244
245    if (proc_arg(ac, av) < 0)
246	goto out;
247    if ((so = connect_to_pccardd(&path)) < 0)
248	goto out;
249    if ((nslot = get_slot_number(so)) < 0)
250	goto out;
251    if (slot_map == 0) {
252	printf("%d\n", nslot);
253    } else {
254	for (i = 0; i < nslot; i++) {
255	    if ((slot_map & (1 << i))) {
256		char           *manuf;
257		char           *version;
258		char           *device;
259		int             state;
260
261		if (get_slot_info(so, i, &manuf, &version, &device,
262				  &state) < 0)
263		    goto out;
264		if (manuf == NULL || version == NULL || device == NULL)
265		    goto out;
266		printf("%d~%s~%s~%s~%s\n",
267		       i, manuf, version, device, strstate(state));
268		free(manuf);
269		free(version);
270		free(device);
271	    }
272	}
273    }
274  out:
275    if (path) {
276	unlink(path);
277	free(path);
278    }
279    if (so >= 0)
280	close(so);
281    exit(0);
282}
283