1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <ctype.h> 31 #include <unistd.h> 32 #include <sys/sysmacros.h> 33 #include <libintl.h> 34 #include <wait.h> 35 #include <string.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <signal.h> 39 #include <sys/buf.h> 40 #include <sys/stat.h> 41 #include <grp.h> 42 #include "addrem.h" 43 #include "errmsg.h" 44 #include "plcysubr.h" 45 46 static char *add_rem_lock; /* lock file */ 47 static char *tmphold; /* temperary file for updating */ 48 49 static int get_cached_n_to_m_file(char *filename, char ***cache); 50 static int get_name_to_major_entry(int *major_no, char *driver_name, 51 char *file_name); 52 53 static int is_blank(char *); 54 55 /*ARGSUSED*/ 56 void 57 log_minorperm_error(minorperm_err_t err, int key) 58 { 59 switch (err) { 60 case MP_FOPEN_ERR: 61 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 62 MINOR_PERM_FILE); 63 break; 64 case MP_FCLOSE_ERR: 65 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 66 MINOR_PERM_FILE); 67 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 68 break; 69 case MP_IGNORING_LINE_ERR: 70 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 71 MINOR_PERM_FILE); 72 break; 73 case MP_ALLOC_ERR: 74 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 75 MINOR_PERM_FILE); 76 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 77 break; 78 case MP_NVLIST_ERR: 79 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 80 MINOR_PERM_FILE); 81 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 82 break; 83 case MP_CANT_FIND_USER_ERR: 84 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 85 MINOR_PERM_FILE); 86 break; 87 case MP_CANT_FIND_GROUP_ERR: 88 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 89 MINOR_PERM_FILE); 90 break; 91 } 92 } 93 94 /* 95 * open file 96 * for each entry in list 97 * where list entries are separated by <list_separator> 98 * append entry : driver_name <entry_separator> entry 99 * close file 100 * return error/noerr 101 */ 102 int 103 append_to_file( 104 char *driver_name, 105 char *entry_list, 106 char *filename, 107 char list_separator, 108 char *entry_separator) 109 { 110 int i, len; 111 int fpint; 112 char *current_head, *previous_head; 113 char *line, *one_entry; 114 FILE *fp; 115 116 if ((fp = fopen(filename, "a")) == NULL) { 117 perror(NULL); 118 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 119 filename); 120 return (ERROR); 121 } 122 123 len = strlen(entry_list); 124 125 one_entry = calloc(len + 1, 1); 126 if (one_entry == NULL) { 127 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), filename); 128 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 129 (void) fclose(fp); 130 return (ERROR); 131 } 132 133 previous_head = entry_list; 134 135 line = calloc(strlen(driver_name) + len + 4, 1); 136 if (line == NULL) { 137 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 138 (void) fclose(fp); 139 err_exit(); 140 } 141 142 /* 143 * get one entry at a time from list and append to <filename> file 144 */ 145 146 do { 147 148 for (i = 0; i <= len; i++) 149 one_entry[i] = 0; 150 151 for (i = 0; i <= (int)strlen(line); i++) 152 line[i] = 0; 153 154 current_head = get_entry(previous_head, one_entry, 155 list_separator); 156 previous_head = current_head; 157 158 (void) strcpy(line, driver_name); 159 (void) strcat(line, entry_separator); 160 (void) strcat(line, one_entry); 161 (void) strcat(line, "\n"); 162 163 if ((fputs(line, fp)) == EOF) { 164 perror(NULL); 165 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 166 filename); 167 } 168 169 } while (*current_head != '\0'); 170 171 172 (void) fflush(fp); 173 174 fpint = fileno(fp); 175 (void) fsync(fpint); 176 177 (void) fclose(fp); 178 179 free(one_entry); 180 free(line); 181 182 return (NOERR); 183 } 184 185 186 /* 187 * open file 188 * read thru file, deleting all entries if first 189 * entry = driver_name 190 * close 191 * if error, leave original file intact with message 192 * assumption : drvconfig has been modified to work with clone 193 * entries in /etc/minor_perm as driver:mummble NOT 194 * clone:driver mummble 195 * this implementation will NOT find clone entries 196 * clone:driver mummble 197 * match: 198 * delete just the matching entry 199 * 200 */ 201 int 202 delete_entry( 203 char *oldfile, 204 char *driver_name, 205 char *marker, 206 char *match) 207 { 208 int rv, i; 209 int status = NOERR; 210 int drvr_found = 0; 211 boolean_t nomatch = B_TRUE; 212 char *newfile, *tptr, *cp, *dup; 213 char line[MAX_DBFILE_ENTRY], drv[FILENAME_MAX + 1]; 214 FILE *fp, *newfp; 215 struct group *sysgrp; 216 217 /* 218 * check if match is specified and if it equals " " 219 * this is a special case handling as we do a strstr(3STRING) 220 * to match an entry. By default all entries are space separated 221 * and without this check all entries of the file could get deleted. 222 */ 223 if (match && (*match == ' ' && strlen(match) == 1)) { 224 (void) fprintf(stderr, gettext(ERR_INT_UPDATE), oldfile); 225 return (ERROR); 226 } 227 228 if ((fp = fopen(oldfile, "r")) == NULL) { 229 perror(NULL); 230 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile); 231 return (ERROR); 232 } 233 234 /* 235 * Build filename for temporary file 236 */ 237 238 if ((tptr = calloc(strlen(oldfile) + strlen(XEND) + 1, 1)) == NULL) { 239 perror(NULL); 240 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 241 } 242 243 (void) strcpy(tptr, oldfile); 244 (void) strcat(tptr, XEND); 245 246 /* 247 * Set gid so we preserve group attribute. Ideally we wouldn't 248 * assume a gid of "sys" but we can't undo the damage on already 249 * installed systems unless we force the issue. 250 */ 251 if ((sysgrp = getgrnam("sys")) != NULL) { 252 (void) setgid(sysgrp->gr_gid); 253 } 254 255 newfile = mktemp(tptr); 256 257 if ((newfp = fopen(newfile, "w")) == NULL) { 258 perror(NULL); 259 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 260 newfile); 261 return (ERROR); 262 } 263 264 while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) { 265 /* copy the whole line into dup */ 266 if ((dup = strdup(line)) == NULL) { 267 perror(NULL); 268 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 269 status = ERROR; 270 break; 271 } 272 /* cut off comments starting with '#' */ 273 if ((cp = strchr(dup, '#')) != NULL) 274 *cp = '\0'; 275 /* ignore comment or blank lines */ 276 if (is_blank(dup)) { 277 if (fputs(line, newfp) == EOF) { 278 (void) fprintf(stderr, gettext(ERR_UPDATE), 279 oldfile); 280 status = ERROR; 281 } 282 free(dup); 283 continue; 284 } 285 286 /* get the driver name */ 287 if (sscanf(dup, "%s", drv) != 1) { 288 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 289 oldfile, line); 290 status = ERROR; 291 free(dup); 292 break; 293 } 294 free(dup); 295 296 for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) { 297 drv[i] = '\0'; 298 } 299 300 if (strcmp(driver_name, drv) != 0) { 301 if ((fputs(line, newfp)) == EOF) { 302 (void) fprintf(stderr, gettext(ERR_UPDATE), 303 oldfile); 304 status = ERROR; 305 } 306 } else { 307 drvr_found++; 308 if (match) { /* Just delete one entry */ 309 /* for now delete just minor_perm and aliases */ 310 if ((strcmp(oldfile, minor_perm) == 0) || 311 (strcmp(oldfile, extra_privs) == 0) || 312 (strcmp(oldfile, driver_aliases) == 0)) { 313 if (strstr(line, match)) { 314 nomatch = B_FALSE; 315 } else { 316 if ((fputs(line, newfp)) == 317 EOF) { 318 (void) fprintf(stderr, 319 gettext(ERR_UPDATE), 320 oldfile); 321 status = ERROR; 322 } 323 if (nomatch != B_FALSE) 324 nomatch = B_TRUE; 325 } 326 } 327 } 328 329 } /* end of else */ 330 } /* end of while */ 331 332 (void) fclose(fp); 333 334 /* Make sure that the file is on disk */ 335 if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0) 336 status = ERROR; 337 else 338 rv = NOERR; 339 340 (void) fclose(newfp); 341 342 /* no matching driver found */ 343 rv = NOERR; 344 if (!drvr_found || 345 (nomatch == B_TRUE)) { 346 rv = NONE_FOUND; 347 } 348 349 /* 350 * if error, leave original file, delete new file 351 * if noerr, replace original file with new file 352 */ 353 354 if (status == NOERR) { 355 if (rename(oldfile, tmphold) == -1) { 356 perror(NULL); 357 (void) fprintf(stderr, gettext(ERR_UPDATE), oldfile); 358 (void) unlink(newfile); 359 return (ERROR); 360 } else if (rename(newfile, oldfile) == -1) { 361 perror(NULL); 362 (void) fprintf(stderr, gettext(ERR_UPDATE), oldfile); 363 (void) unlink(oldfile); 364 (void) unlink(newfile); 365 if (link(tmphold, oldfile) == -1) { 366 perror(NULL); 367 (void) fprintf(stderr, gettext(ERR_BAD_LINK), 368 oldfile, tmphold); 369 } 370 return (ERROR); 371 } 372 (void) unlink(tmphold); 373 } else { 374 /* 375 * since there's an error, leave file alone; remove 376 * new file 377 */ 378 if (unlink(newfile) == -1) { 379 (void) fprintf(stderr, gettext(ERR_CANT_RM), newfile); 380 } 381 return (ERROR); 382 } 383 384 return (rv); 385 } 386 387 388 /* 389 * wrapper for call to get_name_to_major_entry(): given driver name, 390 * retrieve major number. 391 */ 392 int 393 get_major_no(char *driver_name, char *file_name) 394 { 395 int major = UNIQUE; 396 397 if (get_name_to_major_entry(&major, driver_name, file_name) == ERROR) 398 return (ERROR); 399 else 400 return (major); 401 } 402 403 /* 404 * wrapper for call to get_name_to_major_entry(): given major number, 405 * retrieve driver name. 406 */ 407 int 408 get_driver_name(int major, char *file_name, char *buf) 409 { 410 if (major < 0) 411 return (ERROR); 412 return (get_name_to_major_entry(&major, buf, file_name)); 413 } 414 415 416 /* 417 * return pointer to cached name_to_major file - reads file into 418 * cache if this has not already been done. Since there may be 419 * requests for multiple name_to_major files (rem_name_to_major, 420 * name_to_major), this routine keeps a list of cached files. 421 */ 422 static int 423 get_cached_n_to_m_file(char *filename, char ***cache) 424 { 425 struct n_to_m_cache { 426 char *file; 427 char **cached_file; 428 int size; 429 struct n_to_m_cache *next; 430 }; 431 static struct n_to_m_cache *head = NULL; 432 struct n_to_m_cache *ptr; 433 FILE *fp; 434 char drv[FILENAME_MAX + 1]; 435 char entry[FILENAME_MAX + 1]; 436 char line[MAX_N2M_ALIAS_LINE], *cp; 437 int maj; 438 int size = 0; 439 440 441 /* 442 * see if the file is already cached - either 443 * rem_name_to_major or name_to_major 444 */ 445 ptr = head; 446 while (ptr != NULL) { 447 if (strcmp(ptr->file, filename) == 0) 448 break; 449 ptr = ptr->next; 450 } 451 452 if (ptr == NULL) { /* we need to cache the contents */ 453 if ((fp = fopen(filename, "r")) == NULL) { 454 perror(NULL); 455 (void) fprintf(stderr, gettext(ERR_CANT_OPEN), 456 filename); 457 return (ERROR); 458 } 459 460 while (fgets(line, sizeof (line), fp) != NULL) { 461 /* cut off comments starting with '#' */ 462 if ((cp = strchr(line, '#')) != NULL) 463 *cp = '\0'; 464 /* ignore comment or blank lines */ 465 if (is_blank(line)) 466 continue; 467 /* sanity-check */ 468 if (sscanf(line, "%s%s", drv, entry) != 2) { 469 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 470 filename, line); 471 continue; 472 } 473 maj = atoi(entry); 474 if (maj > size) 475 size = maj; 476 } 477 478 /* allocate struct to cache the file */ 479 ptr = (struct n_to_m_cache *)calloc(1, 480 sizeof (struct n_to_m_cache)); 481 if (ptr == NULL) { 482 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 483 return (ERROR); 484 } 485 ptr->size = size + 1; 486 /* allocate space to cache contents of file */ 487 ptr->cached_file = (char **)calloc(ptr->size, sizeof (char *)); 488 if (ptr->cached_file == NULL) { 489 free(ptr); 490 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 491 return (ERROR); 492 } 493 494 rewind(fp); 495 496 /* 497 * now fill the cache 498 * the cache is an array of char pointers indexed by major 499 * number 500 */ 501 while (fgets(line, sizeof (line), fp) != NULL) { 502 /* cut off comments starting with '#' */ 503 if ((cp = strchr(line, '#')) != NULL) 504 *cp = '\0'; 505 /* ignore comment or blank lines */ 506 if (is_blank(line)) 507 continue; 508 /* sanity-check */ 509 if (sscanf(line, "%s%s", drv, entry) != 2) { 510 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 511 filename, line); 512 continue; 513 } 514 maj = atoi(entry); 515 if ((ptr->cached_file[maj] = strdup(drv)) == NULL) { 516 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 517 free(ptr->cached_file); 518 free(ptr); 519 return (ERROR); 520 } 521 (void) strcpy(ptr->cached_file[maj], drv); 522 } 523 (void) fclose(fp); 524 /* link the cache struct into the list of cached files */ 525 ptr->file = strdup(filename); 526 if (ptr->file == NULL) { 527 for (maj = 0; maj <= ptr->size; maj++) 528 free(ptr->cached_file[maj]); 529 free(ptr->cached_file); 530 free(ptr); 531 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 532 return (ERROR); 533 } 534 ptr->next = head; 535 head = ptr; 536 } 537 /* return value pointer to contents of file */ 538 *cache = ptr->cached_file; 539 540 /* return size */ 541 return (ptr->size); 542 } 543 544 545 /* 546 * Using get_cached_n_to_m_file(), retrieve maximum major number 547 * found in the specificed file (name_to_major/rem_name_to_major). 548 * 549 * The return value is actually the size of the internal cache including 0. 550 */ 551 int 552 get_max_major(char *file_name) 553 { 554 char **n_to_m_cache = NULL; 555 556 return (get_cached_n_to_m_file(file_name, &n_to_m_cache)); 557 } 558 559 560 /* 561 * searching name_to_major: if major_no == UNIQUE then the caller wants to 562 * use the driver name as the key. Otherwise, the caller wants to use 563 * the major number as a key. 564 * 565 * This routine caches the contents of the name_to_major file on 566 * first call. And it could be generalized to deal with other 567 * config files if necessary. 568 */ 569 static int 570 get_name_to_major_entry(int *major_no, char *driver_name, char *file_name) 571 { 572 int maj; 573 char **n_to_m_cache = NULL; 574 int size = 0; 575 576 int ret = NOT_UNIQUE; 577 578 /* 579 * read the file in - we cache it in case caller wants to 580 * do multiple lookups 581 */ 582 size = get_cached_n_to_m_file(file_name, &n_to_m_cache); 583 584 if (size == ERROR) 585 return (ERROR); 586 587 /* search with driver name as key */ 588 if (*major_no == UNIQUE) { 589 for (maj = 0; maj < size; maj++) { 590 if ((n_to_m_cache[maj] != NULL) && 591 (strcmp(driver_name, n_to_m_cache[maj]) == 0)) { 592 *major_no = maj; 593 break; 594 } 595 } 596 if (maj >= size) 597 ret = UNIQUE; 598 /* search with major number as key */ 599 } else { 600 /* 601 * Bugid 1254588, drvconfig dump core after loading driver 602 * with major number bigger than entries defined in 603 * /etc/name_to_major. 604 */ 605 if (*major_no >= size) 606 return (UNIQUE); 607 608 if (n_to_m_cache[*major_no] != NULL) { 609 (void) strcpy(driver_name, n_to_m_cache[*major_no]); 610 } else 611 ret = UNIQUE; 612 } 613 return (ret); 614 } 615 616 /* 617 * given pointer to member n in space separated list, return pointer 618 * to member n+1, return member n 619 */ 620 char * 621 get_entry( 622 char *prev_member, 623 char *current_entry, 624 char separator) 625 { 626 char *ptr; 627 628 ptr = prev_member; 629 630 /* skip white space */ 631 while (*ptr == '\t' || *ptr == ' ') 632 ptr++; 633 634 /* read thru the current entry */ 635 while (*ptr != separator && *ptr != '\0') { 636 *current_entry++ = *ptr++; 637 } 638 *current_entry = '\0'; 639 640 if ((separator == ',') && (*ptr == separator)) 641 ptr++; /* skip over comma */ 642 643 /* skip white space */ 644 while (*ptr == '\t' || *ptr == ' ') { 645 ptr++; 646 } 647 648 return (ptr); 649 } 650 651 /*ARGSUSED0*/ 652 static void 653 signal_rtn(int sig) 654 { 655 exit_unlock(); 656 } 657 658 void 659 enter_lock(void) 660 { 661 int fd; 662 663 /* 664 * Setup handler to clean lock file in case user terminates 665 * the command. 666 */ 667 (void) sigset(SIGINT, signal_rtn); 668 (void) sigset(SIGHUP, signal_rtn); 669 (void) sigset(SIGTERM, signal_rtn); 670 671 /* 672 * attempt to create the lock file 673 */ 674 if ((fd = open(add_rem_lock, O_CREAT | O_EXCL | O_WRONLY, 675 S_IRUSR | S_IWUSR)) == -1) { 676 if (errno == EEXIST) { 677 (void) fprintf(stderr, gettext(ERR_PROG_IN_USE)); 678 } else { 679 perror(gettext(ERR_LOCKFILE)); 680 } 681 exit(1); 682 } 683 (void) close(fd); 684 } 685 686 void 687 err_exit(void) 688 { 689 /* release memory allocated for moddir */ 690 cleanup_moddir(); 691 /* remove add_drv/rem_drv lock */ 692 exit_unlock(); 693 exit(1); 694 } 695 696 void 697 cleanup_moddir(void) 698 { 699 struct drvmod_dir *walk_ptr; 700 struct drvmod_dir *free_ptr = moddir; 701 702 while (free_ptr != NULL) { 703 walk_ptr = free_ptr->next; 704 free(free_ptr); 705 free_ptr = walk_ptr; 706 } 707 } 708 709 void 710 exit_unlock(void) 711 { 712 struct stat buf; 713 714 if (stat(add_rem_lock, &buf) == NOERR) { 715 if (unlink(add_rem_lock) == -1) { 716 (void) fprintf(stderr, gettext(ERR_REM_LOCK), 717 add_rem_lock); 718 } 719 } 720 } 721 722 /* 723 * error adding driver; need to back out any changes to files. 724 * check flag to see which files need entries removed 725 * entry removal based on driver name 726 */ 727 void 728 remove_entry( 729 int c_flag, 730 char *driver_name) 731 { 732 733 if (c_flag & CLEAN_NAM_MAJ) { 734 if (delete_entry(name_to_major, driver_name, " ", 735 NULL) == ERROR) { 736 (void) fprintf(stderr, gettext(ERR_NO_CLEAN), 737 name_to_major, driver_name); 738 } 739 } 740 741 if (c_flag & CLEAN_DRV_ALIAS) { 742 if (delete_entry(driver_aliases, driver_name, " ", 743 NULL) == ERROR) { 744 (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 745 driver_name, driver_aliases); 746 } 747 } 748 749 if (c_flag & CLEAN_DRV_CLASSES) { 750 if (delete_entry(driver_classes, driver_name, "\t", NULL) == 751 ERROR) { 752 (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 753 driver_name, driver_classes); 754 } 755 } 756 757 if (c_flag & CLEAN_MINOR_PERM) { 758 if (delete_entry(minor_perm, driver_name, ":", NULL) == ERROR) { 759 (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 760 driver_name, minor_perm); 761 } 762 } 763 /* 764 * There's no point in removing entries from files that don't 765 * exist. Prevent error messages by checking for file existence 766 * first. 767 */ 768 if ((c_flag & CLEAN_DEV_POLICY) != 0 && 769 access(device_policy, F_OK) == 0) { 770 if (delete_plcy_entry(device_policy, driver_name) == ERROR) { 771 (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 772 driver_name, device_policy); 773 } 774 } 775 if ((c_flag & CLEAN_DRV_PRIV) != 0 && 776 access(extra_privs, F_OK) == 0) { 777 if (delete_entry(extra_privs, driver_name, ":", NULL) == 778 ERROR) { 779 (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 780 driver_name, extra_privs); 781 } 782 } 783 } 784 785 int 786 check_perms_aliases( 787 int m_flag, 788 int i_flag) 789 { 790 /* 791 * If neither i_flag nor m_flag are specified no need to check the 792 * files for access permissions 793 */ 794 if (!m_flag && !i_flag) 795 return (NOERR); 796 797 /* check minor_perm file : exits and is writable */ 798 if (m_flag) { 799 if (access(minor_perm, R_OK | W_OK)) { 800 perror(NULL); 801 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 802 minor_perm); 803 return (ERROR); 804 } 805 } 806 807 /* check driver_aliases file : exits and is writable */ 808 if (i_flag) { 809 if (access(driver_aliases, R_OK | W_OK)) { 810 perror(NULL); 811 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 812 driver_aliases); 813 return (ERROR); 814 } 815 } 816 817 return (NOERR); 818 } 819 820 821 int 822 check_name_to_major(int mode) 823 { 824 /* check name_to_major file : exists and is writable */ 825 if (access(name_to_major, mode)) { 826 perror(NULL); 827 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 828 name_to_major); 829 return (ERROR); 830 } 831 832 return (NOERR); 833 } 834 835 836 /* 837 * All this stuff is to support a server installing 838 * drivers on diskless clients. When on the server 839 * need to prepend the basedir 840 */ 841 int 842 build_filenames(char *basedir) 843 { 844 int len; 845 846 if (basedir == NULL) { 847 driver_aliases = DRIVER_ALIAS; 848 driver_classes = DRIVER_CLASSES; 849 minor_perm = MINOR_PERM; 850 name_to_major = NAM_TO_MAJ; 851 rem_name_to_major = REM_NAM_TO_MAJ; 852 add_rem_lock = ADD_REM_LOCK; 853 tmphold = TMPHOLD; 854 devfs_root = DEVFS_ROOT; 855 device_policy = DEV_POLICY; 856 extra_privs = EXTRA_PRIVS; 857 858 } else { 859 len = strlen(basedir); 860 861 driver_aliases = malloc(len + sizeof (DRIVER_ALIAS)); 862 driver_classes = malloc(len + sizeof (DRIVER_CLASSES)); 863 minor_perm = malloc(len + sizeof (MINOR_PERM)); 864 name_to_major = malloc(len + sizeof (NAM_TO_MAJ)); 865 rem_name_to_major = malloc(len + sizeof (REM_NAM_TO_MAJ)); 866 add_rem_lock = malloc(len + sizeof (ADD_REM_LOCK)); 867 tmphold = malloc(len + sizeof (TMPHOLD)); 868 devfs_root = malloc(len + sizeof (DEVFS_ROOT)); 869 device_policy = malloc(len + sizeof (DEV_POLICY)); 870 extra_privs = malloc(len + sizeof (EXTRA_PRIVS)); 871 872 873 if ((driver_aliases == NULL) || 874 (driver_classes == NULL) || 875 (minor_perm == NULL) || 876 (name_to_major == NULL) || 877 (rem_name_to_major == NULL) || 878 (add_rem_lock == NULL) || 879 (tmphold == NULL) || 880 (devfs_root == NULL) || 881 (device_policy == NULL) || 882 (extra_privs == NULL)) { 883 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 884 return (ERROR); 885 } 886 887 (void) sprintf(driver_aliases, "%s%s", basedir, DRIVER_ALIAS); 888 (void) sprintf(driver_classes, "%s%s", basedir, DRIVER_CLASSES); 889 (void) sprintf(minor_perm, "%s%s", basedir, MINOR_PERM); 890 (void) sprintf(name_to_major, "%s%s", basedir, NAM_TO_MAJ); 891 (void) sprintf(rem_name_to_major, "%s%s", basedir, 892 REM_NAM_TO_MAJ); 893 (void) sprintf(add_rem_lock, "%s%s", basedir, ADD_REM_LOCK); 894 (void) sprintf(tmphold, "%s%s", basedir, TMPHOLD); 895 (void) sprintf(devfs_root, "%s%s", basedir, DEVFS_ROOT); 896 (void) sprintf(device_policy, "%s%s", basedir, DEV_POLICY); 897 (void) sprintf(extra_privs, "%s%s", basedir, EXTRA_PRIVS); 898 } 899 900 return (NOERR); 901 } 902 903 static int 904 exec_command(char *path, char *cmdline[MAX_CMD_LINE]) 905 { 906 pid_t pid; 907 uint_t stat_loc; 908 int waitstat; 909 int exit_status; 910 911 /* child */ 912 if ((pid = fork()) == 0) { 913 (void) execv(path, cmdline); 914 perror(NULL); 915 return (ERROR); 916 } else if (pid == -1) { 917 /* fork failed */ 918 perror(NULL); 919 (void) fprintf(stderr, gettext(ERR_FORK_FAIL), cmdline); 920 return (ERROR); 921 } else { 922 /* parent */ 923 do { 924 waitstat = waitpid(pid, (int *)&stat_loc, 0); 925 926 } while ((!WIFEXITED(stat_loc) && 927 !WIFSIGNALED(stat_loc)) || (waitstat == 0)); 928 929 exit_status = WEXITSTATUS(stat_loc); 930 931 return (exit_status); 932 } 933 } 934 935 /* 936 * check that major_num doesn't exceed maximum on this machine 937 * do this here to support add_drv on server for diskless clients 938 */ 939 int 940 config_driver( 941 char *driver_name, 942 major_t major_num, 943 char *aliases, 944 char *classes, 945 int cleanup_flag, 946 int verbose_flag) 947 { 948 int max_dev; 949 int n = 0; 950 char *cmdline[MAX_CMD_LINE]; 951 char maj_num[128]; 952 char *previous; 953 char *current; 954 int exec_status; 955 int len; 956 957 if (modctl(MODRESERVED, NULL, &max_dev) < 0) { 958 perror(NULL); 959 (void) fprintf(stderr, gettext(ERR_MAX_MAJOR)); 960 return (ERROR); 961 } 962 963 if (major_num >= max_dev) { 964 (void) fprintf(stderr, gettext(ERR_MAX_EXCEEDS), 965 major_num, max_dev); 966 return (ERROR); 967 } 968 969 /* bind major number and driver name */ 970 971 /* build command line */ 972 cmdline[n++] = DRVCONFIG; 973 if (verbose_flag) { 974 cmdline[n++] = "-v"; 975 } 976 cmdline[n++] = "-b"; 977 if (classes) { 978 cmdline[n++] = "-c"; 979 cmdline[n++] = classes; 980 } 981 cmdline[n++] = "-i"; 982 cmdline[n++] = driver_name; 983 cmdline[n++] = "-m"; 984 (void) sprintf(maj_num, "%lu", major_num); 985 cmdline[n++] = maj_num; 986 987 if (aliases != NULL) { 988 len = strlen(aliases); 989 previous = aliases; 990 do { 991 cmdline[n++] = "-a"; 992 cmdline[n] = calloc(len + 1, 1); 993 if (cmdline[n] == NULL) { 994 (void) fprintf(stderr, 995 gettext(ERR_NO_MEM)); 996 return (ERROR); 997 } 998 current = get_entry(previous, 999 cmdline[n++], ' '); 1000 previous = current; 1001 1002 } while (*current != '\0'); 1003 1004 } 1005 cmdline[n] = (char *)0; 1006 1007 exec_status = exec_command(DRVCONFIG_PATH, cmdline); 1008 1009 if (exec_status == NOERR) 1010 return (NOERR); 1011 perror(NULL); 1012 remove_entry(cleanup_flag, driver_name); 1013 return (ERROR); 1014 } 1015 1016 void 1017 load_driver(char *driver_name, int verbose_flag) 1018 { 1019 int n = 0; 1020 char *cmdline[MAX_CMD_LINE]; 1021 int exec_status; 1022 1023 /* build command line */ 1024 cmdline[n++] = DEVFSADM; 1025 if (verbose_flag) { 1026 cmdline[n++] = "-v"; 1027 } 1028 cmdline[n++] = "-i"; 1029 cmdline[n++] = driver_name; 1030 cmdline[n] = (char *)0; 1031 1032 exec_status = exec_command(DEVFSADM_PATH, cmdline); 1033 1034 if (exec_status != NOERR) { 1035 /* no clean : name and major number are bound */ 1036 (void) fprintf(stderr, gettext(ERR_CONFIG), 1037 driver_name); 1038 } 1039 } 1040 1041 void 1042 get_modid(char *driver_name, int *mod) 1043 { 1044 struct modinfo modinfo; 1045 1046 modinfo.mi_id = -1; 1047 modinfo.mi_info = MI_INFO_ALL; 1048 do { 1049 /* 1050 * If we are at the end of the list of loaded modules 1051 * then set *mod = -1 and return 1052 */ 1053 if (modctl(MODINFO, 0, &modinfo) < 0) { 1054 *mod = -1; 1055 return; 1056 } 1057 1058 *mod = modinfo.mi_id; 1059 } while (strcmp(driver_name, modinfo.mi_name) != 0); 1060 } 1061 1062 int 1063 create_reconfig(char *basedir) 1064 { 1065 char reconfig_file[MAXPATHLEN + FILENAME_MAX + 1]; 1066 FILE *reconfig_fp; 1067 1068 if (basedir != NULL) { 1069 (void) strcpy(reconfig_file, basedir); 1070 (void) strcat(reconfig_file, RECONFIGURE); 1071 } else { 1072 (void) strcpy(reconfig_file, RECONFIGURE); 1073 } 1074 if ((reconfig_fp = fopen(reconfig_file, "a")) == NULL) 1075 return (ERROR); 1076 1077 (void) fclose(reconfig_fp); 1078 return (NOERR); 1079 } 1080 1081 1082 /* 1083 * update_minor_entry: 1084 * open file 1085 * for each entry in list 1086 * where list entries are separated by <list_separator> 1087 * modify entry : driver_name <entry_separator> entry 1088 * close file 1089 * 1090 * return error/noerr 1091 */ 1092 int 1093 update_minor_entry(char *driver_name, char *perm_list) 1094 { 1095 FILE *fp; 1096 FILE *newfp; 1097 struct group *sysgrp; 1098 int match = 0; 1099 char line[MAX_DBFILE_ENTRY], *cp, *dup; 1100 char drv[FILENAME_MAX + 1], *drv_minor; 1101 char minor[FILENAME_MAX + 1], perm[OPT_LEN + 1]; 1102 char own[OPT_LEN + 1], grp[OPT_LEN + 1]; 1103 int status = NOERR, i; 1104 char *newfile, *tptr; 1105 extern void bzero(); 1106 1107 if ((fp = fopen(minor_perm, "r")) == NULL) { 1108 perror(NULL); 1109 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 1110 minor_perm); 1111 1112 return (ERROR); 1113 } 1114 1115 /* 1116 * Build filename for temporary file 1117 */ 1118 if ((tptr = calloc(strlen(minor_perm) + strlen(XEND) + 1, 1)) == NULL) { 1119 perror(NULL); 1120 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1121 } 1122 (void) strcpy(tptr, minor_perm); 1123 (void) strcat(tptr, XEND); 1124 1125 /* 1126 * Set gid so we preserve group attribute. Ideally we wouldn't 1127 * assume a gid of "sys" but we can't undo the damage on already 1128 * installed systems unless we force the issue. 1129 */ 1130 if ((sysgrp = getgrnam("sys")) != NULL) { 1131 (void) setgid(sysgrp->gr_gid); 1132 } 1133 1134 newfile = mktemp(tptr); 1135 if ((newfp = fopen(newfile, "w")) == NULL) { 1136 perror(NULL); 1137 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 1138 newfile); 1139 return (ERROR); 1140 } 1141 1142 if (sscanf(perm_list, "%s%s%s%s", minor, perm, own, grp) != 4) { 1143 status = ERROR; 1144 } 1145 1146 while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) { 1147 /* copy the whole line into dup */ 1148 if ((dup = strdup(line)) == NULL) { 1149 perror(NULL); 1150 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1151 status = ERROR; 1152 break; 1153 } 1154 /* cut off comments starting with '#' */ 1155 if ((cp = strchr(dup, '#')) != NULL) 1156 *cp = '\0'; 1157 /* ignore comment or blank lines */ 1158 if (is_blank(dup)) { 1159 if (fputs(line, newfp) == EOF) { 1160 (void) fprintf(stderr, gettext(ERR_UPDATE), 1161 minor_perm); 1162 status = ERROR; 1163 } 1164 free(dup); 1165 continue; 1166 } 1167 1168 /* get the driver name */ 1169 if (sscanf(dup, "%s", drv) != 1) { 1170 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 1171 minor_perm, line); 1172 status = ERROR; 1173 free(dup); 1174 break; 1175 } 1176 1177 /* 1178 * get the minor name; place the NULL character at the 1179 * end of the driver name, then make the drv_minor 1180 * point to the first character of the minor name. 1181 * the line missing ':' must be treated as a broken one. 1182 */ 1183 i = strcspn(drv, ":"); 1184 if (i == strlen(drv)) { 1185 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 1186 minor_perm, line); 1187 status = ERROR; 1188 free(dup); 1189 break; 1190 } 1191 drv[i] = '\0'; 1192 drv_minor = &drv[strlen(drv) + 1]; 1193 1194 /* 1195 * compare both of the driver name and the minor name. 1196 * then the new line should be written to the file if 1197 * both of them match 1198 */ 1199 if ((strcmp(drv, driver_name) == 0) && 1200 (strcmp(minor, drv_minor) == 0)) { 1201 /* if it has a comment, keep it */ 1202 if (cp != NULL) { 1203 cp++; /* skip a terminator */ 1204 (void) sprintf(line, "%s:%s %s %s %s #%s\n", 1205 drv, minor, perm, own, grp, cp); 1206 } else { 1207 (void) sprintf(line, "%s:%s %s %s %s\n", 1208 drv, minor, perm, own, grp); 1209 } 1210 match = 1; 1211 } 1212 free(dup); 1213 1214 /* update the file */ 1215 if ((fputs(line, newfp)) == EOF) { 1216 (void) fprintf(stderr, gettext(ERR_UPDATE), 1217 minor_perm); 1218 status = ERROR; 1219 } 1220 } 1221 1222 if (!match) { 1223 (void) bzero(line, sizeof (&line[0])); 1224 (void) sprintf(line, "%s:%s %s %s %s\n", 1225 driver_name, minor, perm, own, grp); 1226 1227 /* add the new entry */ 1228 if ((fputs(line, newfp)) == EOF) { 1229 (void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm); 1230 status = ERROR; 1231 } 1232 } 1233 1234 (void) fclose(fp); 1235 1236 if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0) 1237 status = ERROR; 1238 1239 (void) fclose(newfp); 1240 1241 /* 1242 * if error, leave original file, delete new file 1243 * if noerr, replace original file with new file 1244 */ 1245 if (status == NOERR) { 1246 if (rename(minor_perm, tmphold) == -1) { 1247 perror(NULL); 1248 (void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm); 1249 (void) unlink(newfile); 1250 return (ERROR); 1251 } else if (rename(newfile, minor_perm) == -1) { 1252 perror(NULL); 1253 (void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm); 1254 (void) unlink(minor_perm); 1255 (void) unlink(newfile); 1256 if (link(tmphold, minor_perm) == -1) { 1257 perror(NULL); 1258 (void) fprintf(stderr, gettext(ERR_BAD_LINK), 1259 minor_perm, tmphold); 1260 } 1261 return (ERROR); 1262 } 1263 (void) unlink(tmphold); 1264 } else { 1265 /* 1266 * since there's an error, leave file alone; remove 1267 * new file 1268 */ 1269 if (unlink(newfile) == -1) { 1270 (void) fprintf(stderr, gettext(ERR_CANT_RM), newfile); 1271 } 1272 return (ERROR); 1273 } 1274 1275 return (NOERR); 1276 1277 } 1278 1279 1280 /* 1281 * list_entry: 1282 * open file 1283 * read thru file, listing all entries if first entry = driver_name 1284 * close 1285 */ 1286 void 1287 list_entry( 1288 char *oldfile, 1289 char *driver_name, 1290 char *marker) 1291 { 1292 FILE *fp; 1293 int i; 1294 char line[MAX_DBFILE_ENTRY], *cp; 1295 char drv[FILENAME_MAX + 1]; 1296 1297 if ((fp = fopen(oldfile, "r")) == NULL) { 1298 perror(NULL); 1299 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile); 1300 1301 return; 1302 } 1303 1304 while (fgets(line, sizeof (line), fp) != NULL) { 1305 /* cut off comments starting with '#' */ 1306 if ((cp = strchr(line, '#')) != NULL) 1307 *cp = '\0'; 1308 /* ignore comment or blank lines */ 1309 if (is_blank(line)) 1310 continue; 1311 /* sanity-check */ 1312 if (sscanf(line, "%s", drv) != 1) { 1313 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 1314 oldfile, line); 1315 } 1316 1317 for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) { 1318 drv[i] = '\0'; 1319 } 1320 1321 if (strcmp(driver_name, drv) == 0) { 1322 (void) fprintf(stdout, "%s", line); 1323 } 1324 } 1325 1326 (void) fclose(fp); 1327 } 1328 1329 static boolean_t 1330 is_token(char *tok) 1331 { 1332 /* 1333 * Check the token here. According to IEEE1275 Open Firmware Boot 1334 * Standard, the name is composed of 1 to 31 letters, 1335 * digits and punctuation characters from the set ",._+-", and 1336 * uppercase and lowercase characters are considered distinct. 1337 * (ie. token := [a-zA-Z0-9,._+-]+, length(token) <= 31) 1338 * However, since either the definition of driver or aliase names is 1339 * not known well, only '#' is avoided explicitly. (the kernel lexical 1340 * analyzer treats it as a start of a comment) 1341 */ 1342 for (/* nothing */; *tok != '\0'; tok++) 1343 if (*tok == '#' || iscntrl(*tok)) 1344 return (B_FALSE); 1345 1346 return (B_TRUE); 1347 } 1348 1349 /* 1350 * check each entry in perm_list for: 1351 * 4 arguments 1352 * permission arg is in valid range 1353 * permlist entries separated by comma 1354 * return ERROR/NOERR 1355 */ 1356 int 1357 check_perm_opts(char *perm_list) 1358 { 1359 char *current_head; 1360 char *previous_head; 1361 char *one_entry; 1362 int i, len, scan_stat; 1363 char minor[FILENAME_MAX + 1]; 1364 char perm[OPT_LEN + 1]; 1365 char own[OPT_LEN + 1]; 1366 char grp[OPT_LEN + 1]; 1367 char dumb[OPT_LEN + 1]; 1368 int status = NOERR; 1369 int intperm; 1370 1371 len = strlen(perm_list); 1372 1373 if (len == 0) { 1374 return (ERROR); 1375 } 1376 1377 one_entry = calloc(len + 1, 1); 1378 if (one_entry == NULL) { 1379 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1380 return (ERROR); 1381 } 1382 1383 previous_head = perm_list; 1384 current_head = perm_list; 1385 1386 while (*current_head != '\0') { 1387 1388 for (i = 0; i <= len; i++) 1389 one_entry[i] = 0; 1390 1391 current_head = get_entry(previous_head, one_entry, ','); 1392 1393 previous_head = current_head; 1394 scan_stat = sscanf(one_entry, "%s%s%s%s%s", minor, perm, own, 1395 grp, dumb); 1396 1397 if (scan_stat < 4) { 1398 (void) fprintf(stderr, gettext(ERR_MIS_TOK), 1399 "-m", one_entry); 1400 status = ERROR; 1401 } 1402 if (scan_stat > 4) { 1403 (void) fprintf(stderr, gettext(ERR_TOO_MANY_ARGS), 1404 "-m", one_entry); 1405 status = ERROR; 1406 } 1407 1408 intperm = atoi(perm); 1409 if (intperm < 0000 || intperm > 4777) { 1410 (void) fprintf(stderr, gettext(ERR_BAD_MODE), perm); 1411 status = ERROR; 1412 } 1413 } 1414 1415 free(one_entry); 1416 return (status); 1417 } 1418 1419 1420 /* 1421 * check each alias : 1422 * alias list members separated by white space 1423 * cannot exist as driver name in /etc/name_to_major 1424 * cannot exist as driver or alias name in /etc/driver_aliases 1425 */ 1426 int 1427 aliases_unique(char *aliases) 1428 { 1429 char *current_head; 1430 char *previous_head; 1431 char *one_entry; 1432 int i, len; 1433 int is_unique; 1434 1435 len = strlen(aliases); 1436 1437 one_entry = calloc(len + 1, 1); 1438 if (one_entry == NULL) { 1439 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1440 return (ERROR); 1441 } 1442 1443 previous_head = aliases; 1444 1445 do { 1446 for (i = 0; i <= len; i++) 1447 one_entry[i] = 0; 1448 1449 current_head = get_entry(previous_head, one_entry, ' '); 1450 previous_head = current_head; 1451 1452 if ((unique_driver_name(one_entry, name_to_major, 1453 &is_unique)) == ERROR) { 1454 free(one_entry); 1455 return (ERROR); 1456 } 1457 1458 if (is_unique != UNIQUE) { 1459 (void) fprintf(stderr, gettext(ERR_ALIAS_IN_NAM_MAJ), 1460 one_entry); 1461 free(one_entry); 1462 return (ERROR); 1463 } 1464 1465 if (unique_drv_alias(one_entry) != NOERR) { 1466 free(one_entry); 1467 return (ERROR); 1468 } 1469 1470 if (!is_token(one_entry)) { 1471 (void) fprintf(stderr, gettext(ERR_BAD_TOK), 1472 "-i", one_entry); 1473 free(one_entry); 1474 return (ERROR); 1475 } 1476 1477 } while (*current_head != '\0'); 1478 1479 free(one_entry); 1480 1481 return (NOERR); 1482 1483 } 1484 1485 1486 int 1487 update_driver_aliases( 1488 char *driver_name, 1489 char *aliases) 1490 { 1491 /* make call to update the aliases file */ 1492 return (append_to_file(driver_name, aliases, driver_aliases, ' ', " ")); 1493 1494 } 1495 1496 1497 int 1498 unique_drv_alias(char *drv_alias) 1499 { 1500 FILE *fp; 1501 char drv[FILENAME_MAX + 1]; 1502 char line[MAX_N2M_ALIAS_LINE + 1], *cp; 1503 char alias[FILENAME_MAX + 1]; 1504 int status = NOERR; 1505 1506 fp = fopen(driver_aliases, "r"); 1507 1508 if (fp != NULL) { 1509 while ((fgets(line, sizeof (line), fp) != 0) && 1510 status != ERROR) { 1511 /* cut off comments starting with '#' */ 1512 if ((cp = strchr(line, '#')) != NULL) 1513 *cp = '\0'; 1514 /* ignore comment or blank lines */ 1515 if (is_blank(line)) 1516 continue; 1517 /* sanity-check */ 1518 if (sscanf(line, "%s %s", drv, alias) != 2) 1519 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 1520 driver_aliases, line); 1521 1522 if ((strcmp(drv_alias, drv) == 0) || 1523 (strcmp(drv_alias, alias) == 0)) { 1524 (void) fprintf(stderr, 1525 gettext(ERR_ALIAS_IN_USE), 1526 drv_alias); 1527 status = ERROR; 1528 } 1529 } 1530 (void) fclose(fp); 1531 return (status); 1532 } else { 1533 perror(NULL); 1534 (void) fprintf(stderr, gettext(ERR_CANT_OPEN), driver_aliases); 1535 return (ERROR); 1536 } 1537 1538 } 1539 1540 1541 /* 1542 * search for driver_name in first field of file file_name 1543 * searching name_to_major and driver_aliases: name separated from rest of 1544 * line by blank 1545 * if there return 1546 * else return 1547 */ 1548 int 1549 unique_driver_name(char *driver_name, char *file_name, 1550 int *is_unique) 1551 { 1552 int ret; 1553 1554 if ((ret = get_major_no(driver_name, file_name)) == ERROR) { 1555 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 1556 file_name); 1557 } else { 1558 /* XXX */ 1559 /* check alias file for name collision */ 1560 if (unique_drv_alias(driver_name) == ERROR) { 1561 ret = ERROR; 1562 } else { 1563 if (ret != UNIQUE) 1564 *is_unique = NOT_UNIQUE; 1565 else 1566 *is_unique = ret; 1567 ret = NOERR; 1568 } 1569 } 1570 return (ret); 1571 } 1572 1573 1574 int 1575 check_space_within_quote(char *str) 1576 { 1577 register int i; 1578 register int len; 1579 int quoted = 0; 1580 1581 len = strlen(str); 1582 for (i = 0; i < len; i++, str++) { 1583 if (*str == '"') { 1584 if (quoted == 0) 1585 quoted++; 1586 else 1587 quoted--; 1588 } else if (*str == ' ' && quoted) 1589 return (ERROR); 1590 } 1591 1592 return (0); 1593 } 1594 1595 1596 /* 1597 * get major number 1598 * write driver_name major_num to name_to_major file 1599 * major_num returned in major_num 1600 * return success/failure 1601 */ 1602 int 1603 update_name_to_major(char *driver_name, major_t *major_num, int server) 1604 { 1605 char major[MAX_STR_MAJOR + 1]; 1606 struct stat buf; 1607 char *num_list; 1608 char drv_majnum_str[MAX_STR_MAJOR + 1]; 1609 int new_maj = -1; 1610 int i, tmp = 0, is_unique, have_rem_n2m = 0; 1611 int max_dev = 0; 1612 1613 /* 1614 * if driver_name already in rem_name_to_major 1615 * delete entry from rem_nam_to_major 1616 * put entry into name_to_major 1617 */ 1618 1619 if (stat(rem_name_to_major, &buf) == 0) { 1620 have_rem_n2m = 1; 1621 } 1622 1623 if (have_rem_n2m) { 1624 if ((is_unique = get_major_no(driver_name, rem_name_to_major)) 1625 == ERROR) 1626 return (ERROR); 1627 1628 /* 1629 * found a match in rem_name_to_major 1630 */ 1631 if (is_unique != UNIQUE) { 1632 char scratch[FILENAME_MAX]; 1633 1634 /* 1635 * If there is a match in /etc/rem_name_to_major then 1636 * be paranoid: is that major number already in 1637 * /etc/name_to_major (potentially under another name)? 1638 */ 1639 if (get_driver_name(is_unique, name_to_major, 1640 scratch) != UNIQUE) { 1641 /* 1642 * nuke the rem_name_to_major entry-- it 1643 * isn't helpful. 1644 */ 1645 (void) delete_entry(rem_name_to_major, 1646 driver_name, " ", NULL); 1647 } else { 1648 (void) snprintf(major, sizeof (major), 1649 "%d", is_unique); 1650 1651 if (append_to_file(driver_name, major, 1652 name_to_major, ' ', " ") == ERROR) { 1653 (void) fprintf(stderr, 1654 gettext(ERR_NO_UPDATE), 1655 name_to_major); 1656 return (ERROR); 1657 } 1658 1659 if (delete_entry(rem_name_to_major, 1660 driver_name, " ", NULL) == ERROR) { 1661 (void) fprintf(stderr, 1662 gettext(ERR_DEL_ENTRY), driver_name, 1663 rem_name_to_major); 1664 return (ERROR); 1665 } 1666 1667 /* found matching entry : no errors */ 1668 *major_num = is_unique; 1669 return (NOERR); 1670 } 1671 } 1672 } 1673 1674 /* 1675 * Bugid: 1264079 1676 * In a server case (with -b option), we can't use modctl() to find 1677 * the maximum major number, we need to dig thru client's 1678 * /etc/name_to_major and /etc/rem_name_to_major for the max_dev. 1679 * 1680 * if (server) 1681 * get maximum major number thru (rem_)name_to_major file on client 1682 * else 1683 * get maximum major number allowable on current system using modctl 1684 */ 1685 if (server) { 1686 max_dev = 0; 1687 tmp = 0; 1688 1689 max_dev = get_max_major(name_to_major); 1690 1691 /* If rem_name_to_major exists, we need to check it too */ 1692 if (have_rem_n2m) { 1693 tmp = get_max_major(rem_name_to_major); 1694 1695 /* 1696 * If name_to_major is missing, we can get max_dev from 1697 * /etc/rem_name_to_major. If both missing, bail out! 1698 */ 1699 if ((max_dev == ERROR) && (tmp == ERROR)) { 1700 (void) fprintf(stderr, 1701 gettext(ERR_CANT_ACCESS_FILE), 1702 name_to_major); 1703 return (ERROR); 1704 } 1705 1706 /* guard against bigger maj_num in rem_name_to_major */ 1707 if (tmp > max_dev) 1708 max_dev = tmp; 1709 } else { 1710 /* 1711 * If we can't get major from name_to_major file 1712 * and there is no /etc/rem_name_to_major file, 1713 * then we don't have a max_dev, bail out quick! 1714 */ 1715 if (max_dev == ERROR) 1716 return (ERROR); 1717 } 1718 1719 /* 1720 * In case there is no more slack in current name_to_major 1721 * table, provide at least 1 extra entry so the add_drv can 1722 * succeed. Since only one add_drv process is allowed at one 1723 * time, and hence max_dev will be re-calculated each time 1724 * add_drv is ran, we don't need to worry about adding more 1725 * than 1 extra slot for max_dev. 1726 */ 1727 max_dev++; 1728 1729 } else { 1730 if (modctl(MODRESERVED, NULL, &max_dev) < 0) { 1731 perror(NULL); 1732 (void) fprintf(stderr, gettext(ERR_MAX_MAJOR)); 1733 return (ERROR); 1734 } 1735 } 1736 1737 /* 1738 * max_dev is really how many slots the kernel has allocated for 1739 * devices... [0 , maxdev-1], not the largest available device num. 1740 */ 1741 if ((num_list = calloc(max_dev, 1)) == NULL) { 1742 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1743 return (ERROR); 1744 } 1745 1746 /* 1747 * Populate the num_list array 1748 */ 1749 if (fill_n2m_array(name_to_major, &num_list, &max_dev) != 0) { 1750 return (ERROR); 1751 } 1752 if (have_rem_n2m) { 1753 if (fill_n2m_array(rem_name_to_major, &num_list, &max_dev) != 0) 1754 return (ERROR); 1755 } 1756 1757 /* find first free major number */ 1758 for (i = 0; i < max_dev; i++) { 1759 if (num_list[i] != 1) { 1760 new_maj = i; 1761 break; 1762 } 1763 } 1764 1765 if (new_maj == -1) { 1766 (void) fprintf(stderr, gettext(ERR_NO_FREE_MAJOR)); 1767 return (ERROR); 1768 } 1769 1770 (void) sprintf(drv_majnum_str, "%d", new_maj); 1771 if (do_the_update(driver_name, drv_majnum_str) == ERROR) { 1772 return (ERROR); 1773 } 1774 1775 *major_num = new_maj; 1776 return (NOERR); 1777 } 1778 1779 1780 int 1781 fill_n2m_array(char *filename, char **array, int *nelems) 1782 { 1783 FILE *fp; 1784 char line[MAX_N2M_ALIAS_LINE + 1], *cp; 1785 char drv[FILENAME_MAX + 1]; 1786 u_longlong_t dnum; 1787 major_t drv_majnum; 1788 1789 /* 1790 * Read through the file, marking each major number found 1791 * order is not relevant 1792 */ 1793 if ((fp = fopen(filename, "r")) == NULL) { 1794 perror(NULL); 1795 (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), filename); 1796 return (ERROR); 1797 } 1798 1799 while (fgets(line, sizeof (line), fp) != 0) { 1800 /* cut off comments starting with '#' */ 1801 if ((cp = strchr(line, '#')) != NULL) 1802 *cp = '\0'; 1803 /* ignore comment or blank lines */ 1804 if (is_blank(line)) 1805 continue; 1806 /* sanity-check */ 1807 if (sscanf(line, "%s %llu", drv, &dnum) != 2) { 1808 (void) fprintf(stderr, gettext(ERR_BAD_LINE), 1809 filename, line); 1810 (void) fclose(fp); 1811 return (ERROR); 1812 } 1813 1814 if (dnum > L_MAXMAJ32) { 1815 (void) fprintf(stderr, gettext(ERR_MAJ_TOOBIG), drv, 1816 dnum, filename, L_MAXMAJ32); 1817 continue; 1818 } 1819 /* 1820 * cast down to a major_t; we can be sure this is safe because 1821 * of the above range-check. 1822 */ 1823 drv_majnum = (major_t)dnum; 1824 1825 if (drv_majnum >= *nelems) { 1826 /* 1827 * Allocate some more space, up to drv_majnum + 1 so 1828 * we can accomodate 0 through drv_majnum. 1829 * 1830 * Note that in the failure case, we leak all of the 1831 * old contents of array. It's ok, since we just 1832 * wind up exiting immediately anyway. 1833 */ 1834 *nelems = drv_majnum + 1; 1835 *array = realloc(*array, *nelems); 1836 if (*array == NULL) { 1837 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1838 return (ERROR); 1839 } 1840 } 1841 (*array)[drv_majnum] = 1; 1842 } 1843 1844 (void) fclose(fp); 1845 return (0); 1846 } 1847 1848 1849 int 1850 do_the_update(char *driver_name, char *major_number) 1851 { 1852 return (append_to_file(driver_name, major_number, name_to_major, 1853 ' ', " ")); 1854 } 1855 1856 /* 1857 * is_blank() returns 1 (true) if a line specified is composed of 1858 * whitespace characters only. otherwise, it returns 0 (false). 1859 * 1860 * Note. the argument (line) must be null-terminated. 1861 */ 1862 static int 1863 is_blank(char *line) 1864 { 1865 for (/* nothing */; *line != '\0'; line++) 1866 if (!isspace(*line)) 1867 return (0); 1868 return (1); 1869 } 1870