Home | History | Annotate | Download | only in common
      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 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include	<sys/types.h>
     28 #include	<sys/stat.h>
     29 #include	<sys/wait.h>
     30 #include	<stdarg.h>
     31 #include	<fcntl.h>
     32 #include	<stdlib.h>
     33 #include	<stdio.h>
     34 #include	<signal.h>
     35 #include	<dirent.h>
     36 #include	<libelf.h>
     37 #include	<gelf.h>
     38 #include	<conv.h>
     39 #include	<dlfcn.h>
     40 #include	<link.h>
     41 #include	<stdarg.h>
     42 #include	<libgen.h>
     43 #include	<libintl.h>
     44 #include	<locale.h>
     45 #include	<unistd.h>
     46 #include	<errno.h>
     47 #include	<ctype.h>
     48 #include	<limits.h>
     49 #include	<strings.h>
     50 #include	<sgs.h>
     51 #include	"msg.h"
     52 #include	"_elfedit.h"
     53 #include	<debug.h>	/* liblddb */
     54 
     55 
     56 
     57 /*
     58  * Column at which elfedit_format_command_usage() will wrap the
     59  * generated usage string if the wrap argument is True (1).
     60  */
     61 #define	USAGE_WRAP_COL 55
     62 
     63 
     64 
     65 
     66 /*
     67  * Type used to represent a string buffer that can grow as needed
     68  * to hold strings of arbitrary length. The user should declare
     69  * variables of this type sa static. The strbuf_ensure_size() function
     70  * is used to ensure that it has a minimum desired size.
     71  */
     72 typedef struct {
     73 	char *buf;		/* String buffer */
     74 	size_t n;		/* Size of buffer */
     75 } STRBUF;
     76 
     77 
     78 
     79 
     80 /*
     81  * Types used by tokenize_user_cmd() to represent the result of
     82  * spliting a user command into individual tokens.
     83  */
     84 typedef struct {
     85 	char	*tok_str;	/* Token string */
     86 	size_t	tok_len;	/* strlen(str) */
     87 	size_t	tok_line_off;	/* Token offset in original string */
     88 } TOK_ELT;
     89 typedef struct {
     90 	size_t	tokst_cmd_len;	/* Length of original user command, without */
     91 				/*	newline or NULL termination chars */
     92 	size_t	tokst_str_size;	/* Space needed to hold all the resulting */
     93 				/*	tokens, including terminating NULL */
     94 	TOK_ELT	*tokst_buf;	/* The array of tokens */
     95 	size_t	tokst_cnt;	/* # of tokens in array */
     96 	size_t	tokst_bufsize;	/* capacity of array */
     97 } TOK_STATE;
     98 
     99 
    100 
    101 
    102 /* State block used by gettok_init() and gettok() */
    103 typedef struct {
    104 	const char	*gtok_buf;	/* Addr of buffer containing string */
    105 	char		*gtok_cur_buf;	/* Addr withing buffer for next token */
    106 	int		gtok_inc_null_final; /* True if final NULL token used */
    107 	int		gtok_null_seen;	/* True when NULL byte seen */
    108 	TOK_ELT		gtok_last_token; /* Last token parsed */
    109 
    110 } GETTOK_STATE;
    111 
    112 
    113 
    114 
    115 /*
    116  * The elfedit_cpl_*() functions are used for command line completion.
    117  * Currently this uses the tecla library, but to allow for changing the
    118  * library used, we hide all tecla interfaces from our modules. Instead,
    119  * cmd_match_fcn() builds an ELFEDIT_CPL_STATE struct, and we pass the
    120  * address of that struct as an opaque handle to the modules. Since the
    121  * pointer is opaque, the contents of ELFEDIT_CPL_STATE are free to change
    122  * as necessary.
    123  */
    124 typedef struct {
    125 	WordCompletion	*ecpl_cpl;		/* tecla handle */
    126 	const char	*ecpl_line;		/* raw input line */
    127 	int		ecpl_word_start;	/* start offset within line */
    128 	int		ecpl_word_end;		/* offset just past token */
    129 	/*
    130 	 * ecpl_add_mod_colon is a secret handshake between
    131 	 * elfedit_cpl_command() and  elfedit_cpl_add_match(). It adds
    132 	 * ':' to end of matched modules.
    133 	 */
    134 	int		ecpl_add_mod_colon;
    135 	const char	*ecpl_token_str;	/* token being completed */
    136 	size_t		ecpl_token_len;		/* strlen(ecpl_token_str) */
    137 } ELFEDIT_CPL_STATE;
    138 
    139 
    140 
    141 
    142 /* This structure maintains elfedit global state */
    143 STATE_T state;
    144 
    145 
    146 
    147 /*
    148  * Define a pair of static global variables that contain the
    149  * ISA strings that correspond to %i and %I tokens in module search
    150  * paths.
    151  *
    152  *	isa_i_str - The ISA string for the currently running program
    153  *	isa_I_str - For 64-bit programs, the same as isa_i_str. For
    154  *		32-bit programs, an empty string.
    155  */
    156 #ifdef __sparc
    157 #ifdef __sparcv9
    158 static const char *isa_i_str = MSG_ORIG(MSG_ISA_SPARC_64);
    159 static const char *isa_I_str = MSG_ORIG(MSG_ISA_SPARC_64);
    160 #else
    161 static const char *isa_i_str = MSG_ORIG(MSG_ISA_SPARC_32);
    162 static const char *isa_I_str = MSG_ORIG(MSG_STR_EMPTY);
    163 #endif
    164 #endif
    165 
    166 #ifdef __i386
    167 static const char *isa_i_str = MSG_ORIG(MSG_ISA_X86_32);
    168 static const char *isa_I_str = MSG_ORIG(MSG_STR_EMPTY);
    169 #endif
    170 #ifdef __amd64
    171 static const char *isa_i_str = MSG_ORIG(MSG_ISA_X86_64);
    172 static const char *isa_I_str = MSG_ORIG(MSG_ISA_X86_64);
    173 #endif
    174 
    175 
    176 
    177 /* Forward declarations */
    178 static void free_user_cmds(void);
    179 static void elfedit_pager_cleanup(void);
    180 
    181 
    182 
    183 /*
    184  * We supply this function for the msg module
    185  */
    186 const char *
    187 _elfedit_msg(Msg mid)
    188 {
    189 	return (gettext(MSG_ORIG(mid)));
    190 }
    191 
    192 
    193 /*
    194  * Copy at most min(cpsize, dstsize-1) bytes from src into dst,
    195  * truncating src if necessary.  The  result is always null-terminated.
    196  *
    197  * entry:
    198  *	dst - Destination buffer
    199  *	src - Source string
    200  *	dstsize - sizeof(dst)
    201  *
    202  * note:
    203  *	This is similar to strncpy(), but with two modifications:
    204  *	1) You specify the number of characters to copy, not just
    205  *		the size of the destination. Hence, you can copy non-NULL
    206  *		terminated strings.
    207  *	2) The destination is guaranteed to be NULL terminated. strncpy()
    208  *		does not terminate a completely full buffer.
    209  */
    210 static void
    211 elfedit_strnbcpy(char *dst, const char *src, size_t cpsize, size_t dstsize)
    212 {
    213 	if (cpsize >= dstsize)
    214 		cpsize = dstsize - 1;
    215 	if (cpsize > 0)
    216 		(void) strncpy(dst, src, cpsize + 1);
    217 	dst[cpsize] = '\0';
    218 }
    219 
    220 
    221 /*
    222  * Calls exit() on behalf of elfedit.
    223  */
    224 void
    225 elfedit_exit(int status)
    226 {
    227 	if (state.file.present) {
    228 		/* Exiting with unflushed changes pending? Issue debug notice */
    229 		if (state.file.dirty)
    230 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    231 			    MSG_INTL(MSG_DEBUG_DIRTYEXIT));
    232 
    233 		/*
    234 		 * If the edit file is marked for unlink on exit, then
    235 		 * take care of it here.
    236 		 */
    237 		if (state.file.unlink_on_exit) {
    238 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    239 			    MSG_INTL(MSG_DEBUG_UNLINKFILE),
    240 			    state.file.outfile);
    241 			(void) unlink(state.file.outfile);
    242 		}
    243 	}
    244 
    245 	exit(status);
    246 }
    247 
    248 
    249 /*
    250  * Standard message function for elfedit. All user visible
    251  * output, for error or informational reasons, should go through
    252  * this function.
    253  *
    254  * entry:
    255  *	type - Type of message. One of the ELFEDIT_MSG_* values.
    256  *	format, ... - As per the printf() family
    257  *
    258  * exit:
    259  *	The desired message has been output. For informational
    260  *	messages, control returns to the caller. For errors,
    261  *	this routine will terminate execution or strip the execution
    262  *	stack and return control directly to the outer control loop.
    263  *	In either case, the caller will not receive control.
    264  */
    265 /*PRINTFLIKE2*/
    266 void
    267 elfedit_msg(elfedit_msg_t type, const char *format, ...)
    268 {
    269 	typedef enum {			/* What to do after finished */
    270 		DISP_RET = 0,		/* Return to caller */
    271 		DISP_JMP = 1, 		/* if (interactive) longjmp else exit */
    272 		DISP_EXIT = 2		/* exit under all circumstances */
    273 	} DISP;
    274 
    275 	va_list args;
    276 	FILE *stream = stderr;
    277 	DISP disp = DISP_RET;
    278 	int do_output = 1;
    279 	int need_prefix = 1;
    280 
    281 	va_start(args, format);
    282 
    283 	switch (type) {
    284 	case ELFEDIT_MSG_ERR:
    285 	case ELFEDIT_MSG_CMDUSAGE:
    286 		disp = DISP_JMP;
    287 		break;
    288 	case ELFEDIT_MSG_FATAL:
    289 		disp = DISP_EXIT;
    290 		break;
    291 	case ELFEDIT_MSG_USAGE:
    292 		need_prefix = 0;
    293 		break;
    294 	case ELFEDIT_MSG_DEBUG:
    295 		if (!(state.flags & ELFEDIT_F_DEBUG))
    296 			return;
    297 		stream = stdout;
    298 		break;
    299 	case ELFEDIT_MSG_QUIET:
    300 		do_output = 0;
    301 		disp = DISP_JMP;
    302 		break;
    303 	}
    304 
    305 
    306 	/*
    307 	 * If there is a pager process running, we are returning to the
    308 	 * caller, and the output is going to stdout, then let the
    309 	 * pager handle it instead of writing it directly from this process.
    310 	 * That way, the output gets paged along with everything else.
    311 	 *
    312 	 * If there is a pager process running, and we are not returning
    313 	 * to the caller, then end the pager process now, before we generate
    314 	 * any new output. This allows for any text buffered in the pager
    315 	 * pipe to be output before the new stuff.
    316 	 */
    317 	if (state.pager.fptr != NULL) {
    318 		if (disp == DISP_RET) {
    319 			if (stream == stdout)
    320 				stream = state.pager.fptr;
    321 		} else {
    322 			elfedit_pager_cleanup();
    323 		}
    324 	}
    325 
    326 	/*
    327 	 * If this message is coming from within the libtecla command
    328 	 * completion code, call gl_normal_io() to give the library notice.
    329 	 * That function sets the tty back to cooked mode and advances
    330 	 * the cursor to the beginning of the next line so that our output
    331 	 * will appear properly. When we return to the command completion code,
    332 	 * tecla will re-enter raw mode and redraw the current command line.
    333 	 */
    334 	if (state.input.in_tecla)
    335 		(void) gl_normal_io(state.input.gl);
    336 
    337 	if (do_output) {
    338 		if (need_prefix)
    339 			(void) fprintf(stream, MSG_ORIG(MSG_STR_ELFEDIT));
    340 		(void) vfprintf(stream, format, args);
    341 		(void) fflush(stream);
    342 	}
    343 	va_end(args);
    344 
    345 	/*
    346 	 * If this is an error, then we do not return to the caller.
    347 	 * The action taken depends on whether the outer loop has registered
    348 	 * a jump buffer for us or not.
    349 	 */
    350 	if (disp != DISP_RET) {
    351 		if (state.msg_jbuf.active && (disp == DISP_JMP)) {
    352 			/* Free the user command list */
    353 			free_user_cmds();
    354 
    355 			/* Clean up to reflect effect of non-local goto */
    356 			state.input.in_tecla = FALSE;
    357 
    358 			/* Jump to the outer loop to resume */
    359 			siglongjmp(state.msg_jbuf.env, 1);
    360 		} else {
    361 			elfedit_exit(1);
    362 		}
    363 	}
    364 }
    365 
    366 
    367 /*
    368  * Wrapper on elfedit_msg() that issues an error that results from
    369  * a call to libelf.
    370  *
    371  * entry:
    372  *	file - Name of ELF object
    373  *	libelf_rtn_name - Name of routine that was called
    374  *
    375  * exit:
    376  *	An error has been issued that shows the routine called
    377  *	and the libelf error string for it from elf_errmsg().
    378  *	This routine does not return to the caller.
    379  */
    380 void
    381 elfedit_elferr(const char *file, const char *libelf_rtn_name)
    382 {
    383 	const char *errstr = elf_errmsg(elf_errno());
    384 
    385 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_LIBELF), file,
    386 	    libelf_rtn_name, errstr ? errstr : MSG_INTL(MSG_FMT_UNKNOWN));
    387 }
    388 
    389 
    390 /*
    391  * Start an output pager process for elfedit_printf()/elfedit_write() to use.
    392  *
    393  * note:
    394  *	If this elfedit session is not interactive, then no pager is
    395  *	started. Paging is only intended for interactive use. The caller
    396  *	is not supposed to worry about this point, but simply to use
    397  *	this function to flag situations in which paging might be needed.
    398  */
    399 void
    400 elfedit_pager_init(void)
    401 {
    402 	const char	*errstr;
    403 	const char	*cmd;
    404 	int		err;
    405 
    406 	/*
    407 	 * If there is no pager process running, start one.
    408 	 * Only do this for interactive sessions --- elfedit_pager()
    409 	 * won't use a pager in batch mode.
    410 	 */
    411 	if (state.msg_jbuf.active && state.input.full_tty &&
    412 	    (state.pager.fptr == NULL)) {
    413 		/*
    414 		 * If the user has the PAGER environment variable set,
    415 		 * then we will use that program. Otherwise we default
    416 		 * to /bin/more.
    417 		 */
    418 		cmd = getenv(MSG_ORIG(MSG_STR_PAGER));
    419 		if ((cmd == NULL) || (*cmd == '\0'))
    420 			cmd = MSG_ORIG(MSG_STR_BINMORE);
    421 
    422 		/*
    423 		 * The popen() manpage says that on failure, it "may set errno",
    424 		 * which is somewhat ambiguous. We explicitly zero it here, and
    425 		 * assume that any change is due to popen() failing.
    426 		 */
    427 		errno = 0;
    428 		state.pager.fptr = popen(cmd, MSG_ORIG(MSG_STR_W));
    429 		if (state.pager.fptr == NULL) {
    430 			err = errno;
    431 			errstr = (err == 0) ? MSG_INTL(MSG_ERR_UNKNOWNSYSERR) :
    432 			    strerror(err);
    433 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTEXEC),
    434 			    MSG_ORIG(MSG_STR_ELFEDIT), cmd, errstr);
    435 		}
    436 	}
    437 }
    438 
    439 
    440 /*
    441  * If there is a pager process present, close it out.
    442  *
    443  * note:
    444  *	This function is called from within elfedit_msg(), and as
    445  *	such, must not use elfedit_msg() to report errors. Furthermore,
    446  *	any such errors are not a sufficient reason to terminate the process
    447  *	or to longjmp(). This is a rare case where errors are written
    448  *	directly to stderr.
    449  */
    450 static void
    451 elfedit_pager_cleanup(void)
    452 {
    453 	if (state.pager.fptr != NULL) {
    454 		if (pclose(state.pager.fptr) == -1)
    455 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_PAGERFINI));
    456 
    457 		state.pager.fptr = NULL;
    458 	}
    459 }
    460 
    461 
    462 /*
    463  * Print general formtted text for the user, using printf()-style
    464  * formatting. Uses the pager process if one has been started, or
    465  * stdout otherwise.
    466  */
    467 void
    468 elfedit_printf(const char *format, ...)
    469 {
    470 	va_list	args;
    471 	int	err;
    472 	FILE	*fptr;
    473 	int	pager;
    474 	int	broken_pipe = 0;
    475 
    476 	/*
    477 	 * If there is a pager process, then use it. Otherwise write
    478 	 * directly to stdout.
    479 	 */
    480 	pager = (state.pager.fptr != NULL);
    481 	fptr = pager ? state.pager.fptr : stdout;
    482 
    483 	va_start(args, format);
    484 	errno = 0;
    485 	err = vfprintf(fptr, format, args);
    486 
    487 	/* Did we fail because a child pager process has exited? */
    488 	broken_pipe = pager && (err < 0) && (errno == EPIPE);
    489 
    490 	va_end(args);
    491 
    492 	/*
    493 	 * On error, we simply issue the error without cleaning up
    494 	 * the pager process. The message code handles that as a standard
    495 	 * part of error processing.
    496 	 *
    497 	 * We handle failure due to an exited pager process differently
    498 	 * than a normal error, because it is usually due to the user
    499 	 * intentionally telling it to.
    500 	 */
    501 	if (err < 0) {
    502 		if (broken_pipe)
    503 			elfedit_msg(ELFEDIT_MSG_QUIET, MSG_ORIG(MSG_STR_NULL));
    504 		else
    505 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_PRINTF));
    506 	}
    507 }
    508 
    509 
    510 /*
    511  * Some our modules use liblddb routines to format ELF output.
    512  * In order to ensure that such output is sent to the pager pipe
    513  * when there is one, and stdout otherwise, we redefine the dbg_print()
    514  * function here.
    515  *
    516  * This item should be defined NODIRECT.
    517  */
    518 /* PRINTFLIKE2 */
    519 void
    520 dbg_print(Lm_list *lml, const char *format, ...)
    521 {
    522 	va_list	ap;
    523 	int	err;
    524 	FILE	*fptr;
    525 	int	pager;
    526 	int	broken_pipe = 0;
    527 
    528 #if	defined(lint)
    529 	/*
    530 	 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
    531 	 * Supress the lint error by making a dummy assignment.
    532 	 */
    533 	lml = 0;
    534 #endif
    535 
    536 	/*
    537 	 * If there is a pager process, then use it. Otherwise write
    538 	 * directly to stdout.
    539 	 */
    540 	pager = (state.pager.fptr != NULL);
    541 	fptr = pager ? state.pager.fptr : stdout;
    542 
    543 	va_start(ap, format);
    544 	errno = 0;
    545 	err = vfprintf(fptr, format, ap);
    546 	if (err >= 0)
    547 		err = fprintf(fptr, MSG_ORIG(MSG_STR_NL));
    548 
    549 	/* Did we fail because a child pager process has exited? */
    550 	broken_pipe = (err < 0) && pager && (errno == EPIPE);
    551 
    552 	va_end(ap);
    553 
    554 	/*
    555 	 * On error, we simply issue the error without cleaning up
    556 	 * the pager process. The message code handles that as a standard
    557 	 * part of error processing.
    558 	 *
    559 	 * We handle failure due to an exited pager process differently
    560 	 * than a normal error, because it is usually due to the user
    561 	 * intentionally telling it to.
    562 	 */
    563 	if (err < 0) {
    564 		if (broken_pipe)
    565 			elfedit_msg(ELFEDIT_MSG_QUIET, MSG_ORIG(MSG_STR_NULL));
    566 		else
    567 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_PRINTF));
    568 	}
    569 }
    570 
    571 
    572 /*
    573  * Write raw bytes of text in a manner similar to fwrite().
    574  * Uses the pager process if one has been started, or
    575  * stdout otherwise.
    576  */
    577 void
    578 elfedit_write(const void *ptr, size_t size)
    579 {
    580 	FILE	*fptr;
    581 	int	err;
    582 
    583 	/*
    584 	 * If there is a pager process, then use it. Otherwise write
    585 	 * directly to stdout.
    586 	 */
    587 	fptr = (state.pager.fptr == NULL) ? stdout : state.pager.fptr;
    588 
    589 	if (fwrite(ptr, 1, size, fptr) != size) {
    590 		err = errno;
    591 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_FWRITE),
    592 		    strerror(err));
    593 	}
    594 }
    595 
    596 
    597 /*
    598  * Convert the NULL terminated string to the form used by the C
    599  * language to represent literal strings. See conv_str_to_c_literal()
    600  * for details.
    601  *
    602  * This routine differs from conv_str_to_c_literal() in two ways:
    603  *	1) String is NULL terminated instead of counted
    604  *	2) Signature of outfunc
    605  *
    606  * entry:
    607  *	str - String to be processed
    608  *	outfunc - Function to be called to move output characters. Note
    609  *		that this function has the same signature as elfedit_write(),
    610  *		and that function can be used to write the characters to
    611  *		the output.
    612  *
    613  * exit:
    614  *	The string has been processed, with the resulting data passed
    615  *	to outfunc for processing.
    616  */
    617 static void
    618 elfedit_str_to_c_literal_cb(const void *ptr, size_t size, void *uvalue)
    619 {
    620 	elfedit_write_func_t *outfunc = (elfedit_write_func_t *)uvalue;
    621 
    622 	(* outfunc)(ptr, size);
    623 
    624 }
    625 void
    626 elfedit_str_to_c_literal(const char *str, elfedit_write_func_t *outfunc)
    627 {
    628 	conv_str_to_c_literal(str, strlen(str),
    629 	    elfedit_str_to_c_literal_cb, (void *) outfunc);
    630 }
    631 
    632 
    633 /*
    634  * Wrappers on malloc() and realloc() that check the result for success
    635  * and issue an error if not. The caller can use the result of these
    636  * functions without checking for a NULL pointer, as we do not return to
    637  * the caller in the failure case.
    638  */
    639 void *
    640 elfedit_malloc(const char *item_name, size_t size)
    641 {
    642 	void *m;
    643 
    644 	m = malloc(size);
    645 	if (m == NULL) {
    646 		int err = errno;
    647 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_MALLOC),
    648 		    item_name, strerror(err));
    649 	}
    650 
    651 	return (m);
    652 }
    653 
    654 void *
    655 elfedit_realloc(const char *item_name, void *ptr, size_t size)
    656 {
    657 	void *m;
    658 
    659 	m = realloc(ptr, size);
    660 	if (m == NULL) {
    661 		int err = errno;
    662 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_MALLOC),
    663 		    item_name, strerror(err));
    664 	}
    665 
    666 	return (m);
    667 }
    668 
    669 
    670 /*
    671  * Ensure that the given buffer has room for n bytes of data.
    672  */
    673 static void
    674 strbuf_ensure_size(STRBUF *str, size_t size)
    675 {
    676 #define	INITIAL_STR_ALLOC 128
    677 
    678 	size_t n;
    679 
    680 	n = (str->n == 0) ? INITIAL_STR_ALLOC : str->n;
    681 	while (size > n)	/* Double buffer until string fits */
    682 		n *= 2;
    683 	if (n != str->n) {		/* Alloc new string buffer if needed */
    684 		str->buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_UCMDSTR),
    685 		    str->buf, n);
    686 		str->n = n;
    687 	}
    688 
    689 #undef	INITIAL_STR_ALLOC
    690 }
    691 
    692 
    693 /*
    694  * Extract the argument/option information for the next item referenced
    695  * by optarg, and advance the pointer to the next item.
    696  *
    697  * entry:
    698  *	optarg - Address of pointer to argument or option array
    699  *	item - Struct to be filled in.
    700  *
    701  * exit:
    702  *	The item block has been filled in with the information for
    703  *	the next item in the optarg array. *optarg has been advanced
    704  *	to the next item.
    705  */
    706 void
    707 elfedit_next_optarg(elfedit_cmd_optarg_t **optarg, elfedit_optarg_item_t *item)
    708 {
    709 	/*
    710 	 * Array of inheritable options/arguments. Indexed by one less
    711 	 * than the corresponding ELFEDIT_STDOA_ value.
    712 	 */
    713 	static const elfedit_optarg_item_t stdoa[] = {
    714 		/* ELFEDIT_STDOA_O */
    715 		{ MSG_ORIG(MSG_STR_MINUS_O), MSG_ORIG(MSG_STR_OUTSTYLE),
    716 		    /* MSG_INTL(MSG_STDOA_OPTDESC_O) */
    717 		    (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_O,
    718 		    ELFEDIT_CMDOA_F_VALUE },
    719 
    720 		/* ELFEDIT_STDOA_AND */
    721 		{ MSG_ORIG(MSG_STR_MINUS_AND), NULL,
    722 		    /* MSG_INTL(MSG_STDOA_OPTDESC_AND) */
    723 		    (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_AND, 0 },
    724 
    725 		/* ELFEDIT_STDOA_CMP */
    726 		{ MSG_ORIG(MSG_STR_MINUS_CMP), NULL,
    727 		    /* MSG_INTL(MSG_STDOA_OPTDESC_CMP) */
    728 		    (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_CMP, 0 },
    729 
    730 		/* ELFEDIT_STDOA_OR */
    731 		{ MSG_ORIG(MSG_STR_MINUS_OR), NULL,
    732 		    /* MSG_INTL(MSG_STDOA_OPTDESC_OR) */
    733 		    (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_OR, 0 },
    734 	};
    735 
    736 	elfedit_cmd_optarg_t *oa;
    737 
    738 
    739 	/* Grab first item, advance the callers pointer over it */
    740 	oa = (*optarg)++;
    741 
    742 	if (oa->oa_flags & ELFEDIT_CMDOA_F_INHERIT) {
    743 		/* Values are pre-chewed in the stdoa array above */
    744 		*item = stdoa[((uintptr_t)oa->oa_name) - 1];
    745 
    746 		/*
    747 		 * Set the inherited flag so that elfedit_optarg_helpstr()
    748 		 * can tell who is responsible for translating the help string.
    749 		 */
    750 		item->oai_flags |= ELFEDIT_CMDOA_F_INHERIT;
    751 	} else {	/* Non-inherited item */
    752 		item->oai_name = oa->oa_name;
    753 		if ((oa->oa_flags & ELFEDIT_CMDOA_F_VALUE) != 0) {
    754 			item->oai_vname = oa[1].oa_name;
    755 
    756 			/* Advance users pointer past value element */
    757 			(*optarg)++;
    758 		} else {
    759 			item->oai_vname = NULL;
    760 		}
    761 		item->oai_help = oa->oa_help;
    762 		item->oai_flags = oa->oa_flags;
    763 	}
    764 
    765 	/*
    766 	 * The module determines the idmask and excmask fields whether
    767 	 * or not inheritance is in play.
    768 	 */
    769 	item->oai_idmask = oa->oa_idmask;
    770 	item->oai_excmask = oa->oa_excmask;
    771 }
    772 
    773 
    774 
    775 /*
    776  * Return the help string for an option/argument item, as returned
    777  * by elfedit_next_optarg(). This routine handles the details of
    778  * knowing whether the string is provided by elfedit itself (inherited),
    779  * or needs to be translated by the module.
    780  */
    781 const char *
    782 elfedit_optarg_helpstr(elfeditGC_module_t *mod, elfedit_optarg_item_t *item)
    783 {
    784 	/*
    785 	 * The help string from an inherited item comes right out
    786 	 * of the main elfedit string table.
    787 	 */
    788 	if (item->oai_flags & ELFEDIT_CMDOA_F_INHERIT)
    789 		return (MSG_INTL((Msg) item->oai_help));
    790 
    791 	/*
    792 	 * If the string is defined by the module, then we need to
    793 	 * have the module translate it for us.
    794 	 */
    795 	return ((* mod->mod_i18nhdl_to_str)(item->oai_help));
    796 }
    797 
    798 
    799 
    800 /*
    801  * Used by usage_optarg() to insert a character into the output buffer,
    802  * advancing the buffer pointer and current column, and reducing the
    803  * amount of remaining space.
    804  */
    805 static void
    806 usage_optarg_insert_ch(int ch, char **cur, size_t *n, size_t *cur_col)
    807 {
    808 
    809 	*(*cur)++ = ch;
    810 	**cur = '\0';
    811 	(*n)--;
    812 	(*cur_col)++;
    813 }
    814 
    815 /*
    816  * Used by usage_optarg() to insert a string into the output
    817  * buffer, advancing the buffer pointer and current column, and reducing
    818  * the amount of remaining space.
    819  */
    820 static void
    821 usage_optarg_insert_str(char **cur, size_t *n, size_t *cur_col,
    822     const char *format, ...)
    823 {
    824 	size_t len;
    825 	va_list args;
    826 
    827 	va_start(args, format);
    828 	len = vsnprintf(*cur, *n, format, args);
    829 	va_end(args);
    830 
    831 	*cur += len;
    832 	*n -= len;
    833 	*cur_col += len;
    834 }
    835 /*
    836  * Used by usage_optarg() to insert an optarg item string into the output
    837  * buffer, advancing the buffer pointer and current column, and reducing
    838  * the amount of remaining space.
    839  */
    840 static void
    841 usage_optarg_insert_item(elfedit_optarg_item_t *item, char **cur,
    842     size_t *n, size_t *cur_col)
    843 {
    844 	size_t len;
    845 
    846 	if (item->oai_flags & ELFEDIT_CMDOA_F_VALUE) {
    847 		len = snprintf(*cur, *n, MSG_ORIG(MSG_STR_HLPOPTARG2),
    848 		    item->oai_name, item->oai_vname);
    849 	} else {
    850 		len = snprintf(*cur, *n, MSG_ORIG(MSG_STR_HLPOPTARG),
    851 		    item->oai_name);
    852 	}
    853 	*cur += len;
    854 	*n -= len;
    855 	*cur_col += len;
    856 }
    857 
    858 
    859 
    860 /*
    861  * Write the options/arguments to the usage string.
    862  *
    863  * entry:
    864  *	main_buf_n - Size of main buffer from which buf and buf_n are
    865  *		allocated.
    866  *	buf - Address of pointer to where next item is to be placed.
    867  *	buf_n - Address of count of remaining bytes in buffer
    868  *	buf_cur_col - Address of current output column for current line
    869  *		of generated string.
    870  *	optarg - Options list
    871  *	isopt - True if these are options, false for arguments.
    872  *	wrap_str - String to indent wrapped lines. If NULL, lines
    873  *		are not wrapped
    874  */
    875 static void
    876 usage_optarg(size_t main_buf_n, char **buf, size_t *buf_n, size_t *buf_cur_col,
    877     elfedit_cmd_optarg_t *optarg, int isopt, const char *wrap_str)
    878 {
    879 	/*
    880 	 * An option can be combined into a simple format if it lacks
    881 	 * these flags and is only one character in length.
    882 	 */
    883 	static const elfedit_cmd_oa_flag_t exflags =
    884 	    (ELFEDIT_CMDOA_F_VALUE | ELFEDIT_CMDOA_F_MULT);
    885 
    886 	/*
    887 	 * A static buffer, which is grown as needed to accomodate
    888 	 * the maximum usage string seen.
    889 	 */
    890 	static STRBUF simple_str;
    891 
    892 	char			*cur = *buf;
    893 	size_t			n = *buf_n;
    894 	size_t			cur_col = *buf_cur_col;
    895 	int			len;
    896 	int			use_simple = 0;
    897 	elfedit_optarg_item_t	item;
    898 	elfedit_cmd_oa_mask_t	optmask = 0;
    899 	int			use_bkt;
    900 
    901 	/*
    902 	 * If processing options, pull the 1-character ones that don't have
    903 	 * an associated value and don't have any mutual exclusion issues into
    904 	 * a single combination string to go at the beginning of the usage.
    905 	 */
    906 	if (isopt) {
    907 		elfedit_cmd_optarg_t *tmp_optarg = optarg;
    908 		char *s;
    909 
    910 		/*
    911 		 * The simple string is guaranteed to fit in the same
    912 		 * amount of space reserved for the main buffer.
    913 		 */
    914 		strbuf_ensure_size(&simple_str, main_buf_n);
    915 		s = simple_str.buf;
    916 		*s++ = ' ';
    917 		*s++ = '[';
    918 		*s++ = '-';
    919 		while (tmp_optarg->oa_name != NULL) {
    920 			elfedit_next_optarg(&tmp_optarg, &item);
    921 			if (((item.oai_flags & exflags) == 0) &&
    922 			    (item.oai_name[2] == '\0') &&
    923 			    (item.oai_excmask == 0)) {
    924 				optmask |= item.oai_idmask;
    925 				*s++ = item.oai_name[1];
    926 			}
    927 		}
    928 
    929 		/*
    930 		 * If we found more than one, then finish the string and
    931 		 * add it. Don't do this for a single option, because
    932 		 * it looks better in that case if the option shows up
    933 		 * in alphabetical order rather than being hoisted.
    934 		 */
    935 		use_simple = (s > (simple_str.buf + 4));
    936 		if (use_simple) {
    937 			*s++ = ']';
    938 			*s++ = '\0';
    939 			usage_optarg_insert_str(&cur, &n, &cur_col,
    940 			    MSG_ORIG(MSG_STR_HLPOPTARG), simple_str.buf);
    941 		} else {
    942 			/* Not using it, so reset the cumulative options mask */
    943 			optmask = 0;
    944 		}
    945 	}
    946 
    947 	while (optarg->oa_name != NULL) {
    948 		elfedit_next_optarg(&optarg, &item);
    949 
    950 		if (isopt) {
    951 			/*
    952 			 * If this is an option that was pulled into the
    953 			 * combination string above, then skip over it.
    954 			 */
    955 			if (use_simple && ((item.oai_flags & exflags) == 0) &&
    956 			    (item.oai_name[2] == '\0') &&
    957 			    (item.oai_excmask == 0))
    958 				continue;
    959 
    960 			/*
    961 			 * If this is a mutual exclusion option that was
    962 			 * picked up out of order by a previous iteration
    963 			 * of this loop, then skip over it.
    964 			 */
    965 			if ((optmask & item.oai_idmask) != 0)
    966 				continue;
    967 
    968 			/* Add this item to the accumulating options mask */
    969 			optmask |= item.oai_idmask;
    970 		}
    971 
    972 		/* Wrap line, or insert blank separator */
    973 		if ((wrap_str != NULL) && (cur_col > USAGE_WRAP_COL)) {
    974 			len = snprintf(cur, n, MSG_ORIG(MSG_FMT_WRAPUSAGE),
    975 			    wrap_str);
    976 			cur += len;
    977 			n -= len;
    978 			cur_col = len - 1;   /* Don't count the newline */
    979 		} else {
    980 			usage_optarg_insert_ch(' ', &cur, &n, &cur_col);
    981 		}
    982 
    983 		use_bkt = (item.oai_flags & ELFEDIT_CMDOA_F_OPT) || isopt;
    984 		if (use_bkt)
    985 			usage_optarg_insert_ch('[', &cur, &n, &cur_col);
    986 
    987 		/* Add the item to the buffer */
    988 		usage_optarg_insert_item(&item, &cur, &n, &cur_col);
    989 
    990 		/*
    991 		 * If this item has a non-zero mutual exclusion mask,
    992 		 * then look for the other items and display them all
    993 		 * together with alternation (|). Note that plain arguments
    994 		 * cannot have a non-0 exclusion mask, so this is
    995 		 * effectively options-only (isopt != 0).
    996 		 */
    997 		if (item.oai_excmask != 0) {
    998 			elfedit_cmd_optarg_t *tmp_optarg = optarg;
    999 			elfedit_optarg_item_t tmp_item;
   1000 
   1001 			/*
   1002 			 * When showing alternation, elipses for multiple
   1003 			 * copies need to appear inside the [] brackets.
   1004 			 */
   1005 			if (item.oai_flags & ELFEDIT_CMDOA_F_MULT)
   1006 				usage_optarg_insert_str(&cur, &n, &cur_col,
   1007 				    MSG_ORIG(MSG_STR_ELIPSES));
   1008 
   1009 
   1010 			while (tmp_optarg->oa_name != NULL) {
   1011 				elfedit_next_optarg(&tmp_optarg, &tmp_item);
   1012 				if ((item.oai_excmask & tmp_item.oai_idmask) ==
   1013 				    0)
   1014 					continue;
   1015 				usage_optarg_insert_str(&cur, &n, &cur_col,
   1016 				    MSG_ORIG(MSG_STR_SP_BAR_SP));
   1017 				usage_optarg_insert_item(&tmp_item,
   1018 				    &cur, &n, &cur_col);
   1019 
   1020 				/*
   1021 				 * Add it to the mask of seen options.
   1022 				 * This will keep us from showing it twice.
   1023 				 */
   1024 				optmask |= tmp_item.oai_idmask;
   1025 			}
   1026 		}
   1027 		if (use_bkt)
   1028 			usage_optarg_insert_ch(']', &cur, &n, &cur_col);
   1029 
   1030 		/*
   1031 		 * If alternation was not shown above (non-zero exclusion mask)
   1032 		 * then the elipses for multiple copies are shown outside
   1033 		 * any [] brackets.
   1034 		 */
   1035 		if ((item.oai_excmask == 0) &&
   1036 		    (item.oai_flags & ELFEDIT_CMDOA_F_MULT))
   1037 			usage_optarg_insert_str(&cur, &n, &cur_col,
   1038 			    MSG_ORIG(MSG_STR_ELIPSES));
   1039 
   1040 	}
   1041 
   1042 	*buf = cur;
   1043 	*buf_n = n;
   1044 	*buf_cur_col = cur_col;
   1045 }
   1046 
   1047 
   1048 
   1049 /*
   1050  * Format the usage string for a command into a static buffer and
   1051  * return the pointer to the user. The resultant string is valid
   1052  * until the next call to this routine, and which point it
   1053  * will be overwritten or the memory is freed.
   1054  *
   1055  * entry:
   1056  *	mod, cmd - Module and command definitions for command to be described
   1057  *	wrap_str - NULL, or string to be used to indent when
   1058  *		lines are wrapped. If NULL, no wrapping is done, and
   1059  *		all output is on a single line.
   1060  *	cur_col - Starting column at which the string will be displayed.
   1061  *		Ignored if wrap_str is NULL.
   1062  */
   1063 const char *
   1064 elfedit_format_command_usage(elfeditGC_module_t *mod, elfeditGC_cmd_t *cmd,
   1065     const char *wrap_str, size_t cur_col)
   1066 {
   1067 
   1068 	/*
   1069 	 * A static buffer, which is grown as needed to accomodate
   1070 	 * the maximum usage string seen.
   1071 	 */
   1072 	static STRBUF str;
   1073 
   1074 	elfedit_cmd_optarg_t	*optarg;
   1075 	size_t			len, n, elipses_len;
   1076 	char			*cur;
   1077 	elfedit_optarg_item_t	item;
   1078 
   1079 	/*
   1080 	 * Estimate a worst case size for the usage string:
   1081 	 *	- module name
   1082 	 *	- lengths of the strings
   1083 	 *	- every option or argument is enclosed in brackets
   1084 	 *	- space in between each item, with an alternation (" | ")
   1085 	 *	- elipses will be displayed with each option and argument
   1086 	 */
   1087 	n = strlen(mod->mod_name) + strlen(cmd->cmd_name[0]) + 6;
   1088 	elipses_len = strlen(MSG_ORIG(MSG_STR_ELIPSES));
   1089 	if ((optarg = cmd->cmd_opt) != NULL)
   1090 		while (optarg->oa_name != NULL) {
   1091 			elfedit_next_optarg(&optarg, &item);
   1092 			n += strlen(item.oai_name) + 5 + elipses_len;
   1093 		}
   1094 	if ((optarg = cmd->cmd_args) != NULL)
   1095 		while (optarg->oa_name != NULL) {
   1096 			elfedit_next_optarg(&optarg, &item);
   1097 			n += strlen(item.oai_name) + 5 + elipses_len;
   1098 		}
   1099 	n++;			/* Null termination */
   1100 
   1101 	/*
   1102 	 * If wrapping lines, we insert a newline and then wrap_str
   1103 	 * every USAGE_WRAP_COL characters.
   1104 	 */
   1105 	if (wrap_str != NULL)
   1106 		n += ((n + USAGE_WRAP_COL) / USAGE_WRAP_COL) *
   1107 		    (strlen(wrap_str) + 1);
   1108 
   1109 	strbuf_ensure_size(&str, n);
   1110 
   1111 	/* Command name */
   1112 	cur = str.buf;
   1113 	n = str.n;
   1114 	if (strcmp(mod->mod_name, MSG_ORIG(MSG_MOD_SYS)) == 0)
   1115 		len = snprintf(cur, n, MSG_ORIG(MSG_FMT_SYSCMD),
   1116 		    cmd->cmd_name[0]);
   1117 	else
   1118 		len = snprintf(cur, n, MSG_ORIG(MSG_FMT_MODCMD),
   1119 		    mod->mod_name, cmd->cmd_name[0]);
   1120 	cur += len;
   1121 	n -= len;
   1122 	cur_col += len;
   1123 
   1124 	if (cmd->cmd_opt != NULL)
   1125 		usage_optarg(str.n, &cur, &n, &cur_col, cmd->cmd_opt,
   1126 		    1, wrap_str);
   1127 	if (cmd->cmd_args != NULL)
   1128 		usage_optarg(str.n, &cur, &n, &cur_col, cmd->cmd_args,
   1129 		    0, wrap_str);
   1130 
   1131 	return (str.buf);
   1132 }
   1133 
   1134 /*
   1135  * Wrapper on elfedit_msg() that issues an ELFEDIT_MSG_USAGE
   1136  * error giving usage information for the command currently
   1137  * referenced by state.cur_cmd.
   1138  */
   1139 void
   1140 elfedit_command_usage(void)
   1141 {
   1142 	elfedit_msg(ELFEDIT_MSG_CMDUSAGE, MSG_INTL(MSG_USAGE_CMD),
   1143 	    elfedit_format_command_usage(state.cur_cmd->ucmd_mod,
   1144 	    state.cur_cmd->ucmd_cmd, NULL, 0));
   1145 }
   1146 
   1147 
   1148 /*
   1149  * This function allows the loadable modules to get the command line
   1150  * flags.
   1151  */
   1152 elfedit_flag_t
   1153 elfedit_flags(void)
   1154 {
   1155 	return (state.flags);
   1156 }
   1157 
   1158 /*
   1159  * This function is used to register a per-command invocation output style
   1160  * that will momentarily override the global output style for the duration
   1161  * of the current command. This function must only be called by an
   1162  * active command.
   1163  *
   1164  * entry:
   1165  *	str - One of the valid strings for the output style
   1166  */
   1167 void
   1168 elfedit_set_cmd_outstyle(const char *str)
   1169 {
   1170 	if ((state.cur_cmd != NULL) && (str != NULL)) {
   1171 		if (elfedit_atooutstyle(str, &state.cur_cmd->ucmd_ostyle) == 0)
   1172 			elfedit_msg(ELFEDIT_MSG_ERR,
   1173 			    MSG_INTL(MSG_ERR_BADOSTYLE), str);
   1174 		state.cur_cmd->ucmd_ostyle_set = 1;
   1175 	}
   1176 }
   1177 
   1178 /*
   1179  * This function allows the loadable modules to get the output style.
   1180  */
   1181 elfedit_outstyle_t
   1182 elfedit_outstyle(void)
   1183 {
   1184 	/*
   1185 	 * If there is an active  per-command output style,
   1186 	 * return it.
   1187 	 */
   1188 	if ((state.cur_cmd != NULL) && (state.cur_cmd->ucmd_ostyle_set))
   1189 		return (state.cur_cmd->ucmd_ostyle);
   1190 
   1191 
   1192 	return (state.outstyle);
   1193 }
   1194 
   1195 /*
   1196  * Return the command descriptor of the currently executing command.
   1197  * For use only by the modules or code called by the modules.
   1198  */
   1199 elfeditGC_cmd_t *
   1200 elfedit_curcmd(void)
   1201 {
   1202 	return (state.cur_cmd->ucmd_cmd);
   1203 }
   1204 
   1205 /*
   1206  * Build a dynamically allocated elfedit_obj_state_t struct that
   1207  * contains a cache of the ELF file contents. This pre-chewed form
   1208  * is fed to each command, reducing the amount of ELF boilerplate
   1209  * code each command needs to contain.
   1210  *
   1211  * entry:
   1212  *	file - Name of file to process
   1213  *
   1214  * exit:
   1215  *	Fills state.elf with the necessary information for the open file.
   1216  *
   1217  * note: The resulting elfedit_obj_state_t is allocated from a single
   1218  *	piece of memory, such that a single call to free() suffices
   1219  *	to release it as well as any memory it references.
   1220  */
   1221 static void
   1222 init_obj_state(const char *file)
   1223 {
   1224 	int	fd;
   1225 	Elf	*elf;
   1226 	int	open_flag;
   1227 
   1228 	/*
   1229 	 * In readonly mode, we open the file readonly so that it is
   1230 	 * impossible to modify the file by accident. This also allows
   1231 	 * us to access readonly files, perhaps in a case where we don't
   1232 	 * intend to change it.
   1233 	 *
   1234 	 * We always use ELF_C_RDWR with elf_begin(), even in a readonly
   1235 	 * session. This allows us to modify the in-memory image, which
   1236 	 * can be useful when examining a file, even though we don't intend
   1237 	 * to modify the on-disk data. The file is not writable in
   1238 	 * this case, and we don't call elf_update(), so it is safe to do so.
   1239 	 */
   1240 	open_flag = ((state.flags & ELFEDIT_F_READONLY) ? O_RDONLY : O_RDWR);
   1241 	if ((fd = open(file, open_flag)) == -1) {
   1242 		int err = errno;
   1243 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTOPNFILE),
   1244 		    file, strerror(err));
   1245 	}
   1246 	(void) elf_version(EV_CURRENT);
   1247 	elf = elf_begin(fd, ELF_C_RDWR, NULL);
   1248 	if (elf == NULL) {
   1249 		(void) close(fd);
   1250 		elfedit_elferr(file, MSG_ORIG(MSG_ELF_BEGIN));
   1251 		/*NOTREACHED*/
   1252 	}
   1253 
   1254 	/* We only handle standalone ELF files */
   1255 	switch (elf_kind(elf)) {
   1256 	case ELF_K_AR:
   1257 		(void) close(fd);
   1258 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOAR), file);
   1259 		break;
   1260 	case ELF_K_ELF:
   1261 		break;
   1262 	default:
   1263 		(void) close(fd);
   1264 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_UNRECELFFILE),
   1265 		    file);
   1266 		break;
   1267 	}
   1268 
   1269 	/*
   1270 	 * Tell libelf that we take responsibility for object layout.
   1271 	 * Otherwise, it will compute "proper" values for layout and
   1272 	 * alignment fields, and these values can overwrite the values
   1273 	 * set in the elfedit session. We are modifying existing
   1274 	 * objects --- the layout concerns have already been dealt
   1275 	 * with when the object was built.
   1276 	 */
   1277 	(void) elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT);
   1278 
   1279 	/* Fill in state.elf.obj_state */
   1280 	state.elf.elfclass = gelf_getclass(elf);
   1281 	switch (state.elf.elfclass) {
   1282 	case ELFCLASS32:
   1283 		elfedit32_init_obj_state(file, fd, elf);
   1284 		break;
   1285 	case ELFCLASS64:
   1286 		elfedit64_init_obj_state(file, fd, elf);
   1287 		break;
   1288 	default:
   1289 		(void) close(fd);
   1290 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADELFCLASS),
   1291 		    file);
   1292 		break;
   1293 	}
   1294 }
   1295 
   1296 
   1297 #ifdef DEBUG_MODULE_LIST
   1298 /*
   1299  * Debug routine. Dump the module list to stdout.
   1300  */
   1301 static void
   1302 dbg_module_list(char *title)
   1303 {
   1304 	MODLIST_T *m;
   1305 
   1306 	printf("<MODULE LIST: %s>\n", title);
   1307 	for (m = state.modlist; m != NULL; m = m->next) {
   1308 		printf("Module: >%s<\n", m->mod->mod_name);
   1309 		printf("    hdl:  %llx\n", m->dl_hdl);
   1310 		printf("    path: >%s<\n", m->path ? m->path : "<builtin>");
   1311 	}
   1312 	printf("<END OF MODULE LIST>\n");
   1313 }
   1314 #endif
   1315 
   1316 
   1317 /*
   1318  * Search the module list for the named module.
   1319  *
   1320  * entry:
   1321  *	name - Name of module to find
   1322  *	insdef - Address of variable to receive address of predecessor
   1323  *		node to the desired one.
   1324  *
   1325  * exit:
   1326  *	If the module is it is found, this routine returns the pointer to
   1327  *	its MODLIST_T structure. *insdef references the predecessor node, or
   1328  *	is NULL if the found item is at the head of the list.
   1329  *
   1330  *	If the module is not found, NULL is returned. *insdef references
   1331  *	the predecessor node of the position where an entry for this module
   1332  *	would be placed, or NULL if it would go at the beginning.
   1333  */
   1334 static MODLIST_T *
   1335 module_loaded(const char *name, MODLIST_T **insdef)
   1336 {
   1337 	MODLIST_T	*moddef;
   1338 	int		cmp;
   1339 
   1340 	*insdef = NULL;
   1341 	moddef = state.modlist;
   1342 	if (moddef != NULL) {
   1343 		cmp = strcasecmp(name, moddef->ml_mod->mod_name);
   1344 		if (cmp == 0) {		/* Desired module is first in list */
   1345 			return (moddef);
   1346 		} else if (cmp > 0) {	/* cmp > 0: Insert in middle/end */
   1347 			*insdef = moddef;
   1348 			moddef = moddef->ml_next;
   1349 			cmp = -1;
   1350 			while (moddef && (cmp < 0)) {
   1351 				cmp = strcasecmp(moddef->ml_mod->mod_name,
   1352 				    name);
   1353 				if (cmp == 0)
   1354 					return (moddef);
   1355 				if (cmp < 0) {
   1356 					*insdef = moddef;
   1357 					moddef = (*insdef)->ml_next;
   1358 				}
   1359 			}
   1360 		}
   1361 	}
   1362 
   1363 	return (NULL);
   1364 }
   1365 
   1366 
   1367 /*
   1368  * Determine if a file is a sharable object based on its file path.
   1369  * If path ends in a .so, followed optionally by a period and 1 or more
   1370  * digits, we say that it is and return a pointer to the first character
   1371  * of the suffix. Otherwise NULL is returned.
   1372  */
   1373 static const char *
   1374 path_is_so(const char *path)
   1375 {
   1376 	int		dotso_len;
   1377 	const char	*tail;
   1378 	size_t		len;
   1379 
   1380 	len = strlen(path);
   1381 	if (len == 0)
   1382 		return (NULL);
   1383 	tail = path + len;
   1384 	if (isdigit(*(tail - 1))) {
   1385 		while ((tail > path) && isdigit(*(tail - 1)))
   1386 			tail--;
   1387 		if ((tail <= path) || (*tail != '.'))
   1388 			return (NULL);
   1389 	}
   1390 	dotso_len = strlen(MSG_ORIG(MSG_STR_DOTSO));
   1391 	if ((tail - path) < dotso_len)
   1392 		return (NULL);
   1393 	tail -= dotso_len;
   1394 	if (strncmp(tail, MSG_ORIG(MSG_STR_DOTSO), dotso_len) == 0)
   1395 		return (tail);
   1396 
   1397 	return (NULL);
   1398 }
   1399 
   1400 
   1401 /*
   1402  * Locate the start of the unsuffixed file name within path. Returns pointer
   1403  * to first character of that name in path.
   1404  *
   1405  * entry:
   1406  *	path - Path to be examined.
   1407  *	tail - NULL, or pointer to position at tail of path from which
   1408  *		the search for '/' characters should start. If NULL,
   1409  *		strlen() is used to locate the end of the string.
   1410  *	buf - NULL, or buffer to receive a copy of the characters that
   1411  *		lie between the start of the filename and tail.
   1412  *	bufsize - sizeof(buf)
   1413  *
   1414  * exit:
   1415  *	The pointer to the first character of the unsuffixed file name
   1416  *	within path is returned. If buf is non-NULL, the characters
   1417  *	lying between that point and tail (or the end of path if tail
   1418  *	is NULL) are copied into buf.
   1419  */
   1420 static const char *
   1421 elfedit_basename(const char *path, const char *tail, char *buf, size_t bufsiz)
   1422 {
   1423 	const char 	*s;
   1424 
   1425 	if (tail == NULL)
   1426 		tail = path + strlen(path);
   1427 	s = tail;
   1428 	while ((s > path) && (*(s - 1) != '/'))
   1429 		s--;
   1430 	if (buf != NULL)
   1431 		elfedit_strnbcpy(buf, s, tail - s, bufsiz);
   1432 	return (s);
   1433 }
   1434 
   1435 
   1436 /*
   1437  * Issue an error on behalf of load_module(), taking care to release
   1438  * resources that routine may have aquired:
   1439  *
   1440  * entry:
   1441  *	moddef - NULL, or a module definition to be released via free()
   1442  *	dl_hdl - NULL, or a handle to a sharable object to release via
   1443  *		dlclose().
   1444  *	dl_path - If dl_hdl is non-NULL, the path to the sharable object
   1445  *		file that was loaded.
   1446  *	format - A format string to pass to elfedit_msg(), containing
   1447  *		no more than (3) %s format codes, and no other format codes.
   1448  *	[s1-s4] - Strings to pass to elfedit_msg() to satisfy the four
   1449  *		allowed %s codes in format. Should be set to NULL if the
   1450  *		format string does not need them.
   1451  *
   1452  * note:
   1453  *	This routine makes a copy of the s1-s4 strings before freeing any
   1454  *	memory or unmapping the sharable library. It is therefore safe to
   1455  *	use strings from moddef, or from the sharable library (which will
   1456  *	be unmapped) to satisfy the other arguments s1-s4.
   1457  */
   1458 static void
   1459 load_module_err(MODLIST_T *moddef, void *dl_hdl, const char *dl_path,
   1460     const char *format, const char *s1, const char *s2, const char *s3,
   1461     const char *s4)
   1462 {
   1463 #define	SCRBUFSIZE (PATH_MAX + 256)   /* A path, plus some extra */
   1464 
   1465 	char s1_buf[SCRBUFSIZE];
   1466 	char s2_buf[SCRBUFSIZE];
   1467 	char s3_buf[SCRBUFSIZE];
   1468 	char s4_buf[SCRBUFSIZE];
   1469 
   1470 	/*
   1471 	 * The caller may provide strings for s1-s3 that are from
   1472 	 * moddef. If we free moddef, the printf() will die on access
   1473 	 * to free memory. We could push back on the user and force
   1474 	 * each call to carefully make copies of such data. However, this
   1475 	 * is an easy case to miss. Furthermore, this is an error case,
   1476 	 * and machine efficiency is not the main issue. We therefore make
   1477 	 * copies of the s1-s3 strings here into auto variables, and then
   1478 	 * use those copies. The user is freed from worrying about it.
   1479 	 *
   1480 	 * We use oversized stack based buffers instead of malloc() to
   1481 	 * reduce the number of ways that things can go wrong while
   1482 	 * reporting the error.
   1483 	 */
   1484 	if (s1 != NULL)
   1485 		(void) strlcpy(s1_buf, s1, sizeof (s1_buf));
   1486 	if (s2 != NULL)
   1487 		(void) strlcpy(s2_buf, s2, sizeof (s2_buf));
   1488 	if (s3 != NULL)
   1489 		(void) strlcpy(s3_buf, s3, sizeof (s3_buf));
   1490 	if (s4 != NULL)
   1491 		(void) strlcpy(s4_buf, s4, sizeof (s4_buf));
   1492 
   1493 
   1494 	if (moddef != NULL)
   1495 		free(moddef);
   1496 
   1497 	if ((dl_hdl != NULL) && (dlclose(dl_hdl) != 0))
   1498 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTDLCLOSE),
   1499 		    dl_path, dlerror());
   1500 
   1501 	elfedit_msg(ELFEDIT_MSG_ERR, format, s1_buf, s2_buf, s3_buf, s4_buf);
   1502 #undef	SCRBUFSIZE
   1503 }
   1504 
   1505 
   1506 /*
   1507  * Load a module sharable object for load_module().
   1508  *
   1509  * entry:
   1510  *	path - Path of file to open
   1511  *	moddef - If this function issues a non-returning error, it will
   1512  *		first return the memory referenced by moddef. This argument
   1513  *		is not used otherwise.
   1514  *	must_exist - If True, we consider it to be an error if the file given
   1515  *		by path does not exist. If False, no error is issued
   1516  *		and a NULL value is quietly returned.
   1517  *
   1518  * exit:
   1519  *	Returns a handle to the loaded object on success, or NULL if no
   1520  *	file was loaded.
   1521  */
   1522 static void *
   1523 load_module_dlopen(const char *path, MODLIST_T *moddef, int must_exist)
   1524 {
   1525 	int	fd;
   1526 	void	*hdl;
   1527 
   1528 	/*
   1529 	 * If the file is not required to exist, and it doesn't, then
   1530 	 * we want to quietly return without an error.
   1531 	 */
   1532 	if (!must_exist) {
   1533 		fd = open(path, O_RDONLY);
   1534 		if (fd >= 0) {
   1535 			(void) close(fd);
   1536 		} else if (errno == ENOENT) {
   1537 			return (NULL);
   1538 		}
   1539 	}
   1540 
   1541 	if ((hdl = dlopen(path, RTLD_LAZY|RTLD_FIRST)) == NULL)
   1542 		load_module_err(moddef, NULL, NULL,
   1543 		    MSG_INTL(MSG_ERR_CNTDLOPEN), path, dlerror(), NULL, NULL);
   1544 
   1545 	return (hdl);
   1546 }
   1547 
   1548 
   1549 /*
   1550  * Sanity check option arguments to prevent common errors. The rest of
   1551  * elfedit assumes these tests have been done, and does not check
   1552  * again.
   1553  */
   1554 static void
   1555 validate_optarg(elfedit_cmd_optarg_t *optarg, int isopt, MODLIST_T *moddef,
   1556     const char *mod_name, const char *cmd_name,
   1557     void *dl_hdl, const char *dl_path)
   1558 {
   1559 #define	FAIL(_msg) errmsg = _msg; goto fail
   1560 
   1561 	Msg errmsg;
   1562 	elfedit_cmd_oa_mask_t	optmask = 0;
   1563 
   1564 	for (; optarg->oa_name != NULL; optarg++) {
   1565 		/*
   1566 		 * If ELFEDIT_CMDOA_F_INHERIT is set:
   1567 		 *	- oa_name must be a value in the range of
   1568 		 *		known ELFEDIT_STDOA_ values.
   1569 		 *	- oa_help must be NULL
   1570 		 *	- ELFEDIT_CMDOA_F_INHERIT must be the only flag set
   1571 		 */
   1572 		if (optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) {
   1573 			if ((((uintptr_t)optarg->oa_name) >
   1574 			    ELFEDIT_NUM_STDOA) ||
   1575 			    (optarg->oa_help != 0) ||
   1576 			    (optarg->oa_flags != ELFEDIT_CMDOA_F_INHERIT))
   1577 				/*
   1578 				 * Can't use FAIL --- oa_name is not a valid
   1579 				 * string, and load_module_err() looks at args.
   1580 				 */
   1581 				load_module_err(moddef, dl_hdl, dl_path,
   1582 				    MSG_INTL(MSG_ERR_BADSTDOA), dl_path,
   1583 				    mod_name, cmd_name, NULL);
   1584 			continue;
   1585 		}
   1586 
   1587 		if (isopt) {
   1588 			/*
   1589 			 * Option name must start with a '-', and must
   1590 			 * have at one following character.
   1591 			 */
   1592 			if (optarg->oa_name[0] != '-') {
   1593 				/* MSG_INTL(MSG_ERR_OPT_MODPRE) */
   1594 				FAIL(MSG_ERR_OPT_MODPRE);
   1595 			}
   1596 			if (optarg->oa_name[1] == '\0') {
   1597 				/* MSG_INTL(MSG_ERR_OPT_MODLEN) */
   1598 				FAIL(MSG_ERR_OPT_MODLEN);
   1599 			}
   1600 
   1601 			/*
   1602 			 * oa_idmask must be 0, or it must have a single
   1603 			 * bit set (a power of 2).oa_excmask must be 0
   1604 			 * if oa_idmask is 0
   1605 			 */
   1606 			if (optarg->oa_idmask == 0) {
   1607 				if (optarg->oa_excmask != 0) {
   1608 					/* MSG_INTL(MSG_ERR_OPT_EXCMASKN0) */
   1609 					FAIL(MSG_ERR_OPT_EXCMASKN0);
   1610 				}
   1611 			} else {
   1612 				if (elfedit_bits_set(optarg->oa_idmask,
   1613 				    sizeof (optarg->oa_idmask)) != 1) {
   1614 					/* MSG_INTL(MSG_ERR_OPT_IDMASKPOW2) */
   1615 					FAIL(MSG_ERR_OPT_IDMASKPOW2);
   1616 				}
   1617 
   1618 				/* Non-zero idmask must be unique */
   1619 				if ((optarg->oa_idmask & optmask) != 0) {
   1620 					/* MSG_INTL(MSG_ERR_OPT_IDMASKUNIQ) */
   1621 					FAIL(MSG_ERR_OPT_IDMASKUNIQ);
   1622 				}
   1623 
   1624 				/* Add this one to the overall mask */
   1625 				optmask |= optarg->oa_idmask;
   1626 			}
   1627 		} else {
   1628 			/*
   1629 			 * Argument name cannot start with a'-', and must
   1630 			 * not be a null string.
   1631 			 */
   1632 			if (optarg->oa_name[0] == '-') {
   1633 				/* MSG_INTL(MSG_ERR_ARG_MODPRE) */
   1634 				FAIL(MSG_ERR_ARG_MODPRE);
   1635 			}
   1636 			if (optarg->oa_name[1] == '\0') {
   1637 				/* MSG_INTL(MSG_ERR_ARG_MODLEN) */
   1638 				FAIL(MSG_ERR_ARG_MODLEN);
   1639 			}
   1640 
   1641 
   1642 			/* oa_idmask and oa_excmask must both be 0 */
   1643 			if ((optarg->oa_idmask != 0) ||
   1644 			    (optarg->oa_excmask != 0)) {
   1645 				/* MSG_INTL(MSG_ERR_ARG_MASKNOT0) */
   1646 				FAIL(MSG_ERR_ARG_MASKNOT0);
   1647 			}
   1648 
   1649 		}
   1650 
   1651 		/*
   1652 		 * If it takes a value, make sure that we are
   1653 		 * processing options, because CMDOA_F_VALUE is not
   1654 		 * allowed for plain arguments. Then check the following
   1655 		 * item in the list:
   1656 		 *	- There must be a following item.
   1657 		 *	- oa_name must be non-NULL. This is the only field
   1658 		 *		that is used by elfedit.
   1659 		 *	- oa_help, oa_flags, oa_idmask, and oa_excmask
   1660 		 *		must be 0.
   1661 		 */
   1662 		if (optarg->oa_flags & ELFEDIT_CMDOA_F_VALUE) {
   1663 			elfedit_cmd_optarg_t *oa1 = optarg + 1;
   1664 
   1665 			if (!isopt) {
   1666 				/* MSG_INTL(MSG_ERR_ARG_CMDOA_VAL) */
   1667 				FAIL(MSG_ERR_ARG_CMDOA_VAL);
   1668 			}
   1669 
   1670 			if ((optarg + 1)->oa_name == NULL) {
   1671 				/* MSG_INTL(MSG_ERR_BADMODOPTVAL) */
   1672 				FAIL(MSG_ERR_BADMODOPTVAL);
   1673 			}
   1674 
   1675 			if (oa1->oa_name == NULL) {
   1676 				/* MSG_INTL(MSG_ERR_CMDOA_VALNAM) */
   1677 				FAIL(MSG_ERR_CMDOA_VALNAM);
   1678 			}
   1679 			if ((oa1->oa_help != NULL) || (oa1->oa_flags != 0) ||
   1680 			    (oa1->oa_idmask != 0) || (oa1->oa_excmask != 0)) {
   1681 				/* MSG_INTL(MSG_ERR_CMDOA_VALNOT0) */
   1682 				FAIL(MSG_ERR_CMDOA_VALNOT0);
   1683 			}
   1684 			optarg++;
   1685 		}
   1686 	}
   1687 
   1688 
   1689 	return;
   1690 
   1691 fail:
   1692 	load_module_err(moddef, dl_hdl, dl_path, MSG_INTL(errmsg),
   1693 	    dl_path, mod_name, cmd_name, optarg->oa_name);
   1694 }
   1695 
   1696 /*
   1697  * Look up the specified module, loading the module if necessary,
   1698  * and return its definition, or NULL on failure.
   1699  *
   1700  * entry:
   1701  *	name - Name of module to load. If name contains a '/' character or has
   1702  *		a ".so" suffix, then it is taken to be an absolute file path,
   1703  *		and is used directly as is. If name does not contain a '/'
   1704  *		character, then we look for it against the locations in
   1705  *		the module path, addint the '.so' suffix, and taking the first
   1706  *		one we find.
   1707  *	must_exist - If True, we consider it to be an error if we are unable
   1708  *		to locate a file to load and the module does not already exist.
   1709  *		If False, NULL is returned quietly in this case.
   1710  *	allow_abs - True if absolute paths are allowed. False to disallow
   1711  *		them.
   1712  *
   1713  * note:
   1714  *	If the path is absolute, then we load the file and take the module
   1715  *	name from the data returned by its elfedit_init() function. If a
   1716  *	module of that name is already loaded, it is unloaded and replaced
   1717  *	with the new one.
   1718  *
   1719  *	If the path is non absolute, then we check to see if the module has
   1720  *	already been loaded, and if so, we return that module definition.
   1721  *	In this case, nothing new is loaded. If the module has not been loaded,
   1722  *	we search the path for it and load it. If the module name provided
   1723  *	by the elfedit_init() function does not match the name of the file,
   1724  *	an error results.
   1725  */
   1726 elfeditGC_module_t *
   1727 elfedit_load_module(const char *name, int must_exist, int allow_abs)
   1728 {
   1729 	elfedit_init_func_t	*init_func;
   1730 	elfeditGC_module_t	*mod;
   1731 	MODLIST_T		*moddef, *insdef;
   1732 	const char		*path;
   1733 	char			path_buf[PATH_MAX + 1];
   1734 	void			*hdl;
   1735 	size_t			i;
   1736 	int			is_abs_path;
   1737 	elfeditGC_cmd_t		*cmd;
   1738 
   1739 	/*
   1740 	 * If the name includes a .so suffix, or has any '/' characters,
   1741 	 * then it is an absolute path that we use as is to load the named
   1742 	 * file. Otherwise, we iterate over the path, adding the .so suffix
   1743 	 * and load the first file that matches.
   1744 	 */
   1745 	is_abs_path = (path_is_so(name) != NULL) ||
   1746 	    (name != elfedit_basename(name, NULL, NULL, 0));
   1747 
   1748 	if (is_abs_path && !allow_abs)
   1749 		load_module_err(NULL, NULL, NULL,
   1750 		    MSG_INTL(MSG_ERR_UNRECMOD), name, NULL, NULL, NULL);
   1751 
   1752 	/*
   1753 	 * If this is a non-absolute path, search for the module already
   1754 	 * having been loaded, and return it if so.
   1755 	 */
   1756 	if (!is_abs_path) {
   1757 		moddef = module_loaded(name, &insdef);
   1758 		if (moddef != NULL)
   1759 			return (moddef->ml_mod);
   1760 		/*
   1761 		 * As a result of module_loaded(), insdef now contains the
   1762 		 * immediate predecessor node for the new one, or NULL if
   1763 		 * it goes at the front. In the absolute-path case, we take
   1764 		 * care of this below, after the sharable object is loaded.
   1765 		 */
   1766 	}
   1767 
   1768 	/*
   1769 	 * malloc() a module definition block before trying to dlopen().
   1770 	 * Doing things in the other order can cause the dlopen()'d object
   1771 	 * to leak: If elfedit_malloc() fails, it can cause a jump to the
   1772 	 * outer command loop without returning to the caller. Hence,
   1773 	 * there will be no opportunity to clean up. Allocaing the module
   1774 	 * first allows us to free it if necessary.
   1775 	 */
   1776 	moddef = elfedit_malloc(MSG_INTL(MSG_ALLOC_MODDEF),
   1777 	    sizeof (*moddef) + PATH_MAX + 1);
   1778 	moddef->ml_path = ((char *)moddef) + sizeof (*moddef);
   1779 
   1780 	if (is_abs_path) {
   1781 		path = name;
   1782 		hdl = load_module_dlopen(name, moddef, must_exist);
   1783 	} else {
   1784 		hdl = NULL;
   1785 		path = path_buf;
   1786 		for (i = 0; i < state.modpath.n; i++) {
   1787 			if (snprintf(path_buf, sizeof (path_buf),
   1788 			    MSG_ORIG(MSG_FMT_BLDSOPATH), state.modpath.seg[i],
   1789 			    name) > sizeof (path_buf))
   1790 				load_module_err(moddef, NULL, NULL,
   1791 				    MSG_INTL(MSG_ERR_PATHTOOLONG),
   1792 				    state.modpath.seg[i], name, NULL, NULL);
   1793 			hdl = load_module_dlopen(path, moddef, 0);
   1794 		}
   1795 		if (must_exist && (hdl == NULL))
   1796 			load_module_err(moddef, NULL, NULL,
   1797 			    MSG_INTL(MSG_ERR_UNRECMOD), name, NULL, NULL, NULL);
   1798 	}
   1799 
   1800 	if (hdl == NULL) {
   1801 		free(moddef);
   1802 		return (NULL);
   1803 	}
   1804 
   1805 	if (state.elf.elfclass == ELFCLASS32) {
   1806 		init_func = (elfedit_init_func_t *)
   1807 		    dlsym(hdl, MSG_ORIG(MSG_STR_ELFEDITINIT32));
   1808 	} else {
   1809 		init_func = (elfedit_init_func_t *)
   1810 		    dlsym(hdl, MSG_ORIG(MSG_STR_ELFEDITINIT64));
   1811 	}
   1812 	if (init_func == NULL)
   1813 		load_module_err(moddef, hdl, path,
   1814 		    MSG_INTL(MSG_ERR_SONOTMOD), path, NULL, NULL, NULL);
   1815 
   1816 	/*
   1817 	 * Note that the init function will be passing us an
   1818 	 * elfedit[32|64]_module_t pointer, which we cast to the
   1819 	 * generic module pointer type in order to be able to manage
   1820 	 * either type with one set of code.
   1821 	 */
   1822 	if (!(mod = (elfeditGC_module_t *)(* init_func)(ELFEDIT_VER_CURRENT)))
   1823 		load_module_err(moddef, hdl, path,
   1824 		    MSG_INTL(MSG_ERR_BADMODLOAD), path, NULL, NULL, NULL);
   1825 
   1826 	/*
   1827 	 * Enforce some rules, to help module developers:
   1828 	 *	- The primary name of a command must not be
   1829 	 *		the empty string ("").
   1830 	 *	- Options must start with a '-' followed by at least
   1831 	 *		one character.
   1832 	 *	- Arguments and options must be well formed.
   1833 	 */
   1834 	for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++) {
   1835 		if (**cmd->cmd_name == '\0')
   1836 			load_module_err(moddef, hdl, path,
   1837 			    MSG_INTL(MSG_ERR_NULLPRICMDNAM), mod->mod_name,
   1838 			    NULL, NULL, NULL);
   1839 
   1840 		if (cmd->cmd_args != NULL)
   1841 			validate_optarg(cmd->cmd_args, 0, moddef, mod->mod_name,
   1842 			    cmd->cmd_name[0], hdl, path);
   1843 		if (cmd->cmd_opt != NULL)
   1844 			validate_optarg(cmd->cmd_opt, 1, moddef, mod->mod_name,
   1845 			    cmd->cmd_name[0], hdl, path);
   1846 	}
   1847 
   1848 	/*
   1849 	 * Check the name the module provides. How we handle this depends
   1850 	 * on whether the path is absolute or the result of a path search.
   1851 	 */
   1852 	if (is_abs_path) {
   1853 		MODLIST_T *old_moddef = module_loaded(mod->mod_name, &insdef);
   1854 
   1855 		if (old_moddef != NULL) {	/* Replace existing */
   1856 			free(moddef);		/* Rare case: Don't need it */
   1857 			/*
   1858 			 * Be sure we don't unload builtin modules!
   1859 			 * These have a NULL dl_hdl field.
   1860 			 */
   1861 			if (old_moddef->ml_dl_hdl == NULL)
   1862 				load_module_err(NULL, hdl, path,
   1863 				    MSG_INTL(MSG_ERR_CNTULSMOD),
   1864 				    old_moddef->ml_mod->mod_name, NULL,
   1865 				    NULL, NULL);
   1866 
   1867 			/* Unload existing */
   1868 			if (dlclose(old_moddef->ml_dl_hdl) != 0)
   1869 				elfedit_msg(ELFEDIT_MSG_ERR,
   1870 				    MSG_INTL(MSG_ERR_CNTDLCLOSE),
   1871 				    old_moddef->ml_path, dlerror());
   1872 			elfedit_msg(ELFEDIT_MSG_DEBUG,
   1873 			    MSG_INTL(MSG_DEBUG_MODUNLOAD),
   1874 			    old_moddef->ml_mod->mod_name, old_moddef->ml_path);
   1875 			old_moddef->ml_mod = mod;
   1876 			old_moddef->ml_dl_hdl = hdl;
   1877 			(void) strlcpy((char *)old_moddef->ml_path, path,
   1878 			    PATH_MAX + 1);
   1879 			elfedit_msg(ELFEDIT_MSG_DEBUG,
   1880 			    MSG_INTL(MSG_DEBUG_MODLOAD),
   1881 			    old_moddef->ml_mod->mod_name, path);
   1882 			return (old_moddef->ml_mod);
   1883 		}
   1884 		/*
   1885 		 * insdef now contains the insertion point for the absolute
   1886 		 * path case.
   1887 		 */
   1888 	} else {
   1889 		/* If the names don't match, then error */
   1890 		if (strcasecmp(name, mod->mod_name) != 0)
   1891 			load_module_err(moddef, hdl, path,
   1892 			    MSG_INTL(MSG_ERR_BADMODNAME),
   1893 			    mod->mod_name, name, path, NULL);
   1894 	}
   1895 
   1896 	/*
   1897 	 * Link module into the module list. If insdef is NULL,
   1898 	 * it goes at the head. If insdef is non-NULL, it goes immediately
   1899 	 * after
   1900 	 */
   1901 	if (insdef == NULL) {
   1902 		moddef->ml_next = state.modlist;
   1903 		state.modlist = moddef;
   1904 	} else {
   1905 		moddef->ml_next = insdef->ml_next;
   1906 		insdef->ml_next = moddef;
   1907 	}
   1908 	moddef->ml_mod = mod;
   1909 	moddef->ml_dl_hdl = hdl;
   1910 	(void) strlcpy((char *)moddef->ml_path, path, PATH_MAX + 1);
   1911 
   1912 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_MODLOAD),
   1913 	    moddef->ml_mod->mod_name, path);
   1914 
   1915 	return (moddef->ml_mod);
   1916 }
   1917 
   1918 
   1919 /*
   1920  * Unload the specified module
   1921  */
   1922 void
   1923 elfedit_unload_module(const char *name)
   1924 {
   1925 	MODLIST_T	*moddef, *insdef;
   1926 
   1927 	moddef = module_loaded(name, &insdef);
   1928 	if (moddef == NULL)
   1929 		return;
   1930 
   1931 	/* Built in modules cannot be unloaded. They have a NULL dl_hdl field */
   1932 	if (moddef->ml_dl_hdl == NULL)
   1933 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTULSMOD),
   1934 		    moddef->ml_mod->mod_name);
   1935 
   1936 	/*
   1937 	 * When we unload it, the name string goes with it. So
   1938 	 * announce it while we still can without having to make a copy.
   1939 	 */
   1940 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_MODUNLOAD),
   1941 	    moddef->ml_mod->mod_name, moddef->ml_path);
   1942 
   1943 	/*
   1944 	 * Close it before going further. On failure, we'll jump, and the
   1945 	 * record will remain in the module list. On success,
   1946 	 * we'll retain control, and can safely remove it.
   1947 	 */
   1948 	if (dlclose(moddef->ml_dl_hdl) != 0)
   1949 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTDLCLOSE),
   1950 		    moddef->ml_path, dlerror());
   1951 
   1952 	/* Unlink the record from the module list */
   1953 	if (insdef == NULL)
   1954 		state.modlist = moddef->ml_next;
   1955 	else
   1956 		insdef->ml_next = moddef->ml_next;
   1957 
   1958 	/* Release the memory */
   1959 	free(moddef);
   1960 }
   1961 
   1962 
   1963 /*
   1964  * Load all sharable objects found in the specified directory.
   1965  *
   1966  * entry:
   1967  *	dirpath - Path of directory to process.
   1968  *	must_exist - If True, it is an error if diropen() fails to open
   1969  *		the given directory. Of False, we quietly ignore it and return.
   1970  *	abs_path - If True, files are loaded using their literal paths.
   1971  *		If False, their module name is extracted from the dirpath
   1972  *		and a path based search is used to locate it.
   1973  */
   1974 void
   1975 elfedit_load_moddir(const char *dirpath, int must_exist, int abs_path)
   1976 {
   1977 	char		path[PATH_MAX + 1];
   1978 	DIR		*dir;
   1979 	struct dirent	*dp;
   1980 	const char 	*tail;
   1981 
   1982 	dir = opendir(dirpath);
   1983 	if (dir == NULL) {
   1984 		int err = errno;
   1985 
   1986 		if (!must_exist && (err == ENOENT))
   1987 			return;
   1988 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTOPNDIR),
   1989 		    dirpath, strerror(err));
   1990 		/*NOTREACHED*/
   1991 	}
   1992 
   1993 	while (dp = readdir(dir)) {
   1994 		if ((tail = path_is_so(dp->d_name)) != NULL) {
   1995 			if (abs_path) {
   1996 				(void) snprintf(path, sizeof (path),
   1997 				    MSG_ORIG(MSG_FMT_BLDPATH), dirpath,
   1998 				    dp->d_name);
   1999 			} else {
   2000 				(void) elfedit_basename(dp->d_name, tail,
   2001 				    path, sizeof (path));
   2002 			}
   2003 			(void) elfedit_load_module(path, must_exist, 1);
   2004 		}
   2005 	}
   2006 	(void) closedir(dir);
   2007 }
   2008 
   2009 
   2010 /*
   2011  * Follow the module load path, and load the first module found for each
   2012  * given name.
   2013  */
   2014 void
   2015 elfedit_load_modpath(void)
   2016 {
   2017 	size_t		i;
   2018 
   2019 	for (i = 0; i < state.modpath.n; i++)
   2020 		elfedit_load_moddir(state.modpath.seg[i], 0, 0);
   2021 }
   2022 
   2023 /*
   2024  * Given a module definition, look for the specified command.
   2025  * Returns the command if found, and NULL otherwise.
   2026  */
   2027 static elfeditGC_cmd_t *
   2028 find_cmd(elfeditGC_module_t *mod, const char *name)
   2029 {
   2030 	elfeditGC_cmd_t *cmd;
   2031 	const char **cmd_name;
   2032 
   2033 	for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++)
   2034 		for (cmd_name = cmd->cmd_name; *cmd_name; cmd_name++)
   2035 			if (strcasecmp(name, *cmd_name) == 0) {
   2036 				if (cmd_name != cmd->cmd_name)
   2037 					elfedit_msg(ELFEDIT_MSG_DEBUG,
   2038 					    MSG_INTL(MSG_DEBUG_CMDALIAS),
   2039 					    mod->mod_name, *cmd_name,
   2040 					    mod->mod_name, *cmd->cmd_name);
   2041 				return (cmd);
   2042 			}
   2043 
   2044 	return (NULL);
   2045 }
   2046 
   2047 
   2048 /*
   2049  * Given a command name, return its command definition.
   2050  *
   2051  * entry:
   2052  *	name - Command to be looked up
   2053  *	must_exist - If True, we consider it to be an error if the command
   2054  *		does not exist. If False, NULL is returned quietly in
   2055  *		this case.
   2056  *	mod_ret - NULL, or address of a variable to receive the
   2057  *		module definition block of the module containing
   2058  *		the command.
   2059  *
   2060  * exit:
   2061  *	On success, returns a pointer to the command definition, and
   2062  *	if mod_ret is non-NULL, *mod_ret receives a pointer to the
   2063  *	module definition. On failure, must_exist determines the
   2064  *	action taken: If must_exist is True, an error is issued and
   2065  *	control does not return to the caller. If must_exist is False,
   2066  *	NULL is quietly returned.
   2067  *
   2068  * note:
   2069  *	A ':' in name is used to delimit the module and command names.
   2070  *	If it is omitted, or if it is the first non-whitespace character
   2071  *	in the name, then the built in sys: module is implied.
   2072  */
   2073 elfeditGC_cmd_t *
   2074 elfedit_find_command(const char *name, int must_exist,
   2075     elfeditGC_module_t **mod_ret)
   2076 {
   2077 	elfeditGC_module_t	*mod;
   2078 	const char		*mod_str;
   2079 	const char		*cmd_str;
   2080 	char			mod_buf[ELFEDIT_MAXMODNAM + 1];
   2081 	size_t			n;
   2082 	elfeditGC_cmd_t		*cmd;
   2083 
   2084 
   2085 	cmd_str = strstr(name, MSG_ORIG(MSG_STR_COLON));
   2086 	if (cmd_str == NULL) {		/* No module name -> sys: */
   2087 		mod_str = MSG_ORIG(MSG_MOD_SYS);
   2088 		cmd_str = name;
   2089 	} else if (cmd_str == name) {	/* Empty module name -> sys: */
   2090 		mod_str = MSG_ORIG(MSG_MOD_SYS);
   2091 		cmd_str++;		/* Skip the colon */
   2092 	} else {			/* Have both module and command */
   2093 		n = cmd_str - name;
   2094 		if (n >= sizeof (mod_buf)) {
   2095 			if (must_exist)
   2096 				elfedit_msg(ELFEDIT_MSG_ERR,
   2097 				    MSG_INTL(MSG_ERR_MODNAMTOOLONG), name);
   2098 			return (NULL);
   2099 		}
   2100 		(void) strlcpy(mod_buf, name, n + 1);
   2101 		mod_str = mod_buf;
   2102 		cmd_str++;
   2103 	}
   2104 
   2105 	/* Lookup/load module. Won't return on error */
   2106 	mod = elfedit_load_module(mod_str, must_exist, 0);
   2107 	if (mod == NULL)
   2108 		return (NULL);
   2109 
   2110 	/* Locate the command */
   2111 	cmd = find_cmd(mod, cmd_str);
   2112 	if (cmd == NULL) {
   2113 		if (must_exist) {
   2114 			/*
   2115 			 * Catch empty command in order to provide
   2116 			 * a better error message.
   2117 			 */
   2118 			if (*cmd_str == '\0') {
   2119 				elfedit_msg(ELFEDIT_MSG_ERR,
   2120 				    MSG_INTL(MSG_ERR_MODNOCMD), mod_str);
   2121 			} else {
   2122 				elfedit_msg(ELFEDIT_MSG_ERR,
   2123 				    MSG_INTL(MSG_ERR_UNRECCMD),
   2124 				    mod_str, cmd_str);
   2125 			}
   2126 		}
   2127 	} else {
   2128 		if (mod_ret != NULL)
   2129 			*mod_ret = mod;
   2130 	}
   2131 	return (cmd);
   2132 }
   2133 
   2134 
   2135 /*
   2136  * Release all user command blocks found on state.ucmd
   2137  */
   2138 static void
   2139 free_user_cmds(void)
   2140 {
   2141 	USER_CMD_T *next;
   2142 
   2143 	while (state.ucmd.list) {
   2144 		next = state.ucmd.list->ucmd_next;
   2145 		free(state.ucmd.list);
   2146 		state.ucmd.list = next;
   2147 	}
   2148 	state.ucmd.tail = NULL;
   2149 	state.ucmd.n = 0;
   2150 	state.cur_cmd = NULL;
   2151 }
   2152 
   2153 
   2154 /*
   2155  * Process all user command blocks found on state.ucmd, and then
   2156  * remove them from the list.
   2157  */
   2158 static void
   2159 dispatch_user_cmds()
   2160 {
   2161 	USER_CMD_T		*ucmd;
   2162 	elfedit_cmdret_t	cmd_ret;
   2163 
   2164 	ucmd = state.ucmd.list;
   2165 	if (ucmd) {
   2166 		/* Do them, in order */
   2167 		for (; ucmd; ucmd = ucmd->ucmd_next) {
   2168 			state.cur_cmd = ucmd;
   2169 			if (!state.msg_jbuf.active)
   2170 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   2171 				    MSG_INTL(MSG_DEBUG_EXECCMD),
   2172 				    ucmd->ucmd_orig_str);
   2173 			/*
   2174 			 * The cmd_func field is the generic definition.
   2175 			 * We need to cast it to the type that matches
   2176 			 * the proper ELFCLASS before calling it.
   2177 			 */
   2178 			if (state.elf.elfclass == ELFCLASS32) {
   2179 				elfedit32_cmd_func_t *cmd_func =
   2180 				    (elfedit32_cmd_func_t *)
   2181 				    ucmd->ucmd_cmd->cmd_func;
   2182 
   2183 				cmd_ret = (* cmd_func)(state.elf.obj_state.s32,
   2184 				    ucmd->ucmd_argc, ucmd->ucmd_argv);
   2185 			} else {
   2186 				elfedit64_cmd_func_t *cmd_func =
   2187 				    (elfedit64_cmd_func_t *)
   2188 				    ucmd->ucmd_cmd->cmd_func;
   2189 
   2190 				cmd_ret = (* cmd_func)(state.elf.obj_state.s64,
   2191 				    ucmd->ucmd_argc, ucmd->ucmd_argv);
   2192 			}
   2193 			state.cur_cmd = NULL;
   2194 			/* If a pager was started, wrap it up */
   2195 			elfedit_pager_cleanup();
   2196 
   2197 			switch (cmd_ret) {
   2198 			case ELFEDIT_CMDRET_MOD_OS_MACH:
   2199 				/*
   2200 				 * Inform the elfconst module that the machine
   2201 				 * or osabi has has changed. It may be necessary
   2202 				 * to fetch new strings from libconv.
   2203 				 */
   2204 				state.elf.elfconst_ehdr_change = 1;
   2205 				/*FALLTHROUGH*/
   2206 			case ELFEDIT_CMDRET_MOD:
   2207 				/*
   2208 				 * Command modified the output ELF image,
   2209 				 * mark the file as needing a flush to disk.
   2210 				 */
   2211 				state.file.dirty = 1;
   2212 				break;
   2213 			case ELFEDIT_CMDRET_FLUSH:
   2214 				/*
   2215 				 * Command flushed the output file,
   2216 				 * clear the dirty bit.
   2217 				 */
   2218 				state.file.dirty = 0;
   2219 			}
   2220 		}
   2221 		free_user_cmds();
   2222 	}
   2223 }
   2224 
   2225 
   2226 /*
   2227  * Given the pointer to the character following a '\' character in
   2228  * a C style literal, return the ASCII character code it represents,
   2229  * and advance the string pointer to the character following the last
   2230  * character in the escape sequence.
   2231  *
   2232  * entry:
   2233  *	str - Address of string pointer to first character following
   2234  *		the backslash.
   2235  *
   2236  * exit:
   2237  *	If the character is not valid, an error is thrown and this routine
   2238  *	does not return to its caller. Otherwise, it returns the ASCII
   2239  *	code for the translated character, and *str has been advanced.
   2240  */
   2241 static int
   2242 translate_c_esc(char **str)
   2243 {
   2244 	char *s = *str;
   2245 	int	ch;
   2246 	int	i;
   2247 
   2248 	ch = *s++;
   2249 	switch (ch) {
   2250 	case 'a':
   2251 		ch = '\a';
   2252 		break;
   2253 	case 'b':
   2254 		ch = '\b';
   2255 		break;
   2256 	case 'f':
   2257 		ch = '\f';
   2258 		break;
   2259 	case 'n':
   2260 		ch = '\n';
   2261 		break;
   2262 	case 'r':
   2263 		ch = '\r';
   2264 		break;
   2265 	case 't':
   2266 		ch = '\t';
   2267 		break;
   2268 	case 'v':
   2269 		ch = '\v';
   2270 		break;
   2271 
   2272 	case '0':
   2273 	case '1':
   2274 	case '2':
   2275 	case '3':
   2276 	case '4':
   2277 	case '5':
   2278 	case '6':
   2279 	case '7':
   2280 		/* Octal constant: There can be up to 3 digits */
   2281 		ch -= '0';
   2282 		for (i = 0; i < 2; i++) {
   2283 			if ((*s < '0') || (*s > '7'))
   2284 				break;
   2285 			ch = (ch << 3) + (*s++ - '0');
   2286 		}
   2287 		break;
   2288 
   2289 	/*
   2290 	 * There are some cases where ch already has the desired value.
   2291 	 * These cases exist simply to remove the special meaning that
   2292 	 * character would otherwise have. We need to match them to
   2293 	 * prevent them from falling into the default error case.
   2294 	 */
   2295 	case '\\':
   2296 	case '\'':
   2297 	case '"':
   2298 		break;
   2299 
   2300 	default:
   2301 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCESC), ch);
   2302 		break;
   2303 	}
   2304 
   2305 	*str = s;
   2306 	return (ch);
   2307 }
   2308 
   2309 
   2310 /*
   2311  * Prepare a GETTOK_STATE struct for gettok().
   2312  *
   2313  * entry:
   2314  *	gettok_state - gettok state block to use
   2315  *	str - Writable buffer to tokenize. Note that gettok()
   2316  *		is allowed to change the contents of this buffer.
   2317  *	inc_null_final - If the line ends in whitespace instead of
   2318  *		immediately hitting a NULL, and inc_null_final is TRUE,
   2319  *		then a null final token is generated. Otherwise trailing
   2320  *		whitespace is ignored.
   2321  */
   2322 static void
   2323 gettok_init(GETTOK_STATE *gettok_state, char *buf, int inc_null_final)
   2324 {
   2325 	gettok_state->gtok_buf = gettok_state->gtok_cur_buf = buf;
   2326 	gettok_state->gtok_inc_null_final = inc_null_final;
   2327 	gettok_state->gtok_null_seen = 0;
   2328 }
   2329 
   2330 
   2331 /*
   2332  * Locate the next token from the buffer.
   2333  *
   2334  * entry:
   2335  *	gettok_state - State of gettok() operation. Initialized
   2336  *		by gettok_init(), and passed to gettok().
   2337  *
   2338  * exit:
   2339  *	If a token is found, gettok_state->gtok_last_token is filled in
   2340  *	with the details and True (1) is returned. If no token is found,
   2341  *	False (1) is returned, and the contents of
   2342  *	gettok_state->gtok_last_token are undefined.
   2343  *
   2344  * note:
   2345  *	- The token returned references the memory in gettok_state->gtok_buf.
   2346  *		The caller should not modify the buffer until all such
   2347  *		pointers have been discarded.
   2348  *	- This routine will modify the contents of gettok_state->gtok_buf
   2349  *		as necessary to remove quotes and eliminate escape
   2350  *		(\)characters.
   2351  */
   2352 static int
   2353 gettok(GETTOK_STATE *gettok_state)
   2354 {
   2355 	char	*str = gettok_state->gtok_cur_buf;
   2356 	char	*look;
   2357 	int	quote_ch = '\0';
   2358 
   2359 	/* Skip leading whitespace */
   2360 	while (isspace(*str))
   2361 		str++;
   2362 
   2363 	if (*str == '\0') {
   2364 		/*
   2365 		 * If user requested it, and there was whitespace at the
   2366 		 * end, then generate one last null token.
   2367 		 */
   2368 		if (gettok_state->gtok_inc_null_final &&
   2369 		    !gettok_state->gtok_null_seen) {
   2370 			gettok_state->gtok_inc_null_final = 0;
   2371 			gettok_state->gtok_null_seen = 1;
   2372 			gettok_state->gtok_last_token.tok_str = str;
   2373 			gettok_state->gtok_last_token.tok_len = 0;
   2374 			gettok_state->gtok_last_token.tok_line_off =
   2375 			    str - gettok_state->gtok_buf;
   2376 			return (1);
   2377 		}
   2378 		gettok_state->gtok_null_seen = 1;
   2379 		return (0);
   2380 	}
   2381 
   2382 	/*
   2383 	 * Read token: The standard delimiter is whitespace, but
   2384 	 * we honor either single or double quotes. Also, we honor
   2385 	 * backslash escapes.
   2386 	 */
   2387 	gettok_state->gtok_last_token.tok_str = look = str;
   2388 	gettok_state->gtok_last_token.tok_line_off =
   2389 	    look - gettok_state->gtok_buf;
   2390 	for (; *look; look++) {
   2391 		if (*look == quote_ch) {	/* Terminates active quote */
   2392 			quote_ch = '\0';
   2393 			continue;
   2394 		}
   2395 
   2396 		if (quote_ch == '\0') {		/* No quote currently active */
   2397 			if ((*look == '\'') || (*look == '"')) {
   2398 				quote_ch = *look;	/* New active quote */
   2399 				continue;
   2400 			}
   2401 			if (isspace(*look))
   2402 				break;
   2403 		}
   2404 
   2405 		/*
   2406 		 * The semantics of the backslash character depends on
   2407 		 * the quote style in use:
   2408 		 *	- Within single quotes, backslash is not
   2409 		 *		an escape character, and is taken literally.
   2410 		 *	- If outside of quotes, the backslash is an escape
   2411 		 *		character. The backslash is ignored and the
   2412 		 *		following character is taken literally, losing
   2413 		 *		any special properties it normally has.
   2414 		 *	- Within double quotes, backslash works like a
   2415 		 *		backslash escape within a C literal. Certain
   2416 		 *		escapes are recognized and replaced with their
   2417 		 *		special character. Any others are an error.
   2418 		 */
   2419 		if (*look == '\\') {
   2420 			if (quote_ch == '\'') {
   2421 				*str++ = *look;
   2422 				continue;
   2423 			}
   2424 
   2425 			look++;
   2426 			if (*look == '\0') {	/* Esc applied to NULL term? */
   2427 				elfedit_msg(ELFEDIT_MSG_ERR,
   2428 				    MSG_INTL(MSG_ERR_ESCEOL));
   2429 				/*NOTREACHED*/
   2430 			}
   2431 
   2432 			if (quote_ch == '"') {
   2433 				*str++ = translate_c_esc(&look);
   2434 				look--;		/* for() will advance by 1 */
   2435 				continue;
   2436 			}
   2437 		}
   2438 
   2439 		if (look != str)
   2440 			*str = *look;
   2441 		str++;
   2442 	}
   2443 
   2444 	/* Don't allow unterminated quoted tokens */
   2445 	if (quote_ch != '\0')
   2446 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_UNTERMQUOTE),
   2447 		    quote_ch);
   2448 
   2449 	gettok_state->gtok_last_token.tok_len = str -
   2450 	    gettok_state->gtok_last_token.tok_str;
   2451 	gettok_state->gtok_null_seen = *look == '\0';
   2452 	if (!gettok_state->gtok_null_seen)
   2453 		look++;
   2454 	*str = '\0';
   2455 	gettok_state->gtok_cur_buf = look;
   2456 
   2457 #ifdef DEBUG_GETTOK
   2458 	printf("GETTOK >");
   2459 	elfedit_str_to_c_literal(gettok_state->gtok_last_token.tok_str,
   2460 	    elfedit_write);
   2461 	printf("< \tlen(%d) offset(%d)\n",
   2462 	    gettok_state->gtok_last_token.tok_len,
   2463 	    gettok_state->gtok_last_token.tok_line_off);
   2464 #endif
   2465 
   2466 	return (1);
   2467 }
   2468 
   2469 
   2470 /*
   2471  * Tokenize the user command string, and return a pointer to the
   2472  * TOK_STATE buffer maintained by this function. That buffer contains
   2473  * the tokenized strings.
   2474  *
   2475  * entry:
   2476  *	user_cmd_str - String to tokenize
   2477  *	len - # of characters in user_cmd_str to examine. If
   2478  *		(len < 0), then the complete string is processed
   2479  *		stopping with the NULL termination. Otherwise,
   2480  *		processing stops after len characters, and any
   2481  *		remaining characters are ignored.
   2482  *	inc_null_final - If True, and if user_cmd_str has whitespace
   2483  *		at the end following the last non-null token, then
   2484  *		a final null token will be included. If False, null
   2485  *		tokens are ignored.
   2486  *
   2487  * note:
   2488  *	This routine returns pointers to internally allocated memory.
   2489  *	The caller must not alter anything contained in the TOK_STATE
   2490  *	buffer returned. Furthermore, the the contents of TOK_STATE
   2491  *	are only valid until the next call to tokenize_user_cmd().
   2492  */
   2493 static TOK_STATE *
   2494 tokenize_user_cmd(const char *user_cmd_str, size_t len, int inc_null_final)
   2495 {
   2496 #define	INITIAL_TOK_ALLOC 5
   2497 
   2498 	/*
   2499 	 * As we parse the user command, we need temporary space to
   2500 	 * hold the tokens. We do this by dynamically allocating a string
   2501 	 * buffer and a token array, and doubling them as necessary. This
   2502 	 * is a single threaded application, so static variables suffice.
   2503 	 */
   2504 	static STRBUF str;
   2505 	static TOK_STATE tokst;
   2506 
   2507 	GETTOK_STATE	gettok_state;
   2508 	size_t		n;
   2509 
   2510 	/*
   2511 	 * Make a copy we can modify. If (len == 0), take the entire
   2512 	 * string. Otherwise limit it to the specified length.
   2513 	 */
   2514 	tokst.tokst_cmd_len = strlen(user_cmd_str);
   2515 	if ((len > 0) && (len < tokst.tokst_cmd_len))
   2516 		tokst.tokst_cmd_len = len;
   2517 	tokst.tokst_cmd_len++;	/* Room for NULL termination */
   2518 	strbuf_ensure_size(&str, tokst.tokst_cmd_len);
   2519 	(void) strlcpy(str.buf, user_cmd_str, tokst.tokst_cmd_len);
   2520 
   2521 	/* Trim off any newline character that might be present */
   2522 	if ((tokst.tokst_cmd_len > 1) &&
   2523 	    (str.buf[tokst.tokst_cmd_len - 2] == '\n')) {
   2524 		tokst.tokst_cmd_len--;
   2525 		str.buf[tokst.tokst_cmd_len - 1] = '\0';
   2526 	}
   2527 
   2528 	/* Tokenize the user command string into tok struct */
   2529 	gettok_init(&gettok_state, str.buf, inc_null_final);
   2530 	tokst.tokst_str_size = 0;	/* Space needed for token strings */
   2531 	for (tokst.tokst_cnt = 0; gettok(&gettok_state) != 0;
   2532 	    tokst.tokst_cnt++) {
   2533 		/* If we need more room, expand the token buffer */
   2534 		if (tokst.tokst_cnt >= tokst.tokst_bufsize) {
   2535 			n = (tokst.tokst_bufsize == 0) ?
   2536 			    INITIAL_TOK_ALLOC : (tokst.tokst_bufsize * 2);
   2537 			tokst.tokst_buf = elfedit_realloc(
   2538 			    MSG_INTL(MSG_ALLOC_TOKBUF), tokst.tokst_buf,
   2539 			    n * sizeof (*tokst.tokst_buf));
   2540 			tokst.tokst_bufsize = n;
   2541 		}
   2542 		tokst.tokst_str_size +=
   2543 		    gettok_state.gtok_last_token.tok_len + 1;
   2544 		tokst.tokst_buf[tokst.tokst_cnt] = gettok_state.gtok_last_token;
   2545 	}
   2546 	/* fold the command token to lowercase */
   2547 	if (tokst.tokst_cnt > 0) {
   2548 		char *s;
   2549 
   2550 		for (s = tokst.tokst_buf[0].tok_str; *s; s++)
   2551 			if (isupper(*s))
   2552 				*s = tolower(*s);
   2553 	}
   2554 
   2555 	return (&tokst);
   2556 
   2557 #undef	INITIAL_TOK_ALLOC
   2558 }
   2559 
   2560 
   2561 /*
   2562  * Parse the user command string, and put an entry for it at the end
   2563  * of state.ucmd.
   2564  */
   2565 static void
   2566 parse_user_cmd(const char *user_cmd_str)
   2567 {
   2568 	TOK_STATE	*tokst;
   2569 	char		*s;
   2570 	size_t		n;
   2571 	size_t		len;
   2572 	USER_CMD_T	*ucmd;
   2573 	elfeditGC_module_t *mod;
   2574 	elfeditGC_cmd_t	*cmd;
   2575 
   2576 	/*
   2577 	 * Break it into tokens. If there are none, then it is
   2578 	 * an empty command and is ignored.
   2579 	 */
   2580 	tokst = tokenize_user_cmd(user_cmd_str, -1, 0);
   2581 	if (tokst->tokst_cnt == 0)
   2582 		return;
   2583 
   2584 	/* Find the command. Won't return on error */
   2585 	cmd = elfedit_find_command(tokst->tokst_buf[0].tok_str, 1, &mod);
   2586 
   2587 	/*
   2588 	 * If there is no ELF file being edited, then only commands
   2589 	 * from the sys: module are allowed.
   2590 	 */
   2591 	if ((state.file.present == 0) &&
   2592 	    (strcmp(mod->mod_name, MSG_ORIG(MSG_MOD_SYS)) != 0))
   2593 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOFILSYSONLY),
   2594 		    mod->mod_name, cmd->cmd_name[0]);
   2595 
   2596 
   2597 	/* Allocate, fill in, and insert a USER_CMD_T block */
   2598 	n = S_DROUND(sizeof (USER_CMD_T));
   2599 	ucmd = elfedit_malloc(MSG_INTL(MSG_ALLOC_UCMD),
   2600 	    n + (sizeof (char *) * (tokst->tokst_cnt - 1)) +
   2601 	    tokst->tokst_cmd_len + tokst->tokst_str_size);
   2602 	ucmd->ucmd_next = NULL;
   2603 	ucmd->ucmd_argc = tokst->tokst_cnt - 1;
   2604 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
   2605 	ucmd->ucmd_argv = (const char **)(n + (char *)ucmd);
   2606 	ucmd->ucmd_orig_str = (char *)(ucmd->ucmd_argv + ucmd->ucmd_argc);
   2607 	(void) strncpy(ucmd->ucmd_orig_str, user_cmd_str, tokst->tokst_cmd_len);
   2608 	ucmd->ucmd_mod = mod;
   2609 	ucmd->ucmd_cmd = cmd;
   2610 	ucmd->ucmd_ostyle_set = 0;
   2611 	s = ucmd->ucmd_orig_str + tokst->tokst_cmd_len;
   2612 	for (n = 1; n < tokst->tokst_cnt; n++) {
   2613 		len = tokst->tokst_buf[n].tok_len + 1;
   2614 		ucmd->ucmd_argv[n - 1] = s;
   2615 		(void) strncpy(s, tokst->tokst_buf[n].tok_str, len);
   2616 		s += len;
   2617 	}
   2618 	if (state.ucmd.list == NULL) {
   2619 		state.ucmd.list = state.ucmd.tail = ucmd;
   2620 	} else {
   2621 		state.ucmd.tail->ucmd_next = ucmd;
   2622 		state.ucmd.tail = ucmd;
   2623 	}
   2624 	state.ucmd.n++;
   2625 }
   2626 
   2627 
   2628 /*
   2629  * Copy infile to a new file with the name given by outfile.
   2630  */
   2631 static void
   2632 create_outfile(const char *infile, const char *outfile)
   2633 {
   2634 	pid_t pid;
   2635 	int statloc;
   2636 	struct stat statbuf;
   2637 
   2638 
   2639 	pid = fork();
   2640 	switch (pid) {
   2641 	case -1:			/* Unable to create process */
   2642 		{
   2643 			int err = errno;
   2644 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTFORK),
   2645 			    strerror(err));
   2646 		}
   2647 		/*NOTREACHED*/
   2648 		return;
   2649 
   2650 	case 0:
   2651 		(void) execl(MSG_ORIG(MSG_STR_BINCP),
   2652 		    MSG_ORIG(MSG_STR_BINCP), infile, outfile, NULL);
   2653 		/*
   2654 		 * exec() only returns on error. This is the child process,
   2655 		 * so we want to stay away from the usual error mechanism
   2656 		 * and handle things directly.
   2657 		 */
   2658 		{
   2659 			int err = errno;
   2660 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_CNTEXEC),
   2661 			    MSG_ORIG(MSG_STR_ELFEDIT),
   2662 			    MSG_ORIG(MSG_STR_BINCP), strerror(err));
   2663 		}
   2664 		exit(1);
   2665 		/*NOTREACHED*/
   2666 	}
   2667 
   2668 	/* This is the parent: Wait for the child to terminate */
   2669 	if (waitpid(pid, &statloc,  0) != pid) {
   2670 		int err = errno;
   2671 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTWAIT),
   2672 		    strerror(err));
   2673 	}
   2674 	/*
   2675 	 * If the child failed, then terminate the process. There is no
   2676 	 * need for an error message, because the child will have taken
   2677 	 * care of that.
   2678 	 */
   2679 	if (!WIFEXITED(statloc) || (WEXITSTATUS(statloc) != 0))
   2680 		exit(1);
   2681 
   2682 	/* Make sure the copy allows user write access */
   2683 	if (stat(outfile, &statbuf) == -1) {
   2684 		int err = errno;
   2685 		(void) unlink(outfile);
   2686 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTSTAT),
   2687 		    outfile, strerror(err));
   2688 	}
   2689 	if ((statbuf.st_mode & S_IWUSR) == 0) {
   2690 		/* Only keep permission bits, and add user write */
   2691 		statbuf.st_mode |= S_IWUSR;
   2692 		statbuf.st_mode &= 07777;   /* Only keep the permission bits */
   2693 		if (chmod(outfile, statbuf.st_mode) == -1) {
   2694 			int err = errno;
   2695 			(void) unlink(outfile);
   2696 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTCHMOD),
   2697 			    outfile, strerror(err));
   2698 		}
   2699 	}
   2700 }
   2701 
   2702 /*
   2703  * Given a module path string, determine how long the resulting path will
   2704  * be when all % tokens have been expanded.
   2705  *
   2706  * entry:
   2707  *	path - Path for which expanded length is desired
   2708  *	origin_root - Root of $ORIGIN  tree containing running elfedit program
   2709  *
   2710  * exit:
   2711  *	Returns the value strlen() will give for the expanded path.
   2712  */
   2713 static size_t
   2714 modpath_strlen(const char *path, const char *origin_root)
   2715 {
   2716 	size_t len = 0;
   2717 	const char *s;
   2718 
   2719 	s = path;
   2720 	len = 0;
   2721 	for (s = path; *s != '\0'; s++) {
   2722 		if (*s == '%') {
   2723 			s++;
   2724 			switch (*s) {
   2725 			case 'i':	/* ISA of running elfedit */
   2726 				len += strlen(isa_i_str);
   2727 				break;
   2728 			case 'I':	/* "" for 32-bit, same as %i for 64 */
   2729 				len += strlen(isa_I_str);
   2730 				break;
   2731 			case 'o':	/* Insert default path */
   2732 				len +=
   2733 				    modpath_strlen(MSG_ORIG(MSG_STR_MODPATH),
   2734 				    origin_root);
   2735 				break;
   2736 			case 'r':	/* root of tree with running elfedit */
   2737 				len += strlen(origin_root);
   2738 				break;
   2739 
   2740 			case '%':	/* %% is reduced to just '%' */
   2741 				len++;
   2742 				break;
   2743 			default:	/* All other % codes are reserved */
   2744 				elfedit_msg(ELFEDIT_MSG_ERR,
   2745 				    MSG_INTL(MSG_ERR_BADPATHCODE), *s);
   2746 				/*NOTREACHED*/
   2747 				break;
   2748 			}
   2749 		} else {	/* Non-% character passes straight through */
   2750 			len++;
   2751 		}
   2752 	}
   2753 
   2754 	return (len);
   2755 }
   2756 
   2757 
   2758 /*
   2759  * Given a module path string, and a buffer large enough to hold the results,
   2760  * fill the buffer with the expanded path.
   2761  *
   2762  * entry:
   2763  *	path - Path for which expanded length is desired
   2764  *	origin_root - Root of tree containing running elfedit program
   2765  *	buf - Buffer to receive the result. buf must as large or larger
   2766  *		than the value given by modpath_strlen().
   2767  *
   2768  * exit:
   2769  *	Returns pointer to location following the last character
   2770  *	written to buf. A NULL byte is written to that address.
   2771  */
   2772 static char *
   2773 modpath_expand(const char *path, const char *origin_root, char *buf)
   2774 {
   2775 	size_t len;
   2776 	const char *cp_str;
   2777 
   2778 	for (; *path != '\0'; path++) {
   2779 		if (*path == '%') {
   2780 			path++;
   2781 			cp_str = NULL;
   2782 			switch (*path) {
   2783 			case 'i':	/* ISA of running elfedit */
   2784 				cp_str = isa_i_str;
   2785 				break;
   2786 			case 'I':	/* "" for 32-bit, same as %i for 64 */
   2787 				cp_str = isa_I_str;
   2788 				break;
   2789 			case 'o':	/* Insert default path */
   2790 				buf = modpath_expand(MSG_ORIG(MSG_STR_MODPATH),
   2791 				    origin_root, buf);
   2792 				break;
   2793 			case 'r':
   2794 				cp_str = origin_root;
   2795 				break;
   2796 			case '%':	/* %% is reduced to just '%' */
   2797 				*buf++ = *path;
   2798 				break;
   2799 			default:	/* All other % codes are reserved */
   2800 				elfedit_msg(ELFEDIT_MSG_ERR,
   2801 				    MSG_INTL(MSG_ERR_BADPATHCODE), *path);
   2802 				/*NOTREACHED*/
   2803 				break;
   2804 			}
   2805 			if ((cp_str != NULL) && ((len = strlen(cp_str)) > 0)) {
   2806 				bcopy(cp_str, buf, len);
   2807 				buf += len;
   2808 			}
   2809 		} else {	/* Non-% character passes straight through */
   2810 			*buf++ = *path;
   2811 		}
   2812 	}
   2813 
   2814 	*buf = '\0';
   2815 	return (buf);
   2816 }
   2817 
   2818 
   2819 /*
   2820  * Establish the module search path: state.modpath
   2821  *
   2822  * The path used comes from the following sources, taking the first
   2823  * one that has a value, and ignoring any others:
   2824  *
   2825  *	- ELFEDIT_PATH environment variable
   2826  *	- -L command line argument
   2827  *	- Default value
   2828  *
   2829  * entry:
   2830  *	path - NULL, or the value of the -L command line argument
   2831  *
   2832  * exit:
   2833  *	state.modpath has been filled in
   2834  */
   2835 static void
   2836 establish_modpath(const char *cmdline_path)
   2837 {
   2838 	char origin_root[PATH_MAX + 1];	/* Where elfedit binary is */
   2839 	const char	*path;		/* Initial path */
   2840 	char		*expath;	/* Expanded path */
   2841 	size_t		len;
   2842 	char		*src, *dst;
   2843 
   2844 	path = getenv(MSG_ORIG(MSG_STR_ENVVAR));
   2845 	if (path == NULL)
   2846 		path = cmdline_path;
   2847 	if (path == NULL)
   2848 		path = MSG_ORIG(MSG_STR_MODPATH);
   2849 
   2850 
   2851 	/*
   2852 	 * Root of tree containing running for running program. 32-bit elfedit
   2853 	 * is installed in /usr/bin, and 64-bit elfedit is one level lower
   2854 	 * in an ISA-specific subdirectory. So, we find the root by
   2855 	 * getting the $ORGIN of the current running program, and trimming
   2856 	 * off the last 2 (32-bit) or 3 (64-bit) directories.
   2857 	 *
   2858 	 * On a standard system, this will simply yield '/'. However,
   2859 	 * doing it this way allows us to run elfedit from a proto area,
   2860 	 * and pick up modules from the same proto area instead of those
   2861 	 * installed on the system.
   2862 	 */
   2863 	if (dlinfo(RTLD_SELF, RTLD_DI_ORIGIN, &origin_root) == -1)
   2864 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTGETORIGIN));
   2865 	len = (sizeof (char *) == 8) ? 3 : 2;
   2866 	src = origin_root + strlen(origin_root);
   2867 	while ((src > origin_root) && (len > 0)) {
   2868 		if (*(src - 1) == '/')
   2869 			len--;
   2870 		src--;
   2871 	}
   2872 	*src = '\0';
   2873 
   2874 
   2875 	/*
   2876 	 * Calculate space needed to hold expanded path. Note that
   2877 	 * this assumes that MSG_STR_MODPATH will never contain a '%o'
   2878 	 * code, and so, the expansion is not recursive. The codes allowed
   2879 	 * are:
   2880 	 *	%i - ISA of running elfedit (sparc, sparcv9, etc)
   2881 	 *	%I - 64-bit ISA: Same as %i for 64-bit versions of elfedit,
   2882 	 *		but yields empty string for 32-bit ISAs.
   2883 	 *	%o - The original (default) path.
   2884 	 *	%r - Root of tree holding elfedit program.
   2885 	 *	%% - A single %
   2886 	 *
   2887 	 * A % followed by anything else is an error. This allows us to
   2888 	 * add new codes in the future without backward compatability issues.
   2889 	 */
   2890 	len = modpath_strlen(path, origin_root);
   2891 
   2892 	expath = elfedit_malloc(MSG_INTL(MSG_ALLOC_EXPATH), len + 1);
   2893 	(void) modpath_expand(path, origin_root, expath);
   2894 
   2895 	/*
   2896 	 * Count path segments, eliminate extra '/', and replace ':'
   2897 	 * with NULL.
   2898 	 */
   2899 	state.modpath.n = 1;
   2900 	for (src = dst = expath; *src; src++) {
   2901 		if (*src == '/') {
   2902 			switch (*(src + 1)) {
   2903 			case '/':
   2904 			case ':':
   2905 			case '\0':
   2906 				continue;
   2907 			}
   2908 		}
   2909 		if (*src == ':') {
   2910 			state.modpath.n++;
   2911 			*dst = '\0';
   2912 		} else if (src != dst) {
   2913 			*dst = *src;
   2914 		}
   2915 		dst++;
   2916 	}
   2917 	if (src != dst)
   2918 		*dst = '\0';
   2919 
   2920 	state.modpath.seg = elfedit_malloc(MSG_INTL(MSG_ALLOC_PATHARR),
   2921 	    sizeof (state.modpath.seg[0]) * state.modpath.n);
   2922 
   2923 	src = expath;
   2924 	for (len = 0; len < state.modpath.n; len++) {
   2925 		if (*src == '\0') {
   2926 			state.modpath.seg[len] = MSG_ORIG(MSG_STR_DOT);
   2927 			src++;
   2928 		} else {
   2929 			state.modpath.seg[len] = src;
   2930 			src += strlen(src) + 1;
   2931 		}
   2932 	}
   2933 }
   2934 
   2935 /*
   2936  * When interactive (reading commands from a tty), we catch
   2937  * SIGINT in order to restart the outer command loop.
   2938  */
   2939 /*ARGSUSED*/
   2940 static void
   2941 sigint_handler(int sig, siginfo_t *sip, void *ucp)
   2942 {
   2943 	/* Jump to the outer loop to resume */
   2944 	if (state.msg_jbuf.active) {
   2945 		state.msg_jbuf.active = 0;
   2946 		siglongjmp(state.msg_jbuf.env, 1);
   2947 	}
   2948 }
   2949 
   2950 
   2951 static void
   2952 usage(int full)
   2953 {
   2954 	elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_BRIEF));
   2955 	if (full) {
   2956 		elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL1));
   2957 		elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL2));
   2958 		elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL3));
   2959 		elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL4));
   2960 		elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL5));
   2961 		elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL6));
   2962 		elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL_LAST));
   2963 	}
   2964 	elfedit_exit(2);
   2965 }
   2966 
   2967 
   2968 /*
   2969  * In order to complete commands, we need to know about them,
   2970  * which means that we need to force all the modules to be
   2971  * loaded. This is a relatively expensive operation, so we use
   2972  * this function, which avoids doing it more than once in a session.
   2973  */
   2974 static void
   2975 elfedit_cpl_load_modules(void)
   2976 {
   2977 	static int loaded;
   2978 
   2979 	if (!loaded) {
   2980 		elfedit_load_modpath();
   2981 		loaded = 1;	/* Don't do it again */
   2982 	}
   2983 }
   2984 
   2985 /*
   2986  * Compare the token to the given string, and if they share a common
   2987  * initial sequence, add the tail of string to the tecla command completion
   2988  * buffer:
   2989  *
   2990  * entry:
   2991  *	cpldata - Current completion state
   2992  *	str - String to match against token
   2993  *	casefold - True to allow case insensitive completion, False
   2994  *		if case must match exactly.
   2995  */
   2996 void
   2997 elfedit_cpl_match(void *cpldata, const char *str, int casefold)
   2998 {
   2999 	ELFEDIT_CPL_STATE *cstate = (ELFEDIT_CPL_STATE *) cpldata;
   3000 	const char	*cont_suffix;
   3001 	const char	*type_suffix;
   3002 
   3003 	/*
   3004 	 * Reasons to return immediately:
   3005 	 *	- NULL strings have no completion value
   3006 	 *	- The string is shorter than the existing item being completed
   3007 	 */
   3008 	if ((str == NULL) || (*str == '\0') ||
   3009 	    ((cstate->ecpl_token_len != 0) &&
   3010 	    ((strlen(str) < cstate->ecpl_token_len))))
   3011 		return;
   3012 
   3013 	/* If the string does not share the existing prefix, don't use it */
   3014 	if (casefold) {
   3015 		if (strncasecmp(cstate->ecpl_token_str, str,
   3016 		    cstate->ecpl_token_len) != 0)
   3017 			return;
   3018 	} else {
   3019 		if (strncmp(cstate->ecpl_token_str, str,
   3020 		    cstate->ecpl_token_len) != 0)
   3021 			return;
   3022 	}
   3023 
   3024 	if (cstate->ecpl_add_mod_colon) {
   3025 		cont_suffix = type_suffix = MSG_ORIG(MSG_STR_COLON);
   3026 	} else {
   3027 		cont_suffix = MSG_ORIG(MSG_STR_SPACE);
   3028 		type_suffix = NULL;
   3029 	}
   3030 	(void) cpl_add_completion(cstate->ecpl_cpl, cstate->ecpl_line,
   3031 	    cstate->ecpl_word_start, cstate->ecpl_word_end,
   3032 	    str + cstate->ecpl_token_len, type_suffix, cont_suffix);
   3033 
   3034 }
   3035 
   3036 
   3037 /*
   3038  * Convenience wrapper on elfedit_cpl_match(): Format an unsigned
   3039  * 32-bit integer as a string and enter the result for command completion.
   3040  */
   3041 void
   3042 elfedit_cpl_ndx(void *cpldata, uint_t ndx)
   3043 {
   3044 	Conv_inv_buf_t	buf;
   3045 
   3046 	(void) snprintf(buf.buf, sizeof (buf.buf),
   3047 	    MSG_ORIG(MSG_FMT_WORDVAL), ndx);
   3048 	elfedit_cpl_match(cpldata, buf.buf, 0);
   3049 }
   3050 
   3051 
   3052 /*
   3053  * Compare the token to the names of the commands from the given module,
   3054  * and if they share a common initial sequence, add the tail of string
   3055  * to the tecla command completion buffer:
   3056  *
   3057  * entry:
   3058  *	tok_buf - Token user has entered
   3059  *	tok_len - strlen(tok_buf)
   3060  *	mod - Module definition from which commands should be matched
   3061  *	cpl, line, word_start, word_end, cont_suffix - As documented
   3062  *		for gl_get_line() and cpl_add_completion.
   3063  */
   3064 static void
   3065 match_module_cmds(ELFEDIT_CPL_STATE *cstate, elfeditGC_module_t *mod)
   3066 {
   3067 	elfeditGC_cmd_t *cmd;
   3068 	const char **cmd_name;
   3069 
   3070 	for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++)
   3071 		for (cmd_name = cmd->cmd_name; *cmd_name; cmd_name++)
   3072 			elfedit_cpl_match(cstate, *cmd_name, 1);
   3073 }
   3074 
   3075 
   3076 /*
   3077  * Compare the token to the known module names, and add those that
   3078  * match to the list of alternatives via elfedit_cpl_match().
   3079  *
   3080  * entry:
   3081  *	load_all_modules - If True, causes all modules to be loaded
   3082  *		before processing is done. If False, only the modules
   3083  *		currently seen will be used.
   3084  */
   3085 void
   3086 elfedit_cpl_module(void *cpldata, int load_all_modules)
   3087 {
   3088 	ELFEDIT_CPL_STATE	*cstate = (ELFEDIT_CPL_STATE *) cpldata;
   3089 	MODLIST_T		*modlist;
   3090 
   3091 	if (load_all_modules)
   3092 		elfedit_cpl_load_modules();
   3093 
   3094 	for (modlist = state.modlist; modlist != NULL;
   3095 	    modlist = modlist->ml_next) {
   3096 		elfedit_cpl_match(cstate, modlist->ml_mod->mod_name, 1);
   3097 	}
   3098 }
   3099 
   3100 
   3101 /*
   3102  * Compare the token to all the known commands, and add those that
   3103  * match to the list of alternatives.
   3104  *
   3105  * note:
   3106  *	This routine will force modules to be loaded as necessary to
   3107  *	obtain the names it needs to match.
   3108  */
   3109 void
   3110 elfedit_cpl_command(void *cpldata)
   3111 {
   3112 	ELFEDIT_CPL_STATE	*cstate = (ELFEDIT_CPL_STATE *) cpldata;
   3113 	ELFEDIT_CPL_STATE	colon_state;
   3114 	const char		*colon_pos;
   3115 	MODLIST_T		*modlist;
   3116 	MODLIST_T		*insdef;
   3117 	char			buf[128];
   3118 
   3119 	/*
   3120 	 * Is there a colon in the command? If so, locate its offset within
   3121 	 * the raw input line.
   3122 	 */
   3123 	for (colon_pos = cstate->ecpl_token_str;
   3124 	    *colon_pos && (*colon_pos != ':'); colon_pos++)
   3125 		;
   3126 
   3127 	/*
   3128 	 * If no colon was seen, then we are completing a module name,
   3129 	 * or one of the commands from 'sys:'
   3130 	 */
   3131 	if (*colon_pos == '\0') {
   3132 		/*
   3133 		 * Setting cstate->add_mod_colon tells elfedit_cpl_match()
   3134 		 * to add an implicit ':' to the names it matches. We use it
   3135 		 * here so the user doesn't have to enter the ':' manually.
   3136 		 * Hiding this in the opaque state instead of making it
   3137 		 * an argument to that function gives us the ability to
   3138 		 * change it later without breaking the published interface.
   3139 		 */
   3140 		cstate->ecpl_add_mod_colon = 1;
   3141 		elfedit_cpl_module(cpldata, 1);
   3142 		cstate->ecpl_add_mod_colon = 0;
   3143 
   3144 		/* Add bare (no sys: prefix) commands from the sys: module */
   3145 		match_module_cmds(cstate,
   3146 		    elfedit_load_module(MSG_ORIG(MSG_MOD_SYS), 1, 0));
   3147 
   3148 		return;
   3149 	}
   3150 
   3151 	/*
   3152 	 * A colon was seen, so we have a module name. Extract the name,
   3153 	 * substituting 'sys' for the case where the given name is empty.
   3154 	 */
   3155 	if (colon_pos == 0)
   3156 		(void) strlcpy(buf, MSG_ORIG(MSG_MOD_SYS), sizeof (buf));
   3157 	else
   3158 		elfedit_strnbcpy(buf, cstate->ecpl_token_str,
   3159 		    colon_pos - cstate->ecpl_token_str, sizeof (buf));
   3160 
   3161 	/*
   3162 	 * Locate the module. If it isn't already loaded, make an explicit
   3163 	 * attempt to load it and try again. If a module definition is
   3164 	 * obtained, process the commands it supplies.
   3165 	 */
   3166 	modlist = module_loaded(buf, &insdef);
   3167 	if (modlist == NULL) {
   3168 		(void) elfedit_load_module(buf, 0, 0);
   3169 		modlist = module_loaded(buf, &insdef);
   3170 	}
   3171 	if (modlist != NULL) {
   3172 		/*
   3173 		 * Make a copy of the cstate, and adjust the line and
   3174 		 * token so that the new one starts just past the colon
   3175 		 * character. We know that the colon exists because
   3176 		 * of the preceeding test that found it. Therefore, we do
   3177 		 * not need to test against running off the end of the
   3178 		 * string here.
   3179 		 */
   3180 		colon_state = *cstate;
   3181 		while (colon_state.ecpl_line[colon_state.ecpl_word_start] !=
   3182 		    ':')
   3183 			colon_state.ecpl_word_start++;
   3184 		while (*colon_state.ecpl_token_str != ':') {
   3185 			colon_state.ecpl_token_str++;
   3186 			colon_state.ecpl_token_len--;
   3187 		}
   3188 		/* Skip past the ':' character */
   3189 		colon_state.ecpl_word_start++;
   3190 		colon_state.ecpl_token_str++;
   3191 		colon_state.ecpl_token_len--;
   3192 
   3193 		match_module_cmds(&colon_state, modlist->ml_mod);
   3194 	}
   3195 }
   3196 
   3197 
   3198 /*
   3199  * Command completion function for use with libtacla.
   3200  */
   3201 /*ARGSUSED1*/
   3202 static int
   3203 cmd_match_fcn(WordCompletion *cpl, void *data, const char *line, int word_end)
   3204 {
   3205 	const char		*argv[ELFEDIT_MAXCPLARGS];
   3206 	ELFEDIT_CPL_STATE	cstate;
   3207 	TOK_STATE		*tokst;
   3208 	int			ndx;
   3209 	int			i;
   3210 	elfeditGC_module_t	*mod;
   3211 	elfeditGC_cmd_t		*cmd;
   3212 	int			num_opt;
   3213 	int			opt_term_seen;
   3214 	int			skip_one;
   3215 	elfedit_cmd_optarg_t	*optarg;
   3216 	elfedit_optarg_item_t	item;
   3217 	int			ostyle_ndx = -1;
   3218 
   3219 	/*
   3220 	 * For debugging, enable the following block. It tells the tecla
   3221 	 * library that the program using is going to write to stdout.
   3222 	 * It will put the tty back into normal mode, and it will cause
   3223 	 * tecla to redraw the current input line when it gets control back.
   3224 	 */
   3225 #ifdef DEBUG_CMD_MATCH
   3226 	gl_normal_io(state.input.gl);
   3227 #endif
   3228 
   3229 	/*
   3230 	 * Tokenize the line up through word_end. The last token in
   3231 	 * the list is the one requiring completion.
   3232 	 */
   3233 	tokst = tokenize_user_cmd(line, word_end, 1);
   3234 	if (tokst->tokst_cnt == 0)
   3235 		return (0);
   3236 
   3237 	/* Set up the cstate block, containing the completion state */
   3238 	ndx = tokst->tokst_cnt - 1;	/* Index of token to complete */
   3239 	cstate.ecpl_cpl = cpl;
   3240 	cstate.ecpl_line = line;
   3241 	cstate.ecpl_word_start = tokst->tokst_buf[ndx].tok_line_off;
   3242 	cstate.ecpl_word_end = word_end;
   3243 	cstate.ecpl_add_mod_colon = 0;
   3244 	cstate.ecpl_token_str = tokst->tokst_buf[ndx].tok_str;
   3245 	cstate.ecpl_token_len = tokst->tokst_buf[ndx].tok_len;
   3246 
   3247 	/*
   3248 	 * If there is only one token, then we are completing the
   3249 	 * command itself.
   3250 	 */
   3251 	if (ndx == 0) {
   3252 		elfedit_cpl_command(&cstate);
   3253 		return (0);
   3254 	}
   3255 
   3256 	/*
   3257 	 * There is more than one token. Use the first one to
   3258 	 * locate the definition for the command. If we don't have
   3259 	 * a definition for the command, then there's nothing more
   3260 	 * we can do.
   3261 	 */
   3262 	cmd = elfedit_find_command(tokst->tokst_buf[0].tok_str, 0, &mod);
   3263 	if (cmd == NULL)
   3264 		return (0);
   3265 
   3266 	/*
   3267 	 * Since we know the command, give them a quick usage message.
   3268 	 * It may be that they just need a quick reminder about the form
   3269 	 * of the command and the options.
   3270 	 */
   3271 	(void) gl_normal_io(state.input.gl);
   3272 	elfedit_printf(MSG_INTL(MSG_USAGE_CMD),
   3273 	    elfedit_format_command_usage(mod, cmd, NULL, 0));
   3274 
   3275 
   3276 	/*
   3277 	 * We have a generous setting for ELFEDIT_MAXCPLARGS, so there
   3278 	 * should always be plenty of room. If there's not room, we
   3279 	 * can't proceed.
   3280 	 */
   3281 	if (ndx >= ELFEDIT_MAXCPLARGS)
   3282 		return (0);
   3283 
   3284 	/*
   3285 	 * Put pointers to the tokens into argv, and determine how
   3286 	 * many of the tokens are optional arguments.
   3287 	 *
   3288 	 * We consider the final optional argument to be the rightmost
   3289 	 * argument that starts with a '-'. If a '--' is seen, then
   3290 	 * we stop there, and any argument that follows is a plain argument
   3291 	 * (even if it starts with '-').
   3292 	 *
   3293 	 * We look for an inherited '-o' option, because we are willing
   3294 	 * to supply command completion for these values.
   3295 	 */
   3296 	num_opt = 0;
   3297 	opt_term_seen = 0;
   3298 	skip_one = 0;
   3299 	for (i = 0; i < ndx; i++) {
   3300 		argv[i] = tokst->tokst_buf[i + 1].tok_str;
   3301 		if (opt_term_seen || skip_one) {
   3302 			skip_one = 0;
   3303 			continue;
   3304 		}
   3305 		skip_one = 0;
   3306 		ostyle_ndx = -1;
   3307 		if ((strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_MINUS)) == NULL) ||
   3308 		    (*argv[i] != '-')) {
   3309 			opt_term_seen = 1;
   3310 			continue;
   3311 		}
   3312 		num_opt = i + 1;
   3313 		/*
   3314 		 * If it is a recognised ELFEDIT_CMDOA_F_VALUE option,
   3315 		 * then the item following it is the associated value.
   3316 		 * Check for this and skip the value.
   3317 		 *
   3318 		 * At the same time, look for STDOA_OPT_O inherited
   3319 		 * options. We want to identify the index of any such
   3320 		 * item. Although the option is simply "-o", we are willing
   3321 		 * to treat any option that starts with "-o" as a potential
   3322 		 * STDOA_OPT_O. This lets us to command completion for things
   3323 		 * like "-onum", and is otherwise harmless, the only cost
   3324 		 * being a few additional strcmps by the cpl code.
   3325 		 */
   3326 		if ((optarg = cmd->cmd_opt) == NULL)
   3327 			continue;
   3328 		while (optarg->oa_name != NULL) {
   3329 			int is_ostyle_optarg =
   3330 			    (optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) &&
   3331 			    (optarg->oa_name == ELFEDIT_STDOA_OPT_O);
   3332 
   3333 			elfedit_next_optarg(&optarg, &item);
   3334 			if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE) {
   3335 				if (is_ostyle_optarg && (strncmp(argv[i],
   3336 				    MSG_ORIG(MSG_STR_MINUS_O), 2) == 0))
   3337 					ostyle_ndx = i + 1;
   3338 
   3339 				if (strcmp(item.oai_name, argv[i]) == 0) {
   3340 					num_opt = i + 2;
   3341 					skip_one = 1;
   3342 					break;
   3343 				}
   3344 				/*
   3345 				 * If it didn't match "-o" exactly, but it is
   3346 				 * ostyle_ndx, then it is a potential combined
   3347 				 * STDOA_OPT_O, as discussed above. It counts
   3348 				 * as a single argument.
   3349 				 */
   3350 				if (ostyle_ndx == ndx)
   3351 					break;
   3352 			}
   3353 		}
   3354 	}
   3355 
   3356 #ifdef DEBUG_CMD_MATCH
   3357 	(void) printf("NDX(%d) NUM_OPT(%d) ostyle_ndx(%d)\n", ndx, num_opt,
   3358 	    ostyle_ndx);
   3359 #endif
   3360 
   3361 	if (ostyle_ndx != -1) {
   3362 		/*
   3363 		 * If ostyle_ndx is one less than ndx, and ndx is
   3364 		 * the same as num_opt, then we have a definitive
   3365 		 * STDOA_OPT_O inherited outstyle option. We supply
   3366 		 * the value strings, and are done.
   3367 		 */
   3368 		if ((ostyle_ndx == (ndx - 1)) && (ndx == num_opt)) {
   3369 			elfedit_cpl_atoconst(&cstate, ELFEDIT_CONST_OUTSTYLE);
   3370 			return (0);
   3371 		}
   3372 
   3373 		/*
   3374 		 * If ostyle is the same as ndx, then we have an option
   3375 		 * staring with "-o" that may end up being a STDOA_OPT_O,
   3376 		 * and we are still inside that token. In this case, we
   3377 		 * supply completion strings that include the leading
   3378 		 * "-o" followed by the values, without a space
   3379 		 * (i.e. "-onum"). We then fall through, allowing any
   3380 		 * other options starting with "-o" to be added
   3381 		 * below. elfedit_cpl_match() will throw out the incorrect
   3382 		 * options, so it is harmless to add these extra items in
   3383 		 * the worst case, and useful otherwise.
   3384 		 */
   3385 		if (ostyle_ndx == ndx)
   3386 			elfedit_cpl_atoconst(&cstate,
   3387 			    ELFEDIT_CONST_OUTSTYLE_MO);
   3388 	}
   3389 
   3390 	/*
   3391 	 * If (ndx <= num_opt), then the token needing completion
   3392 	 * is an option. If the leading '-' is there, then we should fill
   3393 	 * in all of the option alternatives. If anything follows the '-'
   3394 	 * though, we assume that the user has already figured out what
   3395 	 * option to use, and we leave well enough alone.
   3396 	 *
   3397 	 * Note that we are intentionally ignoring a related case
   3398 	 * where supplying option strings would be legal: In the case
   3399 	 * where we are one past the last option (ndx == (num_opt + 1)),
   3400 	 * and the current option is an empty string, the argument can
   3401 	 * be either a plain argument or an option --- the user needs to
   3402 	 * enter the next character before we can tell. It would be
   3403 	 * OK to enter the option strings in this case. However, consider
   3404 	 * what happens when the first plain argument to the command does
   3405 	 * not provide any command completion (e.g. it is a plain integer).
   3406 	 * In this case, tecla will see that all the alternatives start
   3407 	 * with '-', and will insert a '-' into the input. If the user
   3408 	 * intends the next argument to be plain, they will have to delete
   3409 	 * this '-', which is annoying. Worse than that, they may be confused
   3410 	 * by it, and think that the plain argument is not allowed there.
   3411 	 * The best solution is to not supply option strings unless the
   3412 	 * user first enters the '-'.
   3413 	 */
   3414 	if ((ndx <= num_opt) && (argv[ndx - 1][0] == '-')) {
   3415 		if ((optarg = cmd->cmd_opt) != NULL) {
   3416 			while (optarg->oa_name != NULL) {
   3417 				elfedit_next_optarg(&optarg, &item);
   3418 				elfedit_cpl_match(&cstate, item.oai_name, 1);
   3419 			}
   3420 		}
   3421 		return (0);
   3422 	}
   3423 
   3424 	/*
   3425 	 * At this point we know that ndx and num_opt are not equal.
   3426 	 * If num_opt is larger than ndx, then we have an ELFEDIT_CMDOA_F_VALUE
   3427 	 * argument at the end, and the following value has not been entered.
   3428 	 *
   3429 	 * If ndx is greater than num_opt, it means that we are looking
   3430 	 * at a plain argument (or in the case where (ndx == (num_opt + 1)),
   3431 	 * a *potential* plain argument.
   3432 	 *
   3433 	 * If the command has a completion function registered, then we
   3434 	 * hand off the remaining work to it. The cmd_cplfunc field is
   3435 	 * the generic definition. We need to cast it to the type that matches
   3436 	 * the proper ELFCLASS before calling it.
   3437 	 */
   3438 	if (state.elf.elfclass == ELFCLASS32) {
   3439 		elfedit32_cmdcpl_func_t *cmdcpl_func =
   3440 		    (elfedit32_cmdcpl_func_t *)cmd->cmd_cplfunc;
   3441 
   3442 		if (cmdcpl_func != NULL)
   3443 			(* cmdcpl_func)(state.elf.obj_state.s32,
   3444 			    &cstate, ndx, argv, num_opt);
   3445 	} else {
   3446 		elfedit64_cmdcpl_func_t *cmdcpl_func =
   3447 		    (elfedit64_cmdcpl_func_t *)cmd->cmd_cplfunc;
   3448 
   3449 		if (cmdcpl_func != NULL)
   3450 			(* cmdcpl_func)(state.elf.obj_state.s64,
   3451 			    &cstate, ndx, argv, num_opt);
   3452 	}
   3453 
   3454 	return (0);
   3455 }
   3456 
   3457 
   3458 /*
   3459  * Read a line of input from stdin, and return pointer to it.
   3460  *
   3461  * This routine uses a private buffer, so the contents of the returned
   3462  * string are only good until the next call.
   3463  */
   3464 static const char *
   3465 read_cmd(void)
   3466 {
   3467 	char *s;
   3468 
   3469 	if (state.input.full_tty) {
   3470 		state.input.in_tecla = TRUE;
   3471 		s = gl_get_line(state.input.gl,
   3472 		    MSG_ORIG(MSG_STR_PROMPT), NULL, -1);
   3473 		state.input.in_tecla = FALSE;
   3474 		/*
   3475 		 * gl_get_line() returns NULL for EOF or for error. EOF is fine,
   3476 		 * but we need to catch and report anything else. Since
   3477 		 * reading from stdin is critical to our operation, an
   3478 		 * error implies that we cannot recover and must exit.
   3479 		 */
   3480 		if ((s == NULL) &&
   3481 		    (gl_return_status(state.input.gl) == GLR_ERROR)) {
   3482 			elfedit_msg(ELFEDIT_MSG_FATAL, MSG_INTL(MSG_ERR_GLREAD),
   3483 			    gl_error_message(state.input.gl, NULL, 0));
   3484 		}
   3485 	} else {
   3486 		/*
   3487 		 * This should be a dynamically sized buffer, but for now,
   3488 		 * I'm going to take a simpler path.
   3489 		 */
   3490 		static char cmd_buf[ELFEDIT_MAXCMD + 1];
   3491 
   3492 		s = fgets(cmd_buf, sizeof (cmd_buf), stdin);
   3493 	}
   3494 
   3495 	/* Return user string, or 'quit' on EOF */
   3496 	return (s ? s : MSG_ORIG(MSG_SYS_CMD_QUIT));
   3497 }
   3498 
   3499 int
   3500 main(int argc, char **argv, char **envp)
   3501 {
   3502 	/*
   3503 	 * Note: This function can use setjmp()/longjmp() which does
   3504 	 * not preserve the values of auto/register variables. Hence,
   3505 	 * variables that need their values preserved across a jump must
   3506 	 * be marked volatile, or must not be auto/register.
   3507 	 *
   3508 	 * Volatile can be messy, because it requires explictly casting
   3509 	 * away the attribute when passing it to functions, or declaring
   3510 	 * those functions with the attribute as well. In a single threaded
   3511 	 * program like this one, an easier approach is to make things
   3512 	 * static. That can be done here, or by putting things in the
   3513 	 * 'state' structure.
   3514 	 */
   3515 
   3516 	int		c, i;
   3517 	int		num_batch = 0;
   3518 	char		**batch_list = NULL;
   3519 	const char	*modpath = NULL;
   3520 
   3521 	/*
   3522 	 * Always have liblddb display unclipped section names.
   3523 	 * This global is exported by liblddb, and declared in debug.h.
   3524 	 */
   3525 	dbg_desc->d_extra |= DBG_E_LONG;
   3526 
   3527 	opterr = 0;
   3528 	while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
   3529 		switch (c) {
   3530 		case 'a':
   3531 			state.flags |= ELFEDIT_F_AUTOPRINT;
   3532 			break;
   3533 
   3534 		case 'd':
   3535 			state.flags |= ELFEDIT_F_DEBUG;
   3536 			break;
   3537 
   3538 		case 'e':
   3539 			/*
   3540 			 * Delay parsing the -e options until after the call to
   3541 			 * conv_check_native() so that we won't bother loading
   3542 			 * modules of the wrong class.
   3543 			 */
   3544 			if (batch_list == NULL)
   3545 				batch_list = elfedit_malloc(
   3546 				    MSG_INTL(MSG_ALLOC_BATCHLST),
   3547 				    sizeof (*batch_list) * (argc - 1));
   3548 			batch_list[num_batch++] = optarg;
   3549 			break;
   3550 
   3551 		case 'L':
   3552 			modpath = optarg;
   3553 			break;
   3554 
   3555 		case 'o':
   3556 			if (elfedit_atooutstyle(optarg, &state.outstyle) == 0)
   3557 				usage(1);
   3558 			break;
   3559 
   3560 		case 'r':
   3561 			state.flags |= ELFEDIT_F_READONLY;
   3562 			break;
   3563 
   3564 		case '?':
   3565 			usage(1);
   3566 		}
   3567 	}
   3568 
   3569 	/*
   3570 	 * We allow 0, 1, or 2 files:
   3571 	 *
   3572 	 * The no-file case is an extremely limited mode, in which the
   3573 	 * only commands allowed to execute come from the sys: module.
   3574 	 * This mode exists primarily to allow easy access to the help
   3575 	 * facility.
   3576 	 *
   3577 	 * To get full access to elfedit's capablities, there must
   3578 	 * be an input file. If this is not a readonly
   3579 	 * session, then an optional second output file is allowed.
   3580 	 *
   3581 	 * In the case where two files are given and the session is
   3582 	 * readonly, use a full usage message, because the simple
   3583 	 * one isn't enough for the user to understand their error.
   3584 	 * Otherwise, the simple usage message suffices.
   3585 	 */
   3586 	argc = argc - optind;
   3587 	if ((argc == 2) && (state.flags & ELFEDIT_F_READONLY))
   3588 		usage(1);
   3589 	if (argc > 2)
   3590 		usage(0);
   3591 
   3592 	state.file.present = (argc != 0);
   3593 
   3594 	/*
   3595 	 * If we have a file to edit, and unless told otherwise by the
   3596 	 * caller, we try to run the 64-bit version of this program
   3597 	 * when the system is capable of it. If that fails, then we
   3598 	 * continue on with the currently running version.
   3599 	 *
   3600 	 * To force 32-bit execution on a 64-bit host, set the
   3601 	 * LD_NOEXEC_64 environment variable to a non-empty value.
   3602 	 *
   3603 	 * There is no reason to bother with this if in "no file" mode.
   3604 	 */
   3605 	if (state.file.present != 0)
   3606 		(void) conv_check_native(argv, envp);
   3607 
   3608 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_VERSION),
   3609 	    (sizeof (char *) == 8) ? 64 : 32);
   3610 
   3611 	/*
   3612 	 * Put a module definition for the builtin system module on the
   3613 	 * module list. We know it starts out empty, so we do not have
   3614 	 * to go through a more general insertion process than this.
   3615 	 */
   3616 	state.modlist = elfedit_sys_init(ELFEDIT_VER_CURRENT);
   3617 
   3618 	/* Establish the search path for loadable modules */
   3619 	establish_modpath(modpath);
   3620 
   3621 	/*
   3622 	 * Now that we are running the final version of this program,
   3623 	 * deal with the input/output file(s).
   3624 	 */
   3625 	if (state.file.present == 0) {
   3626 		/*
   3627 		 * This is arbitrary --- we simply need to be able to
   3628 		 * load modules so that we can access their help strings
   3629 		 * and command completion functions. Without a file, we
   3630 		 * will refuse to call commands from any module other
   3631 		 * than sys. Those commands have been written to be aware
   3632 		 * of the case where there is no input file, and are
   3633 		 * therefore safe to run.
   3634 		 */
   3635 		state.elf.elfclass = ELFCLASS32;
   3636 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_NOFILE));
   3637 
   3638 	} else {
   3639 		state.file.infile = argv[optind];
   3640 		if (argc == 1) {
   3641 			state.file.outfile = state.file.infile;
   3642 			if (state.flags & ELFEDIT_F_READONLY)
   3643 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   3644 				    MSG_INTL(MSG_DEBUG_READONLY));
   3645 			else
   3646 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   3647 				    MSG_INTL(MSG_DEBUG_INPLACEWARN),
   3648 				    state.file.infile);
   3649 		} else {
   3650 			state.file.outfile = argv[optind + 1];
   3651 			create_outfile(state.file.infile, state.file.outfile);
   3652 			elfedit_msg(ELFEDIT_MSG_DEBUG,
   3653 			    MSG_INTL(MSG_DEBUG_CPFILE),
   3654 			    state.file.infile, state.file.outfile);
   3655 			/*
   3656 			 * We are editing a copy of the original file that we
   3657 			 * just created. If we should exit before the edits are
   3658 			 * updated, then we want to unlink this copy so that we
   3659 			 * don't leave junk lying around. Once an update
   3660 			 * succeeds however, we'll leave it in place even
   3661 			 * if an error occurs afterwards.
   3662 			 */
   3663 			state.file.unlink_on_exit = 1;
   3664 			optind++;	/* Edit copy instead of the original */
   3665 		}
   3666 
   3667 		init_obj_state(state.file.outfile);
   3668 	}
   3669 
   3670 
   3671 	/*
   3672 	 * Process commands.
   3673 	 *
   3674 	 * If any -e options were used, then do them and
   3675 	 * immediately exit. On error, exit immediately without
   3676 	 * updating the target ELF file. On success, the 'write'
   3677 	 * and 'quit' commands are implicit in this mode.
   3678 	 *
   3679 	 * If no -e options are used, read commands from stdin.
   3680 	 * quit must be explicitly used. Exit is implicit on EOF.
   3681 	 * If stdin is a tty, then errors do not cause the editor
   3682 	 * to terminate. Rather, the error message is printed, and the
   3683 	 * user prompted to continue.
   3684 	 */
   3685 	if (batch_list != NULL) {	/* -e was used */
   3686 		/* Compile the commands */
   3687 		for (i = 0; i < num_batch; i++)
   3688 			parse_user_cmd(batch_list[i]);
   3689 		free(batch_list);
   3690 
   3691 		/*
   3692 		 * 'write' and 'quit' are implicit in this mode.
   3693 		 * Add them as well.
   3694 		 */
   3695 		if ((state.flags & ELFEDIT_F_READONLY) == 0)
   3696 			parse_user_cmd(MSG_ORIG(MSG_SYS_CMD_WRITE));
   3697 		parse_user_cmd(MSG_ORIG(MSG_SYS_CMD_QUIT));
   3698 
   3699 		/* And run them. This won't return, thanks to the 'quit' */
   3700 		dispatch_user_cmds();
   3701 	} else {
   3702 		state.input.is_tty = isatty(fileno(stdin));
   3703 		state.input.full_tty = state.input.is_tty &&
   3704 		    isatty(fileno(stdout));
   3705 
   3706 		if (state.input.full_tty) {
   3707 			struct sigaction act;
   3708 
   3709 			act.sa_sigaction = sigint_handler;
   3710 			(void) sigemptyset(&act.sa_mask);
   3711 			act.sa_flags = 0;
   3712 			if (sigaction(SIGINT, &act, NULL) == -1) {
   3713 				int err = errno;
   3714 				elfedit_msg(ELFEDIT_MSG_ERR,
   3715 				    MSG_INTL(MSG_ERR_SIGACTION), strerror(err));
   3716 			}
   3717 			/*
   3718 			 * If pager process exits before we are done
   3719 			 * writing, we can see SIGPIPE. Prevent it
   3720 			 * from killing the process.
   3721 			 */
   3722 			(void) sigignore(SIGPIPE);
   3723 
   3724 			/* Open tecla handle for command line editing */
   3725 			state.input.gl = new_GetLine(ELFEDIT_MAXCMD,
   3726 			    ELFEDIT_MAXHIST);
   3727 			/* Register our command completion function */
   3728 			(void) gl_customize_completion(state.input.gl,
   3729 			    NULL, cmd_match_fcn);
   3730 
   3731 			/*
   3732 			 * Make autoprint the default for interactive
   3733 			 * sessions.
   3734 			 */
   3735 			state.flags |= ELFEDIT_F_AUTOPRINT;
   3736 		}
   3737 		for (;;) {
   3738 			/*
   3739 			 * If this is an interactive session, then use
   3740 			 * sigsetjmp()/siglongjmp() to recover from bad
   3741 			 * commands and keep going. A non-0 return from
   3742 			 * sigsetjmp() means that an error just occurred.
   3743 			 * In that case, we simply restart this loop.
   3744 			 */
   3745 			if (state.input.is_tty) {
   3746 				if (sigsetjmp(state.msg_jbuf.env, 1) != 0) {
   3747 					if (state.input.full_tty)
   3748 						gl_abandon_line(state.input.gl);
   3749 					continue;
   3750 				}
   3751 				state.msg_jbuf.active = TRUE;
   3752 			}
   3753 
   3754 			/*
   3755 			 * Force all output out before each command.
   3756 			 * This is a no-OP when a tty is in use, but
   3757 			 * in a pipeline, it ensures that the block
   3758 			 * mode buffering doesn't delay output past
   3759 			 * the completion of each command.
   3760 			 *
   3761 			 * If we didn't do this, the output would eventually
   3762 			 * arrive at its destination, but the lag can be
   3763 			 * annoying when you pipe the output into a tool
   3764 			 * that displays the results in real time.
   3765 			 */
   3766 			(void) fflush(stdout);
   3767 			(void) fflush(stderr);
   3768 
   3769 			parse_user_cmd(read_cmd());
   3770 			dispatch_user_cmds();
   3771 			state.msg_jbuf.active = FALSE;
   3772 		}
   3773 	}
   3774 
   3775 
   3776 	/*NOTREACHED*/
   3777 	return (0);
   3778 }
   3779