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 2006 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 char *lockfile; 853 char path[MAXPATHLEN]; 854 int size = sizeof (path); 855 856 if (rootdir == NULL) { 857 lockfile = DA_DB_LOCK; 858 } else { 859 path[0] = '\0'; 860 if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size) 861 return (-1); 862 lockfile = path; 863 } 864 865 if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) 866 /* cannot open lock file */ 867 return (-1); 868 869 (void) fchown(lockfd, DA_UID, DA_GID); 870 871 if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) { 872 /* cannot position lock file */ 873 (void) close(lockfd); 874 return (-1); 875 } 876 if (lockf(lockfd, F_TLOCK, 0) == -1) { 877 /* cannot set lock */ 878 (void) close(lockfd); 879 return (-1); 880 } 881 (void) utime(lockfile, NULL); 882 883 return (lockfd); 884 } 885 886 /* 887 * da_open_devdb - 888 * opens one or both database files - device_allocate, device_maps - in 889 * the specified mode. 890 * locks the database files; lock is either broken explicitly by the 891 * caller by closing the lock file fd, or it expires automatically at 892 * process termination. 893 * writes the file pointer of opened file in the input args - dafp, dmfp. 894 * returns fd of the lock file on success, -2 if database file does not 895 * exist, -1 on other errors. 896 */ 897 int 898 da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag) 899 { 900 int oflag = 0; 901 int fda = -1; 902 int fdm = -1; 903 int lockfd = -1; 904 char *fname; 905 char *fmode; 906 char path[MAXPATHLEN]; 907 FILE *devfile; 908 909 if ((dafp == NULL) && (dmfp == NULL)) 910 return (-1); 911 912 if (flag & DA_RDWR) { 913 oflag = DA_RDWR; 914 fmode = "r+F"; 915 } else if (flag & DA_RDONLY) { 916 oflag = DA_RDONLY; 917 fmode = "rF"; 918 } 919 920 if ((lockfd = _da_lock_devdb(rootdir)) == -1) 921 return (-1); 922 923 if ((dafp == NULL) || (flag & DA_MAPS_ONLY)) 924 goto dmap_only; 925 926 path[0] = '\0'; 927 928 /* 929 * open the device allocation file 930 */ 931 if (rootdir == NULL) { 932 fname = DEVALLOC; 933 } else { 934 if (snprintf(path, sizeof (path), "%s%s", rootdir, 935 DEVALLOC) >= sizeof (path)) { 936 if (lockfd != -1) 937 (void) close(lockfd); 938 return (-1); 939 } 940 fname = path; 941 } 942 if ((fda = open(fname, oflag, DA_DBMODE)) == -1) { 943 if (lockfd != -1) 944 (void) close(lockfd); 945 return ((errno == ENOENT) ? -2 : -1); 946 } 947 if ((devfile = fdopen(fda, fmode)) == NULL) { 948 (void) close(fda); 949 if (lockfd != -1) 950 (void) close(lockfd); 951 return (-1); 952 } 953 *dafp = devfile; 954 (void) fchmod(fda, DA_DBMODE); 955 956 if ((flag & DA_ALLOC_ONLY)) 957 goto out; 958 959 dmap_only: 960 path[0] = '\0'; 961 /* 962 * open the device map file 963 */ 964 if (rootdir == NULL) { 965 fname = DEVMAP; 966 } else { 967 if (snprintf(path, sizeof (path), "%s%s", rootdir, 968 DEVMAP) >= sizeof (path)) { 969 (void) close(fda); 970 if (lockfd != -1) 971 (void) close(lockfd); 972 return (-1); 973 } 974 fname = path; 975 } 976 977 if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) { 978 if (lockfd != -1) 979 (void) close(lockfd); 980 return ((errno == ENOENT) ? -2 : -1); 981 } 982 983 if ((devfile = fdopen(fdm, fmode)) == NULL) { 984 (void) close(fdm); 985 (void) close(fda); 986 if (lockfd != -1) 987 (void) close(lockfd); 988 return (-1); 989 } 990 *dmfp = devfile; 991 (void) fchmod(fdm, DA_DBMODE); 992 993 out: 994 return (lockfd); 995 } 996 997 /* 998 * _record_on_off - 999 * adds either DA_ON_STR or DA_OFF_STR to device_allocate 1000 * returns 0 on success, -1 on error. 1001 */ 1002 static int 1003 _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp) 1004 { 1005 int dafd; 1006 int nsize; 1007 int nitems = 1; 1008 int actionlen; 1009 int str_found = 0; 1010 int len = 0, nlen = 0, plen = 0; 1011 char *ptr = NULL; 1012 char *actionstr; 1013 char *nbuf = NULL; 1014 char line[MAX_CANON]; 1015 struct stat dastat; 1016 1017 if (dargs->optflag & DA_ON) 1018 actionstr = DA_ON_STR; 1019 else 1020 actionstr = DA_OFF_STR; 1021 actionlen = strlen(actionstr); 1022 dafd = fileno(dafp); 1023 if (fstat(dafd, &dastat) == -1) 1024 return (-1); 1025 1026 /* check the old device_allocate for on/off string */ 1027 ptr = fgets(line, MAX_CANON, dafp); 1028 if (ptr != NULL) { 1029 if ((strcmp(line, DA_ON_STR) == 0) || 1030 (strcmp(line, DA_OFF_STR) == 0)) { 1031 str_found = 1; 1032 nsize = dastat.st_size; 1033 } 1034 } 1035 if (!ptr || !str_found) { 1036 /* 1037 * the file never had either the on or the off string; 1038 * make room for it. 1039 */ 1040 str_found = 0; 1041 nsize = dastat.st_size + actionlen + 1; 1042 } 1043 if ((nbuf = (char *)malloc(nsize)) == NULL) 1044 return (-1); 1045 nbuf[0] = '\0'; 1046 /* put the on/off string */ 1047 (void) strcpy(nbuf, actionstr); 1048 nlen = strlen(nbuf); 1049 plen = nlen; 1050 if (ptr && !str_found) { 1051 /* now put the first line that we read in fgets */ 1052 nlen = plen + strlen(line) + 1; 1053 len = snprintf(nbuf + plen, nlen - plen, "%s", line); 1054 if (len >= nsize) { 1055 free(nbuf); 1056 return (-1); 1057 } 1058 plen += len; 1059 } 1060 1061 /* now get the rest of the old file */ 1062 while (fgets(line, MAX_CANON, dafp) != NULL) { 1063 nlen = plen + strlen(line) + 1; 1064 len = snprintf(nbuf + plen, nlen - plen, "%s", line); 1065 if (len >= nsize) { 1066 free(nbuf); 1067 return (-1); 1068 } 1069 plen += len; 1070 } 1071 len = strlen(nbuf) + 1; 1072 if (len < nsize) 1073 nbuf[len] = '\n'; 1074 1075 /* write the on/off str + the old device_allocate to the temp file */ 1076 if (fwrite(nbuf, nsize, nitems, tafp) < nitems) { 1077 free(nbuf); 1078 return (-1); 1079 } 1080 1081 free(nbuf); 1082 1083 return (0); 1084 } 1085 1086 /* 1087 * da_update_defattrs - 1088 * writes default attributes to devalloc_defaults 1089 * returns 0 on success, -1 on error. 1090 */ 1091 int 1092 da_update_defattrs(da_args *dargs) 1093 { 1094 int rc = 0, lockfd = 0, tmpfd = 0; 1095 char *defpath = DEFATTRS; 1096 char *tmpdefpath = TMPATTRS; 1097 FILE *tmpfp = NULL; 1098 struct stat dstat; 1099 strentry_t *head_defent = NULL; 1100 1101 if (dargs == NULL) 1102 return (0); 1103 if ((lockfd = _da_lock_devdb(NULL)) == -1) 1104 return (-1); 1105 if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 1106 (void) close(lockfd); 1107 return (-1); 1108 } 1109 (void) fchown(tmpfd, DA_UID, DA_GID); 1110 if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) { 1111 (void) close(tmpfd); 1112 (void) unlink(tmpdefpath); 1113 (void) close(lockfd); 1114 return (-1); 1115 } 1116 /* 1117 * examine all entries, remove an old one if required, check 1118 * if a new one needs to be added. 1119 */ 1120 if (stat(defpath, &dstat) == 0) { 1121 if ((rc = _build_defattrs(dargs, &head_defent)) != 0) { 1122 if (rc == 1) { 1123 (void) close(tmpfd); 1124 (void) unlink(tmpdefpath); 1125 (void) close(lockfd); 1126 return (rc); 1127 } 1128 } 1129 } 1130 /* 1131 * write back any existing entries. 1132 */ 1133 _write_defattrs(tmpfp, head_defent); 1134 1135 if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 1136 /* add new entries */ 1137 rc = _write_new_defattrs(tmpfp, dargs); 1138 (void) fclose(tmpfp); 1139 } else { 1140 (void) fclose(tmpfp); 1141 } 1142 if (rename(tmpdefpath, defpath) != 0) { 1143 rc = -1; 1144 (void) unlink(tmpdefpath); 1145 } 1146 (void) close(lockfd); 1147 1148 return (rc); 1149 } 1150 1151 /* 1152 * da_update_device - 1153 * writes devices entries to device_allocate and device_maps. 1154 * returns 0 on success, -1 on error. 1155 */ 1156 int 1157 da_update_device(da_args *dargs) 1158 { 1159 int rc; 1160 int tafd = -1, tmfd = -1; 1161 int lockfd = -1; 1162 char *rootdir = NULL; 1163 char *apathp = NULL, *mpathp = NULL, *dapathp = NULL, 1164 *dmpathp = NULL; 1165 char apath[MAXPATHLEN], mpath[MAXPATHLEN], 1166 dapath[MAXPATHLEN], dmpath[MAXPATHLEN]; 1167 FILE *tafp = NULL, *tmfp = NULL, *dafp = NULL; 1168 struct stat dastat; 1169 devinfo_t *devinfo; 1170 strentry_t *head_devmapp = NULL; 1171 strentry_t *head_devallocp = NULL; 1172 1173 if (dargs == NULL) 1174 return (0); 1175 1176 rootdir = dargs->rootdir; 1177 devinfo = dargs->devinfo; 1178 1179 /* 1180 * adding/removing entries should be done in both 1181 * device_allocate and device_maps. updates can be 1182 * done in both or either of the files. 1183 */ 1184 if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) { 1185 if (dargs->optflag & DA_ALLOC_ONLY || 1186 dargs->optflag & DA_MAPS_ONLY) 1187 return (0); 1188 } 1189 1190 /* 1191 * name, type and list are required fields for adding a new 1192 * device. 1193 */ 1194 if ((dargs->optflag & DA_ADD) && 1195 ((devinfo->devname == NULL) || 1196 (devinfo->devtype == NULL) || 1197 (devinfo->devlist == NULL))) { 1198 return (-1); 1199 } 1200 1201 if (rootdir != NULL) { 1202 if (snprintf(apath, sizeof (apath), "%s%s", rootdir, 1203 TMPALLOC) >= sizeof (apath)) 1204 return (-1); 1205 apathp = apath; 1206 if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir, 1207 DEVALLOC) >= sizeof (dapath)) 1208 return (-1); 1209 dapathp = dapath; 1210 if (!(dargs->optflag & DA_ALLOC_ONLY)) { 1211 if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir, 1212 TMPMAP) >= sizeof (mpath)) 1213 return (-1); 1214 mpathp = mpath; 1215 if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir, 1216 DEVMAP) >= sizeof (dmpath)) 1217 return (-1); 1218 dmpathp = dmpath; 1219 } 1220 } else { 1221 apathp = TMPALLOC; 1222 dapathp = DEVALLOC; 1223 mpathp = TMPMAP; 1224 dmpathp = DEVMAP; 1225 } 1226 1227 if (dargs->optflag & DA_MAPS_ONLY) 1228 goto dmap_only; 1229 1230 /* 1231 * Check if we are here just to record on/off status of 1232 * device_allocation. 1233 */ 1234 if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) 1235 lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL, 1236 DA_RDONLY|DA_ALLOC_ONLY); 1237 else 1238 lockfd = _da_lock_devdb(rootdir); 1239 if (lockfd == -1) 1240 return (-1); 1241 1242 if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 1243 (void) close(lockfd); 1244 (void) fclose(dafp); 1245 return (-1); 1246 } 1247 (void) fchown(tafd, DA_UID, DA_GID); 1248 if ((tafp = fdopen(tafd, "r+")) == NULL) { 1249 (void) close(tafd); 1250 (void) unlink(apathp); 1251 (void) fclose(dafp); 1252 (void) close(lockfd); 1253 return (-1); 1254 } 1255 1256 /* 1257 * We don't need to parse the file if we are here just to record 1258 * on/off status of device_allocation. 1259 */ 1260 if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) { 1261 if (_record_on_off(dargs, tafp, dafp) == -1) { 1262 (void) close(tafd); 1263 (void) unlink(apathp); 1264 (void) fclose(dafp); 1265 (void) close(lockfd); 1266 return (-1); 1267 } 1268 (void) fclose(dafp); 1269 goto out; 1270 } 1271 1272 /* 1273 * examine all the entries, remove an old one if forced to, 1274 * and check that they are suitable for updating. 1275 * we need to do this only if the file exists already. 1276 */ 1277 if (stat(dapathp, &dastat) == 0) { 1278 if ((rc = _build_lists(dargs, &head_devallocp, 1279 &head_devmapp)) != 0) { 1280 if (rc != 1) { 1281 (void) close(tafd); 1282 (void) unlink(apathp); 1283 (void) close(lockfd); 1284 return (rc); 1285 } 1286 } 1287 } 1288 1289 /* 1290 * write back any existing devalloc entries, along with 1291 * the devalloc on/off string. 1292 */ 1293 _write_device_allocate(dapathp, tafp, head_devallocp); 1294 1295 if (dargs->optflag & DA_ALLOC_ONLY) 1296 goto out; 1297 1298 dmap_only: 1299 if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 1300 (void) close(tafd); 1301 (void) unlink(apathp); 1302 (void) close(lockfd); 1303 return (-1); 1304 } 1305 (void) fchown(tmfd, DA_UID, DA_GID); 1306 if ((tmfp = fdopen(tmfd, "r+")) == NULL) { 1307 (void) close(tafd); 1308 (void) unlink(apathp); 1309 (void) close(tmfd); 1310 (void) unlink(mpathp); 1311 (void) close(lockfd); 1312 return (-1); 1313 } 1314 1315 /* write back any existing devmap entries */ 1316 if (head_devmapp != NULL) 1317 _write_device_maps(tmfp, head_devmapp); 1318 1319 out: 1320 if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 1321 /* add any new entries */ 1322 rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY); 1323 (void) fclose(tafp); 1324 1325 if (rc == 0) 1326 rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY); 1327 (void) fclose(tmfp); 1328 } else { 1329 if (tafp) 1330 (void) fclose(tafp); 1331 if (tmfp) 1332 (void) fclose(tmfp); 1333 } 1334 1335 rc = 0; 1336 if (!(dargs->optflag & DA_MAPS_ONLY)) { 1337 if (rename(apathp, dapathp) != 0) { 1338 rc = -1; 1339 (void) unlink(apathp); 1340 } 1341 } 1342 if (!(dargs->optflag & DA_ALLOC_ONLY)) { 1343 if (rename(mpathp, dmpathp) != 0) { 1344 rc = -1; 1345 (void) unlink(mpathp); 1346 } 1347 } 1348 1349 (void) close(lockfd); 1350 1351 return (rc); 1352 } 1353 1354 /* 1355 * da_add_list - 1356 * adds new /dev link name to the linked list of devices. 1357 * returns 0 if link added successfully, -1 on error. 1358 */ 1359 int 1360 da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) 1361 { 1362 int instance; 1363 int nlen, plen; 1364 int new_entry = 0; 1365 char *dtype, *dexec, *tname, *kval; 1366 char *minstr = NULL, *maxstr = NULL; 1367 char dname[DA_MAXNAME]; 1368 kva_t *kva; 1369 deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL; 1370 da_defs_t *da_defs; 1371 1372 if (dlist == NULL || link == NULL) 1373 return (-1); 1374 1375 dname[0] = '\0'; 1376 if (flag & DA_AUDIO) { 1377 dentry = dlist->audio; 1378 tname = DA_AUDIO_NAME; 1379 dtype = DA_AUDIO_TYPE; 1380 dexec = DA_DEFAULT_AUDIO_CLEAN; 1381 } else if (flag & DA_CD) { 1382 dentry = dlist->cd; 1383 tname = DA_CD_NAME; 1384 dtype = DA_CD_TYPE; 1385 dexec = DA_DEFAULT_DISK_CLEAN; 1386 } else if (flag & DA_FLOPPY) { 1387 dentry = dlist->floppy; 1388 tname = DA_FLOPPY_NAME; 1389 dtype = DA_FLOPPY_TYPE; 1390 dexec = DA_DEFAULT_DISK_CLEAN; 1391 } else if (flag & DA_TAPE) { 1392 dentry = dlist->tape; 1393 tname = DA_TAPE_NAME; 1394 dtype = DA_TAPE_TYPE; 1395 dexec = DA_DEFAULT_TAPE_CLEAN; 1396 } else if (flag & DA_RMDISK) { 1397 dentry = dlist->rmdisk; 1398 tname = DA_RMDISK_NAME; 1399 dtype = DA_RMDISK_TYPE; 1400 dexec = DA_DEFAULT_DISK_CLEAN; 1401 } else { 1402 return (-1); 1403 } 1404 1405 for (nentry = dentry; nentry != NULL; nentry = nentry->next) { 1406 pentry = nentry; 1407 (void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance); 1408 if (nentry->devinfo.instance == new_instance) 1409 /* 1410 * Add the new link name to the list of links 1411 * that the device 'dname' has. 1412 */ 1413 break; 1414 } 1415 1416 if (nentry == NULL) { 1417 /* 1418 * Either this is the first entry ever, or no matching entry 1419 * was found. Create a new one and add to the list. 1420 */ 1421 if (dentry == NULL) /* first entry ever */ 1422 instance = 0; 1423 else /* no matching entry */ 1424 instance++; 1425 (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance); 1426 if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) == 1427 NULL) 1428 return (-1); 1429 if (pentry != NULL) 1430 pentry->next = nentry; 1431 new_entry = 1; 1432 nentry->devinfo.devname = strdup(dname); 1433 nentry->devinfo.devtype = dtype; 1434 nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH; 1435 nentry->devinfo.devexec = dexec; 1436 nentry->devinfo.instance = new_instance; 1437 /* 1438 * Look for default label range, authorizations and cleaning 1439 * program in devalloc_defaults. If label range is not 1440 * specified in devalloc_defaults, assume it to be admin_low 1441 * to admin_high. 1442 */ 1443 minstr = DA_DEFAULT_MIN; 1444 maxstr = DA_DEFAULT_MAX; 1445 setdadefent(); 1446 if (da_defs = getdadeftype(nentry->devinfo.devtype)) { 1447 kva = da_defs->devopts; 1448 if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL) 1449 minstr = strdup(kval); 1450 if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL) 1451 maxstr = strdup(kval); 1452 if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL) 1453 nentry->devinfo.devauths = strdup(kval); 1454 if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL) 1455 nentry->devinfo.devexec = strdup(kval); 1456 freedadefent(da_defs); 1457 } 1458 enddadefent(); 1459 kval = NULL; 1460 nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) + 1461 strlen(minstr) + strlen(KV_TOKEN_DELIMIT) + 1462 strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr) 1463 + 1; /* +1 for terminator */ 1464 if (kval = (char *)malloc(nlen)) 1465 (void) snprintf(kval, nlen, "%s%s%s%s%s%s%s", 1466 DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT, 1467 DAOPT_MAXLABEL, KV_ASSIGN, maxstr); 1468 nentry->devinfo.devopts = kval; 1469 1470 nentry->devinfo.devlist = NULL; 1471 nentry->next = NULL; 1472 } 1473 1474 nlen = strlen(link) + 1; /* +1 terminator */ 1475 if (nentry->devinfo.devlist) { 1476 plen = strlen(nentry->devinfo.devlist); 1477 nlen = nlen + plen + 1; /* +1 for blank to separate entries */ 1478 } else { 1479 plen = 0; 1480 } 1481 1482 if ((nentry->devinfo.devlist = 1483 (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) { 1484 if (new_entry) { 1485 nentry->devinfo.devname = NULL; 1486 free(nentry->devinfo.devname); 1487 nentry = NULL; 1488 free(nentry); 1489 if (pentry != NULL) 1490 pentry->next = NULL; 1491 } 1492 return (-1); 1493 } 1494 1495 if (plen == 0) 1496 (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link); 1497 else 1498 (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen, 1499 " %s", link); 1500 1501 if (pentry == NULL) { 1502 /* 1503 * This is the first entry of this device type. 1504 */ 1505 if (flag & DA_AUDIO) 1506 dlist->audio = nentry; 1507 else if (flag & DA_CD) 1508 dlist->cd = nentry; 1509 else if (flag & DA_FLOPPY) 1510 dlist->floppy = nentry; 1511 else if (flag & DA_TAPE) 1512 dlist->tape = nentry; 1513 else if (flag & DA_RMDISK) 1514 dlist->rmdisk = nentry; 1515 } 1516 1517 return (0); 1518 } 1519 1520 /* 1521 * da_remove_list - 1522 * removes a /dev link name from the linked list of devices. 1523 * returns type of device if link for that device removed 1524 * successfully, else returns -1 on error. 1525 * if all links for a device are removed, stores that device 1526 * name in devname. 1527 */ 1528 int 1529 da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size) 1530 { 1531 int flag; 1532 int remove_dev = 0; 1533 int nlen, plen, slen; 1534 char *lasts, *lname, *oldlist; 1535 struct stat rmstat; 1536 deventry_t *dentry, *current, *prev; 1537 1538 if (type != NULL) 1539 flag = type; 1540 else if (link == NULL) 1541 return (-1); 1542 else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME)) 1543 flag = DA_AUDIO; 1544 else if (strstr(link, "dsk") || strstr(link, "rdsk") || 1545 strstr(link, "sr") || strstr(link, "rsr")) 1546 flag = DA_CD; 1547 else if (strstr(link, "fd") || strstr(link, "rfd") || 1548 strstr(link, "diskette") || strstr(link, "rdiskette")) 1549 flag = DA_FLOPPY; 1550 else if (strstr(link, DA_TAPE_NAME)) 1551 flag = DA_TAPE; 1552 else 1553 flag = DA_RMDISK; 1554 1555 switch (type) { 1556 case DA_AUDIO: 1557 dentry = dlist->audio; 1558 break; 1559 case DA_CD: 1560 dentry = dlist->cd; 1561 break; 1562 case DA_FLOPPY: 1563 dentry = dlist->floppy; 1564 break; 1565 case DA_TAPE: 1566 dentry = dlist->tape; 1567 break; 1568 case DA_RMDISK: 1569 dentry = dlist->rmdisk; 1570 break; 1571 default: 1572 return (-1); 1573 } 1574 1575 if ((type != NULL) && (link == NULL)) { 1576 for (current = dentry, prev = dentry; current != NULL; 1577 current = current->next) { 1578 oldlist = strdup(current->devinfo.devlist); 1579 for (lname = strtok_r(oldlist, " ", &lasts); 1580 lname != NULL; 1581 lname = strtok_r(NULL, " ", &lasts)) { 1582 if (stat(lname, &rmstat) != 0) { 1583 remove_dev = 1; 1584 goto remove_dev; 1585 } 1586 } 1587 prev = current; 1588 } 1589 return (-1); 1590 } 1591 1592 for (current = dentry, prev = dentry; current != NULL; 1593 current = current->next) { 1594 plen = strlen(current->devinfo.devlist); 1595 nlen = strlen(link); 1596 if (plen == nlen) { 1597 if (strcmp(current->devinfo.devlist, link) == 0) { 1598 /* last name in the list */ 1599 remove_dev = 1; 1600 break; 1601 } 1602 } 1603 if (strstr(current->devinfo.devlist, link)) { 1604 nlen = plen - nlen + 1; 1605 oldlist = strdup(current->devinfo.devlist); 1606 if ((current->devinfo.devlist = 1607 (char *)realloc(current->devinfo.devlist, 1608 nlen)) == NULL) { 1609 free(oldlist); 1610 return (-1); 1611 } 1612 current->devinfo.devlist[0] = '\0'; 1613 nlen = plen = slen = 0; 1614 for (lname = strtok_r(oldlist, " ", &lasts); 1615 lname != NULL; 1616 lname = strtok_r(NULL, " ", &lasts)) { 1617 if (strcmp(lname, link) == 0) 1618 continue; 1619 nlen = strlen(lname) + plen + 1; 1620 if (plen == 0) { 1621 slen = 1622 snprintf(current->devinfo.devlist, 1623 nlen, "%s", lname); 1624 } else { 1625 slen = 1626 snprintf(current->devinfo.devlist + 1627 plen, nlen - plen, " %s", 1628 lname); 1629 } 1630 plen = plen + slen + 1; 1631 } 1632 free(oldlist); 1633 break; 1634 } 1635 prev = current; 1636 } 1637 1638 remove_dev: 1639 if (remove_dev == 1) { 1640 (void) strlcpy(devname, current->devinfo.devname, size); 1641 free(current->devinfo.devname); 1642 free(current->devinfo.devlist); 1643 current->devinfo.devname = current->devinfo.devlist = NULL; 1644 prev->next = current->next; 1645 free(current); 1646 current = NULL; 1647 } 1648 if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) { 1649 if (prev->next) { 1650 /* 1651 * what we removed above was the first entry 1652 * in the list. make the next entry to be the 1653 * first. 1654 */ 1655 current = prev->next; 1656 } else { 1657 /* 1658 * the matching entry was the only entry in the list 1659 * for this type. 1660 */ 1661 current = NULL; 1662 } 1663 if (flag & DA_AUDIO) 1664 dlist->audio = current; 1665 else if (flag & DA_CD) 1666 dlist->cd = current; 1667 else if (flag & DA_FLOPPY) 1668 dlist->floppy = current; 1669 else if (flag & DA_TAPE) 1670 dlist->tape = current; 1671 else if (flag & DA_RMDISK) 1672 dlist->rmdisk = current; 1673 } 1674 1675 return (flag); 1676 } 1677 1678 /* 1679 * da_is_on - 1680 * checks if device allocation feature is turned on. 1681 * returns 1 if on, 0 if off, -1 if status string not 1682 * found in device_allocate. 1683 */ 1684 int 1685 da_is_on() 1686 { 1687 return (getdaon()); 1688 } 1689 1690 /* 1691 * da_print_device - 1692 * debug routine to print device entries. 1693 */ 1694 void 1695 da_print_device(int flag, devlist_t *devlist) 1696 { 1697 deventry_t *entry, *dentry; 1698 devinfo_t *devinfo; 1699 1700 if (flag & DA_AUDIO) 1701 dentry = devlist->audio; 1702 else if (flag & DA_CD) 1703 dentry = devlist->cd; 1704 else if (flag & DA_FLOPPY) 1705 dentry = devlist->floppy; 1706 else if (flag & DA_TAPE) 1707 dentry = devlist->tape; 1708 else if (flag & DA_RMDISK) 1709 dentry = devlist->rmdisk; 1710 else 1711 return; 1712 1713 for (entry = dentry; entry != NULL; entry = entry->next) { 1714 devinfo = &(entry->devinfo); 1715 (void) fprintf(stdout, "name: %s\n", devinfo->devname); 1716 (void) fprintf(stdout, "type: %s\n", devinfo->devtype); 1717 (void) fprintf(stdout, "auth: %s\n", devinfo->devauths); 1718 (void) fprintf(stdout, "exec: %s\n", devinfo->devexec); 1719 (void) fprintf(stdout, "list: %s\n\n", devinfo->devlist); 1720 } 1721 } 1722