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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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