xref: /freebsd/usr.sbin/apmd/contrib/pccardq.c (revision 5f4c09dd85bff675e0ca63c55ea3c517e0fddfcc)
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
22 usage(void)
23 {
24     fprintf(stderr, "usage: %s [-a] [-n] [-s slot]\n", prog);
25 }
26 
27 int
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
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
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
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 *
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
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