xref: /illumos-gate/usr/src/cmd/sgs/elfedit/common/sys.c (revision d29b2c44)
1*d29b2c44Sab /*
2*d29b2c44Sab  * CDDL HEADER START
3*d29b2c44Sab  *
4*d29b2c44Sab  * The contents of this file are subject to the terms of the
5*d29b2c44Sab  * Common Development and Distribution License (the "License").
6*d29b2c44Sab  * You may not use this file except in compliance with the License.
7*d29b2c44Sab  *
8*d29b2c44Sab  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d29b2c44Sab  * or http://www.opensolaris.org/os/licensing.
10*d29b2c44Sab  * See the License for the specific language governing permissions
11*d29b2c44Sab  * and limitations under the License.
12*d29b2c44Sab  *
13*d29b2c44Sab  * When distributing Covered Code, include this CDDL HEADER in each
14*d29b2c44Sab  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d29b2c44Sab  * If applicable, add the following below this CDDL HEADER, with the
16*d29b2c44Sab  * fields enclosed by brackets "[]" replaced with your own identifying
17*d29b2c44Sab  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d29b2c44Sab  *
19*d29b2c44Sab  * CDDL HEADER END
20*d29b2c44Sab  */
21*d29b2c44Sab 
22*d29b2c44Sab /*
23*d29b2c44Sab  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*d29b2c44Sab  * Use is subject to license terms.
25*d29b2c44Sab  */
26*d29b2c44Sab #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*d29b2c44Sab 
28*d29b2c44Sab #include <fcntl.h>
29*d29b2c44Sab #include <sys/types.h>
30*d29b2c44Sab #include <sys/stat.h>
31*d29b2c44Sab #include <unistd.h>
32*d29b2c44Sab #include <strings.h>
33*d29b2c44Sab #include <elfedit.h>
34*d29b2c44Sab #include "_elfedit.h"
35*d29b2c44Sab #include "msg.h"
36*d29b2c44Sab 
37*d29b2c44Sab 
38*d29b2c44Sab 
39*d29b2c44Sab 
40*d29b2c44Sab /*
41*d29b2c44Sab  * This file provides the builtin sys module. It is similar to the
42*d29b2c44Sab  * other modules, but differs in several important ways:
43*d29b2c44Sab  *
44*d29b2c44Sab  *	- It is built as a static part of elfedit, and not
45*d29b2c44Sab  *		as a sharable object.
46*d29b2c44Sab  *	- It must be avaialble before the ELFCLASS of the object
47*d29b2c44Sab  *		is known, so it is not ELFCLASS specific. We don't build
48*d29b2c44Sab  *		it twice with machdep.h, as we do for the loadable modules.
49*d29b2c44Sab  *		This means that commands need to test for the type
50*d29b2c44Sab  *		of their obj_state argument at runtime.
51*d29b2c44Sab  *	- The init function signature is different. We build an entire
52*d29b2c44Sab  *		module definition statically.
53*d29b2c44Sab  */
54*d29b2c44Sab 
55*d29b2c44Sab 
56*d29b2c44Sab 
57*d29b2c44Sab /*
58*d29b2c44Sab  * This function is supplied to elfedit through our elfedit_module_t
59*d29b2c44Sab  * definition. It translates the opaque elfedit_i18nhdl_t handles
60*d29b2c44Sab  * in our module interface into the actual strings for elfedit to
61*d29b2c44Sab  * use.
62*d29b2c44Sab  *
63*d29b2c44Sab  * note:
64*d29b2c44Sab  *	This module uses Msg codes for its i18n handle type.
65*d29b2c44Sab  *	So the translation is simply to use MSG_INTL() to turn
66*d29b2c44Sab  *	it into a string and return it.
67*d29b2c44Sab  */
68*d29b2c44Sab static const char *
69*d29b2c44Sab mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
70*d29b2c44Sab {
71*d29b2c44Sab 	Msg msg = (Msg)hdl;
72*d29b2c44Sab 
73*d29b2c44Sab 	return (MSG_INTL(msg));
74*d29b2c44Sab }
75*d29b2c44Sab 
76*d29b2c44Sab 
77*d29b2c44Sab 
78*d29b2c44Sab /*
79*d29b2c44Sab  * The sys_opt_t enum specifies a bit value for every optional argument
80*d29b2c44Sab  * allowed by a command in this module.
81*d29b2c44Sab  */
82*d29b2c44Sab typedef enum {
83*d29b2c44Sab 	SYS_OPT_F_ALL =		1,	/* -a */
84*d29b2c44Sab 	SYS_OPT_F_FORCE =	2,	/* -f */
85*d29b2c44Sab 	SYS_OPT_F_SYNOPSIS =	4,	/* -s */
86*d29b2c44Sab } dyn_opt_t;
87*d29b2c44Sab 
88*d29b2c44Sab 
89*d29b2c44Sab /*
90*d29b2c44Sab  * Given a generic (void *) pointer to an obj_state argument, determine
91*d29b2c44Sab  * which type it is, and return the st_file, st_fd and st_elf fields.
92*d29b2c44Sab  */
93*d29b2c44Sab static void
94*d29b2c44Sab get_obj_state_info(void *obj_state, const char **file, int *fd, Elf **elf)
95*d29b2c44Sab {
96*d29b2c44Sab 	if (state.elf.elfclass == ELFCLASS32) {
97*d29b2c44Sab 		elfedit32_obj_state_t *s = (elfedit32_obj_state_t *)obj_state;
98*d29b2c44Sab 
99*d29b2c44Sab 		*file = s->os_file;
100*d29b2c44Sab 		*fd = s->os_fd;
101*d29b2c44Sab 		*elf = s->os_elf;
102*d29b2c44Sab 	} else {
103*d29b2c44Sab 		elfedit64_obj_state_t *s = (elfedit64_obj_state_t *)obj_state;
104*d29b2c44Sab 
105*d29b2c44Sab 		*file = s->os_file;
106*d29b2c44Sab 		*fd = s->os_fd;
107*d29b2c44Sab 		*elf = s->os_elf;
108*d29b2c44Sab 	}
109*d29b2c44Sab }
110*d29b2c44Sab 
111*d29b2c44Sab 
112*d29b2c44Sab 
113*d29b2c44Sab /*
114*d29b2c44Sab  * Helper for cmd_help(). Displays synopsis information for one command.
115*d29b2c44Sab  */
116*d29b2c44Sab static void
117*d29b2c44Sab cmd_help_synopsis(elfeditGC_module_t *mod, elfeditGC_cmd_t *cmd)
118*d29b2c44Sab {
119*d29b2c44Sab 	char		name_buf[128];
120*d29b2c44Sab 	const char	*name;
121*d29b2c44Sab 	const char	**cmd_name;
122*d29b2c44Sab 
123*d29b2c44Sab 	if (cmd->cmd_name[1] == NULL) {   /* One name */
124*d29b2c44Sab 		name = *cmd->cmd_name;
125*d29b2c44Sab 	} else {
126*d29b2c44Sab 		const char *cname;
127*d29b2c44Sab 		int need_comma = 0;
128*d29b2c44Sab 
129*d29b2c44Sab 		name = name_buf;
130*d29b2c44Sab 		(void) snprintf(name_buf, sizeof (name_buf),
131*d29b2c44Sab 		    MSG_ORIG(MSG_HLPFMT_MULTNAM), cmd->cmd_name[0]);
132*d29b2c44Sab 		for (cmd_name = cmd->cmd_name + 1;
133*d29b2c44Sab 		    *cmd_name; cmd_name++) {
134*d29b2c44Sab 			if (need_comma)
135*d29b2c44Sab 				(void) strlcat(name_buf,
136*d29b2c44Sab 				    MSG_ORIG(MSG_STR_COMMA_SP),
137*d29b2c44Sab 				    sizeof (name_buf));
138*d29b2c44Sab 			need_comma = 1;
139*d29b2c44Sab 			cname = (cmd_name[0][0] == '\0') ?
140*d29b2c44Sab 			    MSG_INTL(MSG_HLPFMT_MODDEFCMD) : *cmd_name;
141*d29b2c44Sab 			(void) strlcat(name_buf, cname,
142*d29b2c44Sab 			    sizeof (name_buf));
143*d29b2c44Sab 		}
144*d29b2c44Sab 		(void) strlcat(name_buf, MSG_ORIG(MSG_STR_CPAREN),
145*d29b2c44Sab 		    sizeof (name_buf));
146*d29b2c44Sab 	}
147*d29b2c44Sab 	elfedit_printf(MSG_ORIG(MSG_HLPFMT_NAMSUMHDR), name,
148*d29b2c44Sab 	    (* mod->mod_i18nhdl_to_str)(cmd->cmd_desc));
149*d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_HLPFMT_SUMSYNOPSIS),
150*d29b2c44Sab 	    elfedit_format_command_usage(mod, cmd,
151*d29b2c44Sab 	    MSG_ORIG(MSG_STR_HLPSUMINDENT),
152*d29b2c44Sab 	    strlen(MSG_ORIG(MSG_STR_HLPSUMINDENT))));
153*d29b2c44Sab }
154*d29b2c44Sab 
155*d29b2c44Sab 
156*d29b2c44Sab /*
157*d29b2c44Sab  * Helper for cmd_help(). Displays synopsis information for one module.
158*d29b2c44Sab  */
159*d29b2c44Sab static void
160*d29b2c44Sab cmd_help_showmod(elfeditGC_module_t *mod)
161*d29b2c44Sab {
162*d29b2c44Sab 	elfeditGC_cmd_t	*cmd;
163*d29b2c44Sab 
164*d29b2c44Sab 	elfedit_printf(MSG_ORIG(MSG_HLPFMT_NAMDSCHDR),
165*d29b2c44Sab 	    mod->mod_name, (* mod->mod_i18nhdl_to_str)(mod->mod_desc));
166*d29b2c44Sab 	for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++) {
167*d29b2c44Sab 		if (cmd != mod->mod_cmds)
168*d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
169*d29b2c44Sab 		elfedit_printf(MSG_ORIG(MSG_STR_NL));
170*d29b2c44Sab 		cmd_help_synopsis(mod, cmd);
171*d29b2c44Sab 	}
172*d29b2c44Sab }
173*d29b2c44Sab 
174*d29b2c44Sab 
175*d29b2c44Sab /*
176*d29b2c44Sab  * Given a string containing newline characters, break it into
177*d29b2c44Sab  * individual lines, and output each line with the given
178*d29b2c44Sab  * prefix string in front.
179*d29b2c44Sab  */
180*d29b2c44Sab static void
181*d29b2c44Sab write_help_str(const char *str, const char *prefix)
182*d29b2c44Sab {
183*d29b2c44Sab 	size_t i;
184*d29b2c44Sab 
185*d29b2c44Sab 	if (str == NULL)
186*d29b2c44Sab 		return;
187*d29b2c44Sab 	while (*str) {
188*d29b2c44Sab 		i = strcspn(str, MSG_ORIG(MSG_STR_NL));
189*d29b2c44Sab 		if (*(str + i) != '\0')
190*d29b2c44Sab 			i++;
191*d29b2c44Sab 		elfedit_printf(prefix);
192*d29b2c44Sab 		elfedit_write(str, i);
193*d29b2c44Sab 		str += i;
194*d29b2c44Sab 	}
195*d29b2c44Sab }
196*d29b2c44Sab 
197*d29b2c44Sab 
198*d29b2c44Sab /*
199*d29b2c44Sab  * Given a title, and a NULL terminated list of option/argument
200*d29b2c44Sab  * descriptors, output the list contents.
201*d29b2c44Sab  */
202*d29b2c44Sab static void
203*d29b2c44Sab write_optarg(elfeditGC_module_t *mod, const char *title,
204*d29b2c44Sab     elfedit_cmd_optarg_t *optarg)
205*d29b2c44Sab {
206*d29b2c44Sab 	int			cnt;
207*d29b2c44Sab 	int			len;
208*d29b2c44Sab 	const char		*help;
209*d29b2c44Sab 	elfedit_optarg_item_t	item;
210*d29b2c44Sab 
211*d29b2c44Sab 	elfedit_printf(title);
212*d29b2c44Sab 	for (cnt = 0; optarg->oa_name != NULL; cnt++) {
213*d29b2c44Sab 		elfedit_next_optarg(&optarg, &item);
214*d29b2c44Sab 
215*d29b2c44Sab 		/* Insert a blank line between items */
216*d29b2c44Sab 		if (cnt > 0)
217*d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
218*d29b2c44Sab 
219*d29b2c44Sab 		/* Indentation */
220*d29b2c44Sab 		elfedit_printf(MSG_ORIG(MSG_STR_HLPINDENT));
221*d29b2c44Sab 		len = strlen(item.oai_name);
222*d29b2c44Sab 		help = elfedit_optarg_helpstr(mod, &item);
223*d29b2c44Sab 		if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE) {
224*d29b2c44Sab 			len += 1 + strlen(item.oai_vname);
225*d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_STR_HLPOPTARG2),
226*d29b2c44Sab 			    item.oai_name, item.oai_vname);
227*d29b2c44Sab 		} else {
228*d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_STR_HLPOPTARG),
229*d29b2c44Sab 			    item.oai_name);
230*d29b2c44Sab 		}
231*d29b2c44Sab 
232*d29b2c44Sab 		/*
233*d29b2c44Sab 		 * If name is too long, inject a newline to avoid
234*d29b2c44Sab 		 * crowding the help text.
235*d29b2c44Sab 		 */
236*d29b2c44Sab 		if (len > 3)
237*d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
238*d29b2c44Sab 
239*d29b2c44Sab 		/* Output the help text with a tab prefix */
240*d29b2c44Sab 		write_help_str(help, MSG_ORIG(MSG_STR_TAB));
241*d29b2c44Sab 	}
242*d29b2c44Sab }
243*d29b2c44Sab 
244*d29b2c44Sab 
245*d29b2c44Sab /*
246*d29b2c44Sab  * Implementation of sys:help
247*d29b2c44Sab  */
248*d29b2c44Sab /*ARGSUSED*/
249*d29b2c44Sab static elfedit_cmdret_t
250*d29b2c44Sab cmd_help(void *obj_state, int argc, const char *argv[])
251*d29b2c44Sab {
252*d29b2c44Sab #define	INITIAL_ITEM_ALLOC 4
253*d29b2c44Sab 
254*d29b2c44Sab 
255*d29b2c44Sab 	/*
256*d29b2c44Sab 	 * An array of this type is used to collect the data needed to
257*d29b2c44Sab 	 * generate help output.
258*d29b2c44Sab 	 */
259*d29b2c44Sab 	typedef struct {
260*d29b2c44Sab 		elfeditGC_cmd_t		*cmd;
261*d29b2c44Sab 		elfeditGC_module_t	*cmd_mod;	/* Used with cmd */
262*d29b2c44Sab 		elfeditGC_module_t	*mod;
263*d29b2c44Sab 	} ITEM;
264*d29b2c44Sab 
265*d29b2c44Sab 	static ITEM	*item;
266*d29b2c44Sab 	static int	item_cnt;
267*d29b2c44Sab 
268*d29b2c44Sab 	MODLIST_T		*modlist;
269*d29b2c44Sab 	int			dispcnt;
270*d29b2c44Sab 	size_t			i;
271*d29b2c44Sab 	elfeditGC_module_t	*mod;
272*d29b2c44Sab 	elfeditGC_cmd_t		*cmd;
273*d29b2c44Sab 	int			minus_s = 0;
274*d29b2c44Sab 	elfedit_getopt_state_t	getopt_state;
275*d29b2c44Sab 	ITEM			*cur_item;
276*d29b2c44Sab 
277*d29b2c44Sab 	/*
278*d29b2c44Sab 	 * Process options. The only option accepted is -s, so we
279*d29b2c44Sab 	 * don't even have to check the idmask to know.
280*d29b2c44Sab 	 */
281*d29b2c44Sab 	elfedit_getopt_init(&getopt_state, &argc, &argv);
282*d29b2c44Sab 	while (elfedit_getopt(&getopt_state) != NULL)
283*d29b2c44Sab 		minus_s = 1;
284*d29b2c44Sab 
285*d29b2c44Sab 	/*
286*d29b2c44Sab 	 * This command can produce an arbitrary amount of output, so
287*d29b2c44Sab 	 * run a pager.
288*d29b2c44Sab 	 */
289*d29b2c44Sab 	elfedit_pager_init();
290*d29b2c44Sab 
291*d29b2c44Sab 	if (argc == 0) {
292*d29b2c44Sab 		if (minus_s) {
293*d29b2c44Sab 			/* Force all modules to load so we have data */
294*d29b2c44Sab 			elfedit_load_modpath();
295*d29b2c44Sab 			for (modlist = state.modlist; modlist;
296*d29b2c44Sab 			    modlist = modlist->ml_next) {
297*d29b2c44Sab 				cmd_help_showmod(modlist->ml_mod);
298*d29b2c44Sab 				if (modlist->ml_next != NULL) {
299*d29b2c44Sab 					elfedit_printf(MSG_ORIG(MSG_STR_NL));
300*d29b2c44Sab 					elfedit_printf(MSG_ORIG(MSG_STR_NL));
301*d29b2c44Sab 				}
302*d29b2c44Sab 			}
303*d29b2c44Sab 			return (ELFEDIT_CMDRET_NONE);
304*d29b2c44Sab 		}
305*d29b2c44Sab 
306*d29b2c44Sab 		/*
307*d29b2c44Sab 		 * If no arguments are present, we display a simple
308*d29b2c44Sab 		 * "how to use help" tutorial, which will hopefully
309*d29b2c44Sab 		 * bootstrap the user into a position where they
310*d29b2c44Sab 		 * know how to run the help command, and then find
311*d29b2c44Sab 		 * what they're really after.
312*d29b2c44Sab 		 */
313*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_SYS_HELP_HELP_NOARG));
314*d29b2c44Sab 		return (ELFEDIT_CMDRET_NONE);
315*d29b2c44Sab 	}
316*d29b2c44Sab 
317*d29b2c44Sab 
318*d29b2c44Sab 	/*
319*d29b2c44Sab 	 * As we process the arguments, we are willing to treat each
320*d29b2c44Sab 	 * one as either a module or a command:
321*d29b2c44Sab 	 *	1) An item without a colon can be a module,
322*d29b2c44Sab 	 *		or a command from the sys: module.
323*d29b2c44Sab 	 *	2) An item with a colon, and no command part is
324*d29b2c44Sab 	 *		a module, and it can also be the default
325*d29b2c44Sab 	 *		command for the module, if it has one. We choose
326*d29b2c44Sab 	 *		to only display the module info in this case, since
327*d29b2c44Sab 	 *		the use of "" to represent the default command is
328*d29b2c44Sab 	 *		an implementation detail, not a user-facing concept.
329*d29b2c44Sab 	 *	3) An item with a colon and a command part can only be
330*d29b2c44Sab 	 *		a command.
331*d29b2c44Sab 	 *
332*d29b2c44Sab 	 * Note that there are cases where one argument can have two
333*d29b2c44Sab 	 * valid interpretations. In this case, we display them both.
334*d29b2c44Sab 	 *
335*d29b2c44Sab 	 * Pass over the arguments and determine how many distinct
336*d29b2c44Sab 	 * "things" we need to display. At the same time, force any
337*d29b2c44Sab 	 * needed modules to load so that the debug load messages won't
338*d29b2c44Sab 	 * show up in between the displayed items, and save the command
339*d29b2c44Sab 	 * and module definitions we will need to generate the output.
340*d29b2c44Sab 	 */
341*d29b2c44Sab 	if (argc > item_cnt) {
342*d29b2c44Sab 		int n = (item_cnt == 0) ? INITIAL_ITEM_ALLOC : item_cnt;
343*d29b2c44Sab 
344*d29b2c44Sab 		while (n < argc)
345*d29b2c44Sab 			n *= 2;
346*d29b2c44Sab 
347*d29b2c44Sab 		item = elfedit_realloc(MSG_INTL(MSG_ALLOC_HELPITEM), item,
348*d29b2c44Sab 		    n * sizeof (*item));
349*d29b2c44Sab 		item_cnt = n;
350*d29b2c44Sab 	}
351*d29b2c44Sab 
352*d29b2c44Sab 	dispcnt = 0;
353*d29b2c44Sab 	for (i = 0; i < argc; i++) {
354*d29b2c44Sab 		const char *colon = strchr(argv[i], ':');
355*d29b2c44Sab 
356*d29b2c44Sab 		if (colon == NULL) {	/* No colon: sys: cmd or module */
357*d29b2c44Sab 			item[i].cmd =
358*d29b2c44Sab 			    elfedit_find_command(argv[i], 0, &item[i].cmd_mod);
359*d29b2c44Sab 			if (item[i].cmd != NULL)
360*d29b2c44Sab 				dispcnt++;
361*d29b2c44Sab 
362*d29b2c44Sab 			/*
363*d29b2c44Sab 			 * Also try to load it as a module. If a command
364*d29b2c44Sab 			 * was found, then this need not succeed. Otherwise,
365*d29b2c44Sab 			 * it has to be a module, and we cause an error
366*d29b2c44Sab 			 * to be issued if not.
367*d29b2c44Sab 			 */
368*d29b2c44Sab 			item[i].mod = elfedit_load_module(argv[i],
369*d29b2c44Sab 			    item[i].cmd == NULL, 0);
370*d29b2c44Sab 			if (item[i].mod != NULL)
371*d29b2c44Sab 				dispcnt++;
372*d29b2c44Sab 		} else if (*(colon + 1) == '\0') {
373*d29b2c44Sab 			/* Just colon: Module (and maybe default command) */
374*d29b2c44Sab 			char buf[ELFEDIT_MAXMODNAM + 1];
375*d29b2c44Sab 			const char *str = argv[i];
376*d29b2c44Sab 			int len = colon - str;
377*d29b2c44Sab 
378*d29b2c44Sab 			item[i].cmd = NULL;
379*d29b2c44Sab 			/* Strip off the colon */
380*d29b2c44Sab 			if (len < sizeof (buf)) {
381*d29b2c44Sab 				(void) strncpy(buf, str, len);
382*d29b2c44Sab 				buf[len] = '\0';
383*d29b2c44Sab 				str = buf;
384*d29b2c44Sab 			}
385*d29b2c44Sab 			item[i].mod = elfedit_load_module(str, 1, 0);
386*d29b2c44Sab 			dispcnt++;
387*d29b2c44Sab 		} else {	/* A command */
388*d29b2c44Sab 			item[i].cmd =
389*d29b2c44Sab 			    elfedit_find_command(argv[i], 1, &item[i].cmd_mod);
390*d29b2c44Sab 			dispcnt++;
391*d29b2c44Sab 			item[i].mod = NULL;
392*d29b2c44Sab 		}
393*d29b2c44Sab 	}
394*d29b2c44Sab 
395*d29b2c44Sab 	/*
396*d29b2c44Sab 	 * Having validated the items, loop over them again and produce
397*d29b2c44Sab 	 * the required help output.
398*d29b2c44Sab 	 */
399*d29b2c44Sab 	for (cur_item = item; argc--; argv++, cur_item++) {
400*d29b2c44Sab 
401*d29b2c44Sab 
402*d29b2c44Sab 		/* Help for a module? */
403*d29b2c44Sab 		if (cur_item->mod != NULL) {
404*d29b2c44Sab 			if (dispcnt > 1)
405*d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_HLPFMT_MULTIHDR),
406*d29b2c44Sab 				    *argv);
407*d29b2c44Sab 			cmd_help_showmod(cur_item->mod);
408*d29b2c44Sab 			if ((dispcnt > 1) && (argc > 0))
409*d29b2c44Sab 				elfedit_printf(MSG_INTL(MSG_HLPFMT_MULTIEND),
410*d29b2c44Sab 				    argv[0], argv[1]);
411*d29b2c44Sab 			/* An empty line after the last line of output */
412*d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
413*d29b2c44Sab 		}
414*d29b2c44Sab 
415*d29b2c44Sab 		/* Help for a command? */
416*d29b2c44Sab 		if (cur_item->cmd == NULL)
417*d29b2c44Sab 			continue;
418*d29b2c44Sab 		cmd = cur_item->cmd;
419*d29b2c44Sab 		mod = cur_item->cmd_mod;
420*d29b2c44Sab 		if (dispcnt > 1)
421*d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_HLPFMT_MULTIHDR), *argv);
422*d29b2c44Sab 
423*d29b2c44Sab 		/* If -s, display quick synopsis rather than the whole thing */
424*d29b2c44Sab 		if (minus_s) {
425*d29b2c44Sab 			cmd_help_synopsis(mod, cmd);
426*d29b2c44Sab 			continue;
427*d29b2c44Sab 		}
428*d29b2c44Sab 
429*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_MOD), mod->mod_name,
430*d29b2c44Sab 		    (* mod->mod_i18nhdl_to_str)(mod->mod_desc));
431*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_NAME),
432*d29b2c44Sab 		    *cmd->cmd_name,
433*d29b2c44Sab 		    (* mod->mod_i18nhdl_to_str)(cmd->cmd_desc));
434*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_SYNOPSIS),
435*d29b2c44Sab 		    elfedit_format_command_usage(mod, cmd,
436*d29b2c44Sab 		    MSG_ORIG(MSG_STR_HLPUSEINDENT),
437*d29b2c44Sab 		    strlen(MSG_ORIG(MSG_STR_HLPINDENT))));
438*d29b2c44Sab 		/* If there are alias names, show them */
439*d29b2c44Sab 		if (cmd->cmd_name[1] != NULL) {
440*d29b2c44Sab 			const char **alias = cmd->cmd_name + 1;
441*d29b2c44Sab 
442*d29b2c44Sab 			elfedit_printf(MSG_INTL(MSG_HLPFMT_ALIASES));
443*d29b2c44Sab 			do {
444*d29b2c44Sab 				elfedit_printf(
445*d29b2c44Sab 				    MSG_ORIG(MSG_STR_HLPINDENT));
446*d29b2c44Sab 				elfedit_printf(
447*d29b2c44Sab 				    MSG_ORIG(MSG_FMT_MODCMD),
448*d29b2c44Sab 				    mod->mod_name, *alias);
449*d29b2c44Sab 				if (**alias == '\0')
450*d29b2c44Sab 					elfedit_printf(
451*d29b2c44Sab 					    MSG_INTL(MSG_HLPFMT_DEFCMD));
452*d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_STR_NL));
453*d29b2c44Sab 				alias++;
454*d29b2c44Sab 			} while (*alias);
455*d29b2c44Sab 		}
456*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_DESC));
457*d29b2c44Sab 		write_help_str(
458*d29b2c44Sab 		    (* mod->mod_i18nhdl_to_str)(cmd->cmd_help),
459*d29b2c44Sab 		    MSG_ORIG(MSG_STR_HLPINDENT));
460*d29b2c44Sab 		if (cmd->cmd_args != NULL)
461*d29b2c44Sab 			write_optarg(mod, MSG_INTL(MSG_HLPFMT_ARGS),
462*d29b2c44Sab 			    cmd->cmd_args);
463*d29b2c44Sab 		if (cmd->cmd_opt != NULL)
464*d29b2c44Sab 			write_optarg(mod, MSG_INTL(MSG_HLPFMT_OPT),
465*d29b2c44Sab 			    cmd->cmd_opt);
466*d29b2c44Sab 		if ((dispcnt > 1) && (argc > 0))
467*d29b2c44Sab 			elfedit_printf(MSG_INTL(MSG_HLPFMT_MULTIEND),
468*d29b2c44Sab 			    argv[0], argv[1]);
469*d29b2c44Sab 		/* An empty line after the last line of output */
470*d29b2c44Sab 		elfedit_printf(MSG_ORIG(MSG_STR_NL));
471*d29b2c44Sab 	}
472*d29b2c44Sab 
473*d29b2c44Sab 	return (ELFEDIT_CMDRET_NONE);
474*d29b2c44Sab 
475*d29b2c44Sab #undef	INITIAL_ITEM_ALLOC
476*d29b2c44Sab }
477*d29b2c44Sab 
478*d29b2c44Sab 
479*d29b2c44Sab /*
480*d29b2c44Sab  * Command completion function for sys:help
481*d29b2c44Sab  */
482*d29b2c44Sab /*ARGSUSED*/
483*d29b2c44Sab static void
484*d29b2c44Sab cpl_help(void *obj_state, void *cpldata, int argc, const char *argv[],
485*d29b2c44Sab     int num_opt)
486*d29b2c44Sab {
487*d29b2c44Sab 	/*
488*d29b2c44Sab 	 * The arguments can be any module or command. Supplying the
489*d29b2c44Sab 	 * commands implicitly supplies the modules too.
490*d29b2c44Sab 	 */
491*d29b2c44Sab 	elfedit_cpl_command(cpldata);
492*d29b2c44Sab }
493*d29b2c44Sab 
494*d29b2c44Sab 
495*d29b2c44Sab /*
496*d29b2c44Sab  * Implementation of sys:load
497*d29b2c44Sab  */
498*d29b2c44Sab /*ARGSUSED*/
499*d29b2c44Sab static elfedit_cmdret_t
500*d29b2c44Sab cmd_load(void *obj_state, int argc, const char *argv[])
501*d29b2c44Sab {
502*d29b2c44Sab 	elfedit_getopt_state_t	getopt_state;
503*d29b2c44Sab 	elfedit_getopt_ret_t	*getopt_ret;
504*d29b2c44Sab 	struct stat		statbuf;
505*d29b2c44Sab 
506*d29b2c44Sab 	elfedit_getopt_init(&getopt_state, &argc, &argv);
507*d29b2c44Sab 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
508*d29b2c44Sab 		switch (getopt_ret->gor_idmask) {
509*d29b2c44Sab 		case SYS_OPT_F_ALL:
510*d29b2c44Sab 			elfedit_load_modpath();
511*d29b2c44Sab 			break;
512*d29b2c44Sab 		}
513*d29b2c44Sab 	}
514*d29b2c44Sab 
515*d29b2c44Sab 	/* For each remaining argument, load them individually */
516*d29b2c44Sab 	for (; argc-- > 0; argv++) {
517*d29b2c44Sab 		/* Is it a directory? Load everything in it */
518*d29b2c44Sab 		if ((stat(*argv, &statbuf) == 0) &&
519*d29b2c44Sab 		    (statbuf.st_mode & S_IFDIR)) {
520*d29b2c44Sab 			elfedit_load_moddir(*argv, 1, 1);
521*d29b2c44Sab 		} else {	/* Not a directory. Normal load */
522*d29b2c44Sab 			(void) elfedit_load_module(*argv, 1, 1);
523*d29b2c44Sab 		}
524*d29b2c44Sab 	}
525*d29b2c44Sab 
526*d29b2c44Sab 	return (0);
527*d29b2c44Sab }
528*d29b2c44Sab 
529*d29b2c44Sab 
530*d29b2c44Sab /*
531*d29b2c44Sab  * Command completion function for sys:load
532*d29b2c44Sab  */
533*d29b2c44Sab /*ARGSUSED*/
534*d29b2c44Sab static void
535*d29b2c44Sab cpl_load(void *obj_state, void *cpldata, int argc, const char *argv[],
536*d29b2c44Sab     int num_opt)
537*d29b2c44Sab {
538*d29b2c44Sab 	/*
539*d29b2c44Sab 	 * Module names. Note that this causes elfedit to load all
540*d29b2c44Sab 	 * of the modules, which probably makes the current load
541*d29b2c44Sab 	 * operation unnecessary. This could be improved, but I don't
542*d29b2c44Sab 	 * see it as worth the complexity. Explicit load calls are
543*d29b2c44Sab 	 * rare, and the user will usually not use command completion.
544*d29b2c44Sab 	 */
545*d29b2c44Sab 	elfedit_cpl_module(cpldata, 1);
546*d29b2c44Sab }
547*d29b2c44Sab 
548*d29b2c44Sab 
549*d29b2c44Sab /*
550*d29b2c44Sab  * Implementation of sys:quit
551*d29b2c44Sab  */
552*d29b2c44Sab /*ARGSUSED*/
553*d29b2c44Sab static elfedit_cmdret_t
554*d29b2c44Sab cmd_quit(void *obj_state, int argc, const char *argv[])
555*d29b2c44Sab {
556*d29b2c44Sab 	elfedit_getopt_state_t	getopt_state;
557*d29b2c44Sab 	elfedit_getopt_ret_t	*getopt_ret;
558*d29b2c44Sab 	int			force = 0;
559*d29b2c44Sab 	const char		*file;
560*d29b2c44Sab 	int			fd;
561*d29b2c44Sab 	Elf			*elf;
562*d29b2c44Sab 
563*d29b2c44Sab 	elfedit_getopt_init(&getopt_state, &argc, &argv);
564*d29b2c44Sab 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
565*d29b2c44Sab 		switch (getopt_ret->gor_idmask) {
566*d29b2c44Sab 		case SYS_OPT_F_FORCE:
567*d29b2c44Sab 			force = 1;
568*d29b2c44Sab 			break;
569*d29b2c44Sab 		}
570*d29b2c44Sab 	}
571*d29b2c44Sab 	if (argc != 0)
572*d29b2c44Sab 		elfedit_command_usage();
573*d29b2c44Sab 
574*d29b2c44Sab 	if (state.file.present) {
575*d29b2c44Sab 		/*
576*d29b2c44Sab 		 * If session is not READONLY, then refuse to quit if file
577*d29b2c44Sab 		 * needs flushing and -f option was not used.
578*d29b2c44Sab 		 */
579*d29b2c44Sab 		if (!(state.flags & ELFEDIT_F_READONLY) && state.file.dirty &&
580*d29b2c44Sab 		    !force)
581*d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
582*d29b2c44Sab 			    MSG_INTL(MSG_ERR_NODIRTYQUIT));
583*d29b2c44Sab 
584*d29b2c44Sab 		get_obj_state_info(obj_state, &file, &fd, &elf);
585*d29b2c44Sab 		(void) close(fd);
586*d29b2c44Sab 		(void) elf_end(elf);
587*d29b2c44Sab 		free(obj_state);
588*d29b2c44Sab 	}
589*d29b2c44Sab 
590*d29b2c44Sab 	elfedit_exit(0);
591*d29b2c44Sab 	/*NOTREACHED*/
592*d29b2c44Sab 	return (0);
593*d29b2c44Sab }
594*d29b2c44Sab 
595*d29b2c44Sab 
596*d29b2c44Sab /*
597*d29b2c44Sab  * Implementation of sys:status
598*d29b2c44Sab  */
599*d29b2c44Sab /*ARGSUSED*/
600*d29b2c44Sab static elfedit_cmdret_t
601*d29b2c44Sab cmd_status(void *obj_state, int argc, const char *argv[])
602*d29b2c44Sab {
603*d29b2c44Sab 	MODLIST_T	*modlist;
604*d29b2c44Sab 	const char	*s;
605*d29b2c44Sab 	size_t		i;
606*d29b2c44Sab 
607*d29b2c44Sab 	if (argc > 0)
608*d29b2c44Sab 		elfedit_command_usage();
609*d29b2c44Sab 
610*d29b2c44Sab 	/*
611*d29b2c44Sab 	 * This command can produce an arbitrary amount of output, so
612*d29b2c44Sab 	 * run a pager.
613*d29b2c44Sab 	 */
614*d29b2c44Sab 	elfedit_pager_init();
615*d29b2c44Sab 
616*d29b2c44Sab 	/* Files */
617*d29b2c44Sab 	if (state.file.present == 0) {
618*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_INFILENONE));
619*d29b2c44Sab 	} else if (state.flags & ELFEDIT_F_READONLY) {
620*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_INFILERO),
621*d29b2c44Sab 		    state.file.infile);
622*d29b2c44Sab 	} else {
623*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_INFILE), state.file.infile);
624*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_OUTFILE),
625*d29b2c44Sab 		    state.file.outfile);
626*d29b2c44Sab 	}
627*d29b2c44Sab 	if (state.file.dirty)
628*d29b2c44Sab 		elfedit_printf(MSG_INTL(MSG_HLPFMT_CNGPENDING));
629*d29b2c44Sab 
630*d29b2c44Sab 	/* Option Variables */
631*d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_HLPFMT_VARHDR));
632*d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_HLPFMT_AFLG),
633*d29b2c44Sab 	    (state.flags & ELFEDIT_F_AUTOPRINT) ? MSG_ORIG(MSG_STR_ON) :
634*d29b2c44Sab 	    MSG_ORIG(MSG_STR_OFF));
635*d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_HLPFMT_DFLG),
636*d29b2c44Sab 	    (state.flags & ELFEDIT_F_DEBUG) ? MSG_ORIG(MSG_STR_ON) :
637*d29b2c44Sab 	    MSG_ORIG(MSG_STR_OFF));
638*d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_HLPFMT_OFLG),
639*d29b2c44Sab 	    elfedit_atoconst_value_to_str(ELFEDIT_CONST_OUTSTYLE,
640*d29b2c44Sab 	    state.outstyle, 1));
641*d29b2c44Sab 
642*d29b2c44Sab 	/* Module Load Path */
643*d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_HLPFMT_PATHHDR));
644*d29b2c44Sab 	for (i = 0; i < state.modpath.n; i++)
645*d29b2c44Sab 		elfedit_printf(MSG_ORIG(MSG_HLPFMT_PATHELT),
646*d29b2c44Sab 		    state.modpath.seg[i]);
647*d29b2c44Sab 
648*d29b2c44Sab 	/* Currently Loaded Modules */
649*d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_HLPFMT_MODHDR));
650*d29b2c44Sab 	for (modlist = state.modlist; modlist;
651*d29b2c44Sab 	    modlist = modlist->ml_next) {
652*d29b2c44Sab 		s = modlist->ml_path ? modlist->ml_path :
653*d29b2c44Sab 		    MSG_INTL(MSG_FMT_BUILTIN);
654*d29b2c44Sab 		elfedit_printf(MSG_ORIG(MSG_HLPFMT_NAMDSCCOL),
655*d29b2c44Sab 		    modlist->ml_mod->mod_name, s);
656*d29b2c44Sab 	}
657*d29b2c44Sab 
658*d29b2c44Sab 	return (ELFEDIT_CMDRET_NONE);
659*d29b2c44Sab }
660*d29b2c44Sab 
661*d29b2c44Sab /*
662*d29b2c44Sab  * Implementation of sys:set
663*d29b2c44Sab  */
664*d29b2c44Sab /*ARGSUSED*/
665*d29b2c44Sab static elfedit_cmdret_t
666*d29b2c44Sab cmd_set(void *obj_state, int argc, const char *argv[])
667*d29b2c44Sab {
668*d29b2c44Sab 	if ((argc != 2) || (strlen(argv[0]) > 1))
669*d29b2c44Sab 		elfedit_command_usage();
670*d29b2c44Sab 
671*d29b2c44Sab 	switch (**argv) {
672*d29b2c44Sab 	case 'a':
673*d29b2c44Sab 	case 'A':
674*d29b2c44Sab 		if (elfedit_atobool(argv[1], MSG_INTL(MSG_SYSSET_A)))
675*d29b2c44Sab 			state.flags |= ELFEDIT_F_AUTOPRINT;
676*d29b2c44Sab 		else
677*d29b2c44Sab 			state.flags &= ~ELFEDIT_F_AUTOPRINT;
678*d29b2c44Sab 		break;
679*d29b2c44Sab 
680*d29b2c44Sab 	case 'd':
681*d29b2c44Sab 	case 'D':
682*d29b2c44Sab 		if (elfedit_atobool(argv[1], MSG_INTL(MSG_SYSSET_D)))
683*d29b2c44Sab 			state.flags |= ELFEDIT_F_DEBUG;
684*d29b2c44Sab 		else
685*d29b2c44Sab 			state.flags &= ~ELFEDIT_F_DEBUG;
686*d29b2c44Sab 		break;
687*d29b2c44Sab 
688*d29b2c44Sab 	case 'o':
689*d29b2c44Sab 	case 'O':
690*d29b2c44Sab 		if (elfedit_atooutstyle(argv[1], &state.outstyle) == 0)
691*d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
692*d29b2c44Sab 			    MSG_INTL(MSG_ERR_BADOSTYLE), argv[1]);
693*d29b2c44Sab 		break;
694*d29b2c44Sab 
695*d29b2c44Sab 	default:
696*d29b2c44Sab 		elfedit_command_usage();
697*d29b2c44Sab 	}
698*d29b2c44Sab 
699*d29b2c44Sab 	return (0);
700*d29b2c44Sab }
701*d29b2c44Sab 
702*d29b2c44Sab 
703*d29b2c44Sab /*
704*d29b2c44Sab  * Command completion function for sys:set
705*d29b2c44Sab  */
706*d29b2c44Sab /*ARGSUSED*/
707*d29b2c44Sab static void
708*d29b2c44Sab cpl_set(void *obj_state, void *cpldata, int argc, const char *argv[],
709*d29b2c44Sab     int num_opt)
710*d29b2c44Sab {
711*d29b2c44Sab 	const char *s;
712*d29b2c44Sab 
713*d29b2c44Sab 	/*
714*d29b2c44Sab 	 * This command doesn't accept options, so num_opt should be
715*d29b2c44Sab 	 * 0. This is a defensive measure, in case that should change.
716*d29b2c44Sab 	 */
717*d29b2c44Sab 	argc -= num_opt;
718*d29b2c44Sab 	argv += num_opt;
719*d29b2c44Sab 
720*d29b2c44Sab 	if ((argc < 1) || (argc > 2))
721*d29b2c44Sab 		return;
722*d29b2c44Sab 
723*d29b2c44Sab 	if (argc == 1) {	/* The first argument is a variable letter */
724*d29b2c44Sab 		elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_A), 1);
725*d29b2c44Sab 		elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_D), 1);
726*d29b2c44Sab 		elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_O), 1);
727*d29b2c44Sab 		elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_W), 1);
728*d29b2c44Sab 		return;
729*d29b2c44Sab 	}
730*d29b2c44Sab 
731*d29b2c44Sab 	/* We're dealing with the second argument, the value */
732*d29b2c44Sab 	s = argv[0];
733*d29b2c44Sab 	if (strlen(s) > 1)	/* One letter variables */
734*d29b2c44Sab 		return;
735*d29b2c44Sab 	switch (*s) {
736*d29b2c44Sab 	case 'a':		/* Booleans */
737*d29b2c44Sab 	case 'A':
738*d29b2c44Sab 	case 'd':
739*d29b2c44Sab 	case 'D':
740*d29b2c44Sab 	case 'w':
741*d29b2c44Sab 	case 'W':
742*d29b2c44Sab 		/* The second argument is a boolean */
743*d29b2c44Sab 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_BOOL);
744*d29b2c44Sab 
745*d29b2c44Sab 		/* The numbers are not symbolic, but we want them in the list */
746*d29b2c44Sab 		elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_0), 1);
747*d29b2c44Sab 		elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_1), 1);
748*d29b2c44Sab 		break;
749*d29b2c44Sab 
750*d29b2c44Sab 	case 'o':		/* Output style */
751*d29b2c44Sab 	case 'O':
752*d29b2c44Sab 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_OUTSTYLE);
753*d29b2c44Sab 		break;
754*d29b2c44Sab 	}
755*d29b2c44Sab }
756*d29b2c44Sab 
757*d29b2c44Sab 
758*d29b2c44Sab /*
759*d29b2c44Sab  * Implementation of sys:unload
760*d29b2c44Sab  */
761*d29b2c44Sab /*ARGSUSED*/
762*d29b2c44Sab static elfedit_cmdret_t
763*d29b2c44Sab cmd_unload(void *obj_state, int argc, const char *argv[])
764*d29b2c44Sab {
765*d29b2c44Sab 	elfedit_getopt_state_t	getopt_state;
766*d29b2c44Sab 	elfedit_getopt_ret_t	*getopt_ret;
767*d29b2c44Sab 	MODLIST_T		*moddef;
768*d29b2c44Sab 	int			do_all = 0;
769*d29b2c44Sab 
770*d29b2c44Sab 	elfedit_getopt_init(&getopt_state, &argc, &argv);
771*d29b2c44Sab 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
772*d29b2c44Sab 		switch (getopt_ret->gor_idmask) {
773*d29b2c44Sab 		case SYS_OPT_F_ALL:
774*d29b2c44Sab 			do_all = 1;
775*d29b2c44Sab 			break;
776*d29b2c44Sab 		}
777*d29b2c44Sab 	}
778*d29b2c44Sab 
779*d29b2c44Sab 	/*
780*d29b2c44Sab 	 * If -a is specified, unload everything except builtins. Don't
781*d29b2c44Sab 	 * allow plain arguments in this case because there is nothing
782*d29b2c44Sab 	 * left to unload after -a.
783*d29b2c44Sab 	 */
784*d29b2c44Sab 	if (do_all) {
785*d29b2c44Sab 		if (argc > 0)
786*d29b2c44Sab 			elfedit_command_usage();
787*d29b2c44Sab 		/*
788*d29b2c44Sab 		 * Until we run out of non-builtin modules, take the first
789*d29b2c44Sab 		 * one from the list and unload it. Each removal alters
790*d29b2c44Sab 		 * the list, so we always start at the beginning, but this
791*d29b2c44Sab 		 * is efficient since we always remove the first available item
792*d29b2c44Sab 		 */
793*d29b2c44Sab 		while (state.modlist != NULL) {
794*d29b2c44Sab 			for (moddef = state.modlist; moddef != NULL;
795*d29b2c44Sab 			    moddef = moddef->ml_next)
796*d29b2c44Sab 				if (moddef->ml_dl_hdl != NULL) break;
797*d29b2c44Sab 
798*d29b2c44Sab 			/* If we made it to the end, then the list is empty */
799*d29b2c44Sab 			if (moddef == NULL)
800*d29b2c44Sab 				break;
801*d29b2c44Sab 
802*d29b2c44Sab 			elfedit_unload_module(moddef->ml_mod->mod_name);
803*d29b2c44Sab 		}
804*d29b2c44Sab 		return (0);
805*d29b2c44Sab 	}
806*d29b2c44Sab 
807*d29b2c44Sab 	/* Unload each module individually */
808*d29b2c44Sab 	for (; argc-- > 0; argv++)
809*d29b2c44Sab 		elfedit_unload_module(*argv);
810*d29b2c44Sab 
811*d29b2c44Sab 	return (0);
812*d29b2c44Sab }
813*d29b2c44Sab 
814*d29b2c44Sab 
815*d29b2c44Sab /*
816*d29b2c44Sab  * Command completion function for sys:unload
817*d29b2c44Sab  */
818*d29b2c44Sab /*ARGSUSED*/
819*d29b2c44Sab static void
820*d29b2c44Sab cpl_unload(void *obj_state, void *cpldata, int argc, const char *argv[],
821*d29b2c44Sab     int num_opt)
822*d29b2c44Sab {
823*d29b2c44Sab 	/*
824*d29b2c44Sab 	 * Module names. Don't allow elfedit to load all the modules,
825*d29b2c44Sab 	 * as the only modules we want to unload are those already
826*d29b2c44Sab 	 * in memory.
827*d29b2c44Sab 	 */
828*d29b2c44Sab 	elfedit_cpl_module(cpldata, 0);
829*d29b2c44Sab }
830*d29b2c44Sab 
831*d29b2c44Sab 
832*d29b2c44Sab /*
833*d29b2c44Sab  * Implementation of sys:write
834*d29b2c44Sab  */
835*d29b2c44Sab /*ARGSUSED2*/
836*d29b2c44Sab static elfedit_cmdret_t
837*d29b2c44Sab cmd_write(void *obj_state, int argc, const char *argv[])
838*d29b2c44Sab {
839*d29b2c44Sab 	const char	*file;
840*d29b2c44Sab 	int		fd;
841*d29b2c44Sab 	Elf		*elf;
842*d29b2c44Sab 
843*d29b2c44Sab 	if (argc != 0)
844*d29b2c44Sab 		elfedit_command_usage();
845*d29b2c44Sab 
846*d29b2c44Sab 	if (state.file.present != 0) {
847*d29b2c44Sab 		if (state.flags & ELFEDIT_F_READONLY)
848*d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
849*d29b2c44Sab 			    MSG_INTL(MSG_ERR_READONLY));
850*d29b2c44Sab 
851*d29b2c44Sab 		get_obj_state_info(obj_state, &file, &fd, &elf);
852*d29b2c44Sab 		if (elf_update(elf, ELF_C_WRITE) == -1)
853*d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_LIBELF),
854*d29b2c44Sab 			    file, MSG_ORIG(MSG_ELF_UPDATE),
855*d29b2c44Sab 			    elf_errmsg(elf_errno()));
856*d29b2c44Sab 
857*d29b2c44Sab 		/*
858*d29b2c44Sab 		 * An update has succeeded for this file, so revoke the need
859*d29b2c44Sab 		 * to unlink it on exit.
860*d29b2c44Sab 		 */
861*d29b2c44Sab 		state.file.unlink_on_exit = 0;
862*d29b2c44Sab 	}
863*d29b2c44Sab 
864*d29b2c44Sab 	return (ELFEDIT_CMDRET_FLUSH);
865*d29b2c44Sab }
866*d29b2c44Sab 
867*d29b2c44Sab 
868*d29b2c44Sab 
869*d29b2c44Sab 
870*d29b2c44Sab 
871*d29b2c44Sab /*ARGSUSED*/
872*d29b2c44Sab MODLIST_T *
873*d29b2c44Sab elfedit_sys_init(elfedit_module_version_t version)
874*d29b2c44Sab {
875*d29b2c44Sab 	/* sys:help */
876*d29b2c44Sab 	static const char *name_help[] = { MSG_ORIG(MSG_SYS_CMD_HELP),
877*d29b2c44Sab 	    MSG_ORIG(MSG_SYS_CMD_HELP_A1), MSG_ORIG(MSG_SYS_CMD_HELP_A2),
878*d29b2c44Sab 	    NULL };
879*d29b2c44Sab 	static elfedit_cmd_optarg_t opt_help[] = {
880*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_S),
881*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_OPTDESC_HELP_S) */
882*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_HELP_S), 0,
883*d29b2c44Sab 		    SYS_OPT_F_SYNOPSIS, 0 },
884*d29b2c44Sab 		{ NULL }
885*d29b2c44Sab 	};
886*d29b2c44Sab 	static elfedit_cmd_optarg_t arg_help[] = {
887*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_ARG),
888*d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_HELP_ARG) */
889*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_HELP_ARG),
890*d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
891*d29b2c44Sab 		{ NULL }
892*d29b2c44Sab 	};
893*d29b2c44Sab 
894*d29b2c44Sab 	/* sys:load */
895*d29b2c44Sab 	static const char *name_load[] = {
896*d29b2c44Sab 	    MSG_ORIG(MSG_SYS_CMD_LOAD), NULL };
897*d29b2c44Sab 	static elfedit_cmd_optarg_t opt_load[] = {
898*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_A),
899*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_OPTDESC_LOAD_A) */
900*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_LOAD_A), 0,
901*d29b2c44Sab 		    SYS_OPT_F_ALL, 0 },
902*d29b2c44Sab 		{ NULL }
903*d29b2c44Sab 	};
904*d29b2c44Sab 	static elfedit_cmd_optarg_t arg_load[] = {
905*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MODNAME),
906*d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_LOAD_MODNAME) */
907*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_LOAD_MODNAME),
908*d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
909*d29b2c44Sab 		{ NULL }
910*d29b2c44Sab 	};
911*d29b2c44Sab 
912*d29b2c44Sab 	/* sys:quit */
913*d29b2c44Sab 	static const char *name_quit[] = { MSG_ORIG(MSG_SYS_CMD_QUIT),
914*d29b2c44Sab 	    MSG_ORIG(MSG_SYS_CMD_QUIT_A1), MSG_ORIG(MSG_SYS_CMD_QUIT_A2),
915*d29b2c44Sab 	    NULL };
916*d29b2c44Sab 	static elfedit_cmd_optarg_t opt_quit[] = {
917*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_F),
918*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_OPTDESC_QUIT_F) */
919*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_QUIT_F), 0,
920*d29b2c44Sab 		    SYS_OPT_F_FORCE, 0 },
921*d29b2c44Sab 		{ NULL }
922*d29b2c44Sab 	};
923*d29b2c44Sab 
924*d29b2c44Sab 	/* sys:status */
925*d29b2c44Sab 	static const char *name_status[] = {
926*d29b2c44Sab 	    MSG_ORIG(MSG_SYS_CMD_STATUS), NULL };
927*d29b2c44Sab 
928*d29b2c44Sab 	/* sys:set */
929*d29b2c44Sab 	static const char *name_set[] = {
930*d29b2c44Sab 	    MSG_ORIG(MSG_SYS_CMD_SET), NULL };
931*d29b2c44Sab 	static elfedit_cmd_optarg_t arg_set[] = {
932*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_OPTION),
933*d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_SET_OPTION) */
934*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_SET_OPTION), 0 },
935*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_VALUE),
936*d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_SET_VALUE) */
937*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_SET_VALUE), 0 },
938*d29b2c44Sab 		{ NULL }
939*d29b2c44Sab 	};
940*d29b2c44Sab 
941*d29b2c44Sab 	/* sys:unload */
942*d29b2c44Sab 	static const char *name_unload[] = {
943*d29b2c44Sab 	    MSG_ORIG(MSG_SYS_CMD_UNLOAD), NULL };
944*d29b2c44Sab 	static elfedit_cmd_optarg_t opt_unload[] = {
945*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_A),
946*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_OPTDESC_UNLOAD_A) */
947*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_UNLOAD_A), 0,
948*d29b2c44Sab 		    SYS_OPT_F_ALL, 0},
949*d29b2c44Sab 		{ NULL }
950*d29b2c44Sab 	};
951*d29b2c44Sab 	static elfedit_cmd_optarg_t arg_unload[] = {
952*d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MODNAME),
953*d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_UNLOAD_MODNAME) */
954*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_UNLOAD_MODNAME),
955*d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
956*d29b2c44Sab 		{ NULL }
957*d29b2c44Sab 	};
958*d29b2c44Sab 
959*d29b2c44Sab 	/* sys:write */
960*d29b2c44Sab 	static const char *name_write[] = { MSG_ORIG(MSG_SYS_CMD_WRITE),
961*d29b2c44Sab 	    MSG_ORIG(MSG_SYS_CMD_WRITE_A1), MSG_ORIG(MSG_SYS_CMD_WRITE_A2),
962*d29b2c44Sab 	    NULL };
963*d29b2c44Sab 
964*d29b2c44Sab 	static elfedit_cmd_t cmds[] = {
965*d29b2c44Sab 		/* sym:help */
966*d29b2c44Sab 		{ (elfedit_cmd_func_t *)cmd_help,
967*d29b2c44Sab 		    (elfedit_cmdcpl_func_t *)cpl_help, name_help,
968*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_DESC_HELP) */
969*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_DESC_HELP),
970*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_HELP_HELP) */
971*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_HELP_HELP),
972*d29b2c44Sab 		    opt_help, arg_help },
973*d29b2c44Sab 
974*d29b2c44Sab 		/* sym:load */
975*d29b2c44Sab 		{ (elfedit_cmd_func_t *)cmd_load,
976*d29b2c44Sab 		    (elfedit_cmdcpl_func_t *)cpl_load, name_load,
977*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_DESC_LOAD) */
978*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_DESC_LOAD),
979*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_HELP_LOAD) */
980*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_HELP_LOAD),
981*d29b2c44Sab 		    opt_load, arg_load },
982*d29b2c44Sab 
983*d29b2c44Sab 		/* sym:quit */
984*d29b2c44Sab 		{ (elfedit_cmd_func_t *)cmd_quit, NULL, name_quit,
985*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_DESC_QUIT) */
986*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_DESC_QUIT),
987*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_HELP_QUIT) */
988*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_HELP_QUIT),
989*d29b2c44Sab 		    opt_quit, NULL },
990*d29b2c44Sab 
991*d29b2c44Sab 		/* sym:status */
992*d29b2c44Sab 		{ (elfedit_cmd_func_t *)cmd_status, NULL, name_status,
993*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_DESC_STATUS) */
994*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_DESC_STATUS),
995*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_HELP_STATUS) */
996*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_HELP_STATUS),
997*d29b2c44Sab 		    NULL, NULL },
998*d29b2c44Sab 
999*d29b2c44Sab 		/* sym:set */
1000*d29b2c44Sab 		{ (elfedit_cmd_func_t *)cmd_set,
1001*d29b2c44Sab 		    (elfedit_cmdcpl_func_t *)cpl_set, name_set,
1002*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_DESC_SET) */
1003*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_DESC_SET),
1004*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_HELP_SET) */
1005*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_HELP_SET),
1006*d29b2c44Sab 		    NULL, arg_set },
1007*d29b2c44Sab 
1008*d29b2c44Sab 		/* sym:unload */
1009*d29b2c44Sab 		{ (elfedit_cmd_func_t *)cmd_unload,
1010*d29b2c44Sab 		    (elfedit_cmdcpl_func_t *)cpl_unload, name_unload,
1011*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_DESC_UNLOAD) */
1012*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_DESC_UNLOAD),
1013*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_HELP_UNLOAD) */
1014*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_HELP_UNLOAD),
1015*d29b2c44Sab 		    opt_unload, arg_unload },
1016*d29b2c44Sab 
1017*d29b2c44Sab 		/* sym:write */
1018*d29b2c44Sab 		{ (elfedit_cmd_func_t *)cmd_write, NULL, name_write,
1019*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_DESC_WRITE) */
1020*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_DESC_WRITE),
1021*d29b2c44Sab 		    /* MSG_INTL(MSG_SYS_HELP_WRITE) */
1022*d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_SYS_HELP_WRITE),
1023*d29b2c44Sab 		    NULL, NULL},
1024*d29b2c44Sab 
1025*d29b2c44Sab 		{ NULL }
1026*d29b2c44Sab 	};
1027*d29b2c44Sab 
1028*d29b2c44Sab 	static elfedit_module_t module = {
1029*d29b2c44Sab 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_SYS),
1030*d29b2c44Sab 	    /* MSG_INTL(MSG_MOD_SYS_DESC) */
1031*d29b2c44Sab 	    ELFEDIT_I18NHDL(MSG_MOD_SYS_DESC),
1032*d29b2c44Sab 	    cmds, mod_i18nhdl_to_str };
1033*d29b2c44Sab 
1034*d29b2c44Sab 	static MODLIST_T moddef = {
1035*d29b2c44Sab 		NULL,		/* next */
1036*d29b2c44Sab 		(elfeditGC_module_t *)&module,	/* Module definition */
1037*d29b2c44Sab 		NULL,		/* Didn't dlopen() it, so NULL handle */
1038*d29b2c44Sab 		NULL		/* Didn't dlopen() it, so no file path */
1039*d29b2c44Sab 	};
1040*d29b2c44Sab 
1041*d29b2c44Sab 	return (&moddef);
1042*d29b2c44Sab }
1043