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