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