1 /* $FreeBSD: stable/9/usr.sbin/apmd/contrib/pccardq.c 208075 2010-05-14 14:26:56Z uqs $ */
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
usage(void)23 usage(void)
24 {
25 fprintf(stderr, "usage: %s [-a] [-n] [-s slot]\n", prog);
26 }
27
28 int
proc_arg(int ac,char ** av)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
connect_to_pccardd(char ** path)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
get_slot_number(int so)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
get_slot_info(int so,int slot,char ** manuf,char ** version,char ** device,int * state)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 *
strstate(int state)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
main(int ac,char ** av)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