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