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