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