1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <string.h> 27 #include <strings.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <limits.h> 31 #include <device_info.h> 32 #include <bsm/devices.h> 33 #include <bsm/devalloc.h> 34 35 char *strtok_r(char *, const char *, char **); 36 37 /* externs from getdaent.c */ 38 extern char *trim_white(char *); 39 extern int pack_white(char *); 40 extern char *getdadmfield(char *, char *); 41 extern int getdadmline(char *, int, FILE *); 42 43 static struct _dmapbuff { 44 FILE *_dmapf; /* for /etc/security/device_maps */ 45 devmap_t _interpdevmap; 46 char _interpdmline[DA_BUFSIZE + 1]; 47 char *_DEVMAP; 48 } *__dmapbuff; 49 50 #define dmapf (_dmap->_dmapf) 51 #define interpdevmap (_dmap->_interpdevmap) 52 #define interpdmline (_dmap->_interpdmline) 53 #define DEVMAPS_FILE (_dmap->_DEVMAP) 54 55 devmap_t *dmap_interpret(char *, devmap_t *); 56 static devmap_t *dmap_interpretf(char *, devmap_t *); 57 static devmap_t *dmap_dlexpand(devmap_t *); 58 59 int dmap_matchdev(devmap_t *, char *); 60 int dmap_matchname(devmap_t *, char *); 61 62 63 /* 64 * _dmapalloc - 65 * allocates common buffers and structures. 66 * returns pointer to the new structure, else returns NULL on error. 67 */ 68 static struct _dmapbuff * 69 _dmapalloc(void) 70 { 71 struct _dmapbuff *_dmap = __dmapbuff; 72 73 if (_dmap == NULL) { 74 _dmap = (struct _dmapbuff *)calloc((unsigned)1, 75 (unsigned)sizeof (*__dmapbuff)); 76 if (_dmap == NULL) 77 return (NULL); 78 DEVMAPS_FILE = "/etc/security/device_maps"; 79 dmapf = NULL; 80 __dmapbuff = _dmap; 81 } 82 83 return (_dmap); 84 } 85 86 /* 87 * setdmapent - 88 * rewinds the device_maps file to the beginning. 89 */ 90 void 91 setdmapent(void) 92 { 93 struct _dmapbuff *_dmap = _dmapalloc(); 94 95 if (_dmap == NULL) 96 return; 97 if (dmapf == NULL) 98 dmapf = fopen(DEVMAPS_FILE, "rF"); 99 else 100 rewind(dmapf); 101 } 102 103 /* 104 * enddmapent - 105 * closes device_maps file. 106 */ 107 void 108 enddmapent(void) 109 { 110 struct _dmapbuff *_dmap = _dmapalloc(); 111 112 if (_dmap == NULL) 113 return; 114 if (dmapf != NULL) { 115 (void) fclose(dmapf); 116 dmapf = NULL; 117 } 118 } 119 120 void 121 freedmapent(devmap_t *dmap) 122 { 123 char **darp; 124 125 if ((darp = dmap->dmap_devarray) != NULL) { 126 while (*darp != NULL) 127 free(*darp++); 128 free(dmap->dmap_devarray); 129 dmap->dmap_devarray = NULL; 130 } 131 } 132 133 /* 134 * setdmapfile - 135 * changes the default device_maps file to the one specified. 136 * It does not close the previous file. If this is desired, enddmapent 137 * should be called prior to setdampfile. 138 */ 139 void 140 setdmapfile(char *file) 141 { 142 struct _dmapbuff *_dmap = _dmapalloc(); 143 144 if (_dmap == NULL) 145 return; 146 if (dmapf != NULL) { 147 (void) fclose(dmapf); 148 dmapf = NULL; 149 } 150 DEVMAPS_FILE = file; 151 } 152 153 /* 154 * getdmapent - 155 * When first called, returns a pointer to the first devmap_t structure 156 * in device_maps; thereafter, it returns a pointer to the next devmap_t 157 * structure in the file. Thus successive calls can be used to read the 158 * entire file. 159 * call to getdmapent should be bracketed by setdmapent and enddmapent. 160 * returns pointer to devmap_t found, else returns NULL if no entry found 161 * or on error. 162 */ 163 devmap_t * 164 getdmapent(void) 165 { 166 devmap_t *dmap; 167 struct _dmapbuff *_dmap = _dmapalloc(); 168 169 if ((_dmap == 0) || (dmapf == NULL)) 170 return (NULL); 171 172 while (getdadmline(interpdmline, (int)sizeof (interpdmline), 173 dmapf) != 0) { 174 if ((dmap = dmap_interpret(interpdmline, 175 &interpdevmap)) == NULL) 176 continue; 177 return (dmap); 178 } 179 180 return (NULL); 181 } 182 183 /* 184 * getdmapnam - 185 * searches from the beginning of device_maps for the device specified by 186 * its name. 187 * call to getdmapnam should be bracketed by setdmapent and enddmapent. 188 * returns pointer to devmapt_t for the device if it is found, else 189 * returns NULL if device not found or in case of error. 190 */ 191 devmap_t * 192 getdmapnam(char *name) 193 { 194 devmap_t *dmap; 195 struct _dmapbuff *_dmap = _dmapalloc(); 196 197 if ((name == NULL) || (_dmap == 0) || (dmapf == NULL)) 198 return (NULL); 199 200 while (getdadmline(interpdmline, (int)sizeof (interpdmline), 201 dmapf) != 0) { 202 if (strstr(interpdmline, name) == NULL) 203 continue; 204 if ((dmap = dmap_interpretf(interpdmline, 205 &interpdevmap)) == NULL) 206 continue; 207 if (dmap_matchname(dmap, name)) { 208 if ((dmap = dmap_dlexpand(dmap)) == NULL) 209 continue; 210 enddmapent(); 211 return (dmap); 212 } 213 freedmapent(dmap); 214 } 215 216 return (NULL); 217 } 218 219 /* 220 * getdmapdev - 221 * searches from the beginning of device_maps for the device specified by 222 * its logical name. 223 * call to getdmapdev should be bracketed by setdmapent and enddmapent. 224 * returns pointer to the devmap_t for the device if device is found, 225 * else returns NULL if device not found or on error. 226 */ 227 devmap_t * 228 getdmapdev(char *dev) 229 { 230 devmap_t *dmap; 231 struct _dmapbuff *_dmap = _dmapalloc(); 232 233 if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL)) 234 return (NULL); 235 236 while (getdadmline(interpdmline, (int)sizeof (interpdmline), 237 dmapf) != 0) { 238 if ((dmap = dmap_interpret(interpdmline, 239 &interpdevmap)) == NULL) 240 continue; 241 if (dmap_matchdev(dmap, dev)) { 242 enddmapent(); 243 return (dmap); 244 } 245 freedmapent(dmap); 246 } 247 248 return (NULL); 249 } 250 251 /* 252 * getdmaptype - 253 * searches from the beginning of device_maps for the device specified by 254 * its type. 255 * call to getdmaptype should be bracketed by setdmapent and enddmapent. 256 * returns pointer to devmap_t found, else returns NULL if no entry found 257 * or on error. 258 */ 259 devmap_t * 260 getdmaptype(char *type) 261 { 262 devmap_t *dmap; 263 struct _dmapbuff *_dmap = _dmapalloc(); 264 265 if ((type == NULL) || (_dmap == 0) || (dmapf == NULL)) 266 return (NULL); 267 268 while (getdadmline(interpdmline, (int)sizeof (interpdmline), 269 dmapf) != 0) { 270 if ((dmap = dmap_interpretf(interpdmline, 271 &interpdevmap)) == NULL) 272 continue; 273 if (dmap->dmap_devtype != NULL && 274 strcmp(type, dmap->dmap_devtype) == 0) { 275 if ((dmap = dmap_dlexpand(dmap)) == NULL) 276 continue; 277 return (dmap); 278 } 279 freedmapent(dmap); 280 } 281 282 return (NULL); 283 } 284 285 /* 286 * dmap_match_one_dev - 287 * Checks if the specified devmap_t contains strings 288 * for the same logical link as the device specified. 289 * This guarantees that the beginnings of a devlist build 290 * match a more-complete devlist for the same device. 291 * 292 * Returns 1 for a match, else returns 0. 293 */ 294 static int 295 dmap_match_one_dev(devmap_t *dmap, char *dev) 296 { 297 char **dva; 298 char *dv; 299 300 if (dmap->dmap_devarray == NULL) 301 return (0); 302 303 for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva++) { 304 if (strstr(dev, dv) != NULL) 305 return (1); 306 } 307 return (0); 308 } 309 310 /* 311 * dmap_matchdev - 312 * checks if the specified devmap_t is for the device specified. 313 * returns 1 if it is, else returns 0. 314 */ 315 int 316 dmap_matchdev(devmap_t *dmap, char *dev) 317 { 318 char **dva; 319 char *dv; 320 321 if (dmap->dmap_devarray == NULL) 322 return (0); 323 for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) { 324 if (strcmp(dv, dev) == 0) 325 return (1); 326 } 327 328 return (0); 329 } 330 331 /* 332 * Requires a match of the /dev/?dsk links, not just the logical devname 333 * Returns 1 for match found, 0 for match not found, 2 for invalid arguments. 334 */ 335 int 336 dmap_exact_dev(devmap_t *dmap, char *dev, int *num) 337 { 338 char *dv; 339 340 if ((dev == NULL) || (dmap->dmap_devname == NULL)) 341 return (2); 342 dv = dmap->dmap_devname; 343 dv += strcspn(dmap->dmap_devname, "0123456789"); 344 if (sscanf(dv, "%d", num) != 1) 345 return (2); 346 /* during some add processes, dev can be shorter than dmap */ 347 return (dmap_match_one_dev(dmap, dev)); 348 } 349 350 /* 351 * dmap_matchtype - 352 * checks if the specified devmap_t is for the device specified. 353 * returns 1 if it is, else returns 0. 354 */ 355 int 356 dmap_matchtype(devmap_t *dmap, char *type) 357 { 358 if ((dmap->dmap_devtype == NULL) || (type == NULL)) 359 return (0); 360 361 return ((strcmp(dmap->dmap_devtype, type) == 0)); 362 } 363 364 /* 365 * dmap_matchname - 366 * checks if the specified devmap_t is for the device specified. 367 * returns 1 if it is, else returns 0. 368 */ 369 int 370 dmap_matchname(devmap_t *dmap, char *name) 371 { 372 if (dmap->dmap_devname == NULL) 373 return (0); 374 375 return ((strcmp(dmap->dmap_devname, name) == 0)); 376 } 377 378 /* 379 * dmap_physname: path to /devices device 380 * Returns: 381 * strdup'd (i.e. malloc'd) real device file if successful 382 * NULL on error 383 */ 384 char * 385 dmap_physname(devmap_t *dmap) 386 { 387 char *oldlink; 388 char stage_link[PATH_MAX + 1]; 389 390 if ((dmap == NULL) || (dmap->dmap_devarray == NULL) || 391 (dmap->dmap_devarray[0] == NULL)) 392 return (NULL); 393 394 (void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link)); 395 396 if (devfs_resolve_link(stage_link, &oldlink) == 0) 397 return (oldlink); 398 return (NULL); 399 } 400 401 /* 402 * dm_match - 403 * calls dmap_matchname or dmap_matchtype as appropriate. 404 */ 405 int 406 dm_match(devmap_t *dmap, da_args *dargs) 407 { 408 if (dargs->devinfo->devname) 409 return (dmap_matchname(dmap, dargs->devinfo->devname)); 410 else if (dargs->devinfo->devtype) 411 return (dmap_matchtype(dmap, dargs->devinfo->devtype)); 412 413 return (0); 414 } 415 416 /* 417 * dmap_interpret - 418 * calls dmap_interpretf and dmap_dlexpand to parse devmap_t line. 419 * returns pointer to parsed devmapt_t entry, else returns NULL on error. 420 */ 421 devmap_t * 422 dmap_interpret(char *val, devmap_t *dm) 423 { 424 if (dmap_interpretf(val, dm) == NULL) 425 return (NULL); 426 427 return (dmap_dlexpand(dm)); 428 } 429 430 /* 431 * dmap_interpretf - 432 * parses string "val" and initializes pointers in the given devmap_t to 433 * fields in "val". 434 * returns pointer to updated devmap_t. 435 */ 436 static devmap_t * 437 dmap_interpretf(char *val, devmap_t *dm) 438 { 439 dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT); 440 dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT); 441 dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT); 442 dm->dmap_devarray = NULL; 443 if (dm->dmap_devname == NULL || 444 dm->dmap_devtype == NULL || 445 dm->dmap_devlist == NULL) 446 return (NULL); 447 448 return (dm); 449 } 450 451 /* 452 * dmap_dlexpand - 453 * expands dmap_devlist of the form `devlist_generate` 454 * returns unexpanded form if there is no '\`' or in case of error. 455 */ 456 static devmap_t * 457 dmap_dlexpand(devmap_t *dmp) 458 { 459 char tmplist[DA_BUFSIZE + 1]; 460 char *cp, *cpl, **darp; 461 int count; 462 FILE *expansion; 463 464 dmp->dmap_devarray = NULL; 465 if (dmp->dmap_devlist == NULL) 466 return (NULL); 467 if (*(dmp->dmap_devlist) != '`') { 468 (void) strcpy(tmplist, dmp->dmap_devlist); 469 } else { 470 (void) strcpy(tmplist, dmp->dmap_devlist + 1); 471 if ((cp = strchr(tmplist, '`')) != NULL) 472 *cp = '\0'; 473 if ((expansion = popen(tmplist, "rF")) == NULL) 474 return (NULL); 475 count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion); 476 (void) pclose(expansion); 477 tmplist[count] = '\0'; 478 } 479 480 /* cleanup the list */ 481 count = pack_white(tmplist); 482 dmp->dmap_devarray = darp = 483 (char **)malloc((count + 2) * sizeof (char *)); 484 if (darp == NULL) 485 return (NULL); 486 cp = tmplist; 487 while ((cp = strtok_r(cp, " ", &cpl)) != NULL) { 488 *darp = strdup(cp); 489 if (*darp == NULL) { 490 freedmapent(dmp); 491 return (NULL); 492 } 493 darp++; 494 cp = NULL; 495 } 496 *darp = NULL; 497 498 return (dmp); 499 } 500 501 /* 502 * dmapskip - 503 * scans input string to find next colon or end of line. 504 * returns pointer to next char. 505 */ 506 static char * 507 dmapskip(char *p) 508 { 509 while (*p && *p != ':' && *p != '\n') 510 ++p; 511 if (*p == '\n') 512 *p = '\0'; 513 else if (*p != '\0') 514 *p++ = '\0'; 515 516 return (p); 517 } 518 519 /* 520 * dmapdskip - 521 * scans input string to find next space or end of line. 522 * returns pointer to next char. 523 */ 524 static char * 525 dmapdskip(p) 526 register char *p; 527 { 528 while (*p && *p != ' ' && *p != '\n') 529 ++p; 530 if (*p != '\0') 531 *p++ = '\0'; 532 533 return (p); 534 } 535 536 char * 537 getdmapfield(char *ptr) 538 { 539 static char *tptr; 540 541 if (ptr == NULL) 542 ptr = tptr; 543 if (ptr == NULL) 544 return (NULL); 545 tptr = dmapskip(ptr); 546 ptr = trim_white(ptr); 547 if (ptr == NULL) 548 return (NULL); 549 if (*ptr == NULL) 550 return (NULL); 551 552 return (ptr); 553 } 554 555 char * 556 getdmapdfield(char *ptr) 557 { 558 static char *tptr; 559 if (ptr != NULL) { 560 ptr = trim_white(ptr); 561 } else { 562 ptr = tptr; 563 } 564 if (ptr == NULL) 565 return (NULL); 566 tptr = dmapdskip(ptr); 567 if (ptr == NULL) 568 return (NULL); 569 if (*ptr == NULL) 570 return (NULL); 571 572 return (ptr); 573 } 574