[illumos-Developer] [PATCH] modload: Unload modules by name

Alexey Zaytsev alexey.zaytsev at gmail.com
Thu May 26 14:57:31 PDT 2011


Signed-off-by: Alexey Zaytsev <alexey.zaytsev at gmail.com>
---

Hi.

I've seen all new nexenta people submit their first patches into
illumos pretty quick, so to solidify this tradition, here's one from me.

It lets you unload modules by name, as simple as

modunload vioif virtio

And yes, it takes multiple modules, and you can actually even add one more
by using the -i option. The dependencies are not tracked, so you should pass
inter-dependent modules in the right order.

I did not rebuild the whole tree, but the code passed both cstyle and lint checks,
and seems to work fine.


 usr/src/cmd/modload/modunload.c |   94 ++++++++++++++++++++++++++++++++-------
 1 files changed, 78 insertions(+), 16 deletions(-)

diff --git a/usr/src/cmd/modload/modunload.c b/usr/src/cmd/modload/modunload.c
index f57a4b5..0451404 100644
--- a/usr/src/cmd/modload/modunload.c
+++ b/usr/src/cmd/modload/modunload.c
@@ -37,6 +37,8 @@
 
 void	usage();
 void	exec_userfile(char *execfile, int id, char **envp);
+int	name_to_id(char *modname);
+void	do_unload(int id, char *modname, char *exectfile, char *envp[]);
 
 extern void fatal(char *fmt, ...);
 extern void error(char *fmt, ...);
@@ -47,16 +49,12 @@ extern void error(char *fmt, ...);
 int
 main(int argc, char *argv[], char *envp[])
 {
-	int child;
-	int status;
-	int id;
+	int i;
+	int id = -1;
 	char *execfile = NULL;
 	int opt;
 	extern char *optarg;
 
-	if (argc < 3)
-		usage();
-
 	while ((opt = getopt(argc, argv, "i:e:")) != -1) {
 		switch (opt) {
 		case 'i':
@@ -72,6 +70,64 @@ main(int argc, char *argv[], char *envp[])
 		fatal("modunload can only be run from the global zone\n");
 	}
 
+	if (id >= 0) {
+		do_unload(id, NULL, execfile, envp);
+	} else if (optind >= argc) {
+		/* Eiter pass id with -i, or a module name as arg. Or both. */
+		usage();
+	}
+
+	/*
+	 * If id is not specified explicitly, we loop over
+	 * the given module names.
+	 */
+	for (i = optind; i < argc; i++) {
+		id = name_to_id(argv[i]);
+		if (id < 0) {
+			fprintf(stderr, "Module '%s' not loaded\n", argv[i]);
+			continue;
+		}
+
+		do_unload(id, argv[i], execfile, envp);
+	}
+
+	return (0); /* success */
+}
+
+int
+name_to_id(char *modname)
+{
+	struct modinfo modinfo;
+	int id = -1;
+
+	modinfo.mi_id = modinfo.mi_nextid = id = -1;
+	modinfo.mi_info = MI_INFO_ALL | MI_INFO_CNT;
+
+	for (;;) {
+		if (modctl(MODINFO, id, &modinfo) < 0)
+			break;
+
+		id = modinfo.mi_id;
+
+		if (!(modinfo.mi_state & MI_LOADED))
+			continue;
+
+		if (!(strncmp(modinfo.mi_name, modname, MODMAXNAMELEN)))
+			return (id);
+	}
+
+	return (-1);
+}
+
+/*
+ * Unload a module. Optionally, run execfile.
+ */
+void
+do_unload(int id, char *modname, char *execfile, char *envp[])
+{
+	int child;
+	int status;
+
 	if (execfile) {
 		child = fork();
 		if (child == -1)
@@ -88,17 +144,22 @@ main(int argc, char *argv[], char *envp[])
 		}
 	}
 
-	/*
-	 * Unload the module.
-	 */
 	if (modctl(MODUNLOAD, id) < 0) {
-		if (errno == EPERM)
-			fatal("Insufficient privileges to unload a module\n");
-		else if (id != 0)
-			error("can't unload the module");
+		if (errno == EPERM) {
+			fatal("Insufficient privileges to"
+					"unload a module\n");
+		} else if (id != 0) {
+			if (modname) {
+				fprintf(stderr,
+					"can't unload module '%s': %s\n",
+					modname, strerror(errno));
+			} else {
+				fprintf(stderr,
+					"can't unload module (id %d): %s\n",
+					id, strerror(errno));
+			}
+		}
 	}
-
-	return (0);			/* success */
 }
 
 /*
@@ -129,5 +190,6 @@ exec_userfile(char *execfile, int id, char **envp)
 void
 usage()
 {
-	fatal("usage:  modunload -i <module_id> [-e <exec_file>]\n");
+	fatal("usage: modunload [-i <module_id>]"
+		"[-e <exec_file>] [module_name ... ]\n");
 }
-- 
1.5.6.5




More information about the Developer mailing list