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