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() 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:")) != EOF) { 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 slen = snprintf(buf, sizeof buf, "N%d", slot); 168 if ((rv = write(so, buf, slen)) < 0) { 169 warn("write"); 170 goto err; 171 } else if (rv != slen) { 172 warnc(0, "write"); 173 goto err; 174 } 175 176 if ((rv = read(so, buf, sizeof buf)) < 0) { 177 warn("read"); 178 goto err; 179 } 180 181 s = buf; 182 if ((sl = strsep(&s, "~")) == NULL) 183 goto parse_err; 184 if (atoi(sl) != slot) 185 goto parse_err; 186 if ((_manuf = strsep(&s, "~")) == NULL) 187 goto parse_err; 188 if ((_version = strsep(&s, "~")) == NULL) 189 goto parse_err; 190 if ((_device = strsep(&s, "~")) == NULL) 191 goto parse_err; 192 if (sscanf(s, "%1d", state) != 1) 193 goto parse_err; 194 if (s != NULL && strchr(s, '~') != NULL) 195 goto parse_err; 196 197 if ((*manuf = strdup(_manuf)) == NULL) { 198 warn("strdup"); 199 goto err; 200 } 201 if ((*version = strdup(_version)) == NULL) { 202 warn("strdup"); 203 goto err; 204 } 205 if ((*device = strdup(_device)) == NULL) { 206 warn("strdup"); 207 goto err; 208 } 209 if (*manuf == NULL || *version == NULL || *device == NULL) { 210 warn("strdup"); 211 goto err; 212 } 213 214 rc = 0; 215 err: 216 return rc; 217 parse_err: 218 warnc(0, "Invalid response: %*s", rv, buf); 219 return rc; 220 } 221 222 const char * 223 strstate(int state) 224 { 225 switch (state) { 226 case 0: 227 return "empty"; 228 case 1: 229 return "filled"; 230 case 2: 231 return "inactive"; 232 default: 233 return "unknown"; 234 } 235 } 236 237 int 238 main(int ac, char **av) 239 { 240 char *path = NULL; 241 int so = -1; 242 int nslot; 243 int i; 244 245 if (proc_arg(ac, av) < 0) 246 goto out; 247 if ((so = connect_to_pccardd(&path)) < 0) 248 goto out; 249 if ((nslot = get_slot_number(so)) < 0) 250 goto out; 251 if (slot_map == 0) { 252 printf("%d\n", nslot); 253 } else { 254 for (i = 0; i < nslot; i++) { 255 if ((slot_map & (1 << i))) { 256 char *manuf; 257 char *version; 258 char *device; 259 int state; 260 261 if (get_slot_info(so, i, &manuf, &version, &device, 262 &state) < 0) 263 goto out; 264 if (manuf == NULL || version == NULL || device == NULL) 265 goto out; 266 printf("%d~%s~%s~%s~%s\n", 267 i, manuf, version, device, strstate(state)); 268 free(manuf); 269 free(version); 270 free(device); 271 } 272 } 273 } 274 out: 275 if (path) { 276 unlink(path); 277 free(path); 278 } 279 if (so >= 0) 280 close(so); 281 exit(0); 282 } 283