10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52805Seota * Common Development and Distribution License (the "License"). 62805Seota * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 228831SJerry.Gilliam@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <stdio.h> 270Sstevel@tonic-gate #include <stdlib.h> 282805Seota #include <ctype.h> 290Sstevel@tonic-gate #include <unistd.h> 300Sstevel@tonic-gate #include <sys/sysmacros.h> 310Sstevel@tonic-gate #include <libintl.h> 320Sstevel@tonic-gate #include <wait.h> 330Sstevel@tonic-gate #include <string.h> 348331SJerry.Gilliam@Sun.COM #include <strings.h> 350Sstevel@tonic-gate #include <errno.h> 360Sstevel@tonic-gate #include <fcntl.h> 370Sstevel@tonic-gate #include <signal.h> 380Sstevel@tonic-gate #include <sys/buf.h> 390Sstevel@tonic-gate #include <sys/stat.h> 400Sstevel@tonic-gate #include <grp.h> 410Sstevel@tonic-gate #include "addrem.h" 420Sstevel@tonic-gate #include "errmsg.h" 430Sstevel@tonic-gate #include "plcysubr.h" 440Sstevel@tonic-gate 450Sstevel@tonic-gate static char *add_rem_lock; /* lock file */ 460Sstevel@tonic-gate static char *tmphold; /* temperary file for updating */ 473442Svikram static int add_rem_lock_fd = -1; 480Sstevel@tonic-gate 490Sstevel@tonic-gate static int get_cached_n_to_m_file(char *filename, char ***cache); 500Sstevel@tonic-gate static int get_name_to_major_entry(int *major_no, char *driver_name, 510Sstevel@tonic-gate char *file_name); 520Sstevel@tonic-gate 532805Seota static int is_blank(char *); 542805Seota 550Sstevel@tonic-gate /*ARGSUSED*/ 560Sstevel@tonic-gate void 570Sstevel@tonic-gate log_minorperm_error(minorperm_err_t err, int key) 580Sstevel@tonic-gate { 590Sstevel@tonic-gate switch (err) { 600Sstevel@tonic-gate case MP_FOPEN_ERR: 610Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 628331SJerry.Gilliam@Sun.COM MINOR_PERM_FILE); 630Sstevel@tonic-gate break; 640Sstevel@tonic-gate case MP_FCLOSE_ERR: 650Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 668331SJerry.Gilliam@Sun.COM MINOR_PERM_FILE); 670Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 680Sstevel@tonic-gate break; 690Sstevel@tonic-gate case MP_IGNORING_LINE_ERR: 700Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 718331SJerry.Gilliam@Sun.COM MINOR_PERM_FILE); 720Sstevel@tonic-gate break; 730Sstevel@tonic-gate case MP_ALLOC_ERR: 740Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 758331SJerry.Gilliam@Sun.COM MINOR_PERM_FILE); 760Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 770Sstevel@tonic-gate break; 780Sstevel@tonic-gate case MP_NVLIST_ERR: 790Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 808331SJerry.Gilliam@Sun.COM MINOR_PERM_FILE); 810Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 820Sstevel@tonic-gate break; 830Sstevel@tonic-gate case MP_CANT_FIND_USER_ERR: 840Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 858331SJerry.Gilliam@Sun.COM MINOR_PERM_FILE); 860Sstevel@tonic-gate break; 870Sstevel@tonic-gate case MP_CANT_FIND_GROUP_ERR: 880Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 898331SJerry.Gilliam@Sun.COM MINOR_PERM_FILE); 900Sstevel@tonic-gate break; 910Sstevel@tonic-gate } 920Sstevel@tonic-gate } 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * open file 960Sstevel@tonic-gate * for each entry in list 970Sstevel@tonic-gate * where list entries are separated by <list_separator> 980Sstevel@tonic-gate * append entry : driver_name <entry_separator> entry 990Sstevel@tonic-gate * close file 1000Sstevel@tonic-gate * return error/noerr 1010Sstevel@tonic-gate */ 1020Sstevel@tonic-gate int 1030Sstevel@tonic-gate append_to_file( 1040Sstevel@tonic-gate char *driver_name, 1050Sstevel@tonic-gate char *entry_list, 1060Sstevel@tonic-gate char *filename, 1070Sstevel@tonic-gate char list_separator, 1084145Scth char *entry_separator, 1094145Scth int quoted) 1100Sstevel@tonic-gate { 1110Sstevel@tonic-gate int i, len; 1120Sstevel@tonic-gate int fpint; 1130Sstevel@tonic-gate char *current_head, *previous_head; 1140Sstevel@tonic-gate char *line, *one_entry; 1150Sstevel@tonic-gate FILE *fp; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate if ((fp = fopen(filename, "a")) == NULL) { 1180Sstevel@tonic-gate perror(NULL); 1190Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 1200Sstevel@tonic-gate filename); 1210Sstevel@tonic-gate return (ERROR); 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate len = strlen(entry_list); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate one_entry = calloc(len + 1, 1); 1270Sstevel@tonic-gate if (one_entry == NULL) { 1280Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), filename); 1290Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1300Sstevel@tonic-gate (void) fclose(fp); 1310Sstevel@tonic-gate return (ERROR); 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate previous_head = entry_list; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate line = calloc(strlen(driver_name) + len + 4, 1); 1370Sstevel@tonic-gate if (line == NULL) { 1380Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 1390Sstevel@tonic-gate (void) fclose(fp); 1400Sstevel@tonic-gate err_exit(); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* 1440Sstevel@tonic-gate * get one entry at a time from list and append to <filename> file 1450Sstevel@tonic-gate */ 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate do { 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate for (i = 0; i <= len; i++) 1500Sstevel@tonic-gate one_entry[i] = 0; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate for (i = 0; i <= (int)strlen(line); i++) 1530Sstevel@tonic-gate line[i] = 0; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate current_head = get_entry(previous_head, one_entry, 1564145Scth list_separator, quoted); 1570Sstevel@tonic-gate previous_head = current_head; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate (void) strcpy(line, driver_name); 1600Sstevel@tonic-gate (void) strcat(line, entry_separator); 1614145Scth if (quoted) 1624145Scth (void) strcat(line, "\""); 1630Sstevel@tonic-gate (void) strcat(line, one_entry); 1644145Scth if (quoted) 1654145Scth (void) strcat(line, "\""); 1660Sstevel@tonic-gate (void) strcat(line, "\n"); 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate if ((fputs(line, fp)) == EOF) { 1690Sstevel@tonic-gate perror(NULL); 1700Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 1710Sstevel@tonic-gate filename); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate } while (*current_head != '\0'); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate (void) fflush(fp); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate fpint = fileno(fp); 1800Sstevel@tonic-gate (void) fsync(fpint); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate (void) fclose(fp); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate free(one_entry); 1850Sstevel@tonic-gate free(line); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate return (NOERR); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1908456SJerry.Gilliam@Sun.COM /* 1918456SJerry.Gilliam@Sun.COM * Require exact match to delete a driver alias/permission entry. 1928456SJerry.Gilliam@Sun.COM * Note line argument does not remain unchanged. Return 1 if matched. 1938456SJerry.Gilliam@Sun.COM */ 1948456SJerry.Gilliam@Sun.COM static int 1958456SJerry.Gilliam@Sun.COM match_entry(char *line, char *match) 1968456SJerry.Gilliam@Sun.COM { 1978456SJerry.Gilliam@Sun.COM char *token, *p; 1988456SJerry.Gilliam@Sun.COM int n; 1998456SJerry.Gilliam@Sun.COM 2008456SJerry.Gilliam@Sun.COM /* skip any leading white space */ 2018456SJerry.Gilliam@Sun.COM while (*line && ((*line == ' ') || (*line == '\t'))) 2028456SJerry.Gilliam@Sun.COM line++; 2038456SJerry.Gilliam@Sun.COM /* 2048456SJerry.Gilliam@Sun.COM * Find separator for driver name, either space or colon 2058456SJerry.Gilliam@Sun.COM * minor_perm: <driver>:<perm> 2068456SJerry.Gilliam@Sun.COM * driver_aliases: <driver> <alias> 2078456SJerry.Gilliam@Sun.COM * extra_privs: <driver>:<priv> 2088456SJerry.Gilliam@Sun.COM */ 2098456SJerry.Gilliam@Sun.COM if ((token = strpbrk(line, " :\t")) == NULL) 2108456SJerry.Gilliam@Sun.COM return (0); 2118456SJerry.Gilliam@Sun.COM token++; 2128456SJerry.Gilliam@Sun.COM /* skip leading white space and quotes */ 2138456SJerry.Gilliam@Sun.COM while (*token && (*token == ' ' || *token == '\t' || 2148456SJerry.Gilliam@Sun.COM *token == '"' || *token == '\'')) 2158456SJerry.Gilliam@Sun.COM token++; 2168456SJerry.Gilliam@Sun.COM /* strip trailing newline, white space and quotes */ 2178456SJerry.Gilliam@Sun.COM n = strlen(token); 2188456SJerry.Gilliam@Sun.COM p = token + n-1; 2198456SJerry.Gilliam@Sun.COM while (n > 0 && (*p == '\n' || *p == ' ' || *p == '\t' || 2208456SJerry.Gilliam@Sun.COM *p == '"' || *p == '\'')) { 2218456SJerry.Gilliam@Sun.COM *p-- = 0; 2228456SJerry.Gilliam@Sun.COM n--; 2238456SJerry.Gilliam@Sun.COM } 2248456SJerry.Gilliam@Sun.COM if (n == 0) 2258456SJerry.Gilliam@Sun.COM return (0); 2268456SJerry.Gilliam@Sun.COM return (strcmp(token, match) == 0); 2278456SJerry.Gilliam@Sun.COM } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * open file 2310Sstevel@tonic-gate * read thru file, deleting all entries if first 2320Sstevel@tonic-gate * entry = driver_name 2330Sstevel@tonic-gate * close 2340Sstevel@tonic-gate * if error, leave original file intact with message 2350Sstevel@tonic-gate * assumption : drvconfig has been modified to work with clone 2360Sstevel@tonic-gate * entries in /etc/minor_perm as driver:mummble NOT 2370Sstevel@tonic-gate * clone:driver mummble 2380Sstevel@tonic-gate * this implementation will NOT find clone entries 2390Sstevel@tonic-gate * clone:driver mummble 2400Sstevel@tonic-gate * match: 2410Sstevel@tonic-gate * delete just the matching entry 2420Sstevel@tonic-gate * 2430Sstevel@tonic-gate */ 2440Sstevel@tonic-gate int 2450Sstevel@tonic-gate delete_entry( 2460Sstevel@tonic-gate char *oldfile, 2470Sstevel@tonic-gate char *driver_name, 2480Sstevel@tonic-gate char *marker, 2490Sstevel@tonic-gate char *match) 2500Sstevel@tonic-gate { 2510Sstevel@tonic-gate int rv, i; 2520Sstevel@tonic-gate int status = NOERR; 2530Sstevel@tonic-gate int drvr_found = 0; 2540Sstevel@tonic-gate boolean_t nomatch = B_TRUE; 2558456SJerry.Gilliam@Sun.COM char *newfile, *tptr, *cp; 2560Sstevel@tonic-gate char line[MAX_DBFILE_ENTRY], drv[FILENAME_MAX + 1]; 2570Sstevel@tonic-gate FILE *fp, *newfp; 2580Sstevel@tonic-gate struct group *sysgrp; 2598456SJerry.Gilliam@Sun.COM char *copy; /* same size as line */ 260*9268SJerry.Gilliam@Sun.COM char *match2 = NULL; /* match with quotes cleaned up */ 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 263*9268SJerry.Gilliam@Sun.COM * if match is specified, sanity check it and clean it 264*9268SJerry.Gilliam@Sun.COM * up by removing surrounding quotes as we require 265*9268SJerry.Gilliam@Sun.COM * an exact match. 2660Sstevel@tonic-gate */ 267*9268SJerry.Gilliam@Sun.COM if (match) { 268*9268SJerry.Gilliam@Sun.COM cp = match; 269*9268SJerry.Gilliam@Sun.COM while (*cp && (*cp == '"' || *cp == '\'')) 270*9268SJerry.Gilliam@Sun.COM cp++; 271*9268SJerry.Gilliam@Sun.COM i = strlen(cp); 272*9268SJerry.Gilliam@Sun.COM if (i > 0) { 273*9268SJerry.Gilliam@Sun.COM if ((match2 = strdup(cp)) == NULL) { 274*9268SJerry.Gilliam@Sun.COM perror(NULL); 275*9268SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_NO_MEM)); 276*9268SJerry.Gilliam@Sun.COM return (ERROR); 277*9268SJerry.Gilliam@Sun.COM } 278*9268SJerry.Gilliam@Sun.COM if ((cp = strchr(match2, '\'')) != NULL) 279*9268SJerry.Gilliam@Sun.COM *cp = 0; 280*9268SJerry.Gilliam@Sun.COM if ((cp = strchr(match2, '"')) != NULL) 281*9268SJerry.Gilliam@Sun.COM *cp = 0; 282*9268SJerry.Gilliam@Sun.COM if ((cp = strchr(match2, ' ')) != NULL) 283*9268SJerry.Gilliam@Sun.COM *cp = 0; 284*9268SJerry.Gilliam@Sun.COM } 285*9268SJerry.Gilliam@Sun.COM if (match2 == NULL || (strlen(match2) == 0)) { 286*9268SJerry.Gilliam@Sun.COM (void) fprintf(stderr, 287*9268SJerry.Gilliam@Sun.COM gettext(ERR_INT_UPDATE), oldfile); 288*9268SJerry.Gilliam@Sun.COM return (ERROR); 289*9268SJerry.Gilliam@Sun.COM } 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate if ((fp = fopen(oldfile, "r")) == NULL) { 2930Sstevel@tonic-gate perror(NULL); 2940Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile); 2950Sstevel@tonic-gate return (ERROR); 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2988456SJerry.Gilliam@Sun.COM /* Space for defensive copy of input line */ 2998456SJerry.Gilliam@Sun.COM copy = calloc(sizeof (line), 1); 3000Sstevel@tonic-gate 3018456SJerry.Gilliam@Sun.COM /* Build filename for temporary file */ 3028456SJerry.Gilliam@Sun.COM tptr = calloc(strlen(oldfile) + strlen(XEND) + 1, 1); 3038456SJerry.Gilliam@Sun.COM if (tptr == NULL || copy == NULL) { 3040Sstevel@tonic-gate perror(NULL); 3050Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 3068456SJerry.Gilliam@Sun.COM return (ERROR); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate (void) strcpy(tptr, oldfile); 3100Sstevel@tonic-gate (void) strcat(tptr, XEND); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate /* 3130Sstevel@tonic-gate * Set gid so we preserve group attribute. Ideally we wouldn't 3140Sstevel@tonic-gate * assume a gid of "sys" but we can't undo the damage on already 3150Sstevel@tonic-gate * installed systems unless we force the issue. 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate if ((sysgrp = getgrnam("sys")) != NULL) { 3180Sstevel@tonic-gate (void) setgid(sysgrp->gr_gid); 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate newfile = mktemp(tptr); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if ((newfp = fopen(newfile, "w")) == NULL) { 3240Sstevel@tonic-gate perror(NULL); 3250Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 3260Sstevel@tonic-gate newfile); 3270Sstevel@tonic-gate return (ERROR); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) { 3318456SJerry.Gilliam@Sun.COM /* copy the whole line */ 3328456SJerry.Gilliam@Sun.COM if (strlcpy(copy, line, sizeof (line)) >= sizeof (line)) { 3338456SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_UPDATE), oldfile); 3342805Seota status = ERROR; 3352805Seota break; 3362805Seota } 3372805Seota /* cut off comments starting with '#' */ 3388456SJerry.Gilliam@Sun.COM if ((cp = strchr(copy, '#')) != NULL) 3392805Seota *cp = '\0'; 3402805Seota /* ignore comment or blank lines */ 3418456SJerry.Gilliam@Sun.COM if (is_blank(copy)) { 3422805Seota if (fputs(line, newfp) == EOF) { 3430Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), 3440Sstevel@tonic-gate oldfile); 3450Sstevel@tonic-gate status = ERROR; 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate continue; 3480Sstevel@tonic-gate } 3492805Seota 3502805Seota /* get the driver name */ 351*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 3528456SJerry.Gilliam@Sun.COM if (sscanf(copy, "%s", drv) != 1) { 3530Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINE), 3540Sstevel@tonic-gate oldfile, line); 3550Sstevel@tonic-gate status = ERROR; 3562805Seota break; 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) { 3600Sstevel@tonic-gate drv[i] = '\0'; 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate if (strcmp(driver_name, drv) != 0) { 3640Sstevel@tonic-gate if ((fputs(line, newfp)) == EOF) { 3650Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), 3660Sstevel@tonic-gate oldfile); 3670Sstevel@tonic-gate status = ERROR; 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate } else { 3700Sstevel@tonic-gate drvr_found++; 371*9268SJerry.Gilliam@Sun.COM if (match2) { /* Just delete one entry */ 3720Sstevel@tonic-gate /* for now delete just minor_perm and aliases */ 3730Sstevel@tonic-gate if ((strcmp(oldfile, minor_perm) == 0) || 3740Sstevel@tonic-gate (strcmp(oldfile, extra_privs) == 0) || 3750Sstevel@tonic-gate (strcmp(oldfile, driver_aliases) == 0)) { 3768456SJerry.Gilliam@Sun.COM 3778456SJerry.Gilliam@Sun.COM /* make defensive copy */ 3788456SJerry.Gilliam@Sun.COM if (strlcpy(copy, line, sizeof (line)) 3798456SJerry.Gilliam@Sun.COM >= sizeof (line)) { 3808456SJerry.Gilliam@Sun.COM (void) fprintf(stderr, 3818456SJerry.Gilliam@Sun.COM gettext(ERR_UPDATE), 3828456SJerry.Gilliam@Sun.COM oldfile); 3838456SJerry.Gilliam@Sun.COM status = ERROR; 3848456SJerry.Gilliam@Sun.COM break; 3858456SJerry.Gilliam@Sun.COM } 386*9268SJerry.Gilliam@Sun.COM if (match_entry(copy, match2)) { 3870Sstevel@tonic-gate nomatch = B_FALSE; 3880Sstevel@tonic-gate } else { 3890Sstevel@tonic-gate if ((fputs(line, newfp)) == 3900Sstevel@tonic-gate EOF) { 3910Sstevel@tonic-gate (void) fprintf(stderr, 3920Sstevel@tonic-gate gettext(ERR_UPDATE), 3930Sstevel@tonic-gate oldfile); 3940Sstevel@tonic-gate status = ERROR; 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate if (nomatch != B_FALSE) 3970Sstevel@tonic-gate nomatch = B_TRUE; 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate } /* end of else */ 4030Sstevel@tonic-gate } /* end of while */ 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate (void) fclose(fp); 4068456SJerry.Gilliam@Sun.COM free(tptr); 4078456SJerry.Gilliam@Sun.COM free(copy); 408*9268SJerry.Gilliam@Sun.COM if (match2) 409*9268SJerry.Gilliam@Sun.COM free(match2); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* Make sure that the file is on disk */ 4120Sstevel@tonic-gate if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0) 4130Sstevel@tonic-gate status = ERROR; 4140Sstevel@tonic-gate else 4150Sstevel@tonic-gate rv = NOERR; 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate (void) fclose(newfp); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* no matching driver found */ 4200Sstevel@tonic-gate rv = NOERR; 4210Sstevel@tonic-gate if (!drvr_found || 4220Sstevel@tonic-gate (nomatch == B_TRUE)) { 4230Sstevel@tonic-gate rv = NONE_FOUND; 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate /* 4270Sstevel@tonic-gate * if error, leave original file, delete new file 4280Sstevel@tonic-gate * if noerr, replace original file with new file 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate if (status == NOERR) { 4320Sstevel@tonic-gate if (rename(oldfile, tmphold) == -1) { 4330Sstevel@tonic-gate perror(NULL); 4340Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), oldfile); 4350Sstevel@tonic-gate (void) unlink(newfile); 4360Sstevel@tonic-gate return (ERROR); 4370Sstevel@tonic-gate } else if (rename(newfile, oldfile) == -1) { 4380Sstevel@tonic-gate perror(NULL); 4390Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), oldfile); 4400Sstevel@tonic-gate (void) unlink(oldfile); 4410Sstevel@tonic-gate (void) unlink(newfile); 4420Sstevel@tonic-gate if (link(tmphold, oldfile) == -1) { 4430Sstevel@tonic-gate perror(NULL); 4440Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINK), 4450Sstevel@tonic-gate oldfile, tmphold); 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate return (ERROR); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate (void) unlink(tmphold); 4500Sstevel@tonic-gate } else { 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * since there's an error, leave file alone; remove 4530Sstevel@tonic-gate * new file 4540Sstevel@tonic-gate */ 4550Sstevel@tonic-gate if (unlink(newfile) == -1) { 4560Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_RM), newfile); 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate return (ERROR); 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate return (rv); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* 4660Sstevel@tonic-gate * wrapper for call to get_name_to_major_entry(): given driver name, 4670Sstevel@tonic-gate * retrieve major number. 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate int 4700Sstevel@tonic-gate get_major_no(char *driver_name, char *file_name) 4710Sstevel@tonic-gate { 4720Sstevel@tonic-gate int major = UNIQUE; 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate if (get_name_to_major_entry(&major, driver_name, file_name) == ERROR) 4750Sstevel@tonic-gate return (ERROR); 4760Sstevel@tonic-gate else 4770Sstevel@tonic-gate return (major); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * wrapper for call to get_name_to_major_entry(): given major number, 4820Sstevel@tonic-gate * retrieve driver name. 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate int 4850Sstevel@tonic-gate get_driver_name(int major, char *file_name, char *buf) 4860Sstevel@tonic-gate { 4870Sstevel@tonic-gate if (major < 0) 4880Sstevel@tonic-gate return (ERROR); 4890Sstevel@tonic-gate return (get_name_to_major_entry(&major, buf, file_name)); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * return pointer to cached name_to_major file - reads file into 4950Sstevel@tonic-gate * cache if this has not already been done. Since there may be 4960Sstevel@tonic-gate * requests for multiple name_to_major files (rem_name_to_major, 4970Sstevel@tonic-gate * name_to_major), this routine keeps a list of cached files. 4980Sstevel@tonic-gate */ 4990Sstevel@tonic-gate static int 5000Sstevel@tonic-gate get_cached_n_to_m_file(char *filename, char ***cache) 5010Sstevel@tonic-gate { 5020Sstevel@tonic-gate struct n_to_m_cache { 5030Sstevel@tonic-gate char *file; 5040Sstevel@tonic-gate char **cached_file; 5050Sstevel@tonic-gate int size; 5060Sstevel@tonic-gate struct n_to_m_cache *next; 5070Sstevel@tonic-gate }; 5080Sstevel@tonic-gate static struct n_to_m_cache *head = NULL; 5090Sstevel@tonic-gate struct n_to_m_cache *ptr; 5100Sstevel@tonic-gate FILE *fp; 5110Sstevel@tonic-gate char drv[FILENAME_MAX + 1]; 5120Sstevel@tonic-gate char entry[FILENAME_MAX + 1]; 5132805Seota char line[MAX_N2M_ALIAS_LINE], *cp; 5140Sstevel@tonic-gate int maj; 5150Sstevel@tonic-gate int size = 0; 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * see if the file is already cached - either 5200Sstevel@tonic-gate * rem_name_to_major or name_to_major 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate ptr = head; 5230Sstevel@tonic-gate while (ptr != NULL) { 5240Sstevel@tonic-gate if (strcmp(ptr->file, filename) == 0) 5250Sstevel@tonic-gate break; 5260Sstevel@tonic-gate ptr = ptr->next; 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate if (ptr == NULL) { /* we need to cache the contents */ 5300Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 5310Sstevel@tonic-gate perror(NULL); 5320Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_OPEN), 5330Sstevel@tonic-gate filename); 5340Sstevel@tonic-gate return (ERROR); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != NULL) { 5382805Seota /* cut off comments starting with '#' */ 5392805Seota if ((cp = strchr(line, '#')) != NULL) 5402805Seota *cp = '\0'; 5412805Seota /* ignore comment or blank lines */ 5422805Seota if (is_blank(line)) 5432805Seota continue; 5442805Seota /* sanity-check */ 545*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 5460Sstevel@tonic-gate if (sscanf(line, "%s%s", drv, entry) != 2) { 5470Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINE), 5480Sstevel@tonic-gate filename, line); 5490Sstevel@tonic-gate continue; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate maj = atoi(entry); 5520Sstevel@tonic-gate if (maj > size) 5530Sstevel@tonic-gate size = maj; 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate /* allocate struct to cache the file */ 5570Sstevel@tonic-gate ptr = (struct n_to_m_cache *)calloc(1, 5580Sstevel@tonic-gate sizeof (struct n_to_m_cache)); 5590Sstevel@tonic-gate if (ptr == NULL) { 5600Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 5610Sstevel@tonic-gate return (ERROR); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate ptr->size = size + 1; 5640Sstevel@tonic-gate /* allocate space to cache contents of file */ 5650Sstevel@tonic-gate ptr->cached_file = (char **)calloc(ptr->size, sizeof (char *)); 5660Sstevel@tonic-gate if (ptr->cached_file == NULL) { 5670Sstevel@tonic-gate free(ptr); 5680Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 5690Sstevel@tonic-gate return (ERROR); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate rewind(fp); 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate /* 5750Sstevel@tonic-gate * now fill the cache 5760Sstevel@tonic-gate * the cache is an array of char pointers indexed by major 5770Sstevel@tonic-gate * number 5780Sstevel@tonic-gate */ 5790Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != NULL) { 5802805Seota /* cut off comments starting with '#' */ 5812805Seota if ((cp = strchr(line, '#')) != NULL) 5822805Seota *cp = '\0'; 5832805Seota /* ignore comment or blank lines */ 5842805Seota if (is_blank(line)) 5852805Seota continue; 5862805Seota /* sanity-check */ 587*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 5880Sstevel@tonic-gate if (sscanf(line, "%s%s", drv, entry) != 2) { 5890Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINE), 5900Sstevel@tonic-gate filename, line); 5910Sstevel@tonic-gate continue; 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate maj = atoi(entry); 5940Sstevel@tonic-gate if ((ptr->cached_file[maj] = strdup(drv)) == NULL) { 5950Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 5960Sstevel@tonic-gate free(ptr->cached_file); 5970Sstevel@tonic-gate free(ptr); 5980Sstevel@tonic-gate return (ERROR); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate (void) strcpy(ptr->cached_file[maj], drv); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate (void) fclose(fp); 6030Sstevel@tonic-gate /* link the cache struct into the list of cached files */ 6040Sstevel@tonic-gate ptr->file = strdup(filename); 6050Sstevel@tonic-gate if (ptr->file == NULL) { 6060Sstevel@tonic-gate for (maj = 0; maj <= ptr->size; maj++) 6070Sstevel@tonic-gate free(ptr->cached_file[maj]); 6080Sstevel@tonic-gate free(ptr->cached_file); 6090Sstevel@tonic-gate free(ptr); 6100Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 6110Sstevel@tonic-gate return (ERROR); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate ptr->next = head; 6140Sstevel@tonic-gate head = ptr; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate /* return value pointer to contents of file */ 6170Sstevel@tonic-gate *cache = ptr->cached_file; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate /* return size */ 6200Sstevel@tonic-gate return (ptr->size); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* 6250Sstevel@tonic-gate * Using get_cached_n_to_m_file(), retrieve maximum major number 6260Sstevel@tonic-gate * found in the specificed file (name_to_major/rem_name_to_major). 6270Sstevel@tonic-gate * 6280Sstevel@tonic-gate * The return value is actually the size of the internal cache including 0. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate int 6310Sstevel@tonic-gate get_max_major(char *file_name) 6320Sstevel@tonic-gate { 6330Sstevel@tonic-gate char **n_to_m_cache = NULL; 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate return (get_cached_n_to_m_file(file_name, &n_to_m_cache)); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* 6400Sstevel@tonic-gate * searching name_to_major: if major_no == UNIQUE then the caller wants to 6410Sstevel@tonic-gate * use the driver name as the key. Otherwise, the caller wants to use 6420Sstevel@tonic-gate * the major number as a key. 6430Sstevel@tonic-gate * 6440Sstevel@tonic-gate * This routine caches the contents of the name_to_major file on 6450Sstevel@tonic-gate * first call. And it could be generalized to deal with other 6460Sstevel@tonic-gate * config files if necessary. 6470Sstevel@tonic-gate */ 6480Sstevel@tonic-gate static int 6490Sstevel@tonic-gate get_name_to_major_entry(int *major_no, char *driver_name, char *file_name) 6500Sstevel@tonic-gate { 6510Sstevel@tonic-gate int maj; 6520Sstevel@tonic-gate char **n_to_m_cache = NULL; 6530Sstevel@tonic-gate int size = 0; 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate int ret = NOT_UNIQUE; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate /* 6580Sstevel@tonic-gate * read the file in - we cache it in case caller wants to 6590Sstevel@tonic-gate * do multiple lookups 6600Sstevel@tonic-gate */ 6610Sstevel@tonic-gate size = get_cached_n_to_m_file(file_name, &n_to_m_cache); 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate if (size == ERROR) 6640Sstevel@tonic-gate return (ERROR); 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate /* search with driver name as key */ 6670Sstevel@tonic-gate if (*major_no == UNIQUE) { 6680Sstevel@tonic-gate for (maj = 0; maj < size; maj++) { 6690Sstevel@tonic-gate if ((n_to_m_cache[maj] != NULL) && 6700Sstevel@tonic-gate (strcmp(driver_name, n_to_m_cache[maj]) == 0)) { 6710Sstevel@tonic-gate *major_no = maj; 6720Sstevel@tonic-gate break; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate if (maj >= size) 6760Sstevel@tonic-gate ret = UNIQUE; 6770Sstevel@tonic-gate /* search with major number as key */ 6780Sstevel@tonic-gate } else { 6790Sstevel@tonic-gate /* 6800Sstevel@tonic-gate * Bugid 1254588, drvconfig dump core after loading driver 6810Sstevel@tonic-gate * with major number bigger than entries defined in 6820Sstevel@tonic-gate * /etc/name_to_major. 6830Sstevel@tonic-gate */ 6840Sstevel@tonic-gate if (*major_no >= size) 6850Sstevel@tonic-gate return (UNIQUE); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate if (n_to_m_cache[*major_no] != NULL) { 6880Sstevel@tonic-gate (void) strcpy(driver_name, n_to_m_cache[*major_no]); 6890Sstevel@tonic-gate } else 6900Sstevel@tonic-gate ret = UNIQUE; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate return (ret); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate /* 6964145Scth * Given pointer to begining of member 'n' in a space (or separator) 6974145Scth * separated list, return pointer to member 'n+1', and establish member 'n' 6984145Scth * in *current_entry. If unquote, then we skip a leading quote and treat 6994145Scth * the trailing quote as a separator (and skip). 7000Sstevel@tonic-gate */ 7010Sstevel@tonic-gate char * 7020Sstevel@tonic-gate get_entry( 7030Sstevel@tonic-gate char *prev_member, 7040Sstevel@tonic-gate char *current_entry, 7054145Scth char separator, 7064145Scth int unquote) 7070Sstevel@tonic-gate { 7084145Scth char *ptr; 7094145Scth int quoted = 0; 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate ptr = prev_member; 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* skip white space */ 7140Sstevel@tonic-gate while (*ptr == '\t' || *ptr == ' ') 7150Sstevel@tonic-gate ptr++; 7160Sstevel@tonic-gate 7174145Scth /* if unquote skip leading quote */ 7184145Scth if (unquote && *ptr == '"') { 7194145Scth quoted++; 7204145Scth ptr++; 7214145Scth } 7224145Scth 7234145Scth /* read thru the current entry looking for end, separator, or unquote */ 7244145Scth while (*ptr && 7254145Scth (*ptr != separator) && 7264145Scth ((separator != ' ') || (*ptr != '\t')) && 7274145Scth (!quoted || (*ptr != '"'))) { 7280Sstevel@tonic-gate *current_entry++ = *ptr++; 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate *current_entry = '\0'; 7310Sstevel@tonic-gate 7324145Scth if (separator && (*ptr == separator)) 7334145Scth ptr++; /* skip over separator */ 7344145Scth if (quoted && (*ptr == '"')) 7354145Scth ptr++; /* skip over trailing quote */ 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate /* skip white space */ 7380Sstevel@tonic-gate while (*ptr == '\t' || *ptr == ' ') { 7390Sstevel@tonic-gate ptr++; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate return (ptr); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate void 7460Sstevel@tonic-gate enter_lock(void) 7470Sstevel@tonic-gate { 7483442Svikram struct flock lock; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate /* 7510Sstevel@tonic-gate * attempt to create the lock file 7520Sstevel@tonic-gate */ 7533442Svikram add_rem_lock_fd = open(add_rem_lock, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); 7543442Svikram if (add_rem_lock_fd < 0) { 7553442Svikram (void) fprintf(stderr, gettext(ERR_CREAT_LOCK), 7563442Svikram add_rem_lock, strerror(errno)); 7573442Svikram exit(1); 7583442Svikram } 7593442Svikram 7603442Svikram lock.l_type = F_WRLCK; 7613442Svikram lock.l_whence = SEEK_SET; 7623442Svikram lock.l_start = 0; 7633442Svikram lock.l_len = 0; 7643442Svikram 7653442Svikram /* Try for the lock but don't wait. */ 7663442Svikram if (fcntl(add_rem_lock_fd, F_SETLK, &lock) == -1) { 7673442Svikram if (errno == EACCES || errno == EAGAIN) { 7680Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_PROG_IN_USE)); 7690Sstevel@tonic-gate } else { 7703442Svikram (void) fprintf(stderr, gettext(ERR_LOCK), 7713442Svikram add_rem_lock, strerror(errno)); 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate exit(1); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate void 7780Sstevel@tonic-gate err_exit(void) 7790Sstevel@tonic-gate { 7800Sstevel@tonic-gate /* release memory allocated for moddir */ 7810Sstevel@tonic-gate cleanup_moddir(); 7820Sstevel@tonic-gate /* remove add_drv/rem_drv lock */ 7830Sstevel@tonic-gate exit_unlock(); 7840Sstevel@tonic-gate exit(1); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate void 7880Sstevel@tonic-gate cleanup_moddir(void) 7890Sstevel@tonic-gate { 7900Sstevel@tonic-gate struct drvmod_dir *walk_ptr; 7910Sstevel@tonic-gate struct drvmod_dir *free_ptr = moddir; 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate while (free_ptr != NULL) { 7940Sstevel@tonic-gate walk_ptr = free_ptr->next; 7950Sstevel@tonic-gate free(free_ptr); 7960Sstevel@tonic-gate free_ptr = walk_ptr; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate void 8010Sstevel@tonic-gate exit_unlock(void) 8020Sstevel@tonic-gate { 8033442Svikram struct flock unlock; 8043442Svikram 8053442Svikram if (add_rem_lock_fd < 0) 8063442Svikram return; 8070Sstevel@tonic-gate 8083442Svikram unlock.l_type = F_UNLCK; 8093442Svikram unlock.l_whence = SEEK_SET; 8103442Svikram unlock.l_start = 0; 8113442Svikram unlock.l_len = 0; 8123442Svikram 8133442Svikram if (fcntl(add_rem_lock_fd, F_SETLK, &unlock) == -1) { 8143442Svikram (void) fprintf(stderr, gettext(ERR_UNLOCK), 8153442Svikram add_rem_lock, strerror(errno)); 8163442Svikram } else { 8173442Svikram (void) close(add_rem_lock_fd); 8183442Svikram add_rem_lock_fd = -1; 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * error adding driver; need to back out any changes to files. 8240Sstevel@tonic-gate * check flag to see which files need entries removed 8250Sstevel@tonic-gate * entry removal based on driver name 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate void 8280Sstevel@tonic-gate remove_entry( 8290Sstevel@tonic-gate int c_flag, 8300Sstevel@tonic-gate char *driver_name) 8310Sstevel@tonic-gate { 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate if (c_flag & CLEAN_NAM_MAJ) { 8340Sstevel@tonic-gate if (delete_entry(name_to_major, driver_name, " ", 8350Sstevel@tonic-gate NULL) == ERROR) { 8360Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_CLEAN), 8370Sstevel@tonic-gate name_to_major, driver_name); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate if (c_flag & CLEAN_DRV_ALIAS) { 8420Sstevel@tonic-gate if (delete_entry(driver_aliases, driver_name, " ", 8430Sstevel@tonic-gate NULL) == ERROR) { 8440Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 8450Sstevel@tonic-gate driver_name, driver_aliases); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate if (c_flag & CLEAN_DRV_CLASSES) { 8500Sstevel@tonic-gate if (delete_entry(driver_classes, driver_name, "\t", NULL) == 8510Sstevel@tonic-gate ERROR) { 8520Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 8530Sstevel@tonic-gate driver_name, driver_classes); 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate if (c_flag & CLEAN_MINOR_PERM) { 8580Sstevel@tonic-gate if (delete_entry(minor_perm, driver_name, ":", NULL) == ERROR) { 8590Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 8600Sstevel@tonic-gate driver_name, minor_perm); 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate /* 8640Sstevel@tonic-gate * There's no point in removing entries from files that don't 8650Sstevel@tonic-gate * exist. Prevent error messages by checking for file existence 8660Sstevel@tonic-gate * first. 8670Sstevel@tonic-gate */ 8680Sstevel@tonic-gate if ((c_flag & CLEAN_DEV_POLICY) != 0 && 8690Sstevel@tonic-gate access(device_policy, F_OK) == 0) { 8700Sstevel@tonic-gate if (delete_plcy_entry(device_policy, driver_name) == ERROR) { 8710Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 8728331SJerry.Gilliam@Sun.COM driver_name, device_policy); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate if ((c_flag & CLEAN_DRV_PRIV) != 0 && 8760Sstevel@tonic-gate access(extra_privs, F_OK) == 0) { 8770Sstevel@tonic-gate if (delete_entry(extra_privs, driver_name, ":", NULL) == 8780Sstevel@tonic-gate ERROR) { 8790Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DEL_ENTRY), 8808331SJerry.Gilliam@Sun.COM driver_name, extra_privs); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate int 8860Sstevel@tonic-gate check_perms_aliases( 8870Sstevel@tonic-gate int m_flag, 8880Sstevel@tonic-gate int i_flag) 8890Sstevel@tonic-gate { 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * If neither i_flag nor m_flag are specified no need to check the 8920Sstevel@tonic-gate * files for access permissions 8930Sstevel@tonic-gate */ 8940Sstevel@tonic-gate if (!m_flag && !i_flag) 8950Sstevel@tonic-gate return (NOERR); 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate /* check minor_perm file : exits and is writable */ 8980Sstevel@tonic-gate if (m_flag) { 8990Sstevel@tonic-gate if (access(minor_perm, R_OK | W_OK)) { 9000Sstevel@tonic-gate perror(NULL); 9010Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 9020Sstevel@tonic-gate minor_perm); 9030Sstevel@tonic-gate return (ERROR); 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate /* check driver_aliases file : exits and is writable */ 9080Sstevel@tonic-gate if (i_flag) { 9090Sstevel@tonic-gate if (access(driver_aliases, R_OK | W_OK)) { 9100Sstevel@tonic-gate perror(NULL); 9110Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 9120Sstevel@tonic-gate driver_aliases); 9130Sstevel@tonic-gate return (ERROR); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate return (NOERR); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate int 9220Sstevel@tonic-gate check_name_to_major(int mode) 9230Sstevel@tonic-gate { 9240Sstevel@tonic-gate /* check name_to_major file : exists and is writable */ 9250Sstevel@tonic-gate if (access(name_to_major, mode)) { 9260Sstevel@tonic-gate perror(NULL); 9270Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 9280Sstevel@tonic-gate name_to_major); 9290Sstevel@tonic-gate return (ERROR); 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate return (NOERR); 9330Sstevel@tonic-gate } 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate /* 9370Sstevel@tonic-gate * All this stuff is to support a server installing 9380Sstevel@tonic-gate * drivers on diskless clients. When on the server 9390Sstevel@tonic-gate * need to prepend the basedir 9400Sstevel@tonic-gate */ 9410Sstevel@tonic-gate int 9420Sstevel@tonic-gate build_filenames(char *basedir) 9430Sstevel@tonic-gate { 944*9268SJerry.Gilliam@Sun.COM int len; 945*9268SJerry.Gilliam@Sun.COM int driver_aliases_len; 946*9268SJerry.Gilliam@Sun.COM int driver_classes_len; 947*9268SJerry.Gilliam@Sun.COM int minor_perm_len; 948*9268SJerry.Gilliam@Sun.COM int name_to_major_len; 949*9268SJerry.Gilliam@Sun.COM int rem_name_to_major_len; 950*9268SJerry.Gilliam@Sun.COM int add_rem_lock_len; 951*9268SJerry.Gilliam@Sun.COM int tmphold_len; 952*9268SJerry.Gilliam@Sun.COM int devfs_root_len; 953*9268SJerry.Gilliam@Sun.COM int device_policy_len; 954*9268SJerry.Gilliam@Sun.COM int extra_privs_len; 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate if (basedir == NULL) { 9570Sstevel@tonic-gate driver_aliases = DRIVER_ALIAS; 9580Sstevel@tonic-gate driver_classes = DRIVER_CLASSES; 9590Sstevel@tonic-gate minor_perm = MINOR_PERM; 9600Sstevel@tonic-gate name_to_major = NAM_TO_MAJ; 9610Sstevel@tonic-gate rem_name_to_major = REM_NAM_TO_MAJ; 9620Sstevel@tonic-gate add_rem_lock = ADD_REM_LOCK; 9630Sstevel@tonic-gate tmphold = TMPHOLD; 9640Sstevel@tonic-gate devfs_root = DEVFS_ROOT; 9650Sstevel@tonic-gate device_policy = DEV_POLICY; 9660Sstevel@tonic-gate extra_privs = EXTRA_PRIVS; 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate } else { 969*9268SJerry.Gilliam@Sun.COM len = strlen(basedir) + 1; 9700Sstevel@tonic-gate 971*9268SJerry.Gilliam@Sun.COM driver_aliases_len = len + sizeof (DRIVER_ALIAS); 972*9268SJerry.Gilliam@Sun.COM driver_classes_len = len + sizeof (DRIVER_CLASSES); 973*9268SJerry.Gilliam@Sun.COM minor_perm_len = len + sizeof (MINOR_PERM); 974*9268SJerry.Gilliam@Sun.COM name_to_major_len = len + sizeof (NAM_TO_MAJ); 975*9268SJerry.Gilliam@Sun.COM rem_name_to_major_len = len + sizeof (REM_NAM_TO_MAJ); 976*9268SJerry.Gilliam@Sun.COM add_rem_lock_len = len + sizeof (ADD_REM_LOCK); 977*9268SJerry.Gilliam@Sun.COM tmphold_len = len + sizeof (TMPHOLD); 978*9268SJerry.Gilliam@Sun.COM devfs_root_len = len + sizeof (DEVFS_ROOT); 979*9268SJerry.Gilliam@Sun.COM device_policy_len = len + sizeof (DEV_POLICY); 980*9268SJerry.Gilliam@Sun.COM extra_privs_len = len + sizeof (EXTRA_PRIVS); 9810Sstevel@tonic-gate 982*9268SJerry.Gilliam@Sun.COM driver_aliases = malloc(driver_aliases_len); 983*9268SJerry.Gilliam@Sun.COM driver_classes = malloc(driver_classes_len); 984*9268SJerry.Gilliam@Sun.COM minor_perm = malloc(minor_perm_len); 985*9268SJerry.Gilliam@Sun.COM name_to_major = malloc(name_to_major_len); 986*9268SJerry.Gilliam@Sun.COM rem_name_to_major = malloc(rem_name_to_major_len); 987*9268SJerry.Gilliam@Sun.COM add_rem_lock = malloc(add_rem_lock_len); 988*9268SJerry.Gilliam@Sun.COM tmphold = malloc(tmphold_len); 989*9268SJerry.Gilliam@Sun.COM devfs_root = malloc(devfs_root_len); 990*9268SJerry.Gilliam@Sun.COM device_policy = malloc(device_policy_len); 991*9268SJerry.Gilliam@Sun.COM extra_privs = malloc(extra_privs_len); 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate if ((driver_aliases == NULL) || 9940Sstevel@tonic-gate (driver_classes == NULL) || 9950Sstevel@tonic-gate (minor_perm == NULL) || 9960Sstevel@tonic-gate (name_to_major == NULL) || 9970Sstevel@tonic-gate (rem_name_to_major == NULL) || 9980Sstevel@tonic-gate (add_rem_lock == NULL) || 9990Sstevel@tonic-gate (tmphold == NULL) || 10000Sstevel@tonic-gate (devfs_root == NULL) || 10010Sstevel@tonic-gate (device_policy == NULL) || 10020Sstevel@tonic-gate (extra_privs == NULL)) { 10030Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 10040Sstevel@tonic-gate return (ERROR); 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate 1007*9268SJerry.Gilliam@Sun.COM (void) snprintf(driver_aliases, driver_aliases_len, 1008*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, DRIVER_ALIAS); 1009*9268SJerry.Gilliam@Sun.COM (void) snprintf(driver_classes, driver_classes_len, 1010*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, DRIVER_CLASSES); 1011*9268SJerry.Gilliam@Sun.COM (void) snprintf(minor_perm, minor_perm_len, 1012*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, MINOR_PERM); 1013*9268SJerry.Gilliam@Sun.COM (void) snprintf(name_to_major, name_to_major_len, 1014*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, NAM_TO_MAJ); 1015*9268SJerry.Gilliam@Sun.COM (void) snprintf(rem_name_to_major, rem_name_to_major_len, 1016*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, REM_NAM_TO_MAJ); 1017*9268SJerry.Gilliam@Sun.COM (void) snprintf(add_rem_lock, add_rem_lock_len, 1018*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, ADD_REM_LOCK); 1019*9268SJerry.Gilliam@Sun.COM (void) snprintf(tmphold, tmphold_len, 1020*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, TMPHOLD); 1021*9268SJerry.Gilliam@Sun.COM (void) snprintf(devfs_root, devfs_root_len, 1022*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, DEVFS_ROOT); 1023*9268SJerry.Gilliam@Sun.COM (void) snprintf(device_policy, device_policy_len, 1024*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, DEV_POLICY); 1025*9268SJerry.Gilliam@Sun.COM (void) snprintf(extra_privs, extra_privs_len, 1026*9268SJerry.Gilliam@Sun.COM "%s%s", basedir, EXTRA_PRIVS); 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate return (NOERR); 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate static int 10330Sstevel@tonic-gate exec_command(char *path, char *cmdline[MAX_CMD_LINE]) 10340Sstevel@tonic-gate { 10350Sstevel@tonic-gate pid_t pid; 10360Sstevel@tonic-gate uint_t stat_loc; 10370Sstevel@tonic-gate int waitstat; 10380Sstevel@tonic-gate int exit_status; 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate /* child */ 10410Sstevel@tonic-gate if ((pid = fork()) == 0) { 10420Sstevel@tonic-gate (void) execv(path, cmdline); 10430Sstevel@tonic-gate perror(NULL); 10440Sstevel@tonic-gate return (ERROR); 10450Sstevel@tonic-gate } else if (pid == -1) { 10460Sstevel@tonic-gate /* fork failed */ 10470Sstevel@tonic-gate perror(NULL); 10480Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_FORK_FAIL), cmdline); 10490Sstevel@tonic-gate return (ERROR); 10500Sstevel@tonic-gate } else { 10510Sstevel@tonic-gate /* parent */ 10520Sstevel@tonic-gate do { 10530Sstevel@tonic-gate waitstat = waitpid(pid, (int *)&stat_loc, 0); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate } while ((!WIFEXITED(stat_loc) && 10568331SJerry.Gilliam@Sun.COM !WIFSIGNALED(stat_loc)) || (waitstat == 0)); 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate exit_status = WEXITSTATUS(stat_loc); 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate return (exit_status); 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate } 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate /* 10658831SJerry.Gilliam@Sun.COM * Exec devfsadm to perform driver config/unconfig operation, 10668831SJerry.Gilliam@Sun.COM * adding or removing aliases. 10670Sstevel@tonic-gate */ 10688831SJerry.Gilliam@Sun.COM static int 10698831SJerry.Gilliam@Sun.COM exec_devfsadm( 10708831SJerry.Gilliam@Sun.COM boolean_t config, 10710Sstevel@tonic-gate char *driver_name, 10720Sstevel@tonic-gate major_t major_num, 10730Sstevel@tonic-gate char *aliases, 10740Sstevel@tonic-gate char *classes, 10758831SJerry.Gilliam@Sun.COM int verbose_flag, 10768831SJerry.Gilliam@Sun.COM int force_flag) 10770Sstevel@tonic-gate { 10780Sstevel@tonic-gate int n = 0; 10790Sstevel@tonic-gate char *cmdline[MAX_CMD_LINE]; 10800Sstevel@tonic-gate char maj_num[128]; 10810Sstevel@tonic-gate char *previous; 10820Sstevel@tonic-gate char *current; 10830Sstevel@tonic-gate int len; 10848831SJerry.Gilliam@Sun.COM int rv; 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /* build command line */ 10870Sstevel@tonic-gate cmdline[n++] = DRVCONFIG; 10888831SJerry.Gilliam@Sun.COM if (config == B_FALSE) { 10898831SJerry.Gilliam@Sun.COM cmdline[n++] = "-u"; /* unconfigure */ 10908831SJerry.Gilliam@Sun.COM if (force_flag) 10918831SJerry.Gilliam@Sun.COM cmdline[n++] = "-f"; /* force if currently in use */ 10928831SJerry.Gilliam@Sun.COM } 10930Sstevel@tonic-gate if (verbose_flag) { 10940Sstevel@tonic-gate cmdline[n++] = "-v"; 10950Sstevel@tonic-gate } 10960Sstevel@tonic-gate cmdline[n++] = "-b"; 10970Sstevel@tonic-gate if (classes) { 10980Sstevel@tonic-gate cmdline[n++] = "-c"; 10990Sstevel@tonic-gate cmdline[n++] = classes; 11000Sstevel@tonic-gate } 11010Sstevel@tonic-gate cmdline[n++] = "-i"; 11020Sstevel@tonic-gate cmdline[n++] = driver_name; 11030Sstevel@tonic-gate cmdline[n++] = "-m"; 1104*9268SJerry.Gilliam@Sun.COM (void) snprintf(maj_num, sizeof (maj_num), "%lu", major_num); 11050Sstevel@tonic-gate cmdline[n++] = maj_num; 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate if (aliases != NULL) { 11080Sstevel@tonic-gate len = strlen(aliases); 11090Sstevel@tonic-gate previous = aliases; 11100Sstevel@tonic-gate do { 11110Sstevel@tonic-gate cmdline[n++] = "-a"; 11120Sstevel@tonic-gate cmdline[n] = calloc(len + 1, 1); 11130Sstevel@tonic-gate if (cmdline[n] == NULL) { 11140Sstevel@tonic-gate (void) fprintf(stderr, 11150Sstevel@tonic-gate gettext(ERR_NO_MEM)); 11160Sstevel@tonic-gate return (ERROR); 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate current = get_entry(previous, 11194145Scth cmdline[n++], ' ', 0); 11200Sstevel@tonic-gate previous = current; 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate } while (*current != '\0'); 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate cmdline[n] = (char *)0; 11260Sstevel@tonic-gate 11278831SJerry.Gilliam@Sun.COM rv = exec_command(DRVCONFIG_PATH, cmdline); 11288831SJerry.Gilliam@Sun.COM if (rv == NOERR) 11298831SJerry.Gilliam@Sun.COM return (NOERR); 11308831SJerry.Gilliam@Sun.COM return (ERROR); 11318831SJerry.Gilliam@Sun.COM } 11328831SJerry.Gilliam@Sun.COM 11338831SJerry.Gilliam@Sun.COM int 11348831SJerry.Gilliam@Sun.COM unconfig_driver( 11358831SJerry.Gilliam@Sun.COM char *driver_name, 11368831SJerry.Gilliam@Sun.COM major_t major_num, 11378831SJerry.Gilliam@Sun.COM char *aliases, 11388831SJerry.Gilliam@Sun.COM int verbose_flag, 11398831SJerry.Gilliam@Sun.COM int force_flag) 11408831SJerry.Gilliam@Sun.COM { 11418831SJerry.Gilliam@Sun.COM return (exec_devfsadm(B_FALSE, driver_name, major_num, 11428831SJerry.Gilliam@Sun.COM aliases, NULL, verbose_flag, force_flag)); 11438831SJerry.Gilliam@Sun.COM } 11440Sstevel@tonic-gate 11458831SJerry.Gilliam@Sun.COM /* 11468831SJerry.Gilliam@Sun.COM * check that major_num doesn't exceed maximum on this machine 11478831SJerry.Gilliam@Sun.COM * do this here to support add_drv on server for diskless clients 11488831SJerry.Gilliam@Sun.COM */ 11498831SJerry.Gilliam@Sun.COM int 11508831SJerry.Gilliam@Sun.COM config_driver( 11518831SJerry.Gilliam@Sun.COM char *driver_name, 11528831SJerry.Gilliam@Sun.COM major_t major_num, 11538831SJerry.Gilliam@Sun.COM char *aliases, 11548831SJerry.Gilliam@Sun.COM char *classes, 11558831SJerry.Gilliam@Sun.COM int cleanup_flag, 11568831SJerry.Gilliam@Sun.COM int verbose_flag) 11578831SJerry.Gilliam@Sun.COM { 11588831SJerry.Gilliam@Sun.COM int max_dev; 11598831SJerry.Gilliam@Sun.COM int rv; 11608831SJerry.Gilliam@Sun.COM 11618831SJerry.Gilliam@Sun.COM if (modctl(MODRESERVED, NULL, &max_dev) < 0) { 11628831SJerry.Gilliam@Sun.COM perror(NULL); 11638831SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_MAX_MAJOR)); 11648831SJerry.Gilliam@Sun.COM return (ERROR); 11658831SJerry.Gilliam@Sun.COM } 11668831SJerry.Gilliam@Sun.COM 11678831SJerry.Gilliam@Sun.COM if (major_num >= max_dev) { 11688831SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_MAX_EXCEEDS), 11698831SJerry.Gilliam@Sun.COM major_num, max_dev); 11708831SJerry.Gilliam@Sun.COM return (ERROR); 11718831SJerry.Gilliam@Sun.COM } 11728831SJerry.Gilliam@Sun.COM 11738831SJerry.Gilliam@Sun.COM /* bind major number and driver name */ 11748831SJerry.Gilliam@Sun.COM rv = exec_devfsadm(B_TRUE, driver_name, major_num, 11758831SJerry.Gilliam@Sun.COM aliases, classes, verbose_flag, 0); 11768831SJerry.Gilliam@Sun.COM 11778831SJerry.Gilliam@Sun.COM if (rv == NOERR) 11780Sstevel@tonic-gate return (NOERR); 11790Sstevel@tonic-gate perror(NULL); 11800Sstevel@tonic-gate remove_entry(cleanup_flag, driver_name); 11810Sstevel@tonic-gate return (ERROR); 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate void 11850Sstevel@tonic-gate load_driver(char *driver_name, int verbose_flag) 11860Sstevel@tonic-gate { 11870Sstevel@tonic-gate int n = 0; 11880Sstevel@tonic-gate char *cmdline[MAX_CMD_LINE]; 11890Sstevel@tonic-gate int exec_status; 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate /* build command line */ 11920Sstevel@tonic-gate cmdline[n++] = DEVFSADM; 11930Sstevel@tonic-gate if (verbose_flag) { 11940Sstevel@tonic-gate cmdline[n++] = "-v"; 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate cmdline[n++] = "-i"; 11970Sstevel@tonic-gate cmdline[n++] = driver_name; 11980Sstevel@tonic-gate cmdline[n] = (char *)0; 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate exec_status = exec_command(DEVFSADM_PATH, cmdline); 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate if (exec_status != NOERR) { 12030Sstevel@tonic-gate /* no clean : name and major number are bound */ 12048456SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_CONFIG), driver_name); 12050Sstevel@tonic-gate } 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate void 12090Sstevel@tonic-gate get_modid(char *driver_name, int *mod) 12100Sstevel@tonic-gate { 12110Sstevel@tonic-gate struct modinfo modinfo; 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate modinfo.mi_id = -1; 12140Sstevel@tonic-gate modinfo.mi_info = MI_INFO_ALL; 12150Sstevel@tonic-gate do { 12160Sstevel@tonic-gate /* 12170Sstevel@tonic-gate * If we are at the end of the list of loaded modules 12180Sstevel@tonic-gate * then set *mod = -1 and return 12190Sstevel@tonic-gate */ 12200Sstevel@tonic-gate if (modctl(MODINFO, 0, &modinfo) < 0) { 12210Sstevel@tonic-gate *mod = -1; 12220Sstevel@tonic-gate return; 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate *mod = modinfo.mi_id; 12260Sstevel@tonic-gate } while (strcmp(driver_name, modinfo.mi_name) != 0); 12270Sstevel@tonic-gate } 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate int 12300Sstevel@tonic-gate create_reconfig(char *basedir) 12310Sstevel@tonic-gate { 12320Sstevel@tonic-gate char reconfig_file[MAXPATHLEN + FILENAME_MAX + 1]; 12330Sstevel@tonic-gate FILE *reconfig_fp; 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate if (basedir != NULL) { 12360Sstevel@tonic-gate (void) strcpy(reconfig_file, basedir); 12370Sstevel@tonic-gate (void) strcat(reconfig_file, RECONFIGURE); 12380Sstevel@tonic-gate } else { 12390Sstevel@tonic-gate (void) strcpy(reconfig_file, RECONFIGURE); 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate if ((reconfig_fp = fopen(reconfig_file, "a")) == NULL) 12420Sstevel@tonic-gate return (ERROR); 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate (void) fclose(reconfig_fp); 12450Sstevel@tonic-gate return (NOERR); 12460Sstevel@tonic-gate } 12470Sstevel@tonic-gate 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate /* 12500Sstevel@tonic-gate * update_minor_entry: 12510Sstevel@tonic-gate * open file 12520Sstevel@tonic-gate * for each entry in list 12530Sstevel@tonic-gate * where list entries are separated by <list_separator> 12540Sstevel@tonic-gate * modify entry : driver_name <entry_separator> entry 12550Sstevel@tonic-gate * close file 12560Sstevel@tonic-gate * 12570Sstevel@tonic-gate * return error/noerr 12580Sstevel@tonic-gate */ 12590Sstevel@tonic-gate int 12600Sstevel@tonic-gate update_minor_entry(char *driver_name, char *perm_list) 12610Sstevel@tonic-gate { 12620Sstevel@tonic-gate FILE *fp; 12630Sstevel@tonic-gate FILE *newfp; 12640Sstevel@tonic-gate struct group *sysgrp; 12650Sstevel@tonic-gate int match = 0; 12662805Seota char line[MAX_DBFILE_ENTRY], *cp, *dup; 12672805Seota char drv[FILENAME_MAX + 1], *drv_minor; 12680Sstevel@tonic-gate char minor[FILENAME_MAX + 1], perm[OPT_LEN + 1]; 12690Sstevel@tonic-gate char own[OPT_LEN + 1], grp[OPT_LEN + 1]; 12700Sstevel@tonic-gate int status = NOERR, i; 12710Sstevel@tonic-gate char *newfile, *tptr; 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate if ((fp = fopen(minor_perm, "r")) == NULL) { 12740Sstevel@tonic-gate perror(NULL); 12750Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 12760Sstevel@tonic-gate minor_perm); 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate return (ERROR); 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate /* 12820Sstevel@tonic-gate * Build filename for temporary file 12830Sstevel@tonic-gate */ 12840Sstevel@tonic-gate if ((tptr = calloc(strlen(minor_perm) + strlen(XEND) + 1, 1)) == NULL) { 12850Sstevel@tonic-gate perror(NULL); 12860Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 12870Sstevel@tonic-gate } 12880Sstevel@tonic-gate (void) strcpy(tptr, minor_perm); 12890Sstevel@tonic-gate (void) strcat(tptr, XEND); 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate /* 12920Sstevel@tonic-gate * Set gid so we preserve group attribute. Ideally we wouldn't 12930Sstevel@tonic-gate * assume a gid of "sys" but we can't undo the damage on already 12940Sstevel@tonic-gate * installed systems unless we force the issue. 12950Sstevel@tonic-gate */ 12960Sstevel@tonic-gate if ((sysgrp = getgrnam("sys")) != NULL) { 12970Sstevel@tonic-gate (void) setgid(sysgrp->gr_gid); 12980Sstevel@tonic-gate } 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate newfile = mktemp(tptr); 13010Sstevel@tonic-gate if ((newfp = fopen(newfile, "w")) == NULL) { 13020Sstevel@tonic-gate perror(NULL); 13030Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 13040Sstevel@tonic-gate newfile); 13050Sstevel@tonic-gate return (ERROR); 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate 1308*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 13090Sstevel@tonic-gate if (sscanf(perm_list, "%s%s%s%s", minor, perm, own, grp) != 4) { 13100Sstevel@tonic-gate status = ERROR; 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate while ((fgets(line, sizeof (line), fp) != NULL) && status == NOERR) { 13142805Seota /* copy the whole line into dup */ 13152805Seota if ((dup = strdup(line)) == NULL) { 13162805Seota perror(NULL); 13172805Seota (void) fprintf(stderr, gettext(ERR_NO_MEM)); 13182805Seota status = ERROR; 13192805Seota break; 13202805Seota } 13212805Seota /* cut off comments starting with '#' */ 13222805Seota if ((cp = strchr(dup, '#')) != NULL) 13232805Seota *cp = '\0'; 13242805Seota /* ignore comment or blank lines */ 13252805Seota if (is_blank(dup)) { 13262805Seota if (fputs(line, newfp) == EOF) { 13270Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), 13280Sstevel@tonic-gate minor_perm); 13290Sstevel@tonic-gate status = ERROR; 13300Sstevel@tonic-gate } 13312805Seota free(dup); 13320Sstevel@tonic-gate continue; 13330Sstevel@tonic-gate } 13340Sstevel@tonic-gate 13352805Seota /* get the driver name */ 1336*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 13372805Seota if (sscanf(dup, "%s", drv) != 1) { 13382805Seota (void) fprintf(stderr, gettext(ERR_BAD_LINE), 13392805Seota minor_perm, line); 13402805Seota status = ERROR; 13412805Seota free(dup); 13422805Seota break; 13432805Seota } 13442805Seota 13452805Seota /* 13462805Seota * get the minor name; place the NULL character at the 13472805Seota * end of the driver name, then make the drv_minor 13482805Seota * point to the first character of the minor name. 13492805Seota * the line missing ':' must be treated as a broken one. 13502805Seota */ 13512805Seota i = strcspn(drv, ":"); 13522805Seota if (i == strlen(drv)) { 13530Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINE), 13540Sstevel@tonic-gate minor_perm, line); 13550Sstevel@tonic-gate status = ERROR; 13562805Seota free(dup); 13572805Seota break; 13580Sstevel@tonic-gate } 13592805Seota drv[i] = '\0'; 13602805Seota drv_minor = &drv[strlen(drv) + 1]; 13610Sstevel@tonic-gate 13622805Seota /* 13632805Seota * compare both of the driver name and the minor name. 13642805Seota * then the new line should be written to the file if 13652805Seota * both of them match 13662805Seota */ 13670Sstevel@tonic-gate if ((strcmp(drv, driver_name) == 0) && 13680Sstevel@tonic-gate (strcmp(minor, drv_minor) == 0)) { 13692805Seota /* if it has a comment, keep it */ 13702805Seota if (cp != NULL) { 13712805Seota cp++; /* skip a terminator */ 1372*9268SJerry.Gilliam@Sun.COM (void) snprintf(line, sizeof (line), 1373*9268SJerry.Gilliam@Sun.COM "%s:%s %s %s %s #%s\n", 13742805Seota drv, minor, perm, own, grp, cp); 13752805Seota } else { 1376*9268SJerry.Gilliam@Sun.COM (void) snprintf(line, sizeof (line), 1377*9268SJerry.Gilliam@Sun.COM "%s:%s %s %s %s\n", 13782805Seota drv, minor, perm, own, grp); 13792805Seota } 13800Sstevel@tonic-gate match = 1; 13810Sstevel@tonic-gate } 13822805Seota free(dup); 13830Sstevel@tonic-gate 13842805Seota /* update the file */ 13850Sstevel@tonic-gate if ((fputs(line, newfp)) == EOF) { 13860Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), 13870Sstevel@tonic-gate minor_perm); 13880Sstevel@tonic-gate status = ERROR; 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate } 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate if (!match) { 13930Sstevel@tonic-gate (void) bzero(line, sizeof (&line[0])); 1394*9268SJerry.Gilliam@Sun.COM (void) snprintf(line, sizeof (line), 1395*9268SJerry.Gilliam@Sun.COM "%s:%s %s %s %s\n", 13960Sstevel@tonic-gate driver_name, minor, perm, own, grp); 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate /* add the new entry */ 13990Sstevel@tonic-gate if ((fputs(line, newfp)) == EOF) { 14000Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm); 14010Sstevel@tonic-gate status = ERROR; 14020Sstevel@tonic-gate } 14030Sstevel@tonic-gate } 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate (void) fclose(fp); 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate if (fflush(newfp) != 0 || fsync(fileno(newfp)) != 0) 14080Sstevel@tonic-gate status = ERROR; 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate (void) fclose(newfp); 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate /* 14130Sstevel@tonic-gate * if error, leave original file, delete new file 14140Sstevel@tonic-gate * if noerr, replace original file with new file 14150Sstevel@tonic-gate */ 14160Sstevel@tonic-gate if (status == NOERR) { 14170Sstevel@tonic-gate if (rename(minor_perm, tmphold) == -1) { 14180Sstevel@tonic-gate perror(NULL); 14190Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm); 14200Sstevel@tonic-gate (void) unlink(newfile); 14210Sstevel@tonic-gate return (ERROR); 14220Sstevel@tonic-gate } else if (rename(newfile, minor_perm) == -1) { 14230Sstevel@tonic-gate perror(NULL); 14240Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_UPDATE), minor_perm); 14250Sstevel@tonic-gate (void) unlink(minor_perm); 14260Sstevel@tonic-gate (void) unlink(newfile); 14270Sstevel@tonic-gate if (link(tmphold, minor_perm) == -1) { 14280Sstevel@tonic-gate perror(NULL); 14290Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINK), 14300Sstevel@tonic-gate minor_perm, tmphold); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate return (ERROR); 14330Sstevel@tonic-gate } 14340Sstevel@tonic-gate (void) unlink(tmphold); 14350Sstevel@tonic-gate } else { 14360Sstevel@tonic-gate /* 14370Sstevel@tonic-gate * since there's an error, leave file alone; remove 14380Sstevel@tonic-gate * new file 14390Sstevel@tonic-gate */ 14400Sstevel@tonic-gate if (unlink(newfile) == -1) { 14410Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_RM), newfile); 14420Sstevel@tonic-gate } 14430Sstevel@tonic-gate return (ERROR); 14440Sstevel@tonic-gate } 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate return (NOERR); 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate /* 14520Sstevel@tonic-gate * list_entry: 14530Sstevel@tonic-gate * open file 14540Sstevel@tonic-gate * read thru file, listing all entries if first entry = driver_name 14550Sstevel@tonic-gate * close 14560Sstevel@tonic-gate */ 14570Sstevel@tonic-gate void 14580Sstevel@tonic-gate list_entry( 14590Sstevel@tonic-gate char *oldfile, 14600Sstevel@tonic-gate char *driver_name, 14610Sstevel@tonic-gate char *marker) 14620Sstevel@tonic-gate { 14630Sstevel@tonic-gate FILE *fp; 14640Sstevel@tonic-gate int i; 14652805Seota char line[MAX_DBFILE_ENTRY], *cp; 14660Sstevel@tonic-gate char drv[FILENAME_MAX + 1]; 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate if ((fp = fopen(oldfile, "r")) == NULL) { 14690Sstevel@tonic-gate perror(NULL); 14700Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), oldfile); 14710Sstevel@tonic-gate 14720Sstevel@tonic-gate return; 14730Sstevel@tonic-gate } 14740Sstevel@tonic-gate 14750Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != NULL) { 14762805Seota /* cut off comments starting with '#' */ 14772805Seota if ((cp = strchr(line, '#')) != NULL) 14782805Seota *cp = '\0'; 14792805Seota /* ignore comment or blank lines */ 14802805Seota if (is_blank(line)) 14810Sstevel@tonic-gate continue; 14822805Seota /* sanity-check */ 1483*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 14840Sstevel@tonic-gate if (sscanf(line, "%s", drv) != 1) { 14850Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINE), 14860Sstevel@tonic-gate oldfile, line); 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate for (i = strcspn(drv, marker); i < FILENAME_MAX; i++) { 14900Sstevel@tonic-gate drv[i] = '\0'; 14910Sstevel@tonic-gate } 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate if (strcmp(driver_name, drv) == 0) { 14940Sstevel@tonic-gate (void) fprintf(stdout, "%s", line); 14950Sstevel@tonic-gate } 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate (void) fclose(fp); 14990Sstevel@tonic-gate } 15000Sstevel@tonic-gate 15012805Seota static boolean_t 15022805Seota is_token(char *tok) 15032805Seota { 15042805Seota /* 15052805Seota * Check the token here. According to IEEE1275 Open Firmware Boot 15062805Seota * Standard, the name is composed of 1 to 31 letters, 15072805Seota * digits and punctuation characters from the set ",._+-", and 15082805Seota * uppercase and lowercase characters are considered distinct. 15092805Seota * (ie. token := [a-zA-Z0-9,._+-]+, length(token) <= 31) 15102805Seota * However, since either the definition of driver or aliase names is 15112805Seota * not known well, only '#' is avoided explicitly. (the kernel lexical 15122805Seota * analyzer treats it as a start of a comment) 15132805Seota */ 15142805Seota for (/* nothing */; *tok != '\0'; tok++) 15152805Seota if (*tok == '#' || iscntrl(*tok)) 15162805Seota return (B_FALSE); 15172805Seota 15182805Seota return (B_TRUE); 15192805Seota } 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate /* 15220Sstevel@tonic-gate * check each entry in perm_list for: 15230Sstevel@tonic-gate * 4 arguments 15240Sstevel@tonic-gate * permission arg is in valid range 15250Sstevel@tonic-gate * permlist entries separated by comma 15260Sstevel@tonic-gate * return ERROR/NOERR 15270Sstevel@tonic-gate */ 15280Sstevel@tonic-gate int 15290Sstevel@tonic-gate check_perm_opts(char *perm_list) 15300Sstevel@tonic-gate { 15310Sstevel@tonic-gate char *current_head; 15320Sstevel@tonic-gate char *previous_head; 15330Sstevel@tonic-gate char *one_entry; 15340Sstevel@tonic-gate int i, len, scan_stat; 15350Sstevel@tonic-gate char minor[FILENAME_MAX + 1]; 15360Sstevel@tonic-gate char perm[OPT_LEN + 1]; 15370Sstevel@tonic-gate char own[OPT_LEN + 1]; 15380Sstevel@tonic-gate char grp[OPT_LEN + 1]; 15390Sstevel@tonic-gate char dumb[OPT_LEN + 1]; 15400Sstevel@tonic-gate int status = NOERR; 15410Sstevel@tonic-gate int intperm; 15420Sstevel@tonic-gate 15430Sstevel@tonic-gate len = strlen(perm_list); 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate if (len == 0) { 15460Sstevel@tonic-gate return (ERROR); 15470Sstevel@tonic-gate } 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate one_entry = calloc(len + 1, 1); 15500Sstevel@tonic-gate if (one_entry == NULL) { 15510Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 15520Sstevel@tonic-gate return (ERROR); 15530Sstevel@tonic-gate } 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate previous_head = perm_list; 15560Sstevel@tonic-gate current_head = perm_list; 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate while (*current_head != '\0') { 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate for (i = 0; i <= len; i++) 15610Sstevel@tonic-gate one_entry[i] = 0; 15620Sstevel@tonic-gate 15634145Scth current_head = get_entry(previous_head, one_entry, ',', 0); 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate previous_head = current_head; 1566*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 15670Sstevel@tonic-gate scan_stat = sscanf(one_entry, "%s%s%s%s%s", minor, perm, own, 15680Sstevel@tonic-gate grp, dumb); 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate if (scan_stat < 4) { 15710Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_MIS_TOK), 15720Sstevel@tonic-gate "-m", one_entry); 15730Sstevel@tonic-gate status = ERROR; 15740Sstevel@tonic-gate } 15750Sstevel@tonic-gate if (scan_stat > 4) { 15760Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_TOO_MANY_ARGS), 15770Sstevel@tonic-gate "-m", one_entry); 15780Sstevel@tonic-gate status = ERROR; 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate intperm = atoi(perm); 15820Sstevel@tonic-gate if (intperm < 0000 || intperm > 4777) { 15830Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_MODE), perm); 15840Sstevel@tonic-gate status = ERROR; 15850Sstevel@tonic-gate } 15860Sstevel@tonic-gate } 15870Sstevel@tonic-gate 15880Sstevel@tonic-gate free(one_entry); 15890Sstevel@tonic-gate return (status); 15900Sstevel@tonic-gate } 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate /* 15940Sstevel@tonic-gate * check each alias : 15950Sstevel@tonic-gate * alias list members separated by white space 15960Sstevel@tonic-gate * cannot exist as driver name in /etc/name_to_major 15970Sstevel@tonic-gate * cannot exist as driver or alias name in /etc/driver_aliases 15980Sstevel@tonic-gate */ 15990Sstevel@tonic-gate int 16000Sstevel@tonic-gate aliases_unique(char *aliases) 16010Sstevel@tonic-gate { 16020Sstevel@tonic-gate char *current_head; 16030Sstevel@tonic-gate char *previous_head; 16040Sstevel@tonic-gate char *one_entry; 16058831SJerry.Gilliam@Sun.COM int len; 16060Sstevel@tonic-gate int is_unique; 16078831SJerry.Gilliam@Sun.COM int err; 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate len = strlen(aliases); 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate one_entry = calloc(len + 1, 1); 16120Sstevel@tonic-gate if (one_entry == NULL) { 16130Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 16140Sstevel@tonic-gate return (ERROR); 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate previous_head = aliases; 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate do { 16208831SJerry.Gilliam@Sun.COM bzero(one_entry, len+1); 16214145Scth current_head = get_entry(previous_head, one_entry, ' ', 1); 16220Sstevel@tonic-gate previous_head = current_head; 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate if ((unique_driver_name(one_entry, name_to_major, 16258831SJerry.Gilliam@Sun.COM &is_unique)) == ERROR) 16268831SJerry.Gilliam@Sun.COM goto err_out; 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate if (is_unique != UNIQUE) { 16290Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_ALIAS_IN_NAM_MAJ), 16300Sstevel@tonic-gate one_entry); 16318831SJerry.Gilliam@Sun.COM goto err_out; 16320Sstevel@tonic-gate } 16330Sstevel@tonic-gate 16348831SJerry.Gilliam@Sun.COM if ((err = unique_drv_alias(one_entry)) != UNIQUE) { 16358831SJerry.Gilliam@Sun.COM if (err == NOT_UNIQUE) { 16368831SJerry.Gilliam@Sun.COM (void) fprintf(stderr, 16378831SJerry.Gilliam@Sun.COM gettext(ERR_ALIAS_IN_USE), one_entry); 16388831SJerry.Gilliam@Sun.COM } 16398831SJerry.Gilliam@Sun.COM goto err_out; 16400Sstevel@tonic-gate } 16410Sstevel@tonic-gate 16422805Seota if (!is_token(one_entry)) { 16432805Seota (void) fprintf(stderr, gettext(ERR_BAD_TOK), 16442805Seota "-i", one_entry); 16458831SJerry.Gilliam@Sun.COM goto err_out; 16462805Seota } 16472805Seota 16480Sstevel@tonic-gate } while (*current_head != '\0'); 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate free(one_entry); 16510Sstevel@tonic-gate return (NOERR); 16520Sstevel@tonic-gate 16538831SJerry.Gilliam@Sun.COM err_out: 16548831SJerry.Gilliam@Sun.COM free(one_entry); 16558831SJerry.Gilliam@Sun.COM return (ERROR); 16568831SJerry.Gilliam@Sun.COM } 16578831SJerry.Gilliam@Sun.COM 16588831SJerry.Gilliam@Sun.COM /* 16598831SJerry.Gilliam@Sun.COM * verify each alias : 16608831SJerry.Gilliam@Sun.COM * alias list members separated by white space and quoted 16618831SJerry.Gilliam@Sun.COM * exist as alias name in /etc/driver_aliases 16628831SJerry.Gilliam@Sun.COM */ 16638831SJerry.Gilliam@Sun.COM int 1664*9268SJerry.Gilliam@Sun.COM aliases_exist(char *aliases) 16658831SJerry.Gilliam@Sun.COM { 16668831SJerry.Gilliam@Sun.COM char *current_head; 16678831SJerry.Gilliam@Sun.COM char *previous_head; 16688831SJerry.Gilliam@Sun.COM char *one_entry; 16698831SJerry.Gilliam@Sun.COM int len; 16708831SJerry.Gilliam@Sun.COM 16718831SJerry.Gilliam@Sun.COM len = strlen(aliases); 16728831SJerry.Gilliam@Sun.COM 16738831SJerry.Gilliam@Sun.COM one_entry = calloc(len + 1, 1); 16748831SJerry.Gilliam@Sun.COM if (one_entry == NULL) { 16758831SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_NO_MEM)); 16768831SJerry.Gilliam@Sun.COM return (ERROR); 16778831SJerry.Gilliam@Sun.COM } 16788831SJerry.Gilliam@Sun.COM 16798831SJerry.Gilliam@Sun.COM previous_head = aliases; 16808831SJerry.Gilliam@Sun.COM 16818831SJerry.Gilliam@Sun.COM do { 16828831SJerry.Gilliam@Sun.COM bzero(one_entry, len+1); 16838831SJerry.Gilliam@Sun.COM current_head = get_entry(previous_head, one_entry, ' ', 1); 16848831SJerry.Gilliam@Sun.COM previous_head = current_head; 16858831SJerry.Gilliam@Sun.COM 1686*9268SJerry.Gilliam@Sun.COM if (unique_drv_alias(one_entry) != NOT_UNIQUE) 16878831SJerry.Gilliam@Sun.COM goto err_out; 16888831SJerry.Gilliam@Sun.COM 16898831SJerry.Gilliam@Sun.COM if (!is_token(one_entry)) { 16908831SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_BAD_TOK), 16918831SJerry.Gilliam@Sun.COM "-i", one_entry); 16928831SJerry.Gilliam@Sun.COM goto err_out; 16938831SJerry.Gilliam@Sun.COM } 16948831SJerry.Gilliam@Sun.COM 16958831SJerry.Gilliam@Sun.COM } while (*current_head != '\0'); 16968831SJerry.Gilliam@Sun.COM 16978831SJerry.Gilliam@Sun.COM free(one_entry); 16988831SJerry.Gilliam@Sun.COM return (NOERR); 16998831SJerry.Gilliam@Sun.COM 17008831SJerry.Gilliam@Sun.COM err_out: 17018831SJerry.Gilliam@Sun.COM free(one_entry); 17028831SJerry.Gilliam@Sun.COM return (ERROR); 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate 17050Sstevel@tonic-gate 17064145Scth /* 17074145Scth * check each alias : 17084145Scth * if path-oriented alias, path exists 17094145Scth */ 17104145Scth int 17114145Scth aliases_paths_exist(char *aliases) 17124145Scth { 17134145Scth char *current_head; 17144145Scth char *previous_head; 17154145Scth char *one_entry; 17164145Scth int i, len; 17174145Scth char path[MAXPATHLEN]; 17184145Scth struct stat buf; 17194145Scth 17204145Scth len = strlen(aliases); 17214145Scth 17224145Scth one_entry = calloc(len + 1, 1); 17234145Scth if (one_entry == NULL) { 17244145Scth (void) fprintf(stderr, gettext(ERR_NO_MEM)); 17254145Scth return (ERROR); 17264145Scth } 17274145Scth 17284145Scth previous_head = aliases; 17294145Scth 17304145Scth do { 17314145Scth for (i = 0; i <= len; i++) 17324145Scth one_entry[i] = 0; 17334145Scth 17344145Scth current_head = get_entry(previous_head, one_entry, ' ', 1); 17354145Scth previous_head = current_head; 17364145Scth 17374145Scth /* if the alias is a path, ensure that the path exists */ 17384145Scth if (*one_entry != '/') 17394145Scth continue; 17404145Scth (void) snprintf(path, sizeof (path), "/devices/%s", one_entry); 17414145Scth if (stat(path, &buf) == 0) 17424145Scth continue; 17434145Scth 17444145Scth /* no device at specified path-oriented alias path */ 17454145Scth (void) fprintf(stderr, gettext(ERR_PATH_ORIENTED_ALIAS), 17464145Scth one_entry); 17474145Scth free(one_entry); 17484145Scth return (ERROR); 17494145Scth 17504145Scth } while (*current_head != '\0'); 17514145Scth 17524145Scth free(one_entry); 17534145Scth 17544145Scth return (NOERR); 17554145Scth } 17564145Scth 17574145Scth 17580Sstevel@tonic-gate int 17590Sstevel@tonic-gate update_driver_aliases( 17600Sstevel@tonic-gate char *driver_name, 17610Sstevel@tonic-gate char *aliases) 17620Sstevel@tonic-gate { 17630Sstevel@tonic-gate /* make call to update the aliases file */ 17644145Scth return (append_to_file(driver_name, aliases, driver_aliases, 17654145Scth ' ', " ", 1)); 17660Sstevel@tonic-gate } 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate 17698831SJerry.Gilliam@Sun.COM /* 17708831SJerry.Gilliam@Sun.COM * Return: 17718831SJerry.Gilliam@Sun.COM * ERROR in case of memory or read error 17728831SJerry.Gilliam@Sun.COM * UNIQUE if there is no existing match to the supplied alias 17738831SJerry.Gilliam@Sun.COM * NOT_UNIQUE if there is a match 17748831SJerry.Gilliam@Sun.COM * An error message is emitted in the case of ERROR, 17758831SJerry.Gilliam@Sun.COM * up to the caller otherwise. 17768831SJerry.Gilliam@Sun.COM */ 17770Sstevel@tonic-gate int 17780Sstevel@tonic-gate unique_drv_alias(char *drv_alias) 17790Sstevel@tonic-gate { 17800Sstevel@tonic-gate FILE *fp; 17810Sstevel@tonic-gate char drv[FILENAME_MAX + 1]; 17822805Seota char line[MAX_N2M_ALIAS_LINE + 1], *cp; 17830Sstevel@tonic-gate char alias[FILENAME_MAX + 1]; 17844145Scth char *a; 17858831SJerry.Gilliam@Sun.COM int status = UNIQUE; 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate fp = fopen(driver_aliases, "r"); 17880Sstevel@tonic-gate 17890Sstevel@tonic-gate if (fp != NULL) { 17900Sstevel@tonic-gate while ((fgets(line, sizeof (line), fp) != 0) && 17918831SJerry.Gilliam@Sun.COM status == UNIQUE) { 17922805Seota /* cut off comments starting with '#' */ 17932805Seota if ((cp = strchr(line, '#')) != NULL) 17942805Seota *cp = '\0'; 17952805Seota /* ignore comment or blank lines */ 17962805Seota if (is_blank(line)) 17972805Seota continue; 17982805Seota /* sanity-check */ 1799*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 18000Sstevel@tonic-gate if (sscanf(line, "%s %s", drv, alias) != 2) 18010Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINE), 18020Sstevel@tonic-gate driver_aliases, line); 18030Sstevel@tonic-gate 18044145Scth /* unquote for compare */ 18054145Scth if ((*alias == '"') && 18064145Scth (*(alias + strlen(alias) - 1) == '"')) { 18074145Scth a = &alias[1]; 18084145Scth alias[strlen(alias) - 1] = '\0'; 18094145Scth } else 18104145Scth a = alias; 18114145Scth 18120Sstevel@tonic-gate if ((strcmp(drv_alias, drv) == 0) || 18134145Scth (strcmp(drv_alias, a) == 0)) { 18148831SJerry.Gilliam@Sun.COM status = NOT_UNIQUE; 18158831SJerry.Gilliam@Sun.COM break; 18160Sstevel@tonic-gate } 18170Sstevel@tonic-gate } 18180Sstevel@tonic-gate (void) fclose(fp); 18190Sstevel@tonic-gate return (status); 18200Sstevel@tonic-gate } else { 18210Sstevel@tonic-gate perror(NULL); 18220Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_OPEN), driver_aliases); 18230Sstevel@tonic-gate return (ERROR); 18240Sstevel@tonic-gate } 18250Sstevel@tonic-gate } 18260Sstevel@tonic-gate 18270Sstevel@tonic-gate 18280Sstevel@tonic-gate /* 18290Sstevel@tonic-gate * search for driver_name in first field of file file_name 18308831SJerry.Gilliam@Sun.COM * searching name_to_major and driver_aliases: name separated 18318831SJerry.Gilliam@Sun.COM * from the remainder of the line by white space. 18320Sstevel@tonic-gate */ 18330Sstevel@tonic-gate int 18340Sstevel@tonic-gate unique_driver_name(char *driver_name, char *file_name, 18350Sstevel@tonic-gate int *is_unique) 18360Sstevel@tonic-gate { 18378831SJerry.Gilliam@Sun.COM int ret, err; 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate if ((ret = get_major_no(driver_name, file_name)) == ERROR) { 18400Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), 18410Sstevel@tonic-gate file_name); 18420Sstevel@tonic-gate } else { 18430Sstevel@tonic-gate /* check alias file for name collision */ 18448831SJerry.Gilliam@Sun.COM if ((err = unique_drv_alias(driver_name)) != UNIQUE) { 18458831SJerry.Gilliam@Sun.COM if (err == NOT_UNIQUE) { 18468831SJerry.Gilliam@Sun.COM (void) fprintf(stderr, 18478831SJerry.Gilliam@Sun.COM gettext(ERR_ALIAS_IN_USE), 18488831SJerry.Gilliam@Sun.COM driver_name); 18498831SJerry.Gilliam@Sun.COM } 18500Sstevel@tonic-gate ret = ERROR; 18510Sstevel@tonic-gate } else { 18520Sstevel@tonic-gate if (ret != UNIQUE) 18530Sstevel@tonic-gate *is_unique = NOT_UNIQUE; 18540Sstevel@tonic-gate else 18550Sstevel@tonic-gate *is_unique = ret; 18560Sstevel@tonic-gate ret = NOERR; 18570Sstevel@tonic-gate } 18580Sstevel@tonic-gate } 18590Sstevel@tonic-gate return (ret); 18600Sstevel@tonic-gate } 18610Sstevel@tonic-gate 18628331SJerry.Gilliam@Sun.COM /* 18638331SJerry.Gilliam@Sun.COM * returns: 18648331SJerry.Gilliam@Sun.COM * SUCCESS - not an existing driver alias 18658331SJerry.Gilliam@Sun.COM * NOT_UNIQUE - matching driver alias exists 18668331SJerry.Gilliam@Sun.COM * ERROR - an error occurred 18678331SJerry.Gilliam@Sun.COM */ 18688331SJerry.Gilliam@Sun.COM int 18698331SJerry.Gilliam@Sun.COM check_duplicate_driver_alias(char *driver_name, char *drv_alias) 18708331SJerry.Gilliam@Sun.COM { 18718331SJerry.Gilliam@Sun.COM FILE *fp; 18728331SJerry.Gilliam@Sun.COM char drv[FILENAME_MAX + 1]; 18738331SJerry.Gilliam@Sun.COM char line[MAX_N2M_ALIAS_LINE + 1], *cp; 18748331SJerry.Gilliam@Sun.COM char alias[FILENAME_MAX + 1]; 18758331SJerry.Gilliam@Sun.COM char *a; 18768331SJerry.Gilliam@Sun.COM int status = SUCCESS; 18778331SJerry.Gilliam@Sun.COM 18788331SJerry.Gilliam@Sun.COM if ((fp = fopen(driver_aliases, "r")) == NULL) { 18798331SJerry.Gilliam@Sun.COM perror(NULL); 18808331SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_CANT_OPEN), driver_aliases); 18818331SJerry.Gilliam@Sun.COM return (ERROR); 18828331SJerry.Gilliam@Sun.COM } 18838331SJerry.Gilliam@Sun.COM 18848331SJerry.Gilliam@Sun.COM while (fgets(line, sizeof (line), fp) != 0) { 18858331SJerry.Gilliam@Sun.COM /* cut off comments starting with '#' */ 18868331SJerry.Gilliam@Sun.COM if ((cp = strchr(line, '#')) != NULL) 18878331SJerry.Gilliam@Sun.COM *cp = '\0'; 18888331SJerry.Gilliam@Sun.COM /* ignore comment or blank lines */ 18898331SJerry.Gilliam@Sun.COM if (is_blank(line)) 18908331SJerry.Gilliam@Sun.COM continue; 18918331SJerry.Gilliam@Sun.COM /* sanity-check */ 1892*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 18938331SJerry.Gilliam@Sun.COM if (sscanf(line, "%s %s", drv, alias) != 2) 18948331SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_BAD_LINE), 18958331SJerry.Gilliam@Sun.COM driver_aliases, line); 18968331SJerry.Gilliam@Sun.COM 18978331SJerry.Gilliam@Sun.COM /* unquote for compare */ 18988331SJerry.Gilliam@Sun.COM if ((*alias == '"') && 18998331SJerry.Gilliam@Sun.COM (*(alias + strlen(alias) - 1) == '"')) { 19008331SJerry.Gilliam@Sun.COM a = &alias[1]; 19018331SJerry.Gilliam@Sun.COM alias[strlen(alias) - 1] = '\0'; 19028331SJerry.Gilliam@Sun.COM } else 19038331SJerry.Gilliam@Sun.COM a = alias; 19048331SJerry.Gilliam@Sun.COM 19058331SJerry.Gilliam@Sun.COM if ((strcmp(drv_alias, a) == 0) && 19068331SJerry.Gilliam@Sun.COM (strcmp(drv, driver_name) == 0)) { 19078331SJerry.Gilliam@Sun.COM status = NOT_UNIQUE; 19088331SJerry.Gilliam@Sun.COM } 19098331SJerry.Gilliam@Sun.COM 19108331SJerry.Gilliam@Sun.COM if ((strcmp(drv_alias, drv) == 0) || 19118331SJerry.Gilliam@Sun.COM ((strcmp(drv_alias, a) == 0) && 19128331SJerry.Gilliam@Sun.COM (strcmp(drv, driver_name) != 0))) { 19138331SJerry.Gilliam@Sun.COM (void) fprintf(stderr, 19148331SJerry.Gilliam@Sun.COM gettext(ERR_ALIAS_IN_USE), 19158331SJerry.Gilliam@Sun.COM drv_alias); 19168331SJerry.Gilliam@Sun.COM status = ERROR; 19178331SJerry.Gilliam@Sun.COM goto done; 19188331SJerry.Gilliam@Sun.COM } 19198331SJerry.Gilliam@Sun.COM } 19208331SJerry.Gilliam@Sun.COM 19218331SJerry.Gilliam@Sun.COM done: 19228331SJerry.Gilliam@Sun.COM (void) fclose(fp); 19238331SJerry.Gilliam@Sun.COM return (status); 19248331SJerry.Gilliam@Sun.COM } 19258331SJerry.Gilliam@Sun.COM 19268331SJerry.Gilliam@Sun.COM int 19278331SJerry.Gilliam@Sun.COM trim_duplicate_aliases(char *driver_name, char *aliases, char **aliases2p) 19288331SJerry.Gilliam@Sun.COM { 19298331SJerry.Gilliam@Sun.COM char *current_head; 19308331SJerry.Gilliam@Sun.COM char *previous_head; 19318331SJerry.Gilliam@Sun.COM char *one_entry; 19328331SJerry.Gilliam@Sun.COM char *aliases2; 19338331SJerry.Gilliam@Sun.COM int rv, len; 19348331SJerry.Gilliam@Sun.COM int n = 0; 19358331SJerry.Gilliam@Sun.COM 19368331SJerry.Gilliam@Sun.COM *aliases2p = NULL; 19378331SJerry.Gilliam@Sun.COM len = strlen(aliases) + 1; 19388331SJerry.Gilliam@Sun.COM 19398331SJerry.Gilliam@Sun.COM one_entry = calloc(len, 1); 19408331SJerry.Gilliam@Sun.COM aliases2 = calloc(len, 1); 19418331SJerry.Gilliam@Sun.COM if (one_entry == NULL || aliases2 == NULL) { 19428331SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_NO_MEM)); 19438331SJerry.Gilliam@Sun.COM return (ERROR); 19448331SJerry.Gilliam@Sun.COM } 19458331SJerry.Gilliam@Sun.COM 19468331SJerry.Gilliam@Sun.COM previous_head = aliases; 19478331SJerry.Gilliam@Sun.COM 19488331SJerry.Gilliam@Sun.COM do { 19498331SJerry.Gilliam@Sun.COM (void) bzero(one_entry, len); 19508331SJerry.Gilliam@Sun.COM current_head = get_entry(previous_head, one_entry, ' ', 1); 19518331SJerry.Gilliam@Sun.COM previous_head = current_head; 19528331SJerry.Gilliam@Sun.COM 19538331SJerry.Gilliam@Sun.COM rv = check_duplicate_driver_alias(driver_name, one_entry); 19548331SJerry.Gilliam@Sun.COM switch (rv) { 19558331SJerry.Gilliam@Sun.COM case SUCCESS: 19568331SJerry.Gilliam@Sun.COM /* not an existing driver alias: add it */ 19578331SJerry.Gilliam@Sun.COM if (n > 0) { 19588331SJerry.Gilliam@Sun.COM if (strlcat(aliases2, " ", len) >= len) 19598331SJerry.Gilliam@Sun.COM goto err; 19608331SJerry.Gilliam@Sun.COM } 19618331SJerry.Gilliam@Sun.COM if (strlcat(aliases2, one_entry, len) >= len) 19628331SJerry.Gilliam@Sun.COM goto err; 19638331SJerry.Gilliam@Sun.COM n++; 19648331SJerry.Gilliam@Sun.COM break; 19658331SJerry.Gilliam@Sun.COM case NOT_UNIQUE: 19668331SJerry.Gilliam@Sun.COM /* matching driver alias exists: do not add it */ 19678331SJerry.Gilliam@Sun.COM break; 19688331SJerry.Gilliam@Sun.COM case ERROR: 19698331SJerry.Gilliam@Sun.COM /* error reading the alias file */ 19708331SJerry.Gilliam@Sun.COM goto err; 19718331SJerry.Gilliam@Sun.COM default: 19728331SJerry.Gilliam@Sun.COM goto err; 19738331SJerry.Gilliam@Sun.COM } 19748331SJerry.Gilliam@Sun.COM 19758331SJerry.Gilliam@Sun.COM if (!is_token(one_entry)) { 19768331SJerry.Gilliam@Sun.COM (void) fprintf(stderr, gettext(ERR_BAD_TOK), 19778331SJerry.Gilliam@Sun.COM "-i", one_entry); 19788331SJerry.Gilliam@Sun.COM goto err; 19798331SJerry.Gilliam@Sun.COM } 19808331SJerry.Gilliam@Sun.COM } while (*current_head != '\0'); 19818331SJerry.Gilliam@Sun.COM 19828331SJerry.Gilliam@Sun.COM /* 19838331SJerry.Gilliam@Sun.COM * If all the aliases listed are already 19848331SJerry.Gilliam@Sun.COM * present we actually have none to do. 19858331SJerry.Gilliam@Sun.COM */ 19868331SJerry.Gilliam@Sun.COM if (n == 0) { 19878331SJerry.Gilliam@Sun.COM free(aliases2); 19888331SJerry.Gilliam@Sun.COM } else { 19898331SJerry.Gilliam@Sun.COM *aliases2p = aliases2; 19908331SJerry.Gilliam@Sun.COM } 19918331SJerry.Gilliam@Sun.COM free(one_entry); 19928331SJerry.Gilliam@Sun.COM return (NOERR); 19938331SJerry.Gilliam@Sun.COM 19948331SJerry.Gilliam@Sun.COM err: 19958331SJerry.Gilliam@Sun.COM free(aliases2); 19968331SJerry.Gilliam@Sun.COM free(one_entry); 19978331SJerry.Gilliam@Sun.COM return (ERROR); 19988331SJerry.Gilliam@Sun.COM } 19990Sstevel@tonic-gate 20000Sstevel@tonic-gate int 20010Sstevel@tonic-gate check_space_within_quote(char *str) 20020Sstevel@tonic-gate { 20030Sstevel@tonic-gate register int i; 20040Sstevel@tonic-gate register int len; 20050Sstevel@tonic-gate int quoted = 0; 20060Sstevel@tonic-gate 20070Sstevel@tonic-gate len = strlen(str); 20080Sstevel@tonic-gate for (i = 0; i < len; i++, str++) { 20090Sstevel@tonic-gate if (*str == '"') { 20100Sstevel@tonic-gate if (quoted == 0) 20110Sstevel@tonic-gate quoted++; 20120Sstevel@tonic-gate else 20130Sstevel@tonic-gate quoted--; 20140Sstevel@tonic-gate } else if (*str == ' ' && quoted) 20150Sstevel@tonic-gate return (ERROR); 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate 20180Sstevel@tonic-gate return (0); 20190Sstevel@tonic-gate } 20200Sstevel@tonic-gate 20210Sstevel@tonic-gate 20220Sstevel@tonic-gate /* 20230Sstevel@tonic-gate * get major number 20240Sstevel@tonic-gate * write driver_name major_num to name_to_major file 20250Sstevel@tonic-gate * major_num returned in major_num 20260Sstevel@tonic-gate * return success/failure 20270Sstevel@tonic-gate */ 20280Sstevel@tonic-gate int 20290Sstevel@tonic-gate update_name_to_major(char *driver_name, major_t *major_num, int server) 20300Sstevel@tonic-gate { 20310Sstevel@tonic-gate char major[MAX_STR_MAJOR + 1]; 20320Sstevel@tonic-gate struct stat buf; 20330Sstevel@tonic-gate char *num_list; 20340Sstevel@tonic-gate char drv_majnum_str[MAX_STR_MAJOR + 1]; 20350Sstevel@tonic-gate int new_maj = -1; 20360Sstevel@tonic-gate int i, tmp = 0, is_unique, have_rem_n2m = 0; 20370Sstevel@tonic-gate int max_dev = 0; 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate /* 20400Sstevel@tonic-gate * if driver_name already in rem_name_to_major 20410Sstevel@tonic-gate * delete entry from rem_nam_to_major 20420Sstevel@tonic-gate * put entry into name_to_major 20430Sstevel@tonic-gate */ 20440Sstevel@tonic-gate 20450Sstevel@tonic-gate if (stat(rem_name_to_major, &buf) == 0) { 20460Sstevel@tonic-gate have_rem_n2m = 1; 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate if (have_rem_n2m) { 20500Sstevel@tonic-gate if ((is_unique = get_major_no(driver_name, rem_name_to_major)) 20510Sstevel@tonic-gate == ERROR) 20520Sstevel@tonic-gate return (ERROR); 20530Sstevel@tonic-gate 20540Sstevel@tonic-gate /* 20550Sstevel@tonic-gate * found a match in rem_name_to_major 20560Sstevel@tonic-gate */ 20570Sstevel@tonic-gate if (is_unique != UNIQUE) { 20580Sstevel@tonic-gate char scratch[FILENAME_MAX]; 20590Sstevel@tonic-gate 20600Sstevel@tonic-gate /* 20610Sstevel@tonic-gate * If there is a match in /etc/rem_name_to_major then 20620Sstevel@tonic-gate * be paranoid: is that major number already in 20630Sstevel@tonic-gate * /etc/name_to_major (potentially under another name)? 20640Sstevel@tonic-gate */ 20650Sstevel@tonic-gate if (get_driver_name(is_unique, name_to_major, 20660Sstevel@tonic-gate scratch) != UNIQUE) { 20670Sstevel@tonic-gate /* 20680Sstevel@tonic-gate * nuke the rem_name_to_major entry-- it 20690Sstevel@tonic-gate * isn't helpful. 20700Sstevel@tonic-gate */ 20710Sstevel@tonic-gate (void) delete_entry(rem_name_to_major, 20720Sstevel@tonic-gate driver_name, " ", NULL); 20730Sstevel@tonic-gate } else { 20740Sstevel@tonic-gate (void) snprintf(major, sizeof (major), 20750Sstevel@tonic-gate "%d", is_unique); 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate if (append_to_file(driver_name, major, 20784145Scth name_to_major, ' ', " ", 0) == ERROR) { 20790Sstevel@tonic-gate (void) fprintf(stderr, 20800Sstevel@tonic-gate gettext(ERR_NO_UPDATE), 20810Sstevel@tonic-gate name_to_major); 20820Sstevel@tonic-gate return (ERROR); 20830Sstevel@tonic-gate } 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate if (delete_entry(rem_name_to_major, 20860Sstevel@tonic-gate driver_name, " ", NULL) == ERROR) { 20870Sstevel@tonic-gate (void) fprintf(stderr, 20880Sstevel@tonic-gate gettext(ERR_DEL_ENTRY), driver_name, 20890Sstevel@tonic-gate rem_name_to_major); 20900Sstevel@tonic-gate return (ERROR); 20910Sstevel@tonic-gate } 20920Sstevel@tonic-gate 20930Sstevel@tonic-gate /* found matching entry : no errors */ 20940Sstevel@tonic-gate *major_num = is_unique; 20950Sstevel@tonic-gate return (NOERR); 20960Sstevel@tonic-gate } 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate } 20990Sstevel@tonic-gate 21000Sstevel@tonic-gate /* 21010Sstevel@tonic-gate * Bugid: 1264079 21020Sstevel@tonic-gate * In a server case (with -b option), we can't use modctl() to find 21030Sstevel@tonic-gate * the maximum major number, we need to dig thru client's 21040Sstevel@tonic-gate * /etc/name_to_major and /etc/rem_name_to_major for the max_dev. 21050Sstevel@tonic-gate * 21060Sstevel@tonic-gate * if (server) 21070Sstevel@tonic-gate * get maximum major number thru (rem_)name_to_major file on client 21080Sstevel@tonic-gate * else 21090Sstevel@tonic-gate * get maximum major number allowable on current system using modctl 21100Sstevel@tonic-gate */ 21110Sstevel@tonic-gate if (server) { 21120Sstevel@tonic-gate max_dev = 0; 21130Sstevel@tonic-gate tmp = 0; 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate max_dev = get_max_major(name_to_major); 21160Sstevel@tonic-gate 21170Sstevel@tonic-gate /* If rem_name_to_major exists, we need to check it too */ 21180Sstevel@tonic-gate if (have_rem_n2m) { 21190Sstevel@tonic-gate tmp = get_max_major(rem_name_to_major); 21200Sstevel@tonic-gate 21210Sstevel@tonic-gate /* 21220Sstevel@tonic-gate * If name_to_major is missing, we can get max_dev from 21230Sstevel@tonic-gate * /etc/rem_name_to_major. If both missing, bail out! 21240Sstevel@tonic-gate */ 21250Sstevel@tonic-gate if ((max_dev == ERROR) && (tmp == ERROR)) { 21260Sstevel@tonic-gate (void) fprintf(stderr, 21278331SJerry.Gilliam@Sun.COM gettext(ERR_CANT_ACCESS_FILE), 21288331SJerry.Gilliam@Sun.COM name_to_major); 21290Sstevel@tonic-gate return (ERROR); 21300Sstevel@tonic-gate } 21310Sstevel@tonic-gate 21320Sstevel@tonic-gate /* guard against bigger maj_num in rem_name_to_major */ 21330Sstevel@tonic-gate if (tmp > max_dev) 21340Sstevel@tonic-gate max_dev = tmp; 21350Sstevel@tonic-gate } else { 21360Sstevel@tonic-gate /* 21370Sstevel@tonic-gate * If we can't get major from name_to_major file 21380Sstevel@tonic-gate * and there is no /etc/rem_name_to_major file, 21390Sstevel@tonic-gate * then we don't have a max_dev, bail out quick! 21400Sstevel@tonic-gate */ 21410Sstevel@tonic-gate if (max_dev == ERROR) 21420Sstevel@tonic-gate return (ERROR); 21430Sstevel@tonic-gate } 21440Sstevel@tonic-gate 21450Sstevel@tonic-gate /* 21460Sstevel@tonic-gate * In case there is no more slack in current name_to_major 21470Sstevel@tonic-gate * table, provide at least 1 extra entry so the add_drv can 21480Sstevel@tonic-gate * succeed. Since only one add_drv process is allowed at one 21490Sstevel@tonic-gate * time, and hence max_dev will be re-calculated each time 21500Sstevel@tonic-gate * add_drv is ran, we don't need to worry about adding more 21510Sstevel@tonic-gate * than 1 extra slot for max_dev. 21520Sstevel@tonic-gate */ 21530Sstevel@tonic-gate max_dev++; 21540Sstevel@tonic-gate 21550Sstevel@tonic-gate } else { 21560Sstevel@tonic-gate if (modctl(MODRESERVED, NULL, &max_dev) < 0) { 21570Sstevel@tonic-gate perror(NULL); 21580Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_MAX_MAJOR)); 21590Sstevel@tonic-gate return (ERROR); 21600Sstevel@tonic-gate } 21610Sstevel@tonic-gate } 21620Sstevel@tonic-gate 21630Sstevel@tonic-gate /* 21640Sstevel@tonic-gate * max_dev is really how many slots the kernel has allocated for 21650Sstevel@tonic-gate * devices... [0 , maxdev-1], not the largest available device num. 21660Sstevel@tonic-gate */ 21670Sstevel@tonic-gate if ((num_list = calloc(max_dev, 1)) == NULL) { 21680Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 21690Sstevel@tonic-gate return (ERROR); 21700Sstevel@tonic-gate } 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate /* 21730Sstevel@tonic-gate * Populate the num_list array 21740Sstevel@tonic-gate */ 21750Sstevel@tonic-gate if (fill_n2m_array(name_to_major, &num_list, &max_dev) != 0) { 21760Sstevel@tonic-gate return (ERROR); 21770Sstevel@tonic-gate } 21780Sstevel@tonic-gate if (have_rem_n2m) { 21790Sstevel@tonic-gate if (fill_n2m_array(rem_name_to_major, &num_list, &max_dev) != 0) 21800Sstevel@tonic-gate return (ERROR); 21810Sstevel@tonic-gate } 21820Sstevel@tonic-gate 21830Sstevel@tonic-gate /* find first free major number */ 21840Sstevel@tonic-gate for (i = 0; i < max_dev; i++) { 21850Sstevel@tonic-gate if (num_list[i] != 1) { 21860Sstevel@tonic-gate new_maj = i; 21870Sstevel@tonic-gate break; 21880Sstevel@tonic-gate } 21890Sstevel@tonic-gate } 21900Sstevel@tonic-gate 21910Sstevel@tonic-gate if (new_maj == -1) { 21920Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_FREE_MAJOR)); 21930Sstevel@tonic-gate return (ERROR); 21940Sstevel@tonic-gate } 21950Sstevel@tonic-gate 2196*9268SJerry.Gilliam@Sun.COM (void) snprintf(drv_majnum_str, sizeof (drv_majnum_str), 2197*9268SJerry.Gilliam@Sun.COM "%d", new_maj); 21980Sstevel@tonic-gate if (do_the_update(driver_name, drv_majnum_str) == ERROR) { 21990Sstevel@tonic-gate return (ERROR); 22000Sstevel@tonic-gate } 22010Sstevel@tonic-gate 22020Sstevel@tonic-gate *major_num = new_maj; 22030Sstevel@tonic-gate return (NOERR); 22040Sstevel@tonic-gate } 22050Sstevel@tonic-gate 22060Sstevel@tonic-gate 22070Sstevel@tonic-gate int 22080Sstevel@tonic-gate fill_n2m_array(char *filename, char **array, int *nelems) 22090Sstevel@tonic-gate { 22100Sstevel@tonic-gate FILE *fp; 22112805Seota char line[MAX_N2M_ALIAS_LINE + 1], *cp; 22120Sstevel@tonic-gate char drv[FILENAME_MAX + 1]; 22130Sstevel@tonic-gate u_longlong_t dnum; 22140Sstevel@tonic-gate major_t drv_majnum; 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate /* 22170Sstevel@tonic-gate * Read through the file, marking each major number found 22180Sstevel@tonic-gate * order is not relevant 22190Sstevel@tonic-gate */ 22200Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 22210Sstevel@tonic-gate perror(NULL); 22220Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANT_ACCESS_FILE), filename); 22230Sstevel@tonic-gate return (ERROR); 22240Sstevel@tonic-gate } 22250Sstevel@tonic-gate 22260Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != 0) { 22272805Seota /* cut off comments starting with '#' */ 22282805Seota if ((cp = strchr(line, '#')) != NULL) 22292805Seota *cp = '\0'; 22302805Seota /* ignore comment or blank lines */ 22312805Seota if (is_blank(line)) 22322805Seota continue; 22332805Seota /* sanity-check */ 2234*9268SJerry.Gilliam@Sun.COM /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ 22350Sstevel@tonic-gate if (sscanf(line, "%s %llu", drv, &dnum) != 2) { 22360Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_BAD_LINE), 22370Sstevel@tonic-gate filename, line); 22380Sstevel@tonic-gate (void) fclose(fp); 22390Sstevel@tonic-gate return (ERROR); 22400Sstevel@tonic-gate } 22410Sstevel@tonic-gate 22420Sstevel@tonic-gate if (dnum > L_MAXMAJ32) { 22430Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_MAJ_TOOBIG), drv, 22440Sstevel@tonic-gate dnum, filename, L_MAXMAJ32); 22450Sstevel@tonic-gate continue; 22460Sstevel@tonic-gate } 22470Sstevel@tonic-gate /* 22480Sstevel@tonic-gate * cast down to a major_t; we can be sure this is safe because 22490Sstevel@tonic-gate * of the above range-check. 22500Sstevel@tonic-gate */ 22510Sstevel@tonic-gate drv_majnum = (major_t)dnum; 22520Sstevel@tonic-gate 22530Sstevel@tonic-gate if (drv_majnum >= *nelems) { 22540Sstevel@tonic-gate /* 22550Sstevel@tonic-gate * Allocate some more space, up to drv_majnum + 1 so 22560Sstevel@tonic-gate * we can accomodate 0 through drv_majnum. 22570Sstevel@tonic-gate * 22580Sstevel@tonic-gate * Note that in the failure case, we leak all of the 22590Sstevel@tonic-gate * old contents of array. It's ok, since we just 22600Sstevel@tonic-gate * wind up exiting immediately anyway. 22610Sstevel@tonic-gate */ 22620Sstevel@tonic-gate *nelems = drv_majnum + 1; 22630Sstevel@tonic-gate *array = realloc(*array, *nelems); 22640Sstevel@tonic-gate if (*array == NULL) { 22650Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 22660Sstevel@tonic-gate return (ERROR); 22670Sstevel@tonic-gate } 22680Sstevel@tonic-gate } 22690Sstevel@tonic-gate (*array)[drv_majnum] = 1; 22700Sstevel@tonic-gate } 22710Sstevel@tonic-gate 22720Sstevel@tonic-gate (void) fclose(fp); 22730Sstevel@tonic-gate return (0); 22740Sstevel@tonic-gate } 22750Sstevel@tonic-gate 22760Sstevel@tonic-gate 22770Sstevel@tonic-gate int 22780Sstevel@tonic-gate do_the_update(char *driver_name, char *major_number) 22790Sstevel@tonic-gate { 22800Sstevel@tonic-gate return (append_to_file(driver_name, major_number, name_to_major, 22814145Scth ' ', " ", 0)); 22820Sstevel@tonic-gate } 22832805Seota 22842805Seota /* 22852805Seota * is_blank() returns 1 (true) if a line specified is composed of 22862805Seota * whitespace characters only. otherwise, it returns 0 (false). 22872805Seota * 22882805Seota * Note. the argument (line) must be null-terminated. 22892805Seota */ 22902805Seota static int 22912805Seota is_blank(char *line) 22922805Seota { 22932805Seota for (/* nothing */; *line != '\0'; line++) 22942805Seota if (!isspace(*line)) 22952805Seota return (0); 22962805Seota return (1); 22972805Seota } 2298