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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
53 #include <debug.h> /* liblddb */
58 * Column at which elfedit_format_command_usage() will wrap the
59 * generated usage string if the wrap argument is True (1).
61 #define USAGE_WRAP_COL 55
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.
73 char *buf
; /* String buffer */
74 size_t n
; /* Size of buffer */
81 * Types used by tokenize_user_cmd() to represent the result of
82 * spliting a user command into individual tokens.
85 char *tok_str
; /* Token string */
86 size_t tok_len
; /* strlen(str) */
87 size_t tok_line_off
; /* Token offset in original string */
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 */
102 /* State block used by gettok_init() and gettok() */
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 */
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
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 */
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.
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) */
142 /* This structure maintains elfedit global state */
148 * Define a pair of static global variables that contain the
149 * ISA strings that correspond to %i and %I tokens in module search
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.
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
);
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
);
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
);
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
);
177 /* Forward declarations */
178 static void free_user_cmds(void);
179 static void elfedit_pager_cleanup(void);
184 * We supply this function for the msg module
187 _elfedit_msg(Msg mid
)
189 return (gettext(MSG_ORIG(mid
)));
194 * Copy at most min(cpsize, dstsize-1) bytes from src into dst,
195 * truncating src if necessary. The result is always null-terminated.
198 * dst - Destination buffer
199 * src - Source string
200 * dstsize - sizeof(dst)
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.
211 elfedit_strnbcpy(char *dst
, const char *src
, size_t cpsize
, size_t dstsize
)
213 if (cpsize
>= dstsize
)
214 cpsize
= dstsize
- 1;
216 (void) strncpy(dst
, src
, cpsize
+ 1);
222 * Calls exit() on behalf of elfedit.
225 elfedit_exit(int status
)
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
));
234 * If the edit file is marked for unlink on exit, then
235 * take care of it here.
237 if (state
.file
.unlink_on_exit
) {
238 elfedit_msg(ELFEDIT_MSG_DEBUG
,
239 MSG_INTL(MSG_DEBUG_UNLINKFILE
),
241 (void) unlink(state
.file
.outfile
);
250 * Standard message function for elfedit. All user visible
251 * output, for error or informational reasons, should go through
255 * type - Type of message. One of the ELFEDIT_MSG_* values.
256 * format, ... - As per the printf() family
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.
267 elfedit_msg(elfedit_msg_t type
, const char *format
, ...)
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 */
276 FILE *stream
= stderr
;
277 DISP disp
= DISP_RET
;
281 va_start(args
, format
);
284 case ELFEDIT_MSG_ERR
:
285 case ELFEDIT_MSG_CMDUSAGE
:
288 case ELFEDIT_MSG_FATAL
:
291 case ELFEDIT_MSG_USAGE
:
294 case ELFEDIT_MSG_DEBUG
:
295 if (!(state
.flags
& ELFEDIT_F_DEBUG
))
299 case ELFEDIT_MSG_QUIET
:
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.
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.
317 if (state
.pager
.fptr
!= NULL
) {
318 if (disp
== DISP_RET
) {
319 if (stream
== stdout
)
320 stream
= state
.pager
.fptr
;
322 elfedit_pager_cleanup();
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.
334 if (state
.input
.in_tecla
)
335 (void) gl_normal_io(state
.input
.gl
);
339 (void) fprintf(stream
, MSG_ORIG(MSG_STR_ELFEDIT
));
340 (void) vfprintf(stream
, format
, args
);
341 (void) fflush(stream
);
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.
350 if (disp
!= DISP_RET
) {
351 if (state
.msg_jbuf
.active
&& (disp
== DISP_JMP
)) {
352 /* Free the user command list */
355 /* Clean up to reflect effect of non-local goto */
356 state
.input
.in_tecla
= FALSE
;
358 /* Jump to the outer loop to resume */
359 siglongjmp(state
.msg_jbuf
.env
, 1);
368 * Wrapper on elfedit_msg() that issues an error that results from
372 * file - Name of ELF object
373 * libelf_rtn_name - Name of routine that was called
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.
381 elfedit_elferr(const char *file
, const char *libelf_rtn_name
)
383 const char *errstr
= elf_errmsg(elf_errno());
385 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_LIBELF
), file
,
386 libelf_rtn_name
, errstr
? errstr
: MSG_INTL(MSG_FMT_UNKNOWN
));
391 * Start an output pager process for elfedit_printf()/elfedit_write() to use.
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.
400 elfedit_pager_init(void)
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.
411 if (state
.msg_jbuf
.active
&& state
.input
.full_tty
&&
412 (state
.pager
.fptr
== NULL
)) {
414 * If the user has the PAGER environment variable set,
415 * then we will use that program. Otherwise we default
418 cmd
= getenv(MSG_ORIG(MSG_STR_PAGER
));
419 if ((cmd
== NULL
) || (*cmd
== '\0'))
420 cmd
= MSG_ORIG(MSG_STR_BINMORE
);
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.
428 state
.pager
.fptr
= popen(cmd
, MSG_ORIG(MSG_STR_W
));
429 if (state
.pager
.fptr
== NULL
) {
431 errstr
= (err
== 0) ? MSG_INTL(MSG_ERR_UNKNOWNSYSERR
) :
433 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTEXEC
),
434 MSG_ORIG(MSG_STR_ELFEDIT
), cmd
, errstr
);
441 * If there is a pager process present, close it out.
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.
451 elfedit_pager_cleanup(void)
453 if (state
.pager
.fptr
!= NULL
) {
454 if (pclose(state
.pager
.fptr
) == -1)
455 (void) fprintf(stderr
, MSG_INTL(MSG_ERR_PAGERFINI
));
457 state
.pager
.fptr
= NULL
;
463 * Print general formtted text for the user, using printf()-style
464 * formatting. Uses the pager process if one has been started, or
468 elfedit_printf(const char *format
, ...)
477 * If there is a pager process, then use it. Otherwise write
478 * directly to stdout.
480 pager
= (state
.pager
.fptr
!= NULL
);
481 fptr
= pager
? state
.pager
.fptr
: stdout
;
483 va_start(args
, format
);
485 err
= vfprintf(fptr
, format
, args
);
487 /* Did we fail because a child pager process has exited? */
488 broken_pipe
= pager
&& (err
< 0) && (errno
== EPIPE
);
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.
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.
503 elfedit_msg(ELFEDIT_MSG_QUIET
, MSG_ORIG(MSG_STR_NULL
));
505 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_PRINTF
));
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()
516 * This item should be defined NODIRECT.
520 dbg_print(Lm_list
*lml
, const char *format
, ...)
530 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
531 * Supress the lint error by making a dummy assignment.
537 * If there is a pager process, then use it. Otherwise write
538 * directly to stdout.
540 pager
= (state
.pager
.fptr
!= NULL
);
541 fptr
= pager
? state
.pager
.fptr
: stdout
;
543 va_start(ap
, format
);
545 err
= vfprintf(fptr
, format
, ap
);
547 err
= fprintf(fptr
, MSG_ORIG(MSG_STR_NL
));
549 /* Did we fail because a child pager process has exited? */
550 broken_pipe
= (err
< 0) && pager
&& (errno
== EPIPE
);
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.
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.
565 elfedit_msg(ELFEDIT_MSG_QUIET
, MSG_ORIG(MSG_STR_NULL
));
567 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_PRINTF
));
573 * Write raw bytes of text in a manner similar to fwrite().
574 * Uses the pager process if one has been started, or
578 elfedit_write(const void *ptr
, size_t size
)
584 * If there is a pager process, then use it. Otherwise write
585 * directly to stdout.
587 fptr
= (state
.pager
.fptr
== NULL
) ? stdout
: state
.pager
.fptr
;
589 if (fwrite(ptr
, 1, size
, fptr
) != size
) {
591 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_FWRITE
),
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()
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
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
614 * The string has been processed, with the resulting data passed
615 * to outfunc for processing.
618 elfedit_str_to_c_literal_cb(const void *ptr
, size_t size
, void *uvalue
)
620 elfedit_write_func_t
*outfunc
= (elfedit_write_func_t
*)uvalue
;
622 (* outfunc
)(ptr
, size
);
626 elfedit_str_to_c_literal(const char *str
, elfedit_write_func_t
*outfunc
)
628 conv_str_to_c_literal(str
, strlen(str
),
629 elfedit_str_to_c_literal_cb
, (void *) outfunc
);
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.
640 elfedit_malloc(const char *item_name
, size_t size
)
647 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_MALLOC
),
648 item_name
, strerror(err
));
655 elfedit_realloc(const char *item_name
, void *ptr
, size_t size
)
659 m
= realloc(ptr
, size
);
662 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_MALLOC
),
663 item_name
, strerror(err
));
671 * Ensure that the given buffer has room for n bytes of data.
674 strbuf_ensure_size(STRBUF
*str
, size_t size
)
676 #define INITIAL_STR_ALLOC 128
680 n
= (str
->n
== 0) ? INITIAL_STR_ALLOC
: str
->n
;
681 while (size
> n
) /* Double buffer until string fits */
683 if (n
!= str
->n
) { /* Alloc new string buffer if needed */
684 str
->buf
= elfedit_realloc(MSG_INTL(MSG_ALLOC_UCMDSTR
),
689 #undef INITIAL_STR_ALLOC
694 * Extract the argument/option information for the next item referenced
695 * by optarg, and advance the pointer to the next item.
698 * optarg - Address of pointer to argument or option array
699 * item - Struct to be filled in.
702 * The item block has been filled in with the information for
703 * the next item in the optarg array. *optarg has been advanced
707 elfedit_next_optarg(elfedit_cmd_optarg_t
**optarg
, elfedit_optarg_item_t
*item
)
710 * Array of inheritable options/arguments. Indexed by one less
711 * than the corresponding ELFEDIT_STDOA_ value.
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
},
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 },
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 },
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 },
736 elfedit_cmd_optarg_t
*oa
;
739 /* Grab first item, advance the callers pointer over it */
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];
747 * Set the inherited flag so that elfedit_optarg_helpstr()
748 * can tell who is responsible for translating the help string.
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
;
756 /* Advance users pointer past value element */
759 item
->oai_vname
= NULL
;
761 item
->oai_help
= oa
->oa_help
;
762 item
->oai_flags
= oa
->oa_flags
;
766 * The module determines the idmask and excmask fields whether
767 * or not inheritance is in play.
769 item
->oai_idmask
= oa
->oa_idmask
;
770 item
->oai_excmask
= oa
->oa_excmask
;
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.
782 elfedit_optarg_helpstr(elfeditGC_module_t
*mod
, elfedit_optarg_item_t
*item
)
785 * The help string from an inherited item comes right out
786 * of the main elfedit string table.
788 if (item
->oai_flags
& ELFEDIT_CMDOA_F_INHERIT
)
789 return (MSG_INTL((Msg
) item
->oai_help
));
792 * If the string is defined by the module, then we need to
793 * have the module translate it for us.
795 return ((* mod
->mod_i18nhdl_to_str
)(item
->oai_help
));
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.
806 usage_optarg_insert_ch(int ch
, char **cur
, size_t *n
, size_t *cur_col
)
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.
821 usage_optarg_insert_str(char **cur
, size_t *n
, size_t *cur_col
,
822 const char *format
, ...)
827 va_start(args
, format
);
828 len
= vsnprintf(*cur
, *n
, format
, args
);
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.
841 usage_optarg_insert_item(elfedit_optarg_item_t
*item
, char **cur
,
842 size_t *n
, size_t *cur_col
)
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
);
850 len
= snprintf(*cur
, *n
, MSG_ORIG(MSG_STR_HLPOPTARG
),
861 * Write the options/arguments to the usage string.
864 * main_buf_n - Size of main buffer from which buf and buf_n are
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
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
)
880 * An option can be combined into a simple format if it lacks
881 * these flags and is only one character in length.
883 static const elfedit_cmd_oa_flag_t exflags
=
884 (ELFEDIT_CMDOA_F_VALUE
| ELFEDIT_CMDOA_F_MULT
);
887 * A static buffer, which is grown as needed to accomodate
888 * the maximum usage string seen.
890 static STRBUF simple_str
;
894 size_t cur_col
= *buf_cur_col
;
897 elfedit_optarg_item_t item
;
898 elfedit_cmd_oa_mask_t optmask
= 0;
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.
907 elfedit_cmd_optarg_t
*tmp_optarg
= optarg
;
911 * The simple string is guaranteed to fit in the same
912 * amount of space reserved for the main buffer.
914 strbuf_ensure_size(&simple_str
, main_buf_n
);
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];
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.
935 use_simple
= (s
> (simple_str
.buf
+ 4));
939 usage_optarg_insert_str(&cur
, &n
, &cur_col
,
940 MSG_ORIG(MSG_STR_HLPOPTARG
), simple_str
.buf
);
942 /* Not using it, so reset the cumulative options mask */
947 while (optarg
->oa_name
!= NULL
) {
948 elfedit_next_optarg(&optarg
, &item
);
952 * If this is an option that was pulled into the
953 * combination string above, then skip over it.
955 if (use_simple
&& ((item
.oai_flags
& exflags
) == 0) &&
956 (item
.oai_name
[2] == '\0') &&
957 (item
.oai_excmask
== 0))
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.
965 if ((optmask
& item
.oai_idmask
) != 0)
968 /* Add this item to the accumulating options mask */
969 optmask
|= item
.oai_idmask
;
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
),
978 cur_col
= len
- 1; /* Don't count the newline */
980 usage_optarg_insert_ch(' ', &cur
, &n
, &cur_col
);
983 use_bkt
= (item
.oai_flags
& ELFEDIT_CMDOA_F_OPT
) || isopt
;
985 usage_optarg_insert_ch('[', &cur
, &n
, &cur_col
);
987 /* Add the item to the buffer */
988 usage_optarg_insert_item(&item
, &cur
, &n
, &cur_col
);
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).
997 if (item
.oai_excmask
!= 0) {
998 elfedit_cmd_optarg_t
*tmp_optarg
= optarg
;
999 elfedit_optarg_item_t tmp_item
;
1002 * When showing alternation, elipses for multiple
1003 * copies need to appear inside the [] brackets.
1005 if (item
.oai_flags
& ELFEDIT_CMDOA_F_MULT
)
1006 usage_optarg_insert_str(&cur
, &n
, &cur_col
,
1007 MSG_ORIG(MSG_STR_ELIPSES
));
1010 while (tmp_optarg
->oa_name
!= NULL
) {
1011 elfedit_next_optarg(&tmp_optarg
, &tmp_item
);
1012 if ((item
.oai_excmask
& tmp_item
.oai_idmask
) ==
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
);
1021 * Add it to the mask of seen options.
1022 * This will keep us from showing it twice.
1024 optmask
|= tmp_item
.oai_idmask
;
1028 usage_optarg_insert_ch(']', &cur
, &n
, &cur_col
);
1031 * If alternation was not shown above (non-zero exclusion mask)
1032 * then the elipses for multiple copies are shown outside
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
));
1044 *buf_cur_col
= cur_col
;
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.
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.
1064 elfedit_format_command_usage(elfeditGC_module_t
*mod
, elfeditGC_cmd_t
*cmd
,
1065 const char *wrap_str
, size_t cur_col
)
1069 * A static buffer, which is grown as needed to accomodate
1070 * the maximum usage string seen.
1074 elfedit_cmd_optarg_t
*optarg
;
1075 size_t len
, n
, elipses_len
;
1077 elfedit_optarg_item_t item
;
1080 * Estimate a worst case size for the usage string:
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
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
;
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
;
1099 n
++; /* Null termination */
1102 * If wrapping lines, we insert a newline and then wrap_str
1103 * every USAGE_WRAP_COL characters.
1105 if (wrap_str
!= NULL
)
1106 n
+= ((n
+ USAGE_WRAP_COL
) / USAGE_WRAP_COL
) *
1107 (strlen(wrap_str
) + 1);
1109 strbuf_ensure_size(&str
, n
);
1114 if (strcmp(mod
->mod_name
, MSG_ORIG(MSG_MOD_SYS
)) == 0)
1115 len
= snprintf(cur
, n
, MSG_ORIG(MSG_FMT_SYSCMD
),
1118 len
= snprintf(cur
, n
, MSG_ORIG(MSG_FMT_MODCMD
),
1119 mod
->mod_name
, cmd
->cmd_name
[0]);
1124 if (cmd
->cmd_opt
!= NULL
)
1125 usage_optarg(str
.n
, &cur
, &n
, &cur_col
, cmd
->cmd_opt
,
1127 if (cmd
->cmd_args
!= NULL
)
1128 usage_optarg(str
.n
, &cur
, &n
, &cur_col
, cmd
->cmd_args
,
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.
1140 elfedit_command_usage(void)
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));
1149 * This function allows the loadable modules to get the command line
1155 return (state
.flags
);
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
1165 * str - One of the valid strings for the output style
1168 elfedit_set_cmd_outstyle(const char *str
)
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;
1179 * This function allows the loadable modules to get the output style.
1182 elfedit_outstyle(void)
1185 * If there is an active per-command output style,
1188 if ((state
.cur_cmd
!= NULL
) && (state
.cur_cmd
->ucmd_ostyle_set
))
1189 return (state
.cur_cmd
->ucmd_ostyle
);
1192 return (state
.outstyle
);
1196 * Return the command descriptor of the currently executing command.
1197 * For use only by the modules or code called by the modules.
1200 elfedit_curcmd(void)
1202 return (state
.cur_cmd
->ucmd_cmd
);
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.
1212 * file - Name of file to process
1215 * Fills state.elf with the necessary information for the open file.
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.
1222 init_obj_state(const char *file
)
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.
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.
1240 open_flag
= ((state
.flags
& ELFEDIT_F_READONLY
) ? O_RDONLY
: O_RDWR
);
1241 if ((fd
= open(file
, open_flag
)) == -1) {
1243 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTOPNFILE
),
1244 file
, strerror(err
));
1246 (void) elf_version(EV_CURRENT
);
1247 elf
= elf_begin(fd
, ELF_C_RDWR
, NULL
);
1250 elfedit_elferr(file
, MSG_ORIG(MSG_ELF_BEGIN
));
1254 /* We only handle standalone ELF files */
1255 switch (elf_kind(elf
)) {
1258 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_NOAR
), file
);
1264 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_UNRECELFFILE
),
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.
1277 (void) elf_flagelf(elf
, ELF_C_SET
, ELF_F_LAYOUT
);
1279 /* Fill in state.elf.obj_state */
1280 state
.elf
.elfclass
= gelf_getclass(elf
);
1281 switch (state
.elf
.elfclass
) {
1283 elfedit32_init_obj_state(file
, fd
, elf
);
1286 elfedit64_init_obj_state(file
, fd
, elf
);
1290 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_BADELFCLASS
),
1297 #ifdef DEBUG_MODULE_LIST
1299 * Debug routine. Dump the module list to stdout.
1302 dbg_module_list(char *title
)
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>");
1312 printf("<END OF MODULE LIST>\n");
1318 * Search the module list for the named module.
1321 * name - Name of module to find
1322 * insdef - Address of variable to receive address of predecessor
1323 * node to the desired one.
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.
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.
1335 module_loaded(const char *name
, MODLIST_T
**insdef
)
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 */
1346 } else if (cmp
> 0) { /* cmp > 0: Insert in middle/end */
1348 moddef
= moddef
->ml_next
;
1350 while (moddef
&& (cmp
< 0)) {
1351 cmp
= strcasecmp(moddef
->ml_mod
->mod_name
,
1357 moddef
= (*insdef
)->ml_next
;
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.
1374 path_is_so(const char *path
)
1384 if (isdigit(*(tail
- 1))) {
1385 while ((tail
> path
) && isdigit(*(tail
- 1)))
1387 if ((tail
<= path
) || (*tail
!= '.'))
1390 dotso_len
= strlen(MSG_ORIG(MSG_STR_DOTSO
));
1391 if ((tail
- path
) < dotso_len
)
1394 if (strncmp(tail
, MSG_ORIG(MSG_STR_DOTSO
), dotso_len
) == 0)
1402 * Locate the start of the unsuffixed file name within path. Returns pointer
1403 * to first character of that name in path.
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)
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.
1421 elfedit_basename(const char *path
, const char *tail
, char *buf
, size_t bufsiz
)
1426 tail
= path
+ strlen(path
);
1428 while ((s
> path
) && (*(s
- 1) != '/'))
1431 elfedit_strnbcpy(buf
, s
, tail
- s
, bufsiz
);
1437 * Issue an error on behalf of load_module(), taking care to release
1438 * resources that routine may have aquired:
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
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.
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.
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
,
1463 #define SCRBUFSIZE (PATH_MAX + 256) /* A path, plus some extra */
1465 char s1_buf
[SCRBUFSIZE
];
1466 char s2_buf
[SCRBUFSIZE
];
1467 char s3_buf
[SCRBUFSIZE
];
1468 char s4_buf
[SCRBUFSIZE
];
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.
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.
1485 (void) strlcpy(s1_buf
, s1
, sizeof (s1_buf
));
1487 (void) strlcpy(s2_buf
, s2
, sizeof (s2_buf
));
1489 (void) strlcpy(s3_buf
, s3
, sizeof (s3_buf
));
1491 (void) strlcpy(s4_buf
, s4
, sizeof (s4_buf
));
1497 if ((dl_hdl
!= NULL
) && (dlclose(dl_hdl
) != 0))
1498 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTDLCLOSE
),
1499 dl_path
, dlerror());
1501 elfedit_msg(ELFEDIT_MSG_ERR
, format
, s1_buf
, s2_buf
, s3_buf
, s4_buf
);
1507 * Load a module sharable object for load_module().
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.
1519 * Returns a handle to the loaded object on success, or NULL if no
1523 load_module_dlopen(const char *path
, MODLIST_T
*moddef
, int must_exist
)
1529 * If the file is not required to exist, and it doesn't, then
1530 * we want to quietly return without an error.
1533 fd
= open(path
, O_RDONLY
);
1536 } else if (errno
== ENOENT
) {
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
);
1550 * Sanity check option arguments to prevent common errors. The rest of
1551 * elfedit assumes these tests have been done, and does not check
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
)
1559 #define FAIL(_msg) errmsg = _msg; goto fail
1562 elfedit_cmd_oa_mask_t optmask
= 0;
1564 for (; optarg
->oa_name
!= NULL
; optarg
++) {
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
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
))
1578 * Can't use FAIL --- oa_name is not a valid
1579 * string, and load_module_err() looks at args.
1581 load_module_err(moddef
, dl_hdl
, dl_path
,
1582 MSG_INTL(MSG_ERR_BADSTDOA
), dl_path
,
1583 mod_name
, cmd_name
, NULL
);
1589 * Option name must start with a '-', and must
1590 * have at one following character.
1592 if (optarg
->oa_name
[0] != '-') {
1593 /* MSG_INTL(MSG_ERR_OPT_MODPRE) */
1594 FAIL(MSG_ERR_OPT_MODPRE
);
1596 if (optarg
->oa_name
[1] == '\0') {
1597 /* MSG_INTL(MSG_ERR_OPT_MODLEN) */
1598 FAIL(MSG_ERR_OPT_MODLEN
);
1602 * oa_idmask must be 0, or it must have a single
1603 * bit set (a power of 2).oa_excmask must be 0
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
);
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
);
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
);
1624 /* Add this one to the overall mask */
1625 optmask
|= optarg
->oa_idmask
;
1629 * Argument name cannot start with a'-', and must
1630 * not be a null string.
1632 if (optarg
->oa_name
[0] == '-') {
1633 /* MSG_INTL(MSG_ERR_ARG_MODPRE) */
1634 FAIL(MSG_ERR_ARG_MODPRE
);
1636 if (optarg
->oa_name
[1] == '\0') {
1637 /* MSG_INTL(MSG_ERR_ARG_MODLEN) */
1638 FAIL(MSG_ERR_ARG_MODLEN
);
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
);
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
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
1662 if (optarg
->oa_flags
& ELFEDIT_CMDOA_F_VALUE
) {
1663 elfedit_cmd_optarg_t
*oa1
= optarg
+ 1;
1666 /* MSG_INTL(MSG_ERR_ARG_CMDOA_VAL) */
1667 FAIL(MSG_ERR_ARG_CMDOA_VAL
);
1670 if ((optarg
+ 1)->oa_name
== NULL
) {
1671 /* MSG_INTL(MSG_ERR_BADMODOPTVAL) */
1672 FAIL(MSG_ERR_BADMODOPTVAL
);
1675 if (oa1
->oa_name
== NULL
) {
1676 /* MSG_INTL(MSG_ERR_CMDOA_VALNAM) */
1677 FAIL(MSG_ERR_CMDOA_VALNAM
);
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
);
1692 load_module_err(moddef
, dl_hdl
, dl_path
, MSG_INTL(errmsg
),
1693 dl_path
, mod_name
, cmd_name
, optarg
->oa_name
);
1697 * Look up the specified module, loading the module if necessary,
1698 * and return its definition, or NULL on failure.
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
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
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
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,
1726 elfeditGC_module_t
*
1727 elfedit_load_module(const char *name
, int must_exist
, int allow_abs
)
1729 elfedit_init_func_t
*init_func
;
1730 elfeditGC_module_t
*mod
;
1731 MODLIST_T
*moddef
, *insdef
;
1733 char path_buf
[PATH_MAX
+ 1];
1737 elfeditGC_cmd_t
*cmd
;
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.
1745 is_abs_path
= (path_is_so(name
) != NULL
) ||
1746 (name
!= elfedit_basename(name
, NULL
, NULL
, 0));
1748 if (is_abs_path
&& !allow_abs
)
1749 load_module_err(NULL
, NULL
, NULL
,
1750 MSG_INTL(MSG_ERR_UNRECMOD
), name
, NULL
, NULL
, NULL
);
1753 * If this is a non-absolute path, search for the module already
1754 * having been loaded, and return it if so.
1757 moddef
= module_loaded(name
, &insdef
);
1759 return (moddef
->ml_mod
);
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.
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.
1776 moddef
= elfedit_malloc(MSG_INTL(MSG_ALLOC_MODDEF
),
1777 sizeof (*moddef
) + PATH_MAX
+ 1);
1778 moddef
->ml_path
= ((char *)moddef
) + sizeof (*moddef
);
1782 hdl
= load_module_dlopen(name
, moddef
, must_exist
);
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);
1795 if (must_exist
&& (hdl
== NULL
))
1796 load_module_err(moddef
, NULL
, NULL
,
1797 MSG_INTL(MSG_ERR_UNRECMOD
), name
, NULL
, NULL
, NULL
);
1805 if (state
.elf
.elfclass
== ELFCLASS32
) {
1806 init_func
= (elfedit_init_func_t
*)
1807 dlsym(hdl
, MSG_ORIG(MSG_STR_ELFEDITINIT32
));
1809 init_func
= (elfedit_init_func_t
*)
1810 dlsym(hdl
, MSG_ORIG(MSG_STR_ELFEDITINIT64
));
1812 if (init_func
== NULL
)
1813 load_module_err(moddef
, hdl
, path
,
1814 MSG_INTL(MSG_ERR_SONOTMOD
), path
, NULL
, NULL
, NULL
);
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.
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
);
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
1832 * - Arguments and options must be well formed.
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
,
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
);
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.
1853 MODLIST_T
*old_moddef
= module_loaded(mod
->mod_name
, &insdef
);
1855 if (old_moddef
!= NULL
) { /* Replace existing */
1856 free(moddef
); /* Rare case: Don't need it */
1858 * Be sure we don't unload builtin modules!
1859 * These have a NULL dl_hdl field.
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
,
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
,
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
);
1885 * insdef now contains the insertion point for the absolute
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
);
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
1901 if (insdef
== NULL
) {
1902 moddef
->ml_next
= state
.modlist
;
1903 state
.modlist
= moddef
;
1905 moddef
->ml_next
= insdef
->ml_next
;
1906 insdef
->ml_next
= moddef
;
1908 moddef
->ml_mod
= mod
;
1909 moddef
->ml_dl_hdl
= hdl
;
1910 (void) strlcpy((char *)moddef
->ml_path
, path
, PATH_MAX
+ 1);
1912 elfedit_msg(ELFEDIT_MSG_DEBUG
, MSG_INTL(MSG_DEBUG_MODLOAD
),
1913 moddef
->ml_mod
->mod_name
, path
);
1915 return (moddef
->ml_mod
);
1920 * Unload the specified module
1923 elfedit_unload_module(const char *name
)
1925 MODLIST_T
*moddef
, *insdef
;
1927 moddef
= module_loaded(name
, &insdef
);
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
);
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.
1940 elfedit_msg(ELFEDIT_MSG_DEBUG
, MSG_INTL(MSG_DEBUG_MODUNLOAD
),
1941 moddef
->ml_mod
->mod_name
, moddef
->ml_path
);
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.
1948 if (dlclose(moddef
->ml_dl_hdl
) != 0)
1949 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTDLCLOSE
),
1950 moddef
->ml_path
, dlerror());
1952 /* Unlink the record from the module list */
1954 state
.modlist
= moddef
->ml_next
;
1956 insdef
->ml_next
= moddef
->ml_next
;
1958 /* Release the memory */
1964 * Load all sharable objects found in the specified directory.
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.
1975 elfedit_load_moddir(const char *dirpath
, int must_exist
, int abs_path
)
1977 char path
[PATH_MAX
+ 1];
1982 dir
= opendir(dirpath
);
1986 if (!must_exist
&& (err
== ENOENT
))
1988 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTOPNDIR
),
1989 dirpath
, strerror(err
));
1993 while (dp
= readdir(dir
)) {
1994 if ((tail
= path_is_so(dp
->d_name
)) != NULL
) {
1996 (void) snprintf(path
, sizeof (path
),
1997 MSG_ORIG(MSG_FMT_BLDPATH
), dirpath
,
2000 (void) elfedit_basename(dp
->d_name
, tail
,
2001 path
, sizeof (path
));
2003 (void) elfedit_load_module(path
, must_exist
, 1);
2006 (void) closedir(dir
);
2011 * Follow the module load path, and load the first module found for each
2015 elfedit_load_modpath(void)
2019 for (i
= 0; i
< state
.modpath
.n
; i
++)
2020 elfedit_load_moddir(state
.modpath
.seg
[i
], 0, 0);
2024 * Given a module definition, look for the specified command.
2025 * Returns the command if found, and NULL otherwise.
2027 static elfeditGC_cmd_t
*
2028 find_cmd(elfeditGC_module_t
*mod
, const char *name
)
2030 elfeditGC_cmd_t
*cmd
;
2031 const char **cmd_name
;
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
);
2049 * Given a command name, return its command definition.
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
2056 * mod_ret - NULL, or address of a variable to receive the
2057 * module definition block of the module containing
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.
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.
2074 elfedit_find_command(const char *name
, int must_exist
,
2075 elfeditGC_module_t
**mod_ret
)
2077 elfeditGC_module_t
*mod
;
2078 const char *mod_str
;
2079 const char *cmd_str
;
2080 char mod_buf
[ELFEDIT_MAXMODNAM
+ 1];
2082 elfeditGC_cmd_t
*cmd
;
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
);
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 */
2094 if (n
>= sizeof (mod_buf
)) {
2096 elfedit_msg(ELFEDIT_MSG_ERR
,
2097 MSG_INTL(MSG_ERR_MODNAMTOOLONG
), name
);
2100 (void) strlcpy(mod_buf
, name
, n
+ 1);
2105 /* Lookup/load module. Won't return on error */
2106 mod
= elfedit_load_module(mod_str
, must_exist
, 0);
2110 /* Locate the command */
2111 cmd
= find_cmd(mod
, cmd_str
);
2115 * Catch empty command in order to provide
2116 * a better error message.
2118 if (*cmd_str
== '\0') {
2119 elfedit_msg(ELFEDIT_MSG_ERR
,
2120 MSG_INTL(MSG_ERR_MODNOCMD
), mod_str
);
2122 elfedit_msg(ELFEDIT_MSG_ERR
,
2123 MSG_INTL(MSG_ERR_UNRECCMD
),
2128 if (mod_ret
!= NULL
)
2136 * Release all user command blocks found on state.ucmd
2139 free_user_cmds(void)
2143 while (state
.ucmd
.list
) {
2144 next
= state
.ucmd
.list
->ucmd_next
;
2145 free(state
.ucmd
.list
);
2146 state
.ucmd
.list
= next
;
2148 state
.ucmd
.tail
= NULL
;
2150 state
.cur_cmd
= NULL
;
2155 * Process all user command blocks found on state.ucmd, and then
2156 * remove them from the list.
2159 dispatch_user_cmds()
2162 elfedit_cmdret_t cmd_ret
;
2164 ucmd
= state
.ucmd
.list
;
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
);
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.
2178 if (state
.elf
.elfclass
== ELFCLASS32
) {
2179 elfedit32_cmd_func_t
*cmd_func
=
2180 (elfedit32_cmd_func_t
*)
2181 ucmd
->ucmd_cmd
->cmd_func
;
2183 cmd_ret
= (* cmd_func
)(state
.elf
.obj_state
.s32
,
2184 ucmd
->ucmd_argc
, ucmd
->ucmd_argv
);
2186 elfedit64_cmd_func_t
*cmd_func
=
2187 (elfedit64_cmd_func_t
*)
2188 ucmd
->ucmd_cmd
->cmd_func
;
2190 cmd_ret
= (* cmd_func
)(state
.elf
.obj_state
.s64
,
2191 ucmd
->ucmd_argc
, ucmd
->ucmd_argv
);
2193 state
.cur_cmd
= NULL
;
2194 /* If a pager was started, wrap it up */
2195 elfedit_pager_cleanup();
2198 case ELFEDIT_CMDRET_MOD_OS_MACH
:
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.
2204 state
.elf
.elfconst_ehdr_change
= 1;
2206 case ELFEDIT_CMDRET_MOD
:
2208 * Command modified the output ELF image,
2209 * mark the file as needing a flush to disk.
2211 state
.file
.dirty
= 1;
2213 case ELFEDIT_CMDRET_FLUSH
:
2215 * Command flushed the output file,
2216 * clear the dirty bit.
2218 state
.file
.dirty
= 0;
2227 * Prepare a GETTOK_STATE struct for gettok().
2230 * gettok_state - gettok state block to use
2231 * str - Writable buffer to tokenize. Note that gettok()
2232 * is allowed to change the contents of this buffer.
2233 * inc_null_final - If the line ends in whitespace instead of
2234 * immediately hitting a NULL, and inc_null_final is TRUE,
2235 * then a null final token is generated. Otherwise trailing
2236 * whitespace is ignored.
2239 gettok_init(GETTOK_STATE
*gettok_state
, char *buf
, int inc_null_final
)
2241 gettok_state
->gtok_buf
= gettok_state
->gtok_cur_buf
= buf
;
2242 gettok_state
->gtok_inc_null_final
= inc_null_final
;
2243 gettok_state
->gtok_null_seen
= 0;
2248 * Locate the next token from the buffer.
2251 * gettok_state - State of gettok() operation. Initialized
2252 * by gettok_init(), and passed to gettok().
2255 * If a token is found, gettok_state->gtok_last_token is filled in
2256 * with the details and True (1) is returned. If no token is found,
2257 * False (1) is returned, and the contents of
2258 * gettok_state->gtok_last_token are undefined.
2261 * - The token returned references the memory in gettok_state->gtok_buf.
2262 * The caller should not modify the buffer until all such
2263 * pointers have been discarded.
2264 * - This routine will modify the contents of gettok_state->gtok_buf
2265 * as necessary to remove quotes and eliminate escape
2269 gettok(GETTOK_STATE
*gettok_state
)
2271 char *str
= gettok_state
->gtok_cur_buf
;
2273 int quote_ch
= '\0';
2275 /* Skip leading whitespace */
2276 while (isspace(*str
))
2281 * If user requested it, and there was whitespace at the
2282 * end, then generate one last null token.
2284 if (gettok_state
->gtok_inc_null_final
&&
2285 !gettok_state
->gtok_null_seen
) {
2286 gettok_state
->gtok_inc_null_final
= 0;
2287 gettok_state
->gtok_null_seen
= 1;
2288 gettok_state
->gtok_last_token
.tok_str
= str
;
2289 gettok_state
->gtok_last_token
.tok_len
= 0;
2290 gettok_state
->gtok_last_token
.tok_line_off
=
2291 str
- gettok_state
->gtok_buf
;
2294 gettok_state
->gtok_null_seen
= 1;
2299 * Read token: The standard delimiter is whitespace, but
2300 * we honor either single or double quotes. Also, we honor
2301 * backslash escapes.
2303 gettok_state
->gtok_last_token
.tok_str
= look
= str
;
2304 gettok_state
->gtok_last_token
.tok_line_off
=
2305 look
- gettok_state
->gtok_buf
;
2306 for (; *look
; look
++) {
2307 if (*look
== quote_ch
) { /* Terminates active quote */
2312 if (quote_ch
== '\0') { /* No quote currently active */
2313 if ((*look
== '\'') || (*look
== '"')) {
2314 quote_ch
= *look
; /* New active quote */
2322 * The semantics of the backslash character depends on
2323 * the quote style in use:
2324 * - Within single quotes, backslash is not
2325 * an escape character, and is taken literally.
2326 * - If outside of quotes, the backslash is an escape
2327 * character. The backslash is ignored and the
2328 * following character is taken literally, losing
2329 * any special properties it normally has.
2330 * - Within double quotes, backslash works like a
2331 * backslash escape within a C literal. Certain
2332 * escapes are recognized and replaced with their
2333 * special character. Any others are an error.
2335 if (*look
== '\\') {
2336 if (quote_ch
== '\'') {
2342 if (*look
== '\0') { /* Esc applied to NULL term? */
2343 elfedit_msg(ELFEDIT_MSG_ERR
,
2344 MSG_INTL(MSG_ERR_ESCEOL
));
2348 if (quote_ch
== '"') {
2349 int ch
= conv_translate_c_esc(&look
);
2352 elfedit_msg(ELFEDIT_MSG_ERR
,
2353 MSG_INTL(MSG_ERR_BADCESC
), *look
);
2355 look
--; /* for() will advance by 1 */
2365 /* Don't allow unterminated quoted tokens */
2366 if (quote_ch
!= '\0')
2367 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_UNTERMQUOTE
),
2370 gettok_state
->gtok_last_token
.tok_len
= str
-
2371 gettok_state
->gtok_last_token
.tok_str
;
2372 gettok_state
->gtok_null_seen
= *look
== '\0';
2373 if (!gettok_state
->gtok_null_seen
)
2376 gettok_state
->gtok_cur_buf
= look
;
2380 elfedit_str_to_c_literal(gettok_state
->gtok_last_token
.tok_str
,
2382 printf("< \tlen(%d) offset(%d)\n",
2383 gettok_state
->gtok_last_token
.tok_len
,
2384 gettok_state
->gtok_last_token
.tok_line_off
);
2392 * Tokenize the user command string, and return a pointer to the
2393 * TOK_STATE buffer maintained by this function. That buffer contains
2394 * the tokenized strings.
2397 * user_cmd_str - String to tokenize
2398 * len - # of characters in user_cmd_str to examine. If
2399 * (len < 0), then the complete string is processed
2400 * stopping with the NULL termination. Otherwise,
2401 * processing stops after len characters, and any
2402 * remaining characters are ignored.
2403 * inc_null_final - If True, and if user_cmd_str has whitespace
2404 * at the end following the last non-null token, then
2405 * a final null token will be included. If False, null
2406 * tokens are ignored.
2409 * This routine returns pointers to internally allocated memory.
2410 * The caller must not alter anything contained in the TOK_STATE
2411 * buffer returned. Furthermore, the the contents of TOK_STATE
2412 * are only valid until the next call to tokenize_user_cmd().
2415 tokenize_user_cmd(const char *user_cmd_str
, size_t len
, int inc_null_final
)
2417 #define INITIAL_TOK_ALLOC 5
2420 * As we parse the user command, we need temporary space to
2421 * hold the tokens. We do this by dynamically allocating a string
2422 * buffer and a token array, and doubling them as necessary. This
2423 * is a single threaded application, so static variables suffice.
2426 static TOK_STATE tokst
;
2428 GETTOK_STATE gettok_state
;
2432 * Make a copy we can modify. If (len == 0), take the entire
2433 * string. Otherwise limit it to the specified length.
2435 tokst
.tokst_cmd_len
= strlen(user_cmd_str
);
2436 if ((len
> 0) && (len
< tokst
.tokst_cmd_len
))
2437 tokst
.tokst_cmd_len
= len
;
2438 tokst
.tokst_cmd_len
++; /* Room for NULL termination */
2439 strbuf_ensure_size(&str
, tokst
.tokst_cmd_len
);
2440 (void) strlcpy(str
.buf
, user_cmd_str
, tokst
.tokst_cmd_len
);
2442 /* Trim off any newline character that might be present */
2443 if ((tokst
.tokst_cmd_len
> 1) &&
2444 (str
.buf
[tokst
.tokst_cmd_len
- 2] == '\n')) {
2445 tokst
.tokst_cmd_len
--;
2446 str
.buf
[tokst
.tokst_cmd_len
- 1] = '\0';
2449 /* Tokenize the user command string into tok struct */
2450 gettok_init(&gettok_state
, str
.buf
, inc_null_final
);
2451 tokst
.tokst_str_size
= 0; /* Space needed for token strings */
2452 for (tokst
.tokst_cnt
= 0; gettok(&gettok_state
) != 0;
2453 tokst
.tokst_cnt
++) {
2454 /* If we need more room, expand the token buffer */
2455 if (tokst
.tokst_cnt
>= tokst
.tokst_bufsize
) {
2456 n
= (tokst
.tokst_bufsize
== 0) ?
2457 INITIAL_TOK_ALLOC
: (tokst
.tokst_bufsize
* 2);
2458 tokst
.tokst_buf
= elfedit_realloc(
2459 MSG_INTL(MSG_ALLOC_TOKBUF
), tokst
.tokst_buf
,
2460 n
* sizeof (*tokst
.tokst_buf
));
2461 tokst
.tokst_bufsize
= n
;
2463 tokst
.tokst_str_size
+=
2464 gettok_state
.gtok_last_token
.tok_len
+ 1;
2465 tokst
.tokst_buf
[tokst
.tokst_cnt
] = gettok_state
.gtok_last_token
;
2467 /* fold the command token to lowercase */
2468 if (tokst
.tokst_cnt
> 0) {
2471 for (s
= tokst
.tokst_buf
[0].tok_str
; *s
; s
++)
2478 #undef INITIAL_TOK_ALLOC
2483 * Parse the user command string, and put an entry for it at the end
2487 parse_user_cmd(const char *user_cmd_str
)
2494 elfeditGC_module_t
*mod
;
2495 elfeditGC_cmd_t
*cmd
;
2498 * Break it into tokens. If there are none, then it is
2499 * an empty command and is ignored.
2501 tokst
= tokenize_user_cmd(user_cmd_str
, -1, 0);
2502 if (tokst
->tokst_cnt
== 0)
2505 /* Find the command. Won't return on error */
2506 cmd
= elfedit_find_command(tokst
->tokst_buf
[0].tok_str
, 1, &mod
);
2509 * If there is no ELF file being edited, then only commands
2510 * from the sys: module are allowed.
2512 if ((state
.file
.present
== 0) &&
2513 (strcmp(mod
->mod_name
, MSG_ORIG(MSG_MOD_SYS
)) != 0))
2514 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_NOFILSYSONLY
),
2515 mod
->mod_name
, cmd
->cmd_name
[0]);
2518 /* Allocate, fill in, and insert a USER_CMD_T block */
2519 n
= S_DROUND(sizeof (USER_CMD_T
));
2520 ucmd
= elfedit_malloc(MSG_INTL(MSG_ALLOC_UCMD
),
2521 n
+ (sizeof (char *) * (tokst
->tokst_cnt
- 1)) +
2522 tokst
->tokst_cmd_len
+ tokst
->tokst_str_size
);
2523 ucmd
->ucmd_next
= NULL
;
2524 ucmd
->ucmd_argc
= tokst
->tokst_cnt
- 1;
2525 /*LINTED E_BAD_PTR_CAST_ALIGN*/
2526 ucmd
->ucmd_argv
= (const char **)(n
+ (char *)ucmd
);
2527 ucmd
->ucmd_orig_str
= (char *)(ucmd
->ucmd_argv
+ ucmd
->ucmd_argc
);
2528 (void) strncpy(ucmd
->ucmd_orig_str
, user_cmd_str
, tokst
->tokst_cmd_len
);
2529 ucmd
->ucmd_mod
= mod
;
2530 ucmd
->ucmd_cmd
= cmd
;
2531 ucmd
->ucmd_ostyle_set
= 0;
2532 s
= ucmd
->ucmd_orig_str
+ tokst
->tokst_cmd_len
;
2533 for (n
= 1; n
< tokst
->tokst_cnt
; n
++) {
2534 len
= tokst
->tokst_buf
[n
].tok_len
+ 1;
2535 ucmd
->ucmd_argv
[n
- 1] = s
;
2536 (void) strncpy(s
, tokst
->tokst_buf
[n
].tok_str
, len
);
2539 if (state
.ucmd
.list
== NULL
) {
2540 state
.ucmd
.list
= state
.ucmd
.tail
= ucmd
;
2542 state
.ucmd
.tail
->ucmd_next
= ucmd
;
2543 state
.ucmd
.tail
= ucmd
;
2550 * Copy infile to a new file with the name given by outfile.
2553 create_outfile(const char *infile
, const char *outfile
)
2557 struct stat statbuf
;
2562 case -1: /* Unable to create process */
2565 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTFORK
),
2572 (void) execl(MSG_ORIG(MSG_STR_BINCP
),
2573 MSG_ORIG(MSG_STR_BINCP
), infile
, outfile
, NULL
);
2575 * exec() only returns on error. This is the child process,
2576 * so we want to stay away from the usual error mechanism
2577 * and handle things directly.
2581 (void) fprintf(stderr
, MSG_INTL(MSG_ERR_CNTEXEC
),
2582 MSG_ORIG(MSG_STR_ELFEDIT
),
2583 MSG_ORIG(MSG_STR_BINCP
), strerror(err
));
2589 /* This is the parent: Wait for the child to terminate */
2590 if (waitpid(pid
, &statloc
, 0) != pid
) {
2592 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTWAIT
),
2596 * If the child failed, then terminate the process. There is no
2597 * need for an error message, because the child will have taken
2600 if (!WIFEXITED(statloc
) || (WEXITSTATUS(statloc
) != 0))
2603 /* Make sure the copy allows user write access */
2604 if (stat(outfile
, &statbuf
) == -1) {
2606 (void) unlink(outfile
);
2607 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTSTAT
),
2608 outfile
, strerror(err
));
2610 if ((statbuf
.st_mode
& S_IWUSR
) == 0) {
2611 /* Only keep permission bits, and add user write */
2612 statbuf
.st_mode
|= S_IWUSR
;
2613 statbuf
.st_mode
&= 07777; /* Only keep the permission bits */
2614 if (chmod(outfile
, statbuf
.st_mode
) == -1) {
2616 (void) unlink(outfile
);
2617 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTCHMOD
),
2618 outfile
, strerror(err
));
2624 * Given a module path string, determine how long the resulting path will
2625 * be when all % tokens have been expanded.
2628 * path - Path for which expanded length is desired
2629 * origin_root - Root of $ORIGIN tree containing running elfedit program
2632 * Returns the value strlen() will give for the expanded path.
2635 modpath_strlen(const char *path
, const char *origin_root
)
2642 for (s
= path
; *s
!= '\0'; s
++) {
2646 case 'i': /* ISA of running elfedit */
2647 len
+= strlen(isa_i_str
);
2649 case 'I': /* "" for 32-bit, same as %i for 64 */
2650 len
+= strlen(isa_I_str
);
2652 case 'o': /* Insert default path */
2654 modpath_strlen(MSG_ORIG(MSG_STR_MODPATH
),
2657 case 'r': /* root of tree with running elfedit */
2658 len
+= strlen(origin_root
);
2661 case '%': /* %% is reduced to just '%' */
2664 default: /* All other % codes are reserved */
2665 elfedit_msg(ELFEDIT_MSG_ERR
,
2666 MSG_INTL(MSG_ERR_BADPATHCODE
), *s
);
2670 } else { /* Non-% character passes straight through */
2680 * Given a module path string, and a buffer large enough to hold the results,
2681 * fill the buffer with the expanded path.
2684 * path - Path for which expanded length is desired
2685 * origin_root - Root of tree containing running elfedit program
2686 * buf - Buffer to receive the result. buf must as large or larger
2687 * than the value given by modpath_strlen().
2690 * Returns pointer to location following the last character
2691 * written to buf. A NULL byte is written to that address.
2694 modpath_expand(const char *path
, const char *origin_root
, char *buf
)
2699 for (; *path
!= '\0'; path
++) {
2704 case 'i': /* ISA of running elfedit */
2707 case 'I': /* "" for 32-bit, same as %i for 64 */
2710 case 'o': /* Insert default path */
2711 buf
= modpath_expand(MSG_ORIG(MSG_STR_MODPATH
),
2715 cp_str
= origin_root
;
2717 case '%': /* %% is reduced to just '%' */
2720 default: /* All other % codes are reserved */
2721 elfedit_msg(ELFEDIT_MSG_ERR
,
2722 MSG_INTL(MSG_ERR_BADPATHCODE
), *path
);
2726 if ((cp_str
!= NULL
) && ((len
= strlen(cp_str
)) > 0)) {
2727 bcopy(cp_str
, buf
, len
);
2730 } else { /* Non-% character passes straight through */
2741 * Establish the module search path: state.modpath
2743 * The path used comes from the following sources, taking the first
2744 * one that has a value, and ignoring any others:
2746 * - ELFEDIT_PATH environment variable
2747 * - -L command line argument
2751 * path - NULL, or the value of the -L command line argument
2754 * state.modpath has been filled in
2757 establish_modpath(const char *cmdline_path
)
2759 char origin_root
[PATH_MAX
+ 1]; /* Where elfedit binary is */
2760 const char *path
; /* Initial path */
2761 char *expath
; /* Expanded path */
2765 path
= getenv(MSG_ORIG(MSG_STR_ENVVAR
));
2767 path
= cmdline_path
;
2769 path
= MSG_ORIG(MSG_STR_MODPATH
);
2773 * Root of tree containing running for running program. 32-bit elfedit
2774 * is installed in /usr/bin, and 64-bit elfedit is one level lower
2775 * in an ISA-specific subdirectory. So, we find the root by
2776 * getting the $ORGIN of the current running program, and trimming
2777 * off the last 2 (32-bit) or 3 (64-bit) directories.
2779 * On a standard system, this will simply yield '/'. However,
2780 * doing it this way allows us to run elfedit from a proto area,
2781 * and pick up modules from the same proto area instead of those
2782 * installed on the system.
2784 if (dlinfo(RTLD_SELF
, RTLD_DI_ORIGIN
, &origin_root
) == -1)
2785 elfedit_msg(ELFEDIT_MSG_ERR
, MSG_INTL(MSG_ERR_CNTGETORIGIN
));
2786 len
= (sizeof (char *) == 8) ? 3 : 2;
2787 src
= origin_root
+ strlen(origin_root
);
2788 while ((src
> origin_root
) && (len
> 0)) {
2789 if (*(src
- 1) == '/')
2797 * Calculate space needed to hold expanded path. Note that
2798 * this assumes that MSG_STR_MODPATH will never contain a '%o'
2799 * code, and so, the expansion is not recursive. The codes allowed
2801 * %i - ISA of running elfedit (sparc, sparcv9, etc)
2802 * %I - 64-bit ISA: Same as %i for 64-bit versions of elfedit,
2803 * but yields empty string for 32-bit ISAs.
2804 * %o - The original (default) path.
2805 * %r - Root of tree holding elfedit program.
2808 * A % followed by anything else is an error. This allows us to
2809 * add new codes in the future without backward compatability issues.
2811 len
= modpath_strlen(path
, origin_root
);
2813 expath
= elfedit_malloc(MSG_INTL(MSG_ALLOC_EXPATH
), len
+ 1);
2814 (void) modpath_expand(path
, origin_root
, expath
);
2817 * Count path segments, eliminate extra '/', and replace ':'
2820 state
.modpath
.n
= 1;
2821 for (src
= dst
= expath
; *src
; src
++) {
2823 switch (*(src
+ 1)) {
2833 } else if (src
!= dst
) {
2841 state
.modpath
.seg
= elfedit_malloc(MSG_INTL(MSG_ALLOC_PATHARR
),
2842 sizeof (state
.modpath
.seg
[0]) * state
.modpath
.n
);
2845 for (len
= 0; len
< state
.modpath
.n
; len
++) {
2847 state
.modpath
.seg
[len
] = MSG_ORIG(MSG_STR_DOT
);
2850 state
.modpath
.seg
[len
] = src
;
2851 src
+= strlen(src
) + 1;
2857 * When interactive (reading commands from a tty), we catch
2858 * SIGINT in order to restart the outer command loop.
2862 sigint_handler(int sig
, siginfo_t
*sip
, void *ucp
)
2864 /* Jump to the outer loop to resume */
2865 if (state
.msg_jbuf
.active
) {
2866 state
.msg_jbuf
.active
= 0;
2867 siglongjmp(state
.msg_jbuf
.env
, 1);
2875 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_BRIEF
));
2877 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_DETAIL1
));
2878 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_DETAIL2
));
2879 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_DETAIL3
));
2880 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_DETAIL4
));
2881 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_DETAIL5
));
2882 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_DETAIL6
));
2883 elfedit_msg(ELFEDIT_MSG_USAGE
, MSG_INTL(MSG_USAGE_DETAIL_LAST
));
2890 * In order to complete commands, we need to know about them,
2891 * which means that we need to force all the modules to be
2892 * loaded. This is a relatively expensive operation, so we use
2893 * this function, which avoids doing it more than once in a session.
2896 elfedit_cpl_load_modules(void)
2901 elfedit_load_modpath();
2902 loaded
= 1; /* Don't do it again */
2907 * Compare the token to the given string, and if they share a common
2908 * initial sequence, add the tail of string to the tecla command completion
2912 * cpldata - Current completion state
2913 * str - String to match against token
2914 * casefold - True to allow case insensitive completion, False
2915 * if case must match exactly.
2918 elfedit_cpl_match(void *cpldata
, const char *str
, int casefold
)
2920 ELFEDIT_CPL_STATE
*cstate
= (ELFEDIT_CPL_STATE
*) cpldata
;
2921 const char *cont_suffix
;
2922 const char *type_suffix
;
2925 * Reasons to return immediately:
2926 * - NULL strings have no completion value
2927 * - The string is shorter than the existing item being completed
2929 if ((str
== NULL
) || (*str
== '\0') ||
2930 ((cstate
->ecpl_token_len
!= 0) &&
2931 ((strlen(str
) < cstate
->ecpl_token_len
))))
2934 /* If the string does not share the existing prefix, don't use it */
2936 if (strncasecmp(cstate
->ecpl_token_str
, str
,
2937 cstate
->ecpl_token_len
) != 0)
2940 if (strncmp(cstate
->ecpl_token_str
, str
,
2941 cstate
->ecpl_token_len
) != 0)
2945 if (cstate
->ecpl_add_mod_colon
) {
2946 cont_suffix
= type_suffix
= MSG_ORIG(MSG_STR_COLON
);
2948 cont_suffix
= MSG_ORIG(MSG_STR_SPACE
);
2951 (void) cpl_add_completion(cstate
->ecpl_cpl
, cstate
->ecpl_line
,
2952 cstate
->ecpl_word_start
, cstate
->ecpl_word_end
,
2953 str
+ cstate
->ecpl_token_len
, type_suffix
, cont_suffix
);
2959 * Convenience wrapper on elfedit_cpl_match(): Format an unsigned
2960 * 32-bit integer as a string and enter the result for command completion.
2963 elfedit_cpl_ndx(void *cpldata
, uint_t ndx
)
2967 (void) snprintf(buf
.buf
, sizeof (buf
.buf
),
2968 MSG_ORIG(MSG_FMT_WORDVAL
), ndx
);
2969 elfedit_cpl_match(cpldata
, buf
.buf
, 0);
2974 * Compare the token to the names of the commands from the given module,
2975 * and if they share a common initial sequence, add the tail of string
2976 * to the tecla command completion buffer:
2979 * tok_buf - Token user has entered
2980 * tok_len - strlen(tok_buf)
2981 * mod - Module definition from which commands should be matched
2982 * cpl, line, word_start, word_end, cont_suffix - As documented
2983 * for gl_get_line() and cpl_add_completion.
2986 match_module_cmds(ELFEDIT_CPL_STATE
*cstate
, elfeditGC_module_t
*mod
)
2988 elfeditGC_cmd_t
*cmd
;
2989 const char **cmd_name
;
2991 for (cmd
= mod
->mod_cmds
; cmd
->cmd_func
!= NULL
; cmd
++)
2992 for (cmd_name
= cmd
->cmd_name
; *cmd_name
; cmd_name
++)
2993 elfedit_cpl_match(cstate
, *cmd_name
, 1);
2998 * Compare the token to the known module names, and add those that
2999 * match to the list of alternatives via elfedit_cpl_match().
3002 * load_all_modules - If True, causes all modules to be loaded
3003 * before processing is done. If False, only the modules
3004 * currently seen will be used.
3007 elfedit_cpl_module(void *cpldata
, int load_all_modules
)
3009 ELFEDIT_CPL_STATE
*cstate
= (ELFEDIT_CPL_STATE
*) cpldata
;
3012 if (load_all_modules
)
3013 elfedit_cpl_load_modules();
3015 for (modlist
= state
.modlist
; modlist
!= NULL
;
3016 modlist
= modlist
->ml_next
) {
3017 elfedit_cpl_match(cstate
, modlist
->ml_mod
->mod_name
, 1);
3023 * Compare the token to all the known commands, and add those that
3024 * match to the list of alternatives.
3027 * This routine will force modules to be loaded as necessary to
3028 * obtain the names it needs to match.
3031 elfedit_cpl_command(void *cpldata
)
3033 ELFEDIT_CPL_STATE
*cstate
= (ELFEDIT_CPL_STATE
*) cpldata
;
3034 ELFEDIT_CPL_STATE colon_state
;
3035 const char *colon_pos
;
3041 * Is there a colon in the command? If so, locate its offset within
3042 * the raw input line.
3044 for (colon_pos
= cstate
->ecpl_token_str
;
3045 *colon_pos
&& (*colon_pos
!= ':'); colon_pos
++)
3049 * If no colon was seen, then we are completing a module name,
3050 * or one of the commands from 'sys:'
3052 if (*colon_pos
== '\0') {
3054 * Setting cstate->add_mod_colon tells elfedit_cpl_match()
3055 * to add an implicit ':' to the names it matches. We use it
3056 * here so the user doesn't have to enter the ':' manually.
3057 * Hiding this in the opaque state instead of making it
3058 * an argument to that function gives us the ability to
3059 * change it later without breaking the published interface.
3061 cstate
->ecpl_add_mod_colon
= 1;
3062 elfedit_cpl_module(cpldata
, 1);
3063 cstate
->ecpl_add_mod_colon
= 0;
3065 /* Add bare (no sys: prefix) commands from the sys: module */
3066 match_module_cmds(cstate
,
3067 elfedit_load_module(MSG_ORIG(MSG_MOD_SYS
), 1, 0));
3073 * A colon was seen, so we have a module name. Extract the name,
3074 * substituting 'sys' for the case where the given name is empty.
3077 (void) strlcpy(buf
, MSG_ORIG(MSG_MOD_SYS
), sizeof (buf
));
3079 elfedit_strnbcpy(buf
, cstate
->ecpl_token_str
,
3080 colon_pos
- cstate
->ecpl_token_str
, sizeof (buf
));
3083 * Locate the module. If it isn't already loaded, make an explicit
3084 * attempt to load it and try again. If a module definition is
3085 * obtained, process the commands it supplies.
3087 modlist
= module_loaded(buf
, &insdef
);
3088 if (modlist
== NULL
) {
3089 (void) elfedit_load_module(buf
, 0, 0);
3090 modlist
= module_loaded(buf
, &insdef
);
3092 if (modlist
!= NULL
) {
3094 * Make a copy of the cstate, and adjust the line and
3095 * token so that the new one starts just past the colon
3096 * character. We know that the colon exists because
3097 * of the preceeding test that found it. Therefore, we do
3098 * not need to test against running off the end of the
3101 colon_state
= *cstate
;
3102 while (colon_state
.ecpl_line
[colon_state
.ecpl_word_start
] !=
3104 colon_state
.ecpl_word_start
++;
3105 while (*colon_state
.ecpl_token_str
!= ':') {
3106 colon_state
.ecpl_token_str
++;
3107 colon_state
.ecpl_token_len
--;
3109 /* Skip past the ':' character */
3110 colon_state
.ecpl_word_start
++;
3111 colon_state
.ecpl_token_str
++;
3112 colon_state
.ecpl_token_len
--;
3114 match_module_cmds(&colon_state
, modlist
->ml_mod
);
3120 * Command completion function for use with libtacla.
3124 cmd_match_fcn(WordCompletion
*cpl
, void *data
, const char *line
, int word_end
)
3126 const char *argv
[ELFEDIT_MAXCPLARGS
];
3127 ELFEDIT_CPL_STATE cstate
;
3131 elfeditGC_module_t
*mod
;
3132 elfeditGC_cmd_t
*cmd
;
3136 elfedit_cmd_optarg_t
*optarg
;
3137 elfedit_optarg_item_t item
;
3138 int ostyle_ndx
= -1;
3141 * For debugging, enable the following block. It tells the tecla
3142 * library that the program using is going to write to stdout.
3143 * It will put the tty back into normal mode, and it will cause
3144 * tecla to redraw the current input line when it gets control back.
3146 #ifdef DEBUG_CMD_MATCH
3147 gl_normal_io(state
.input
.gl
);
3151 * Tokenize the line up through word_end. The last token in
3152 * the list is the one requiring completion.
3154 tokst
= tokenize_user_cmd(line
, word_end
, 1);
3155 if (tokst
->tokst_cnt
== 0)
3158 /* Set up the cstate block, containing the completion state */
3159 ndx
= tokst
->tokst_cnt
- 1; /* Index of token to complete */
3160 cstate
.ecpl_cpl
= cpl
;
3161 cstate
.ecpl_line
= line
;
3162 cstate
.ecpl_word_start
= tokst
->tokst_buf
[ndx
].tok_line_off
;
3163 cstate
.ecpl_word_end
= word_end
;
3164 cstate
.ecpl_add_mod_colon
= 0;
3165 cstate
.ecpl_token_str
= tokst
->tokst_buf
[ndx
].tok_str
;
3166 cstate
.ecpl_token_len
= tokst
->tokst_buf
[ndx
].tok_len
;
3169 * If there is only one token, then we are completing the
3173 elfedit_cpl_command(&cstate
);
3178 * There is more than one token. Use the first one to
3179 * locate the definition for the command. If we don't have
3180 * a definition for the command, then there's nothing more
3183 cmd
= elfedit_find_command(tokst
->tokst_buf
[0].tok_str
, 0, &mod
);
3188 * Since we know the command, give them a quick usage message.
3189 * It may be that they just need a quick reminder about the form
3190 * of the command and the options.
3192 (void) gl_normal_io(state
.input
.gl
);
3193 elfedit_printf(MSG_INTL(MSG_USAGE_CMD
),
3194 elfedit_format_command_usage(mod
, cmd
, NULL
, 0));
3198 * We have a generous setting for ELFEDIT_MAXCPLARGS, so there
3199 * should always be plenty of room. If there's not room, we
3202 if (ndx
>= ELFEDIT_MAXCPLARGS
)
3206 * Put pointers to the tokens into argv, and determine how
3207 * many of the tokens are optional arguments.
3209 * We consider the final optional argument to be the rightmost
3210 * argument that starts with a '-'. If a '--' is seen, then
3211 * we stop there, and any argument that follows is a plain argument
3212 * (even if it starts with '-').
3214 * We look for an inherited '-o' option, because we are willing
3215 * to supply command completion for these values.
3220 for (i
= 0; i
< ndx
; i
++) {
3221 argv
[i
] = tokst
->tokst_buf
[i
+ 1].tok_str
;
3222 if (opt_term_seen
|| skip_one
) {
3228 if ((strcmp(argv
[i
], MSG_ORIG(MSG_STR_MINUS_MINUS
)) == NULL
) ||
3229 (*argv
[i
] != '-')) {
3235 * If it is a recognised ELFEDIT_CMDOA_F_VALUE option,
3236 * then the item following it is the associated value.
3237 * Check for this and skip the value.
3239 * At the same time, look for STDOA_OPT_O inherited
3240 * options. We want to identify the index of any such
3241 * item. Although the option is simply "-o", we are willing
3242 * to treat any option that starts with "-o" as a potential
3243 * STDOA_OPT_O. This lets us to command completion for things
3244 * like "-onum", and is otherwise harmless, the only cost
3245 * being a few additional strcmps by the cpl code.
3247 if ((optarg
= cmd
->cmd_opt
) == NULL
)
3249 while (optarg
->oa_name
!= NULL
) {
3250 int is_ostyle_optarg
=
3251 (optarg
->oa_flags
& ELFEDIT_CMDOA_F_INHERIT
) &&
3252 (optarg
->oa_name
== ELFEDIT_STDOA_OPT_O
);
3254 elfedit_next_optarg(&optarg
, &item
);
3255 if (item
.oai_flags
& ELFEDIT_CMDOA_F_VALUE
) {
3256 if (is_ostyle_optarg
&& (strncmp(argv
[i
],
3257 MSG_ORIG(MSG_STR_MINUS_O
), 2) == 0))
3260 if (strcmp(item
.oai_name
, argv
[i
]) == 0) {
3266 * If it didn't match "-o" exactly, but it is
3267 * ostyle_ndx, then it is a potential combined
3268 * STDOA_OPT_O, as discussed above. It counts
3269 * as a single argument.
3271 if (ostyle_ndx
== ndx
)
3277 #ifdef DEBUG_CMD_MATCH
3278 (void) printf("NDX(%d) NUM_OPT(%d) ostyle_ndx(%d)\n", ndx
, num_opt
,
3282 if (ostyle_ndx
!= -1) {
3284 * If ostyle_ndx is one less than ndx, and ndx is
3285 * the same as num_opt, then we have a definitive
3286 * STDOA_OPT_O inherited outstyle option. We supply
3287 * the value strings, and are done.
3289 if ((ostyle_ndx
== (ndx
- 1)) && (ndx
== num_opt
)) {
3290 elfedit_cpl_atoconst(&cstate
, ELFEDIT_CONST_OUTSTYLE
);
3295 * If ostyle is the same as ndx, then we have an option
3296 * staring with "-o" that may end up being a STDOA_OPT_O,
3297 * and we are still inside that token. In this case, we
3298 * supply completion strings that include the leading
3299 * "-o" followed by the values, without a space
3300 * (i.e. "-onum"). We then fall through, allowing any
3301 * other options starting with "-o" to be added
3302 * below. elfedit_cpl_match() will throw out the incorrect
3303 * options, so it is harmless to add these extra items in
3304 * the worst case, and useful otherwise.
3306 if (ostyle_ndx
== ndx
)
3307 elfedit_cpl_atoconst(&cstate
,
3308 ELFEDIT_CONST_OUTSTYLE_MO
);
3312 * If (ndx <= num_opt), then the token needing completion
3313 * is an option. If the leading '-' is there, then we should fill
3314 * in all of the option alternatives. If anything follows the '-'
3315 * though, we assume that the user has already figured out what
3316 * option to use, and we leave well enough alone.
3318 * Note that we are intentionally ignoring a related case
3319 * where supplying option strings would be legal: In the case
3320 * where we are one past the last option (ndx == (num_opt + 1)),
3321 * and the current option is an empty string, the argument can
3322 * be either a plain argument or an option --- the user needs to
3323 * enter the next character before we can tell. It would be
3324 * OK to enter the option strings in this case. However, consider
3325 * what happens when the first plain argument to the command does
3326 * not provide any command completion (e.g. it is a plain integer).
3327 * In this case, tecla will see that all the alternatives start
3328 * with '-', and will insert a '-' into the input. If the user
3329 * intends the next argument to be plain, they will have to delete
3330 * this '-', which is annoying. Worse than that, they may be confused
3331 * by it, and think that the plain argument is not allowed there.
3332 * The best solution is to not supply option strings unless the
3333 * user first enters the '-'.
3335 if ((ndx
<= num_opt
) && (argv
[ndx
- 1][0] == '-')) {
3336 if ((optarg
= cmd
->cmd_opt
) != NULL
) {
3337 while (optarg
->oa_name
!= NULL
) {
3338 elfedit_next_optarg(&optarg
, &item
);
3339 elfedit_cpl_match(&cstate
, item
.oai_name
, 1);
3346 * At this point we know that ndx and num_opt are not equal.
3347 * If num_opt is larger than ndx, then we have an ELFEDIT_CMDOA_F_VALUE
3348 * argument at the end, and the following value has not been entered.
3350 * If ndx is greater than num_opt, it means that we are looking
3351 * at a plain argument (or in the case where (ndx == (num_opt + 1)),
3352 * a *potential* plain argument.
3354 * If the command has a completion function registered, then we
3355 * hand off the remaining work to it. The cmd_cplfunc field is
3356 * the generic definition. We need to cast it to the type that matches
3357 * the proper ELFCLASS before calling it.
3359 if (state
.elf
.elfclass
== ELFCLASS32
) {
3360 elfedit32_cmdcpl_func_t
*cmdcpl_func
=
3361 (elfedit32_cmdcpl_func_t
*)cmd
->cmd_cplfunc
;
3363 if (cmdcpl_func
!= NULL
)
3364 (* cmdcpl_func
)(state
.elf
.obj_state
.s32
,
3365 &cstate
, ndx
, argv
, num_opt
);
3367 elfedit64_cmdcpl_func_t
*cmdcpl_func
=
3368 (elfedit64_cmdcpl_func_t
*)cmd
->cmd_cplfunc
;
3370 if (cmdcpl_func
!= NULL
)
3371 (* cmdcpl_func
)(state
.elf
.obj_state
.s64
,
3372 &cstate
, ndx
, argv
, num_opt
);
3380 * Read a line of input from stdin, and return pointer to it.
3382 * This routine uses a private buffer, so the contents of the returned
3383 * string are only good until the next call.
3390 if (state
.input
.full_tty
) {
3391 state
.input
.in_tecla
= TRUE
;
3392 s
= gl_get_line(state
.input
.gl
,
3393 MSG_ORIG(MSG_STR_PROMPT
), NULL
, -1);
3394 state
.input
.in_tecla
= FALSE
;
3396 * gl_get_line() returns NULL for EOF or for error. EOF is fine,
3397 * but we need to catch and report anything else. Since
3398 * reading from stdin is critical to our operation, an
3399 * error implies that we cannot recover and must exit.
3402 (gl_return_status(state
.input
.gl
) == GLR_ERROR
)) {
3403 elfedit_msg(ELFEDIT_MSG_FATAL
, MSG_INTL(MSG_ERR_GLREAD
),
3404 gl_error_message(state
.input
.gl
, NULL
, 0));
3408 * This should be a dynamically sized buffer, but for now,
3409 * I'm going to take a simpler path.
3411 static char cmd_buf
[ELFEDIT_MAXCMD
+ 1];
3413 s
= fgets(cmd_buf
, sizeof (cmd_buf
), stdin
);
3416 /* Return user string, or 'quit' on EOF */
3417 return (s
? s
: MSG_ORIG(MSG_SYS_CMD_QUIT
));
3421 main(int argc
, char **argv
, char **envp
)
3424 * Note: This function can use setjmp()/longjmp() which does
3425 * not preserve the values of auto/register variables. Hence,
3426 * variables that need their values preserved across a jump must
3427 * be marked volatile, or must not be auto/register.
3429 * Volatile can be messy, because it requires explictly casting
3430 * away the attribute when passing it to functions, or declaring
3431 * those functions with the attribute as well. In a single threaded
3432 * program like this one, an easier approach is to make things
3433 * static. That can be done here, or by putting things in the
3434 * 'state' structure.
3439 char **batch_list
= NULL
;
3440 const char *modpath
= NULL
;
3443 * Always have liblddb display unclipped section names.
3444 * This global is exported by liblddb, and declared in debug.h.
3446 dbg_desc
->d_extra
|= DBG_E_LONG
;
3449 while ((c
= getopt(argc
, argv
, MSG_ORIG(MSG_STR_OPTIONS
))) != EOF
) {
3452 state
.flags
|= ELFEDIT_F_AUTOPRINT
;
3456 state
.flags
|= ELFEDIT_F_DEBUG
;
3461 * Delay parsing the -e options until after the call to
3462 * conv_check_native() so that we won't bother loading
3463 * modules of the wrong class.
3465 if (batch_list
== NULL
)
3466 batch_list
= elfedit_malloc(
3467 MSG_INTL(MSG_ALLOC_BATCHLST
),
3468 sizeof (*batch_list
) * (argc
- 1));
3469 batch_list
[num_batch
++] = optarg
;
3477 if (elfedit_atooutstyle(optarg
, &state
.outstyle
) == 0)
3482 state
.flags
|= ELFEDIT_F_READONLY
;
3491 * We allow 0, 1, or 2 files:
3493 * The no-file case is an extremely limited mode, in which the
3494 * only commands allowed to execute come from the sys: module.
3495 * This mode exists primarily to allow easy access to the help
3498 * To get full access to elfedit's capablities, there must
3499 * be an input file. If this is not a readonly
3500 * session, then an optional second output file is allowed.
3502 * In the case where two files are given and the session is
3503 * readonly, use a full usage message, because the simple
3504 * one isn't enough for the user to understand their error.
3505 * Otherwise, the simple usage message suffices.
3507 argc
= argc
- optind
;
3508 if ((argc
== 2) && (state
.flags
& ELFEDIT_F_READONLY
))
3513 state
.file
.present
= (argc
!= 0);
3516 * If we have a file to edit, and unless told otherwise by the
3517 * caller, we try to run the 64-bit version of this program
3518 * when the system is capable of it. If that fails, then we
3519 * continue on with the currently running version.
3521 * To force 32-bit execution on a 64-bit host, set the
3522 * LD_NOEXEC_64 environment variable to a non-empty value.
3524 * There is no reason to bother with this if in "no file" mode.
3526 if (state
.file
.present
!= 0)
3527 (void) conv_check_native(argv
, envp
);
3529 elfedit_msg(ELFEDIT_MSG_DEBUG
, MSG_INTL(MSG_DEBUG_VERSION
),
3530 (sizeof (char *) == 8) ? 64 : 32);
3533 * Put a module definition for the builtin system module on the
3534 * module list. We know it starts out empty, so we do not have
3535 * to go through a more general insertion process than this.
3537 state
.modlist
= elfedit_sys_init(ELFEDIT_VER_CURRENT
);
3539 /* Establish the search path for loadable modules */
3540 establish_modpath(modpath
);
3543 * Now that we are running the final version of this program,
3544 * deal with the input/output file(s).
3546 if (state
.file
.present
== 0) {
3548 * This is arbitrary --- we simply need to be able to
3549 * load modules so that we can access their help strings
3550 * and command completion functions. Without a file, we
3551 * will refuse to call commands from any module other
3552 * than sys. Those commands have been written to be aware
3553 * of the case where there is no input file, and are
3554 * therefore safe to run.
3556 state
.elf
.elfclass
= ELFCLASS32
;
3557 elfedit_msg(ELFEDIT_MSG_DEBUG
, MSG_INTL(MSG_DEBUG_NOFILE
));
3560 state
.file
.infile
= argv
[optind
];
3562 state
.file
.outfile
= state
.file
.infile
;
3563 if (state
.flags
& ELFEDIT_F_READONLY
)
3564 elfedit_msg(ELFEDIT_MSG_DEBUG
,
3565 MSG_INTL(MSG_DEBUG_READONLY
));
3567 elfedit_msg(ELFEDIT_MSG_DEBUG
,
3568 MSG_INTL(MSG_DEBUG_INPLACEWARN
),
3571 state
.file
.outfile
= argv
[optind
+ 1];
3572 create_outfile(state
.file
.infile
, state
.file
.outfile
);
3573 elfedit_msg(ELFEDIT_MSG_DEBUG
,
3574 MSG_INTL(MSG_DEBUG_CPFILE
),
3575 state
.file
.infile
, state
.file
.outfile
);
3577 * We are editing a copy of the original file that we
3578 * just created. If we should exit before the edits are
3579 * updated, then we want to unlink this copy so that we
3580 * don't leave junk lying around. Once an update
3581 * succeeds however, we'll leave it in place even
3582 * if an error occurs afterwards.
3584 state
.file
.unlink_on_exit
= 1;
3585 optind
++; /* Edit copy instead of the original */
3588 init_obj_state(state
.file
.outfile
);
3595 * If any -e options were used, then do them and
3596 * immediately exit. On error, exit immediately without
3597 * updating the target ELF file. On success, the 'write'
3598 * and 'quit' commands are implicit in this mode.
3600 * If no -e options are used, read commands from stdin.
3601 * quit must be explicitly used. Exit is implicit on EOF.
3602 * If stdin is a tty, then errors do not cause the editor
3603 * to terminate. Rather, the error message is printed, and the
3604 * user prompted to continue.
3606 if (batch_list
!= NULL
) { /* -e was used */
3607 /* Compile the commands */
3608 for (i
= 0; i
< num_batch
; i
++)
3609 parse_user_cmd(batch_list
[i
]);
3613 * 'write' and 'quit' are implicit in this mode.
3616 if ((state
.flags
& ELFEDIT_F_READONLY
) == 0)
3617 parse_user_cmd(MSG_ORIG(MSG_SYS_CMD_WRITE
));
3618 parse_user_cmd(MSG_ORIG(MSG_SYS_CMD_QUIT
));
3620 /* And run them. This won't return, thanks to the 'quit' */
3621 dispatch_user_cmds();
3623 state
.input
.is_tty
= isatty(fileno(stdin
));
3624 state
.input
.full_tty
= state
.input
.is_tty
&&
3625 isatty(fileno(stdout
));
3627 if (state
.input
.full_tty
) {
3628 struct sigaction act
;
3630 act
.sa_sigaction
= sigint_handler
;
3631 (void) sigemptyset(&act
.sa_mask
);
3633 if (sigaction(SIGINT
, &act
, NULL
) == -1) {
3635 elfedit_msg(ELFEDIT_MSG_ERR
,
3636 MSG_INTL(MSG_ERR_SIGACTION
), strerror(err
));
3639 * If pager process exits before we are done
3640 * writing, we can see SIGPIPE. Prevent it
3641 * from killing the process.
3643 (void) sigignore(SIGPIPE
);
3645 /* Open tecla handle for command line editing */
3646 state
.input
.gl
= new_GetLine(ELFEDIT_MAXCMD
,
3648 /* Register our command completion function */
3649 (void) gl_customize_completion(state
.input
.gl
,
3650 NULL
, cmd_match_fcn
);
3653 * Make autoprint the default for interactive
3656 state
.flags
|= ELFEDIT_F_AUTOPRINT
;
3660 * If this is an interactive session, then use
3661 * sigsetjmp()/siglongjmp() to recover from bad
3662 * commands and keep going. A non-0 return from
3663 * sigsetjmp() means that an error just occurred.
3664 * In that case, we simply restart this loop.
3666 if (state
.input
.is_tty
) {
3667 if (sigsetjmp(state
.msg_jbuf
.env
, 1) != 0) {
3668 if (state
.input
.full_tty
)
3669 gl_abandon_line(state
.input
.gl
);
3672 state
.msg_jbuf
.active
= TRUE
;
3676 * Force all output out before each command.
3677 * This is a no-OP when a tty is in use, but
3678 * in a pipeline, it ensures that the block
3679 * mode buffering doesn't delay output past
3680 * the completion of each command.
3682 * If we didn't do this, the output would eventually
3683 * arrive at its destination, but the lag can be
3684 * annoying when you pipe the output into a tool
3685 * that displays the results in real time.
3687 (void) fflush(stdout
);
3688 (void) fflush(stderr
);
3690 parse_user_cmd(read_cmd());
3691 dispatch_user_cmds();
3692 state
.msg_jbuf
.active
= FALSE
;