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