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/wait.h>
28#include <sys/param.h>
29#include <sys/stat.h>
30#include <sys/modctl.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35#include <fcntl.h>
36#include <errno.h>
37#include <zone.h>
38
39void	l_exec_userfile(char *execfile, int id, char **envp);
40void	l_usage();
41
42extern void fatal(char *fmt, ...);
43extern void error(char *fmt, ...);
44
45/*
46 * Load a module.
47 */
48int
49main(int argc, char *argv[], char *envp[])
50{
51	char *execfile = NULL;		/* name of file to exec after loading */
52	char *modpath = NULL;
53	int id;
54	extern int optind;
55	extern char *optarg;
56	int opt;
57	int use_path = 0;
58	char path[1024];
59
60	if (argc < 2 || argc > 5) {
61		l_usage();
62	}
63
64	while ((opt = getopt(argc, argv, "e:p")) != -1) {
65		switch (opt) {
66		case 'e':
67			execfile = optarg;
68			break;
69		case 'p':
70			use_path++;
71			break;
72		case '?':
73			l_usage();
74		}
75	}
76
77	if (getzoneid() != GLOBAL_ZONEID) {
78		fatal("modload can only be run from the global zone\n");
79	}
80
81	modpath = argv[optind];
82
83	if (modpath == NULL) {
84		(void) printf("modpath is null\n");
85		l_usage();
86	}
87	if (!use_path && modpath[0] != '/') {
88		if (getcwd(path, 1023 - strlen(modpath)) == NULL)
89			fatal("Can't get current directory\n");
90		(void) strcat(path, "/");
91		(void) strcat(path, modpath);
92	} else
93		(void) strcpy(path, modpath);
94
95	/*
96	 * Load the module.
97	 */
98	if (modctl(MODLOAD, use_path, path, &id) != 0) {
99		if (errno == EPERM)
100			fatal("Insufficient privileges to load a module\n");
101		else
102			error("can't load module");
103	}
104
105	/*
106	 * Exec the user's file (if any)
107	 */
108	if (execfile)
109		l_exec_userfile(execfile, id, envp);
110
111	return (0);		/* success */
112}
113
114/*
115 * Exec the user's file
116 */
117void
118l_exec_userfile(char *execfile, int id, char **envp)
119{
120	struct modinfo modinfo;
121
122	int child;
123	int status;
124	int waitret;
125	char module_id[8];
126	char mod0[8];
127
128	if ((child = fork()) == -1)
129		error("can't fork %s", execfile);
130
131	/*
132	 * exec the user program.
133	 */
134	if (child == 0) {
135		modinfo.mi_id = id;
136		modinfo.mi_nextid = id;
137		modinfo.mi_info = MI_INFO_ONE;
138		if (modctl(MODINFO, id, &modinfo) < 0)
139			error("can't get module status");
140
141		(void) sprintf(module_id, "%d", modinfo.mi_id);
142		(void) sprintf(mod0, "%d", modinfo.mi_msinfo[0].msi_p0);
143		(void) execle(execfile, execfile, module_id, mod0, NULL, envp);
144
145		/* Shouldn't get here if execle was successful */
146
147		error("couldn't exec %s", execfile);
148	} else {
149		do {
150			/* wait for exec'd program to finish */
151			waitret = wait(&status);
152		} while ((waitret != child) && (waitret != -1));
153
154		waitret = (waitret == -1) ? waitret : status;
155
156		if ((waitret & 0377) != 0) {
157			/* exited because of a signal */
158			(void) printf("'%s' terminated because of signal %d",
159			    execfile, (waitret & 0177));
160			if (waitret & 0200)
161				(void) printf(" and produced a core file\n");
162			(void) printf(".\n");
163			exit(waitret >> 8);
164		} else {
165			/* simple termination */
166			if (((waitret >> 8) & 0377) != 0) {
167				(void) printf("'%s' returned error %d.\n",
168				    execfile, (waitret >> 8) & 0377);
169				exit(waitret >> 8);
170			}
171		}
172	}
173}
174
175void
176l_usage()
177{
178	fatal("usage:  modload [-p] [-e <exec_file>] <filename>\n");
179}
180