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