1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <errno.h> 32 #include <libintl.h> 33 #include <string.h> 34 #include <fcntl.h> 35 #include <sys/buf.h> 36 #include <sys/stat.h> 37 #include <sys/wait.h> 38 #include <limits.h> 39 #include <malloc.h> 40 #include <locale.h> 41 #include <ftw.h> 42 #include <sys/types.h> 43 #include <sys/mkdev.h> 44 #include "addrem.h" 45 #include "errmsg.h" 46 47 #define FT_DEPTH 15 /* device tree depth for nftw() */ 48 49 static void usage(void); 50 51 int 52 main(int argc, char *argv[]) 53 { 54 int opt; 55 char *basedir = NULL, *driver_name = NULL; 56 int server = 0, mod_unloaded = 0; 57 int modid, found; 58 char maj_num[MAX_STR_MAJOR + 1]; 59 int err; 60 61 (void) setlocale(LC_ALL, ""); 62 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 63 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 64 #endif 65 (void) textdomain(TEXT_DOMAIN); 66 67 /* must be run by root */ 68 69 if (getuid() != 0) { 70 (void) fprintf(stderr, gettext(ERR_NOT_ROOT)); 71 exit(1); 72 } 73 74 while ((opt = getopt(argc, argv, "b:")) != -1) { 75 switch (opt) { 76 case 'b' : 77 server = 1; 78 basedir = calloc(strlen(optarg) + 1, 1); 79 if (basedir == NULL) { 80 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 81 exit(1); 82 } 83 (void) strcat(basedir, optarg); 84 break; 85 case '?' : 86 usage(); 87 exit(1); 88 } 89 } 90 91 if (argv[optind] != NULL) { 92 driver_name = calloc(strlen(argv[optind]) + 1, 1); 93 if (driver_name == NULL) { 94 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 95 exit(1); 96 97 } 98 (void) strcat(driver_name, argv[optind]); 99 /* 100 * check for extra args 101 */ 102 if ((optind + 1) != argc) { 103 usage(); 104 exit(1); 105 } 106 107 } else { 108 usage(); 109 exit(1); 110 } 111 112 /* set up add_drv filenames */ 113 if ((build_filenames(basedir)) == ERROR) { 114 exit(1); 115 } 116 117 /* must be only running version of add_drv/mod_drv/rem_drv */ 118 enter_lock(); 119 120 if ((check_perms_aliases(1, 1)) == ERROR) 121 err_exit(); 122 123 if ((check_name_to_major(R_OK | W_OK)) == ERROR) 124 err_exit(); 125 126 /* look up the major number of the driver being removed. */ 127 if ((found = get_major_no(driver_name, name_to_major)) == ERROR) { 128 (void) fprintf(stderr, gettext(ERR_MAX_MAJOR), name_to_major); 129 err_exit(); 130 } 131 if (found == UNIQUE) { 132 (void) fprintf(stderr, gettext(ERR_NOT_INSTALLED), 133 driver_name); 134 err_exit(); 135 } 136 137 if (!server) { 138 mod_unloaded = 1; 139 140 /* get the module id for this driver */ 141 get_modid(driver_name, &modid); 142 143 /* module is installed */ 144 if (modid != -1) { 145 if (modctl(MODUNLOAD, modid) < 0) { 146 perror(NULL); 147 (void) fprintf(stderr, gettext(ERR_MODUN), 148 driver_name); 149 mod_unloaded = 0; 150 } 151 } 152 /* unload driver.conf file */ 153 if (modctl(MODUNLOADDRVCONF, (major_t)found) < 0) { 154 perror(NULL); 155 (void) fprintf(stderr, 156 gettext("cannot unload %s.conf\n"), driver_name); 157 } 158 } 159 160 if (mod_unloaded && (modctl(MODREMMAJBIND, (major_t)found) < 0)) { 161 perror(NULL); 162 (void) fprintf(stderr, gettext(ERR_MODREMMAJ), found); 163 } 164 /* 165 * add driver to rem_name_to_major; if this fails, don`t 166 * delete from name_to_major 167 */ 168 (void) sprintf(maj_num, "%d", found); 169 170 if (append_to_file(driver_name, maj_num, 171 rem_name_to_major, ' ', " ", 0) == ERROR) { 172 (void) fprintf(stderr, gettext(ERR_NO_UPDATE), 173 rem_name_to_major); 174 err_exit(); 175 } 176 177 /* 178 * If removing the driver from the running system, notify 179 * kernel dynamically to remove minor perm entries. 180 */ 181 if (basedir == NULL || (strcmp(basedir, "/") == 0)) { 182 err = devfs_rm_minor_perm(driver_name, log_minorperm_error); 183 if (err != 0) { 184 (void) fprintf(stderr, gettext(ERR_UPDATE_PERM), 185 driver_name, err); 186 } 187 } 188 189 /* 190 * delete references to driver in add_drv/rem_drv database 191 */ 192 remove_entry(CLEAN_ALL, driver_name); 193 194 /* 195 * Clean up any dangling devfs shadow nodes for this 196 * driver so that, in the event the driver is re-added 197 * to the system, newly created nodes won't incorrectly 198 * pick up these stale shadow node permissions. 199 */ 200 if (basedir == NULL || (strcmp(basedir, "/") == 0)) { 201 err = modctl(MODREMDRVCLEANUP, driver_name, 0, NULL); 202 if (err != 0) { 203 (void) fprintf(stderr, gettext(ERR_REMDRV_CLEANUP), 204 driver_name, err); 205 } 206 } 207 208 exit_unlock(); 209 210 return (NOERR); 211 } 212 213 static void 214 usage() 215 { 216 (void) fprintf(stderr, gettext(REM_USAGE1)); 217 } 218