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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
40 #include <sys/types.h>
41 #include <sys/mkdev.h>
42 #include <sys/modctl.h>
43 #include <sys/instance.h>
44 #include <libdevinfo.h>
50 #define FT_DEPTH 15 /* device tree depth for nftw() */
52 static void usage(void);
53 static void cleanup_devfs_attributes(char *, char *);
56 main(int argc
, char *argv
[])
59 char *basedir
= NULL
, *driver_name
= NULL
;
60 int server
= 0, mod_unloaded
= 0;
62 char maj_num
[MAX_STR_MAJOR
+ 1];
67 (void) setlocale(LC_ALL
, "");
68 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
69 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
71 (void) textdomain(TEXT_DOMAIN
);
73 /* must be run by root */
76 (void) fprintf(stderr
, gettext(ERR_NOT_ROOT
));
80 while ((opt
= getopt(argc
, argv
, "b:Cn")) != -1) {
84 basedir
= calloc(strlen(optarg
) + 1, 1);
85 if (basedir
== NULL
) {
86 (void) fprintf(stderr
, gettext(ERR_NO_MEM
));
89 (void) strcat(basedir
, optarg
);
103 if (argv
[optind
] != NULL
) {
104 driver_name
= calloc(strlen(argv
[optind
]) + 1, 1);
105 if (driver_name
== NULL
) {
106 (void) fprintf(stderr
, gettext(ERR_NO_MEM
));
110 (void) strcat(driver_name
, argv
[optind
]);
112 * check for extra args
114 if ((optind
+ 1) != argc
) {
124 if (getzoneid() != GLOBAL_ZONEID
) {
125 (void) fprintf(stderr
, gettext(ERR_NOT_GLOBAL_ZONE
));
129 /* set up add_drv filenames */
130 if ((build_filenames(basedir
)) == ERROR
) {
134 /* must be only running version of add_drv/mod_drv/rem_drv */
137 if ((check_perms_aliases(1, 1)) == ERROR
)
140 if ((check_name_to_major(R_OK
| W_OK
)) == ERROR
)
143 /* look up the major number of the driver being removed. */
144 if ((found
= get_major_no(driver_name
, name_to_major
)) == ERROR
) {
145 (void) fprintf(stderr
, gettext(ERR_MAX_MAJOR
), name_to_major
);
148 if (found
== UNIQUE
) {
149 (void) fprintf(stderr
, gettext(ERR_NOT_INSTALLED
),
154 if (n_flag
== 0 && !server
) {
157 /* get the module id for this driver */
158 get_modid(driver_name
, &modid
);
160 /* module is installed */
162 if (modctl(MODUNLOAD
, modid
) < 0) {
164 (void) fprintf(stderr
, gettext(ERR_MODUN
),
169 /* unload driver.conf file */
170 if (modctl(MODUNLOADDRVCONF
, (major_t
)found
) < 0) {
172 (void) fprintf(stderr
,
173 gettext("cannot unload %s.conf\n"), driver_name
);
177 if (mod_unloaded
&& (modctl(MODREMMAJBIND
, (major_t
)found
) < 0)) {
179 (void) fprintf(stderr
, gettext(ERR_MODREMMAJ
), found
);
182 * add driver to rem_name_to_major; if this fails, don`t
183 * delete from name_to_major
185 (void) sprintf(maj_num
, "%d", found
);
187 if (append_to_file(driver_name
, maj_num
,
188 rem_name_to_major
, ' ', " ", 0) == ERROR
) {
189 (void) fprintf(stderr
, gettext(ERR_NO_UPDATE
),
195 * If removing the driver from the running system, notify
196 * kernel dynamically to remove minor perm entries.
199 (basedir
== NULL
|| (strcmp(basedir
, "/") == 0))) {
200 err
= devfs_rm_minor_perm(driver_name
, log_minorperm_error
);
202 (void) fprintf(stderr
, gettext(ERR_UPDATE_PERM
),
208 * delete references to driver in add_drv/rem_drv database
210 remove_entry(CLEAN_ALL
, driver_name
);
213 * Optionally clean up any dangling devfs shadow nodes for
214 * this driver so that, in the event the driver is re-added
215 * to the system, newly created nodes won't incorrectly
216 * pick up these stale shadow node permissions.
218 if ((n_flag
== 0) && cleanup
) {
219 if ((basedir
== NULL
|| (strcmp(basedir
, "/") == 0))) {
220 err
= modctl(MODREMDRVCLEANUP
, driver_name
, 0, NULL
);
222 (void) fprintf(stderr
,
223 gettext(ERR_REMDRV_CLEANUP
),
226 } else if (strcmp(basedir
, "/") != 0) {
227 cleanup_devfs_attributes(basedir
, driver_name
);
237 * Optionally remove attribute nodes for a driver when
238 * removing drivers on a mounted root image. Useful
239 * when reprovisioning a machine to return to default
240 * permission/ownership settings if the driver is
243 typedef struct cleanup_arg
{
250 * Callback to remove a minor node for a device
254 cleanup_minor_walker(void *cb_arg
, const char *minor_path
)
256 if (unlink(minor_path
) == -1) {
257 (void) fprintf(stderr
, "rem_drv: error removing %s - %s\n",
258 minor_path
, strerror(errno
));
260 return (DI_WALK_CONTINUE
);
264 * Callback for each device registered in the binding file (path_to_inst)
268 cleanup_device_walker(void *cb_arg
, const char *inst_path
,
269 int inst_number
, const char *inst_driver
)
271 char path
[MAXPATHLEN
];
272 cleanup_arg_t
*arg
= (cleanup_arg_t
*)cb_arg
;
273 int rv
= DI_WALK_CONTINUE
;
275 if (strcmp(inst_driver
, arg
->ca_drvname
) == 0) {
276 if (snprintf(path
, MAXPATHLEN
, "%s/devices%s",
277 arg
->ca_basedir
, inst_path
) < MAXPATHLEN
) {
278 rv
= devfs_walk_minor_nodes(path
,
279 cleanup_minor_walker
, NULL
);
286 cleanup_devfs_attributes(char *basedir
, char *driver_name
)
289 char binding_path
[MAXPATHLEN
+1];
291 (void) snprintf(binding_path
, MAXPATHLEN
,
292 "%s%s", basedir
, INSTANCE_FILE
);
294 arg
.ca_basedir
= basedir
;
295 arg
.ca_drvname
= driver_name
;
296 (void) devfs_parse_binding_file(binding_path
,
297 cleanup_device_walker
, (void *)&arg
);
303 (void) fprintf(stderr
, gettext(REM_USAGE1
));