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