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 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdlib.h> 28 #include <ctype.h> 29 #include <unistd.h> 30 #include <limits.h> 31 #include <fcntl.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <utime.h> 35 #include <synch.h> 36 #include <strings.h> 37 #include <string.h> 38 #include <libintl.h> 39 #include <errno.h> 40 #include <auth_list.h> 41 #include <syslog.h> 42 #include <bsm/devices.h> 43 #include <bsm/devalloc.h> 44 45 #define DA_DEFS "/etc/security/tsol/devalloc_defaults" 46 47 extern int _readbufline(char *, int, char *, int, int *); 48 extern char *strtok_r(char *, const char *, char **); 49 extern char *_strtok_escape(char *, char *, char **); 50 extern int getdaon(void); 51 extern int da_matchname(devalloc_t *, char *); 52 extern int da_match(devalloc_t *, da_args *); 53 extern int dmap_matchname(devmap_t *, char *); 54 extern int dm_match(devmap_t *, da_args *); 55 extern int dmap_matchtype(devmap_t *dmap, char *type); 56 extern int dmap_matchdev(devmap_t *dmap, char *dev); 57 extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num); 58 extern char *dmap_physname(devmap_t *dmap); 59 60 /* 61 * The following structure is for recording old entries to be retained. 62 * We read the entries from the database into a linked list in memory, 63 * then turn around and write them out again. 64 */ 65 typedef struct strentry { 66 struct strentry *se_next; 67 char se_str[4096 + 1]; 68 } strentry_t; 69 70 /* 71 * da_check_longindevperm - 72 * reads /etc/logindevperm and checks if specified device is in the file. 73 * returns 1 if specified device found in /etc/logindevperm, else returns 0 74 */ 75 int 76 da_check_logindevperm(char *devname) 77 { 78 int ret = 0; 79 int fd = -1; 80 int nlen, plen, slen, lineno, fsize; 81 char line[MAX_CANON]; 82 char *field_delims = " \t\n"; 83 char *fbuf = NULL; 84 char *ptr, *device; 85 char *lasts = NULL; 86 FILE *fp; 87 struct stat f_stat; 88 89 /* 90 * check if /etc/logindevperm exists and get its size 91 */ 92 if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1) 93 return (0); 94 if (fstat(fd, &f_stat) != 0) { 95 (void) close(fd); 96 return (0); 97 } 98 fsize = f_stat.st_size; 99 if ((fbuf = (char *)malloc(fsize)) == NULL) { 100 (void) close(fd); 101 return (0); 102 } 103 if ((fp = fdopen(fd, "rF")) == NULL) { 104 free(fbuf); 105 (void) close(fd); 106 return (0); 107 } 108 109 /* 110 * read and parse /etc/logindevperm 111 */ 112 plen = nlen = lineno = 0; 113 while (fgets(line, MAX_CANON, fp) != NULL) { 114 lineno++; 115 if ((ptr = strchr(line, '#')) != NULL) 116 *ptr = '\0'; /* handle comments */ 117 if (strtok_r(line, field_delims, &lasts) == NULL) 118 continue; /* ignore blank lines */ 119 if (strtok_r(NULL, field_delims, &lasts) == NULL) 120 /* invalid entry */ 121 continue; 122 if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL) 123 /* empty device list */ 124 continue; 125 nlen = strlen(ptr) + 1; /* +1 terminator */ 126 nlen += (plen + 1); 127 if (plen == 0) 128 slen = snprintf(fbuf, nlen, "%s", ptr); 129 else 130 slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr); 131 if (slen >= fsize) { 132 fbuf[0] = '\0'; 133 (void) fclose(fp); 134 return (slen); 135 } 136 plen += slen; 137 } 138 (void) fclose(fp); 139 140 /* 141 * check if devname exists in /etc/logindevperm 142 */ 143 device = strtok_r(fbuf, ":", &lasts); 144 while (device != NULL) { 145 /* 146 * device and devname may be one of these types - 147 * /dev/xx 148 * /dev/xx* 149 * /dev/dir/xx 150 * /dev/dir/xx* 151 * /dev/dir/"*" 152 */ 153 if (strcmp(device, devname) == 0) { 154 /* /dev/xx, /dev/dir/xx */ 155 free(fbuf); 156 return (1); 157 } 158 if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) { 159 /* all wildcard types */ 160 *ptr = '\0'; 161 if (strncmp(device, devname, strlen(device)) == 0) { 162 free(fbuf); 163 return (1); 164 } 165 } 166 device = strtok_r(NULL, ":", &lasts); 167 } 168 169 return (ret); 170 } 171 172 /* 173 * _da_read_file - 174 * establishes readers/writer lock on fname; reads in the file if its 175 * contents changed since the last time we read it. 176 * returns size of buffer read, or -1 on failure. 177 */ 178 int 179 _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock, 180 int flag) 181 { 182 int fd = -1; 183 int fsize = 0; 184 time_t newtime; 185 struct stat f_stat; 186 187 if (flag & DA_FORCE) 188 *ftime = 0; 189 190 /* check the size and the time stamp on the file */ 191 if (rw_rdlock(flock) != 0) 192 return (-1); 193 if (stat(fname, &f_stat) != 0) { 194 (void) rw_unlock(flock); 195 return (-1); 196 } 197 fsize = f_stat.st_size; 198 newtime = f_stat.st_mtime; 199 (void) rw_unlock(flock); 200 201 while (newtime > *ftime) { 202 /* 203 * file has been modified since we last read it; or this 204 * is a forced read. 205 * read file into the buffer with rw lock. 206 */ 207 if (rw_wrlock(flock) != 0) 208 return (-1); 209 if ((fd = open(fname, O_RDONLY)) == -1) { 210 (void) rw_unlock(flock); 211 return (-1); 212 } 213 if (*fbuf != NULL) { 214 free(*fbuf); 215 *fbuf = NULL; 216 } 217 if ((*fbuf = malloc(fsize)) == NULL) { 218 (void) rw_unlock(flock); 219 (void) close(fd); 220 return (-1); 221 } 222 if (read(fd, *fbuf, fsize) < fsize) { 223 free(*fbuf); 224 (void) rw_unlock(flock); 225 (void) close(fd); 226 return (-1); 227 } 228 (void) rw_unlock(flock); 229 /* 230 * verify that the file did not change just after we read it. 231 */ 232 if (rw_rdlock(flock) != 0) { 233 free(*fbuf); 234 (void) close(fd); 235 return (-1); 236 } 237 if (stat(fname, &f_stat) != 0) { 238 free(*fbuf); 239 (void) rw_unlock(flock); 240 (void) close(fd); 241 return (-1); 242 } 243 fsize = f_stat.st_size; 244 newtime = f_stat.st_mtime; 245 (void) rw_unlock(flock); 246 (void) close(fd); 247 *ftime = newtime; 248 } 249 250 return (fsize); 251 } 252 253 /* 254 * _update_zonename - 255 * add/remove current zone's name to the given devalloc_t. 256 */ 257 void 258 _update_zonename(da_args *dargs, devalloc_t *dap) 259 { 260 int i, j; 261 int oldsize, newsize; 262 int has_zonename = 0; 263 char *zonename; 264 kva_t *newkva, *oldkva; 265 kv_t *newdata, *olddata; 266 devinfo_t *devinfo; 267 268 devinfo = dargs->devinfo; 269 oldkva = dap->da_devopts; 270 if (oldkva == NULL) { 271 if (dargs->optflag & DA_REMOVE_ZONE) 272 return; 273 if (dargs->optflag & DA_ADD_ZONE) { 274 newkva = _str2kva(devinfo->devopts, KV_ASSIGN, 275 KV_TOKEN_DELIMIT); 276 if (newkva != NULL) 277 dap->da_devopts = newkva; 278 return; 279 } 280 } 281 newsize = oldsize = oldkva->length; 282 if (kva_match(oldkva, DAOPT_ZONE)) 283 has_zonename = 1; 284 if (dargs->optflag & DA_ADD_ZONE) { 285 if ((zonename = index(devinfo->devopts, '=')) == NULL) 286 return; 287 zonename++; 288 if (has_zonename) { 289 (void) _insert2kva(oldkva, DAOPT_ZONE, zonename); 290 return; 291 } 292 newsize += 1; 293 } else if (dargs->optflag & DA_REMOVE_ZONE) { 294 if (has_zonename) { 295 newsize -= 1; 296 if (newsize == 0) { 297 /* 298 * If zone name was the only key/value pair, 299 * put 'reserved' in the empty slot. 300 */ 301 _kva_free(oldkva); 302 dap->da_devopts = NULL; 303 return; 304 } 305 } else { 306 return; 307 } 308 } 309 newkva = _new_kva(newsize); 310 newkva->length = 0; 311 newdata = newkva->data; 312 olddata = oldkva->data; 313 for (i = 0, j = 0; i < oldsize; i++) { 314 if ((dargs->optflag & DA_REMOVE_ZONE) && 315 (strcmp(olddata[i].key, DAOPT_ZONE) == 0)) 316 continue; 317 newdata[j].key = strdup(olddata[i].key); 318 newdata[j].value = strdup(olddata[i].value); 319 newkva->length++; 320 j++; 321 } 322 if (dargs->optflag & DA_ADD_ZONE) { 323 newdata[j].key = strdup(DAOPT_ZONE); 324 newdata[j].value = strdup(zonename); 325 newkva->length++; 326 } 327 _kva_free(oldkva); 328 dap->da_devopts = newkva; 329 } 330 331 /* 332 * _dmap2str - 333 * converts a device_map entry into a printable string 334 * returns 0 on success, -1 on error. 335 */ 336 /*ARGSUSED*/ 337 static int 338 _dmap2str(devmap_t *dmp, char *buf, int size, const char *sep) 339 { 340 int length; 341 342 length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep); 343 if (length >= size) 344 return (-1); 345 length += snprintf(buf + length, size - length, "%s%s", 346 dmp->dmap_devtype, sep); 347 if (length >= size) 348 return (-1); 349 length += snprintf(buf + length, size - length, "%s\n", 350 dmp->dmap_devlist); 351 if (length >= size) 352 return (-1); 353 return (0); 354 } 355 356 /* 357 * _dmap2strentry - 358 * calls dmap2str to break given devmap_t into printable entry. 359 * returns pointer to decoded entry, NULL on error. 360 */ 361 static strentry_t * 362 _dmap2strentry(devmap_t *devmapp) 363 { 364 strentry_t *sep; 365 366 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 367 return (NULL); 368 if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str), 369 KV_TOKEN_DELIMIT"\\\n\t") != 0) { 370 free(sep); 371 return (NULL); 372 } 373 return (sep); 374 } 375 376 /* 377 * fix_optstr - 378 * removes trailing ':' from buf. 379 */ 380 void 381 fix_optstr(char *buf) 382 { 383 char *p = NULL; 384 385 if (p = rindex(buf, ':')) 386 *p = ';'; 387 } 388 389 /* 390 * _da2str - 391 * converts a device_allocate entry into a printable string 392 * returns 0 on success, -1 on error. 393 */ 394 static int 395 _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep, 396 const char *osep) 397 { 398 int length; 399 int matching_entry = 0; 400 char **dnames; 401 402 if (dargs->optflag & DA_UPDATE && 403 (dargs->optflag & DA_ADD_ZONE || 404 dargs->optflag & DA_REMOVE_ZONE) && 405 dargs->devnames) { 406 for (dnames = dargs->devnames; *dnames != NULL; dnames++) { 407 if (da_matchname(dap, *dnames)) { 408 matching_entry = 1; 409 break; 410 } 411 } 412 } 413 length = snprintf(buf, size, "%s%s", dap->da_devname, sep); 414 if (length >= size) 415 return (-1); 416 length += snprintf(buf + length, size - length, "%s%s", 417 dap->da_devtype, sep); 418 if (length >= size) 419 return (-1); 420 if (matching_entry) 421 _update_zonename(dargs, dap); 422 if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) && 423 (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) { 424 length += snprintf(buf + length, size - length, "%s%s", 425 DA_RESERVED, sep); 426 } else { 427 if (_kva2str(dap->da_devopts, buf + length, size - length, 428 KV_ASSIGN, (char *)osep) != 0) 429 return (-1); 430 length = strlen(buf); 431 } 432 if (dap->da_devopts) 433 fix_optstr(buf); 434 if (length >= size) 435 return (-1); 436 length += snprintf(buf + length, size - length, "%s%s", 437 DA_RESERVED, sep); 438 if (length >= size) 439 return (-1); 440 length += snprintf(buf + length, size - length, "%s%s", 441 dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep); 442 if (length >= size) 443 return (-1); 444 length += snprintf(buf + length, size - length, "%s\n", 445 dap->da_devexec ? dap->da_devexec : ""); 446 if (length >= size) 447 return (-1); 448 449 return (0); 450 } 451 452 /* 453 * _da2strentry - 454 * calls da2str to break given devalloc_t into printable entry. 455 * returns pointer to decoded entry, NULL on error. 456 */ 457 static strentry_t * 458 _da2strentry(da_args *dargs, devalloc_t *dap) 459 { 460 strentry_t *sep; 461 462 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 463 return (NULL); 464 if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str), 465 KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) { 466 free(sep); 467 return (NULL); 468 } 469 return (sep); 470 } 471 472 /* 473 * _def2str 474 * converts da_defs_t into a printable string. 475 * returns 0 on success, -1 on error. 476 */ 477 static int 478 _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep) 479 { 480 int length; 481 482 length = snprintf(buf, size, "%s%s", da_defs->devtype, sep); 483 if (length >= size) 484 return (-1); 485 if (da_defs->devopts) { 486 if (_kva2str(da_defs->devopts, buf + length, size - length, 487 KV_ASSIGN, KV_DELIMITER) != 0) 488 return (-1); 489 length = strlen(buf); 490 } 491 if (length >= size) 492 return (-1); 493 494 return (0); 495 } 496 497 /* 498 * _def2strentry 499 * calls _def2str to break given da_defs_t into printable entry. 500 * returns pointer decoded entry, NULL on error. 501 */ 502 static strentry_t * 503 _def2strentry(da_defs_t *da_defs) 504 { 505 strentry_t *sep; 506 507 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 508 return (NULL); 509 if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str), 510 KV_TOKEN_DELIMIT) != 0) { 511 free(sep); 512 return (NULL); 513 } 514 515 return (sep); 516 } 517 518 /* 519 * _build_defattrs 520 * cycles through all defattr entries, stores them in memory. removes 521 * entries with the given search_key (device type). 522 * returns 0 if given entry not found, 1 if given entry removed, 2 on 523 * error. 524 */ 525 static int 526 _build_defattrs(da_args *dargs, strentry_t **head_defent) 527 { 528 int rc = 0; 529 da_defs_t *da_defs; 530 strentry_t *tail_str, *tmp_str; 531 532 setdadefent(); 533 while ((da_defs = getdadefent()) != NULL) { 534 rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype)); 535 if (rc && dargs->optflag & DA_ADD && 536 !(dargs->optflag & DA_FORCE)) { 537 /* 538 * During DA_ADD, we keep an existing entry unless 539 * we have DA_FORCE set to override that entry. 540 */ 541 dargs->optflag |= DA_NO_OVERRIDE; 542 rc = 0; 543 } 544 if (rc == 0) { 545 tmp_str = _def2strentry(da_defs); 546 if (tmp_str == NULL) { 547 freedadefent(da_defs); 548 enddadefent(); 549 return (2); 550 } 551 /* retaining defattr entry: tmp_str->se_str */ 552 tmp_str->se_next = NULL; 553 if (*head_defent == NULL) { 554 *head_defent = tail_str = tmp_str; 555 } else { 556 tail_str->se_next = tmp_str; 557 tail_str = tmp_str; 558 } 559 } 560 freedadefent(da_defs); 561 } 562 enddadefent(); 563 564 return (rc); 565 } 566 567 /* 568 * _rebuild_lists - 569 * 570 * If dargs->optflag & DA_EVENT, does not assume the dargs list is 571 * complete or completely believable, since devfsadm caches 572 * ONLY what it has been exposed to via syseventd. 573 * 574 * Cycles through all the entries in the /etc files, stores them 575 * in memory, takes note of device->dname numbers (i.e. rmdisk0, 576 * rmdisk12) 577 * 578 * Cycles through again, adds dargs entry 579 * with the name tname%d (lowest unused number for the device type) 580 * to the list of things for the caller to write out to a file, 581 * IFF it is a new entry. 582 * 583 * It is an error for it to already be there. 584 * 585 * Add: 586 * Returns 0 if successful and 2 on error. 587 * Remove: 588 * Returns 0 if not found, 1 if found, 2 on error. 589 */ 590 static int 591 _rebuild_lists(da_args *dargs, strentry_t **head_devallocp, 592 strentry_t **head_devmapp) 593 { 594 int rc = 0; 595 devalloc_t *devallocp; 596 devmap_t *devmapp; 597 strentry_t *tail_str; 598 strentry_t *tmp_str; 599 uint64_t tmp_bitmap = 0; 600 int tmp = 0; 601 char new_devname[DA_MAXNAME + 1]; 602 char errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80]; 603 char *realname; 604 int suffix = DA_MAX_DEVNO + 1; 605 int found = 0; 606 607 if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY)) 608 return (2); 609 610 if (dargs->optflag & DA_FORCE) 611 return (2); 612 613 /* read both files, maps first so we can compare actual devices */ 614 615 /* build device_maps */ 616 setdmapent(); 617 while ((devmapp = getdmapent()) != NULL) { 618 if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype)) 619 == 1) { 620 if (dargs->optflag & DA_REMOVE) { 621 if ((devmapp->dmap_devarray == NULL) || 622 (devmapp->dmap_devarray[0] == NULL)) { 623 freedmapent(devmapp); 624 enddmapent(); 625 return (2); 626 } 627 realname = dmap_physname(devmapp); 628 if (realname == NULL) { 629 freedmapent(devmapp); 630 enddmapent(); 631 return (2); 632 } 633 if (strstr(realname, dargs->devinfo->devlist) 634 != NULL) { 635 if (dargs->devinfo->devname != NULL) 636 free(dargs->devinfo->devname); 637 dargs->devinfo->devname = 638 strdup(devmapp->dmap_devname); 639 found = 1; 640 freedmapent(devmapp); 641 continue; /* don't retain */ 642 } 643 } else if (dargs->optflag & DA_ADD) { 644 /* 645 * Need to know which suffixes are in use 646 */ 647 rc = (dmap_exact_dev(devmapp, 648 dargs->devinfo->devlist, &suffix)); 649 650 if (rc == 0) { 651 /* 652 * Same type, different device. Record 653 * device suffix already in use. 654 */ 655 if (suffix > DA_MAX_DEVNO) { 656 freedmapent(devmapp); 657 enddmapent(); 658 return (2); 659 } 660 tmp_bitmap |= (uint64_t)(1LL << suffix); 661 } else { 662 /* 663 * Match on add is an error 664 * or mapping attempt returned error 665 */ 666 freedmapent(devmapp); 667 enddmapent(); 668 return (2); 669 } 670 } else 671 /* add other transaction types as needed */ 672 return (2); 673 674 } /* if same type */ 675 676 tmp_str = _dmap2strentry(devmapp); 677 if (tmp_str == NULL) { 678 freedmapent(devmapp); 679 enddmapent(); 680 return (2); 681 } 682 /* retaining devmap entry: tmp_str->se_str */ 683 tmp_str->se_next = NULL; 684 if (*head_devmapp == NULL) { 685 *head_devmapp = tail_str = tmp_str; 686 } else { 687 tail_str->se_next = tmp_str; 688 tail_str = tmp_str; 689 } 690 freedmapent(devmapp); 691 } 692 enddmapent(); 693 694 /* 695 * No need to rewrite the files if the item to be removed is not 696 * in the files -- wait for another call on another darg. 697 */ 698 if ((dargs->optflag & DA_REMOVE) && !found) 699 return (0); 700 701 702 if (dargs->optflag & DA_ADD) { 703 /* 704 * Since we got here from an event, we know the stored 705 * devname is a useless guess, since the files had not 706 * been read when the name was chosen, and we don't keep 707 * them anywhere else that is sufficiently definitive. 708 */ 709 710 for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++) 711 if (!(tmp_bitmap & (1LL << tmp))) 712 break; 713 /* Future: support more than 64 hotplug devices per type? */ 714 if (tmp > DA_MAX_DEVNO) 715 return (2); 716 717 (void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u", 718 dargs->devinfo->devtype, tmp); 719 if (dargs->devinfo->devname != NULL) 720 free(dargs->devinfo->devname); 721 dargs->devinfo->devname = strdup(new_devname); 722 } 723 724 /* 725 * Now adjust devalloc list to match devmaps 726 * Note we now have the correct devname for da_match to use. 727 */ 728 setdaent(); 729 while ((devallocp = getdaent()) != NULL) { 730 rc = da_match(devallocp, dargs); 731 if (rc == 1) { 732 if (dargs->optflag & DA_ADD) { 733 /* logging is on if DA_EVENT is set */ 734 if (dargs->optflag & DA_EVENT) { 735 (void) snprintf(errmsg, sizeof (errmsg), 736 "%s and %s out of sync," 737 "%s only in %s.", 738 DEVALLOC, DEVMAP, 739 devallocp->da_devname, DEVALLOC); 740 syslog(LOG_ERR, "%s", errmsg); 741 } 742 freedaent(devallocp); 743 enddaent(); 744 return (2); 745 } else if (dargs->optflag & DA_REMOVE) { 746 /* make list w/o this entry */ 747 freedaent(devallocp); 748 continue; 749 } 750 } 751 tmp_str = _da2strentry(dargs, devallocp); 752 if (tmp_str == NULL) { 753 freedaent(devallocp); 754 enddaent(); 755 return (2); 756 } 757 /* retaining devalloc entry: tmp_str->se_str */ 758 tmp_str->se_next = NULL; 759 if (*head_devallocp == NULL) { 760 *head_devallocp = tail_str = tmp_str; 761 } else { 762 tail_str->se_next = tmp_str; 763 tail_str = tmp_str; 764 } 765 freedaent(devallocp); 766 } 767 enddaent(); 768 769 /* the caller needs to know if a remove needs to rewrite files */ 770 if (dargs->optflag & DA_REMOVE) 771 return (1); /* 0 and 2 cases returned earlier */ 772 773 return (0); /* Successful DA_ADD */ 774 } 775 /* 776 * _build_lists - 777 * Cycles through all the entries, stores them in memory. removes entries 778 * with the given search_key (device name or type). 779 * returns 0 if given entry not found, 1 if given entry removed, 2 on 780 * error. 781 */ 782 static int 783 _build_lists(da_args *dargs, strentry_t **head_devallocp, 784 strentry_t **head_devmapp) 785 { 786 int rc = 0; 787 devalloc_t *devallocp; 788 devmap_t *devmapp; 789 strentry_t *tail_str; 790 strentry_t *tmp_str; 791 792 if (dargs->optflag & DA_MAPS_ONLY) 793 goto dmap_only; 794 795 /* build device_allocate */ 796 setdaent(); 797 while ((devallocp = getdaent()) != NULL) { 798 rc = da_match(devallocp, dargs); 799 if (rc && dargs->optflag & DA_ADD && 800 !(dargs->optflag & DA_FORCE)) { 801 /* 802 * During DA_ADD, we keep an existing entry unless 803 * we have DA_FORCE set to override that entry. 804 */ 805 dargs->optflag |= DA_NO_OVERRIDE; 806 rc = 0; 807 } 808 if (rc == 0) { 809 tmp_str = _da2strentry(dargs, devallocp); 810 if (tmp_str == NULL) { 811 freedaent(devallocp); 812 enddaent(); 813 return (2); 814 } 815 /* retaining devalloc entry: tmp_str->se_str */ 816 tmp_str->se_next = NULL; 817 if (*head_devallocp == NULL) { 818 *head_devallocp = tail_str = tmp_str; 819 } else { 820 tail_str->se_next = tmp_str; 821 tail_str = tmp_str; 822 } 823 } 824 freedaent(devallocp); 825 } 826 enddaent(); 827 828 dmap_only: 829 if (dargs->optflag & DA_ALLOC_ONLY) 830 return (rc); 831 832 /* build device_maps */ 833 rc = 0; 834 setdmapent(); 835 while ((devmapp = getdmapent()) != NULL) { 836 rc = dm_match(devmapp, dargs); 837 if (rc && dargs->optflag & DA_ADD && 838 !(dargs->optflag & DA_FORCE)) { 839 /* 840 * During DA_ADD, we keep an existing entry unless 841 * we have DA_FORCE set to override that entry. 842 */ 843 dargs->optflag |= DA_NO_OVERRIDE; 844 rc = 0; 845 } 846 if (rc == 0) { 847 tmp_str = _dmap2strentry(devmapp); 848 if (tmp_str == NULL) { 849 freedmapent(devmapp); 850 enddmapent(); 851 return (2); 852 } 853 /* retaining devmap entry: tmp_str->se_str */ 854 tmp_str->se_next = NULL; 855 if (*head_devmapp == NULL) { 856 *head_devmapp = tail_str = tmp_str; 857 } else { 858 tail_str->se_next = tmp_str; 859 tail_str = tmp_str; 860 } 861 } 862 freedmapent(devmapp); 863 } 864 enddmapent(); 865 866 return (rc); 867 } 868 869 /* 870 * _write_defattrs 871 * writes current entries to devalloc_defaults. 872 */ 873 static void 874 _write_defattrs(FILE *fp, strentry_t *head_defent) 875 { 876 strentry_t *tmp_str; 877 878 for (tmp_str = head_defent; tmp_str != NULL; 879 tmp_str = tmp_str->se_next) { 880 (void) fputs(tmp_str->se_str, fp); 881 (void) fputs("\n", fp); 882 } 883 884 } 885 886 /* 887 * _write_device_allocate - 888 * writes current entries in the list to device_allocate. 889 * frees the strings 890 */ 891 static void 892 _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp) 893 { 894 int is_on = -1; 895 strentry_t *tmp_str, *old_str; 896 struct stat dastat; 897 898 (void) fseek(dafp, (off_t)0, SEEK_SET); 899 900 /* 901 * if the devalloc on/off string existed before, 902 * put it back before anything else. 903 * we need to check for the string only if the file 904 * exists. 905 */ 906 if (stat(odevalloc, &dastat) == 0) { 907 is_on = da_is_on(); 908 if (is_on == 0) 909 (void) fputs(DA_OFF_STR, dafp); 910 else if (is_on == 1) 911 (void) fputs(DA_ON_STR, dafp); 912 } 913 tmp_str = head_devallocp; 914 while (tmp_str) { 915 (void) fputs(tmp_str->se_str, dafp); 916 (void) fputs("\n", dafp); 917 old_str = tmp_str; 918 tmp_str = tmp_str->se_next; 919 free(old_str); 920 } 921 } 922 923 /* 924 * _write_device_maps - 925 * writes current entries in the list to device_maps. 926 * and frees the strings 927 */ 928 static void 929 _write_device_maps(FILE *dmfp, strentry_t *head_devmapp) 930 { 931 strentry_t *tmp_str, *old_str; 932 933 (void) fseek(dmfp, (off_t)0, SEEK_SET); 934 935 tmp_str = head_devmapp; 936 while (tmp_str) { 937 (void) fputs(tmp_str->se_str, dmfp); 938 (void) fputs("\n", dmfp); 939 old_str = tmp_str; 940 tmp_str = tmp_str->se_next; 941 free(old_str); 942 } 943 } 944 945 /* 946 * _write_new_defattrs 947 * writes the new entry to devalloc_defaults. 948 * returns 0 on success, -1 on error. 949 */ 950 static int 951 _write_new_defattrs(FILE *fp, da_args *dargs) 952 { 953 int count; 954 char *tok = NULL, *tokp = NULL; 955 char *lasts; 956 devinfo_t *devinfo = dargs->devinfo; 957 958 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 959 return (-1); 960 if (!devinfo->devopts) 961 return (0); 962 (void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""), 963 KV_TOKEN_DELIMIT); 964 if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) { 965 (void) strcpy(tokp, devinfo->devopts); 966 if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) { 967 (void) fprintf(fp, "%s", tok); 968 count = 1; 969 } 970 while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) { 971 if (count) 972 (void) fprintf(fp, "%s", KV_DELIMITER); 973 (void) fprintf(fp, "%s", tok); 974 count++; 975 } 976 } else { 977 (void) fprintf(fp, "%s", devinfo->devopts); 978 } 979 980 return (0); 981 } 982 983 /* 984 * _write_new_entry - 985 * writes the new devalloc_t to device_allocate or the new devmap_t to 986 * device_maps. 987 * returns 0 on success, -1 on error. 988 */ 989 static int 990 _write_new_entry(FILE *fp, da_args *dargs, int flag) 991 { 992 int count; 993 char *tok = NULL, *tokp = NULL; 994 char *lasts; 995 devinfo_t *devinfo = dargs->devinfo; 996 997 if (flag & DA_MAPS_ONLY) 998 goto dmap_only; 999 1000 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 1001 return (-1); 1002 1003 (void) fprintf(fp, "%s%s\\\n\t", 1004 (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER); 1005 (void) fprintf(fp, "%s%s\\\n\t", 1006 (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER); 1007 if (devinfo->devopts == NULL) { 1008 (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, 1009 KV_DELIMITER); 1010 } else { 1011 if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1)) 1012 != NULL) { 1013 (void) strcpy(tokp, devinfo->devopts); 1014 if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) != 1015 NULL) { 1016 (void) fprintf(fp, "%s", tok); 1017 count = 1; 1018 } 1019 while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, 1020 &lasts)) != NULL) { 1021 if (count) 1022 (void) fprintf(fp, "%s", 1023 KV_TOKEN_DELIMIT "\\\n\t"); 1024 (void) fprintf(fp, "%s", tok); 1025 count++; 1026 } 1027 if (count) 1028 (void) fprintf(fp, "%s", 1029 KV_DELIMITER "\\\n\t"); 1030 } else { 1031 (void) fprintf(fp, "%s%s", devinfo->devopts, 1032 KV_DELIMITER "\\\n\t"); 1033 } 1034 } 1035 (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER); 1036 (void) fprintf(fp, "%s%s\\\n\t", 1037 (devinfo->devauths ? devinfo->devauths : DA_ANYUSER), 1038 KV_DELIMITER); 1039 (void) fprintf(fp, "%s\n", 1040 (devinfo->devexec ? devinfo->devexec : KV_DELIMITER)); 1041 1042 dmap_only: 1043 if (flag & DA_ALLOC_ONLY) 1044 return (0); 1045 1046 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 1047 return (-1); 1048 1049 (void) fprintf(fp, "%s%s\\\n", 1050 (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT); 1051 (void) fprintf(fp, "\t%s%s\\\n", 1052 (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT); 1053 (void) fprintf(fp, "\t%s\n", 1054 (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT)); 1055 1056 return (0); 1057 } 1058 1059 /* 1060 * _da_lock_devdb - 1061 * locks the database files; lock can be either broken explicitly by 1062 * closing the fd of the lock file, or it expires automatically at process 1063 * termination. 1064 * returns fd of the lock file or -1 on error. 1065 */ 1066 int 1067 _da_lock_devdb(char *rootdir) 1068 { 1069 int lockfd = -1; 1070 int ret; 1071 int count = 0; 1072 int retry = 10; 1073 int retry_sleep; 1074 uint_t seed; 1075 char *lockfile; 1076 char path[MAXPATHLEN]; 1077 int size = sizeof (path); 1078 1079 if (rootdir == NULL) { 1080 lockfile = DA_DB_LOCK; 1081 } else { 1082 path[0] = '\0'; 1083 if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size) 1084 return (-1); 1085 lockfile = path; 1086 } 1087 1088 if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) 1089 /* cannot open lock file */ 1090 return (-1); 1091 1092 (void) fchown(lockfd, DA_UID, DA_GID); 1093 1094 if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) { 1095 /* cannot position lock file */ 1096 (void) close(lockfd); 1097 return (-1); 1098 } 1099 errno = 0; 1100 while (retry > 0) { 1101 count++; 1102 seed = (uint_t)gethrtime(); 1103 ret = lockf(lockfd, F_TLOCK, 0); 1104 if (ret == 0) { 1105 (void) utime(lockfile, NULL); 1106 return (lockfd); 1107 } 1108 if ((errno != EACCES) && (errno != EAGAIN)) { 1109 /* cannot set lock */ 1110 (void) close(lockfd); 1111 return (-1); 1112 } 1113 retry--; 1114 retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count; 1115 (void) sleep(retry_sleep); 1116 errno = 0; 1117 } 1118 1119 return (-1); 1120 } 1121 1122 /* 1123 * da_open_devdb - 1124 * opens one or both database files - device_allocate, device_maps - in 1125 * the specified mode. 1126 * locks the database files; lock is either broken explicitly by the 1127 * caller by closing the lock file fd, or it expires automatically at 1128 * process termination. 1129 * writes the file pointer of opened file in the input args - dafp, dmfp. 1130 * returns fd of the lock file on success, -2 if database file does not 1131 * exist, -1 on other errors. 1132 */ 1133 int 1134 da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag) 1135 { 1136 int oflag = 0; 1137 int fda = -1; 1138 int fdm = -1; 1139 int lockfd = -1; 1140 char *fname; 1141 char *fmode; 1142 char path[MAXPATHLEN]; 1143 FILE *devfile; 1144 1145 if ((dafp == NULL) && (dmfp == NULL)) 1146 return (-1); 1147 1148 if (flag & DA_RDWR) { 1149 oflag = DA_RDWR; 1150 fmode = "r+F"; 1151 } else if (flag & DA_RDONLY) { 1152 oflag = DA_RDONLY; 1153 fmode = "rF"; 1154 } 1155 1156 if ((lockfd = _da_lock_devdb(rootdir)) == -1) 1157 return (-1); 1158 1159 if ((dafp == NULL) || (flag & DA_MAPS_ONLY)) 1160 goto dmap_only; 1161 1162 path[0] = '\0'; 1163 1164 /* 1165 * open the device allocation file 1166 */ 1167 if (rootdir == NULL) { 1168 fname = DEVALLOC; 1169 } else { 1170 if (snprintf(path, sizeof (path), "%s%s", rootdir, 1171 DEVALLOC) >= sizeof (path)) { 1172 if (lockfd != -1) 1173 (void) close(lockfd); 1174 return (-1); 1175 } 1176 fname = path; 1177 } 1178 if ((fda = open(fname, oflag, DA_DBMODE)) == -1) { 1179 if (lockfd != -1) 1180 (void) close(lockfd); 1181 return ((errno == ENOENT) ? -2 : -1); 1182 } 1183 if ((devfile = fdopen(fda, fmode)) == NULL) { 1184 (void) close(fda); 1185 if (lockfd != -1) 1186 (void) close(lockfd); 1187 return (-1); 1188 } 1189 *dafp = devfile; 1190 (void) fchmod(fda, DA_DBMODE); 1191 1192 if ((flag & DA_ALLOC_ONLY)) 1193 goto out; 1194 1195 dmap_only: 1196 path[0] = '\0'; 1197 /* 1198 * open the device map file 1199 */ 1200 if (rootdir == NULL) { 1201 fname = DEVMAP; 1202 } else { 1203 if (snprintf(path, sizeof (path), "%s%s", rootdir, 1204 DEVMAP) >= sizeof (path)) { 1205 (void) close(fda); 1206 if (lockfd != -1) 1207 (void) close(lockfd); 1208 return (-1); 1209 } 1210 fname = path; 1211 } 1212 1213 if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) { 1214 if (lockfd != -1) 1215 (void) close(lockfd); 1216 return ((errno == ENOENT) ? -2 : -1); 1217 } 1218 1219 if ((devfile = fdopen(fdm, fmode)) == NULL) { 1220 (void) close(fdm); 1221 (void) close(fda); 1222 if (lockfd != -1) 1223 (void) close(lockfd); 1224 return (-1); 1225 } 1226 *dmfp = devfile; 1227 (void) fchmod(fdm, DA_DBMODE); 1228 1229 out: 1230 return (lockfd); 1231 } 1232 1233 /* 1234 * _record_on_off - 1235 * adds either DA_ON_STR or DA_OFF_STR to device_allocate 1236 * returns 0 on success, -1 on error. 1237 */ 1238 static int 1239 _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp) 1240 { 1241 int dafd; 1242 int nsize; 1243 int nitems = 1; 1244 int actionlen; 1245 int str_found = 0; 1246 int len = 0, nlen = 0, plen = 0; 1247 char *ptr = NULL; 1248 char *actionstr; 1249 char *nbuf = NULL; 1250 char line[MAX_CANON]; 1251 struct stat dastat; 1252 1253 if (dargs->optflag & DA_ON) 1254 actionstr = DA_ON_STR; 1255 else 1256 actionstr = DA_OFF_STR; 1257 actionlen = strlen(actionstr); 1258 dafd = fileno(dafp); 1259 if (fstat(dafd, &dastat) == -1) 1260 return (-1); 1261 1262 /* check the old device_allocate for on/off string */ 1263 ptr = fgets(line, MAX_CANON, dafp); 1264 if (ptr != NULL) { 1265 if ((strcmp(line, DA_ON_STR) == 0) || 1266 (strcmp(line, DA_OFF_STR) == 0)) { 1267 str_found = 1; 1268 nsize = dastat.st_size; 1269 } 1270 } 1271 if (!ptr || !str_found) { 1272 /* 1273 * the file never had either the on or the off string; 1274 * make room for it. 1275 */ 1276 str_found = 0; 1277 nsize = dastat.st_size + actionlen + 1; 1278 } 1279 if ((nbuf = (char *)malloc(nsize + 1)) == NULL) 1280 return (-1); 1281 nbuf[0] = '\0'; 1282 /* put the on/off string */ 1283 (void) strcpy(nbuf, actionstr); 1284 nlen = strlen(nbuf); 1285 plen = nlen; 1286 if (ptr && !str_found) { 1287 /* now put the first line that we read in fgets */ 1288 nlen = plen + strlen(line) + 1; 1289 len = snprintf(nbuf + plen, nlen - plen, "%s", line); 1290 if (len >= nsize) { 1291 free(nbuf); 1292 return (-1); 1293 } 1294 plen += len; 1295 } 1296 1297 /* now get the rest of the old file */ 1298 while (fgets(line, MAX_CANON, dafp) != NULL) { 1299 nlen = plen + strlen(line) + 1; 1300 len = snprintf(nbuf + plen, nlen - plen, "%s", line); 1301 if (len >= nsize) { 1302 free(nbuf); 1303 return (-1); 1304 } 1305 plen += len; 1306 } 1307 len = strlen(nbuf) + 1; 1308 if (len < nsize) 1309 nbuf[len] = '\n'; 1310 1311 /* write the on/off str + the old device_allocate to the temp file */ 1312 if (fwrite(nbuf, nsize, nitems, tafp) < nitems) { 1313 free(nbuf); 1314 return (-1); 1315 } 1316 1317 free(nbuf); 1318 1319 return (0); 1320 } 1321 1322 /* 1323 * da_update_defattrs - 1324 * writes default attributes to devalloc_defaults 1325 * returns 0 on success, -1 on error. 1326 */ 1327 int 1328 da_update_defattrs(da_args *dargs) 1329 { 1330 int rc = 0, lockfd = 0, tmpfd = 0; 1331 char *defpath = DEFATTRS; 1332 char *tmpdefpath = TMPATTRS; 1333 FILE *tmpfp = NULL; 1334 struct stat dstat; 1335 strentry_t *head_defent = NULL; 1336 1337 if (dargs == NULL) 1338 return (0); 1339 if ((lockfd = _da_lock_devdb(NULL)) == -1) 1340 return (-1); 1341 if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 1342 (void) close(lockfd); 1343 return (-1); 1344 } 1345 (void) fchown(tmpfd, DA_UID, DA_GID); 1346 if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) { 1347 (void) close(tmpfd); 1348 (void) unlink(tmpdefpath); 1349 (void) close(lockfd); 1350 return (-1); 1351 } 1352 /* 1353 * examine all entries, remove an old one if required, check 1354 * if a new one needs to be added. 1355 */ 1356 if (stat(defpath, &dstat) == 0) { 1357 if ((rc = _build_defattrs(dargs, &head_defent)) != 0) { 1358 if (rc == 1) { 1359 (void) close(tmpfd); 1360 (void) unlink(tmpdefpath); 1361 (void) close(lockfd); 1362 return (rc); 1363 } 1364 } 1365 } 1366 /* 1367 * write back any existing entries. 1368 */ 1369 _write_defattrs(tmpfp, head_defent); 1370 1371 if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 1372 /* add new entries */ 1373 rc = _write_new_defattrs(tmpfp, dargs); 1374 (void) fclose(tmpfp); 1375 } else { 1376 (void) fclose(tmpfp); 1377 } 1378 if (rename(tmpdefpath, defpath) != 0) { 1379 rc = -1; 1380 (void) unlink(tmpdefpath); 1381 } 1382 (void) close(lockfd); 1383 1384 return (rc); 1385 } 1386 1387 /* 1388 * da_update_device - 1389 * Writes existing entries and the SINGLE change requested by da_args, 1390 * to device_allocate and device_maps. 1391 * Returns 0 on success, -1 on error. 1392 */ 1393 int 1394 da_update_device(da_args *dargs) 1395 { 1396 int rc; 1397 int tafd = -1, tmfd = -1; 1398 int lockfd = -1; 1399 char *rootdir = NULL; 1400 char *apathp = NULL, *mpathp = NULL; 1401 char *dapathp = NULL, *dmpathp = NULL; 1402 char apath[MAXPATHLEN], mpath[MAXPATHLEN]; 1403 char dapath[MAXPATHLEN], dmpath[MAXPATHLEN]; 1404 FILE *tafp = NULL, *tmfp = NULL, *dafp = NULL; 1405 struct stat dastat; 1406 devinfo_t *devinfo; 1407 strentry_t *head_devmapp = NULL; 1408 strentry_t *head_devallocp = NULL; 1409 1410 if (dargs == NULL) 1411 return (0); 1412 1413 rootdir = dargs->rootdir; 1414 devinfo = dargs->devinfo; 1415 1416 /* 1417 * adding/removing entries should be done in both 1418 * device_allocate and device_maps. updates can be 1419 * done in both or either of the files. 1420 */ 1421 if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) { 1422 if (dargs->optflag & DA_ALLOC_ONLY || 1423 dargs->optflag & DA_MAPS_ONLY) 1424 return (0); 1425 } 1426 1427 /* 1428 * name, type and list are required fields for adding a new 1429 * device. 1430 */ 1431 if ((dargs->optflag & DA_ADD) && 1432 ((devinfo->devname == NULL) || 1433 (devinfo->devtype == NULL) || 1434 (devinfo->devlist == NULL))) { 1435 return (-1); 1436 } 1437 1438 if (rootdir != NULL) { 1439 if (snprintf(apath, sizeof (apath), "%s%s", rootdir, 1440 TMPALLOC) >= sizeof (apath)) 1441 return (-1); 1442 apathp = apath; 1443 if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir, 1444 DEVALLOC) >= sizeof (dapath)) 1445 return (-1); 1446 dapathp = dapath; 1447 if (!(dargs->optflag & DA_ALLOC_ONLY)) { 1448 if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir, 1449 TMPMAP) >= sizeof (mpath)) 1450 return (-1); 1451 mpathp = mpath; 1452 if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir, 1453 DEVMAP) >= sizeof (dmpath)) 1454 return (-1); 1455 dmpathp = dmpath; 1456 } 1457 } else { 1458 apathp = TMPALLOC; 1459 dapathp = DEVALLOC; 1460 mpathp = TMPMAP; 1461 dmpathp = DEVMAP; 1462 } 1463 1464 if (dargs->optflag & DA_MAPS_ONLY) 1465 goto dmap_only; 1466 1467 /* 1468 * Check if we are here just to record on/off status of 1469 * device_allocation. 1470 */ 1471 if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) 1472 lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL, 1473 DA_RDONLY|DA_ALLOC_ONLY); 1474 else 1475 lockfd = _da_lock_devdb(rootdir); 1476 if (lockfd == -1) 1477 return (-1); 1478 1479 if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 1480 (void) close(lockfd); 1481 (void) fclose(dafp); 1482 return (-1); 1483 } 1484 (void) fchown(tafd, DA_UID, DA_GID); 1485 if ((tafp = fdopen(tafd, "r+")) == NULL) { 1486 (void) close(tafd); 1487 (void) unlink(apathp); 1488 (void) fclose(dafp); 1489 (void) close(lockfd); 1490 return (-1); 1491 } 1492 1493 /* 1494 * We don't need to parse the file if we are here just to record 1495 * on/off status of device_allocation. 1496 */ 1497 if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) { 1498 if (_record_on_off(dargs, tafp, dafp) == -1) { 1499 (void) close(tafd); 1500 (void) unlink(apathp); 1501 (void) fclose(dafp); 1502 (void) close(lockfd); 1503 return (-1); 1504 } 1505 (void) fclose(dafp); 1506 goto out; 1507 } 1508 1509 /* 1510 * If reacting to a hotplug, read the file entries, 1511 * figure out what dname (tname + a new number) goes to the 1512 * device being added/removed, and create a good head_devallocp and 1513 * head_devmapp with everything good still in it (_rebuild_lists) 1514 * 1515 * Else examine all the entries, remove an old one if it is 1516 * a duplicate with a device being added, returning the 1517 * remaining list (_build_lists.) 1518 * 1519 * We need to do this only if the file exists already. 1520 * 1521 * Once we have built these lists, we need to free the strings 1522 * in the head_* arrays before returning. 1523 */ 1524 if (stat(dapathp, &dastat) == 0) { 1525 /* for device allocation, the /etc files are the "master" */ 1526 if ((dargs->optflag & (DA_ADD| DA_EVENT)) && 1527 (!(dargs->optflag & DA_FORCE))) 1528 rc = _rebuild_lists(dargs, &head_devallocp, 1529 &head_devmapp); 1530 else 1531 rc = _build_lists(dargs, &head_devallocp, 1532 &head_devmapp); 1533 1534 if (rc != 0 && rc != 1) { 1535 (void) close(tafd); 1536 (void) unlink(apathp); 1537 (void) close(lockfd); 1538 return (-1); 1539 } 1540 } else 1541 rc = 0; 1542 1543 if ((dargs->optflag & DA_REMOVE) && (rc == 0)) { 1544 (void) close(tafd); 1545 (void) unlink(apathp); 1546 (void) close(lockfd); 1547 return (0); 1548 } 1549 /* 1550 * TODO: clean up the workings of DA_UPDATE. 1551 * Due to da_match looking at fields that are missing 1552 * in dargs for DA_UPDATE, the da_match call returns no match, 1553 * but due to the way _da2str combines the devalloc_t info with 1554 * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work. 1555 * 1556 * This would not scale if any type of update was ever needed 1557 * from the daemon. 1558 */ 1559 1560 /* 1561 * Write out devallocp along with the devalloc on/off string. 1562 */ 1563 _write_device_allocate(dapathp, tafp, head_devallocp); 1564 1565 if (dargs->optflag & DA_ALLOC_ONLY) 1566 goto out; 1567 1568 dmap_only: 1569 if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 1570 (void) close(tafd); 1571 (void) unlink(apathp); 1572 (void) close(lockfd); 1573 return (-1); 1574 } 1575 (void) fchown(tmfd, DA_UID, DA_GID); 1576 if ((tmfp = fdopen(tmfd, "r+")) == NULL) { 1577 (void) close(tafd); 1578 (void) unlink(apathp); 1579 (void) close(tmfd); 1580 (void) unlink(mpathp); 1581 (void) close(lockfd); 1582 return (-1); 1583 } 1584 1585 /* 1586 * Write back any non-removed pre-existing entries. 1587 */ 1588 if (head_devmapp != NULL) 1589 _write_device_maps(tmfp, head_devmapp); 1590 1591 out: 1592 /* 1593 * Add any new entries here. 1594 */ 1595 if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 1596 /* add any new entries */ 1597 rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY); 1598 (void) fclose(tafp); 1599 1600 if (rc == 0) 1601 rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY); 1602 (void) fclose(tmfp); 1603 } else { 1604 if (tafp) 1605 (void) fclose(tafp); 1606 if (tmfp) 1607 (void) fclose(tmfp); 1608 } 1609 1610 rc = 0; 1611 if (!(dargs->optflag & DA_MAPS_ONLY)) { 1612 if (rename(apathp, dapathp) != 0) { 1613 rc = -1; 1614 (void) unlink(apathp); 1615 } 1616 } 1617 if (!(dargs->optflag & DA_ALLOC_ONLY)) { 1618 if (rename(mpathp, dmpathp) != 0) { 1619 rc = -1; 1620 (void) unlink(mpathp); 1621 } 1622 } 1623 1624 (void) close(lockfd); 1625 1626 return (rc); 1627 } 1628 1629 /* 1630 * da_add_list - 1631 * adds new /dev link name to the linked list of devices. 1632 * returns 0 if link added successfully, -1 on error. 1633 */ 1634 int 1635 da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) 1636 { 1637 int instance; 1638 int nlen, plen; 1639 int new_entry = 0; 1640 char *dtype, *dexec, *tname, *kval; 1641 char *minstr = NULL, *maxstr = NULL; 1642 char dname[DA_MAXNAME + 1]; 1643 kva_t *kva; 1644 deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL; 1645 da_defs_t *da_defs; 1646 1647 if (dlist == NULL || link == NULL) 1648 return (-1); 1649 1650 dname[0] = '\0'; 1651 if (flag & DA_AUDIO) { 1652 dentry = dlist->audio; 1653 tname = DA_AUDIO_NAME; 1654 dtype = DA_AUDIO_TYPE; 1655 dexec = DA_DEFAULT_AUDIO_CLEAN; 1656 } else if (flag & DA_CD) { 1657 dentry = dlist->cd; 1658 tname = DA_CD_NAME; 1659 dtype = DA_CD_TYPE; 1660 dexec = DA_DEFAULT_DISK_CLEAN; 1661 } else if (flag & DA_FLOPPY) { 1662 dentry = dlist->floppy; 1663 tname = DA_FLOPPY_NAME; 1664 dtype = DA_FLOPPY_TYPE; 1665 dexec = DA_DEFAULT_DISK_CLEAN; 1666 } else if (flag & DA_TAPE) { 1667 dentry = dlist->tape; 1668 tname = DA_TAPE_NAME; 1669 dtype = DA_TAPE_TYPE; 1670 dexec = DA_DEFAULT_TAPE_CLEAN; 1671 } else if (flag & DA_RMDISK) { 1672 dentry = dlist->rmdisk; 1673 tname = DA_RMDISK_NAME; 1674 dtype = DA_RMDISK_TYPE; 1675 dexec = DA_DEFAULT_DISK_CLEAN; 1676 } else { 1677 return (-1); 1678 } 1679 1680 for (nentry = dentry; nentry != NULL; nentry = nentry->next) { 1681 pentry = nentry; 1682 (void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance); 1683 if (nentry->devinfo.instance == new_instance) 1684 /* 1685 * Add the new link name to the list of links 1686 * that the device 'dname' has. 1687 */ 1688 break; 1689 } 1690 1691 if (nentry == NULL) { 1692 /* 1693 * Either this is the first entry ever, or no matching entry 1694 * was found. Create a new one and add to the list. 1695 */ 1696 if (dentry == NULL) /* first entry ever */ 1697 instance = 0; 1698 else /* no matching entry */ 1699 instance++; 1700 (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance); 1701 if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) == 1702 NULL) 1703 return (-1); 1704 if (pentry != NULL) 1705 pentry->next = nentry; 1706 new_entry = 1; 1707 nentry->devinfo.devname = strdup(dname); 1708 nentry->devinfo.devtype = dtype; 1709 nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH; 1710 nentry->devinfo.devexec = dexec; 1711 nentry->devinfo.instance = new_instance; 1712 /* 1713 * Look for default label range, authorizations and cleaning 1714 * program in devalloc_defaults. If label range is not 1715 * specified in devalloc_defaults, assume it to be admin_low 1716 * to admin_high. 1717 */ 1718 minstr = DA_DEFAULT_MIN; 1719 maxstr = DA_DEFAULT_MAX; 1720 setdadefent(); 1721 if (da_defs = getdadeftype(nentry->devinfo.devtype)) { 1722 kva = da_defs->devopts; 1723 if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL) 1724 minstr = strdup(kval); 1725 if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL) 1726 maxstr = strdup(kval); 1727 if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL) 1728 nentry->devinfo.devauths = strdup(kval); 1729 if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL) 1730 nentry->devinfo.devexec = strdup(kval); 1731 freedadefent(da_defs); 1732 } 1733 enddadefent(); 1734 kval = NULL; 1735 nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) + 1736 strlen(minstr) + strlen(KV_TOKEN_DELIMIT) + 1737 strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr) 1738 + 1; /* +1 for terminator */ 1739 if (kval = (char *)malloc(nlen)) 1740 (void) snprintf(kval, nlen, "%s%s%s%s%s%s%s", 1741 DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT, 1742 DAOPT_MAXLABEL, KV_ASSIGN, maxstr); 1743 nentry->devinfo.devopts = kval; 1744 1745 nentry->devinfo.devlist = NULL; 1746 nentry->next = NULL; 1747 } 1748 1749 nlen = strlen(link) + 1; /* +1 terminator */ 1750 if (nentry->devinfo.devlist) { 1751 plen = strlen(nentry->devinfo.devlist); 1752 nlen = nlen + plen + 1; /* +1 for blank to separate entries */ 1753 } else { 1754 plen = 0; 1755 } 1756 1757 if ((nentry->devinfo.devlist = 1758 (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) { 1759 if (new_entry) { 1760 free(nentry->devinfo.devname); 1761 free(nentry); 1762 if (pentry != NULL) 1763 pentry->next = NULL; 1764 } 1765 return (-1); 1766 } 1767 1768 if (plen == 0) 1769 (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link); 1770 else 1771 (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen, 1772 " %s", link); 1773 1774 if (pentry == NULL) { 1775 /* 1776 * This is the first entry of this device type. 1777 */ 1778 if (flag & DA_AUDIO) 1779 dlist->audio = nentry; 1780 else if (flag & DA_CD) 1781 dlist->cd = nentry; 1782 else if (flag & DA_FLOPPY) 1783 dlist->floppy = nentry; 1784 else if (flag & DA_TAPE) 1785 dlist->tape = nentry; 1786 else if (flag & DA_RMDISK) 1787 dlist->rmdisk = nentry; 1788 } 1789 1790 return (0); 1791 } 1792 1793 /* 1794 * da_remove_list - 1795 * removes a /dev link name from the linked list of devices. 1796 * returns type of device if link for that device removed 1797 * successfully, else returns -1 on error. 1798 * if all links for a device are removed, stores that device 1799 * name in devname. 1800 */ 1801 int 1802 da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size) 1803 { 1804 int flag; 1805 int remove_dev = 0; 1806 int nlen, plen, slen; 1807 char *lasts, *lname, *oldlist; 1808 struct stat rmstat; 1809 deventry_t *dentry, *current, *prev; 1810 1811 if (type != NULL) 1812 flag = type; 1813 else if (link == NULL) 1814 return (-1); 1815 else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME)) 1816 flag = DA_AUDIO; 1817 else if (strstr(link, "dsk") || strstr(link, "rdsk") || 1818 strstr(link, "sr") || strstr(link, "rsr")) 1819 flag = DA_CD; 1820 else if (strstr(link, "fd") || strstr(link, "rfd") || 1821 strstr(link, "diskette") || strstr(link, "rdiskette")) 1822 flag = DA_FLOPPY; 1823 else if (strstr(link, DA_TAPE_NAME)) 1824 flag = DA_TAPE; 1825 else 1826 flag = DA_RMDISK; 1827 1828 switch (type) { 1829 case DA_AUDIO: 1830 dentry = dlist->audio; 1831 break; 1832 case DA_CD: 1833 dentry = dlist->cd; 1834 break; 1835 case DA_FLOPPY: 1836 dentry = dlist->floppy; 1837 break; 1838 case DA_TAPE: 1839 dentry = dlist->tape; 1840 break; 1841 case DA_RMDISK: 1842 dentry = dlist->rmdisk; 1843 break; 1844 default: 1845 return (-1); 1846 } 1847 1848 if ((type != NULL) && (link == NULL)) { 1849 for (current = dentry, prev = dentry; current != NULL; 1850 current = current->next) { 1851 oldlist = strdup(current->devinfo.devlist); 1852 for (lname = strtok_r(oldlist, " ", &lasts); 1853 lname != NULL; 1854 lname = strtok_r(NULL, " ", &lasts)) { 1855 if (stat(lname, &rmstat) != 0) { 1856 remove_dev = 1; 1857 goto remove_dev; 1858 } 1859 } 1860 prev = current; 1861 } 1862 return (-1); 1863 } 1864 1865 for (current = dentry, prev = dentry; current != NULL; 1866 current = current->next) { 1867 plen = strlen(current->devinfo.devlist); 1868 nlen = strlen(link); 1869 if (plen == nlen) { 1870 if (strcmp(current->devinfo.devlist, link) == 0) { 1871 /* last name in the list */ 1872 remove_dev = 1; 1873 break; 1874 } 1875 } 1876 if (strstr(current->devinfo.devlist, link)) { 1877 nlen = plen - nlen + 1; 1878 oldlist = strdup(current->devinfo.devlist); 1879 if ((current->devinfo.devlist = 1880 (char *)realloc(current->devinfo.devlist, 1881 nlen)) == NULL) { 1882 free(oldlist); 1883 return (-1); 1884 } 1885 current->devinfo.devlist[0] = '\0'; 1886 nlen = plen = slen = 0; 1887 for (lname = strtok_r(oldlist, " ", &lasts); 1888 lname != NULL; 1889 lname = strtok_r(NULL, " ", &lasts)) { 1890 if (strcmp(lname, link) == 0) 1891 continue; 1892 nlen = strlen(lname) + plen + 1; 1893 if (plen == 0) { 1894 slen = 1895 snprintf(current->devinfo.devlist, 1896 nlen, "%s", lname); 1897 } else { 1898 slen = 1899 snprintf(current->devinfo.devlist + 1900 plen, nlen - plen, " %s", lname); 1901 } 1902 plen = plen + slen + 1; 1903 } 1904 free(oldlist); 1905 break; 1906 } 1907 prev = current; 1908 } 1909 1910 remove_dev: 1911 if (remove_dev == 1) { 1912 (void) strlcpy(devname, current->devinfo.devname, size); 1913 free(current->devinfo.devname); 1914 free(current->devinfo.devlist); 1915 current->devinfo.devname = current->devinfo.devlist = NULL; 1916 prev->next = current->next; 1917 free(current); 1918 current = NULL; 1919 } 1920 if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) { 1921 if (prev->next) { 1922 /* 1923 * what we removed above was the first entry 1924 * in the list. make the next entry to be the 1925 * first. 1926 */ 1927 current = prev->next; 1928 } else { 1929 /* 1930 * the matching entry was the only entry in the list 1931 * for this type. 1932 */ 1933 current = NULL; 1934 } 1935 if (flag & DA_AUDIO) 1936 dlist->audio = current; 1937 else if (flag & DA_CD) 1938 dlist->cd = current; 1939 else if (flag & DA_FLOPPY) 1940 dlist->floppy = current; 1941 else if (flag & DA_TAPE) 1942 dlist->tape = current; 1943 else if (flag & DA_RMDISK) 1944 dlist->rmdisk = current; 1945 } 1946 1947 return (flag); 1948 } 1949 1950 /* 1951 * da_rm_list_entry - 1952 * 1953 * The adding of devnames to a devlist and the removal of a 1954 * device are not symmetrical -- hot_cleanup gives a /devices 1955 * name which is used to remove the dentry whose links all point to 1956 * that /devices entry. 1957 * 1958 * The link argument is present if available to make debugging 1959 * easier. 1960 * 1961 * da_rm_list_entry removes an entry from the linked list of devices. 1962 * 1963 * Returns 1 if the devname was removed successfully, 1964 * 0 if not found, -1 for error. 1965 */ 1966 /*ARGSUSED*/ 1967 int 1968 da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname) 1969 { 1970 int retval = 0; 1971 deventry_t **dentry, *current, *prev; 1972 1973 switch (type) { 1974 case DA_AUDIO: 1975 dentry = &(dlist->audio); 1976 break; 1977 case DA_CD: 1978 dentry = &(dlist->cd); 1979 break; 1980 case DA_FLOPPY: 1981 dentry = &(dlist->floppy); 1982 break; 1983 case DA_TAPE: 1984 dentry = &(dlist->tape); 1985 break; 1986 case DA_RMDISK: 1987 dentry = &(dlist->rmdisk); 1988 break; 1989 default: 1990 return (-1); 1991 } 1992 1993 /* Presumably in daemon mode, no need to remove entry, list is empty */ 1994 if (*dentry == (deventry_t *)NULL) 1995 return (0); 1996 1997 prev = NULL; 1998 for (current = *dentry; current != NULL; 1999 prev = current, current = current->next) { 2000 if (strcmp(devname, current->devinfo.devname)) 2001 continue; 2002 retval = 1; 2003 break; 2004 } 2005 if (retval == 0) 2006 return (0); 2007 free(current->devinfo.devname); 2008 if (current->devinfo.devlist != NULL) 2009 free(current->devinfo.devlist); 2010 if (current->devinfo.devopts != NULL) 2011 free(current->devinfo.devopts); 2012 2013 if (prev == NULL) 2014 *dentry = current->next; 2015 else 2016 prev->next = current->next; 2017 2018 free(current); 2019 return (retval); 2020 } 2021 2022 /* 2023 * da_is_on - 2024 * checks if device allocation feature is turned on. 2025 * returns 1 if on, 0 if off, -1 if status string not 2026 * found in device_allocate. 2027 */ 2028 int 2029 da_is_on() 2030 { 2031 return (getdaon()); 2032 } 2033 2034 /* 2035 * da_print_device - 2036 * debug routine to print device entries. 2037 */ 2038 void 2039 da_print_device(int flag, devlist_t *devlist) 2040 { 2041 deventry_t *entry, *dentry; 2042 devinfo_t *devinfo; 2043 2044 if (flag & DA_AUDIO) 2045 dentry = devlist->audio; 2046 else if (flag & DA_CD) 2047 dentry = devlist->cd; 2048 else if (flag & DA_FLOPPY) 2049 dentry = devlist->floppy; 2050 else if (flag & DA_TAPE) 2051 dentry = devlist->tape; 2052 else if (flag & DA_RMDISK) 2053 dentry = devlist->rmdisk; 2054 else 2055 return; 2056 2057 for (entry = dentry; entry != NULL; entry = entry->next) { 2058 devinfo = &(entry->devinfo); 2059 (void) fprintf(stdout, "name: %s\n", devinfo->devname); 2060 (void) fprintf(stdout, "type: %s\n", devinfo->devtype); 2061 (void) fprintf(stdout, "auth: %s\n", devinfo->devauths); 2062 (void) fprintf(stdout, "exec: %s\n", devinfo->devexec); 2063 (void) fprintf(stdout, "list: %s\n\n", devinfo->devlist); 2064 } 2065 } 2066