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 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <sys/types.h>
27#include <sys/mman.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <strings.h>
31#include <unistd.h>
32#include <errno.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <sys/modctl.h>
36#include <zone.h>
37
38void	usage();
39void	exec_userfile(char *execfile, int id, char **envp);
40
41extern void fatal(char *fmt, ...);
42extern void error(char *fmt, ...);
43
44/*
45 * Unload a loaded module.
46 */
47int
48main(int argc, char *argv[], char *envp[])
49{
50	int child;
51	int status;
52	int id;
53	char *execfile = NULL;
54	int opt;
55	extern char *optarg;
56
57	if (argc < 3)
58		usage();
59
60	while ((opt = getopt(argc, argv, "i:e:")) != -1) {
61		switch (opt) {
62		case 'i':
63			if (sscanf(optarg, "%d", &id) != 1)
64				fatal("Invalid id %s\n", optarg);
65			break;
66		case 'e':
67			execfile = optarg;
68		}
69	}
70
71	if (getzoneid() != GLOBAL_ZONEID) {
72		fatal("modunload can only be run from the global zone\n");
73	}
74
75	if (execfile) {
76		child = fork();
77		if (child == -1)
78			error("can't fork %s", execfile);
79		else if (child == 0)
80			exec_userfile(execfile, id, envp);
81		else {
82			(void) wait(&status);
83			if (status != 0) {
84				(void) printf("%s returned error %d.\n",
85				    execfile, status);
86				(void) exit(status >> 8);
87			}
88		}
89	}
90
91	/*
92	 * Unload the module.
93	 */
94	if (modctl(MODUNLOAD, id) < 0) {
95		if (errno == EPERM)
96			fatal("Insufficient privileges to unload a module\n");
97		else if (id != 0)
98			error("can't unload the module");
99	}
100
101	return (0);			/* success */
102}
103
104/*
105 * exec the user file.
106 */
107void
108exec_userfile(char *execfile, int id, char **envp)
109{
110	struct modinfo modinfo;
111
112	char modid[8];
113	char mod0[8];
114
115	modinfo.mi_id = modinfo.mi_nextid = id;
116	modinfo.mi_info = MI_INFO_ONE;
117	if (modctl(MODINFO, id, &modinfo) < 0)
118		error("can't get module information");
119
120	(void) sprintf(modid, "%d", id);
121	(void) sprintf(mod0, "%d", modinfo.mi_msinfo[0].msi_p0);
122
123	(void) execle(execfile, execfile, modid, mod0, NULL, envp);
124
125	error("couldn't exec %s\n", execfile);
126}
127
128
129void
130usage()
131{
132	fatal("usage:  modunload -i <module_id> [-e <exec_file>]\n");
133}
134