xref: /freebsd/usr.sbin/apmd/contrib/pccardq.c (revision 42249ef2)
1 /* $FreeBSD$ */
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 
17 const char     *const pccardd_file = "/var/tmp/.pccardd";
18 const char     *prog = "pccardq";
19 const char     *tmp_dir = "/tmp";
20 unsigned        slot_map = ~0;
21 
22 void
23 usage(void)
24 {
25     fprintf(stderr, "usage: %s [-a] [-n] [-s slot]\n", prog);
26 }
27 
28 int
29 proc_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:")) != -1) {
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 
71 int
72 connect_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 
116 int
117 get_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 
145 enum {
146     SLOT_EMPTY = 0,
147     SLOT_FILLED = 1,
148     SLOT_INACTIVE = 2,
149     SLOT_UNDEFINED = 9
150 };
151 
152 int
153 get_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     if ((slen = snprintf(buf, sizeof buf, "N%d", slot)) < 0) {
168 	warnc(0, "write");
169 	goto err;
170     }
171 
172     if ((rv = write(so, buf, slen)) < 0) {
173 	warn("write");
174 	goto err;
175     } else if (rv != slen) {
176 	warnc(0, "write");
177 	goto err;
178     }
179 
180     if ((rv = read(so, buf, sizeof buf)) < 0) {
181 	warn("read");
182 	goto err;
183     }
184 
185     s = buf;
186     if ((sl = strsep(&s, "~")) == NULL)
187 	goto parse_err;
188     if (atoi(sl) != slot)
189 	goto parse_err;
190     if ((_manuf = strsep(&s, "~")) == NULL)
191 	goto parse_err;
192     if ((_version = strsep(&s, "~")) == NULL)
193 	goto parse_err;
194     if ((_device = strsep(&s, "~")) == NULL)
195 	goto parse_err;
196     if (sscanf(s, "%1d", state) != 1)
197 	goto parse_err;
198     if (s != NULL && strchr(s, '~') != NULL)
199 	goto parse_err;
200 
201     if ((*manuf = strdup(_manuf)) == NULL) {
202 	warn("strdup");
203 	goto err;
204     }
205     if ((*version = strdup(_version)) == NULL) {
206 	warn("strdup");
207 	goto err;
208     }
209     if ((*device = strdup(_device)) == NULL) {
210 	warn("strdup");
211 	goto err;
212     }
213     if (*manuf == NULL || *version == NULL || *device == NULL) {
214 	warn("strdup");
215 	goto err;
216     }
217 
218     rc = 0;
219   err:
220     return rc;
221   parse_err:
222     warnc(0, "Invalid response: %*s", rv, buf);
223     return rc;
224 }
225 
226 const char *
227 strstate(int state)
228 {
229     switch (state) {
230     case 0:
231 	return "empty";
232     case 1:
233 	return "filled";
234     case 2:
235 	return "inactive";
236     default:
237 	return "unknown";
238     }
239 }
240 
241 int
242 main(int ac, char **av)
243 {
244     char           *path = NULL;
245     int             so = -1;
246     int             nslot;
247     int             i;
248 
249     if (proc_arg(ac, av) < 0)
250 	goto out;
251     if ((so = connect_to_pccardd(&path)) < 0)
252 	goto out;
253     if ((nslot = get_slot_number(so)) < 0)
254 	goto out;
255     if (slot_map == 0) {
256 	printf("%d\n", nslot);
257     } else {
258 	for (i = 0; i < nslot; i++) {
259 	    if ((slot_map & (1 << i))) {
260 		char           *manuf;
261 		char           *version;
262 		char           *device;
263 		int             state;
264 
265 		if (get_slot_info(so, i, &manuf, &version, &device,
266 				  &state) < 0)
267 		    goto out;
268 		if (manuf == NULL || version == NULL || device == NULL)
269 		    goto out;
270 		printf("%d~%s~%s~%s~%s\n",
271 		       i, manuf, version, device, strstate(state));
272 		free(manuf);
273 		free(version);
274 		free(device);
275 	    }
276 	}
277     }
278   out:
279     if (path) {
280 	unlink(path);
281 	free(path);
282     }
283     if (so >= 0)
284 	close(so);
285     exit(0);
286 }
287