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