sys.c revision d29b2c4438482eb00488be49a1f5d6835f455546
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <elfedit.h>
#include "_elfedit.h"
#include "msg.h"
/*
* This file provides the builtin sys module. It is similar to the
* other modules, but differs in several important ways:
*
* - It is built as a static part of elfedit, and not
* as a sharable object.
* - It must be avaialble before the ELFCLASS of the object
* is known, so it is not ELFCLASS specific. We don't build
* it twice with machdep.h, as we do for the loadable modules.
* This means that commands need to test for the type
* of their obj_state argument at runtime.
* - The init function signature is different. We build an entire
* module definition statically.
*/
/*
* This function is supplied to elfedit through our elfedit_module_t
* definition. It translates the opaque elfedit_i18nhdl_t handles
* in our module interface into the actual strings for elfedit to
* use.
*
* note:
* This module uses Msg codes for its i18n handle type.
* So the translation is simply to use MSG_INTL() to turn
* it into a string and return it.
*/
static const char *
{
}
/*
* The sys_opt_t enum specifies a bit value for every optional argument
* allowed by a command in this module.
*/
typedef enum {
} dyn_opt_t;
/*
* Given a generic (void *) pointer to an obj_state argument, determine
* which type it is, and return the st_file, st_fd and st_elf fields.
*/
static void
{
} else {
}
}
/*
* Helper for cmd_help(). Displays synopsis information for one command.
*/
static void
{
char name_buf[128];
const char *name;
const char **cmd_name;
} else {
const char *cname;
int need_comma = 0;
if (need_comma)
sizeof (name_buf));
need_comma = 1;
sizeof (name_buf));
}
sizeof (name_buf));
}
}
/*
* Helper for cmd_help(). Displays synopsis information for one module.
*/
static void
{
}
}
/*
* Given a string containing newline characters, break it into
* individual lines, and output each line with the given
* prefix string in front.
*/
static void
{
size_t i;
return;
while (*str) {
if (*(str + i) != '\0')
i++;
elfedit_write(str, i);
str += i;
}
}
/*
* descriptors, output the list contents.
*/
static void
{
int cnt;
int len;
const char *help;
/* Insert a blank line between items */
if (cnt > 0)
/* Indentation */
} else {
}
/*
* If name is too long, inject a newline to avoid
* crowding the help text.
*/
if (len > 3)
/* Output the help text with a tab prefix */
}
}
/*
* Implementation of sys:help
*/
/*ARGSUSED*/
static elfedit_cmdret_t
{
#define INITIAL_ITEM_ALLOC 4
/*
* An array of this type is used to collect the data needed to
* generate help output.
*/
typedef struct {
} ITEM;
static int item_cnt;
int dispcnt;
size_t i;
int minus_s = 0;
/*
* Process options. The only option accepted is -s, so we
* don't even have to check the idmask to know.
*/
minus_s = 1;
/*
* This command can produce an arbitrary amount of output, so
* run a pager.
*/
if (argc == 0) {
if (minus_s) {
/* Force all modules to load so we have data */
}
}
return (ELFEDIT_CMDRET_NONE);
}
/*
* If no arguments are present, we display a simple
* "how to use help" tutorial, which will hopefully
* bootstrap the user into a position where they
* know how to run the help command, and then find
* what they're really after.
*/
return (ELFEDIT_CMDRET_NONE);
}
/*
* As we process the arguments, we are willing to treat each
* one as either a module or a command:
* 1) An item without a colon can be a module,
* or a command from the sys: module.
* 2) An item with a colon, and no command part is
* a module, and it can also be the default
* command for the module, if it has one. We choose
* to only display the module info in this case, since
* the use of "" to represent the default command is
* an implementation detail, not a user-facing concept.
* 3) An item with a colon and a command part can only be
* a command.
*
* Note that there are cases where one argument can have two
* valid interpretations. In this case, we display them both.
*
* Pass over the arguments and determine how many distinct
* "things" we need to display. At the same time, force any
* needed modules to load so that the debug load messages won't
* show up in between the displayed items, and save the command
* and module definitions we will need to generate the output.
*/
while (n < argc)
n *= 2;
n * sizeof (*item));
item_cnt = n;
}
dispcnt = 0;
for (i = 0; i < argc; i++) {
dispcnt++;
/*
* Also try to load it as a module. If a command
* was found, then this need not succeed. Otherwise,
* it has to be a module, and we cause an error
* to be issued if not.
*/
dispcnt++;
/* Just colon: Module (and maybe default command) */
/* Strip off the colon */
}
dispcnt++;
} else { /* A command */
dispcnt++;
}
}
/*
* Having validated the items, loop over them again and produce
* the required help output.
*/
/* Help for a module? */
if (dispcnt > 1)
*argv);
/* An empty line after the last line of output */
}
/* Help for a command? */
continue;
if (dispcnt > 1)
/* If -s, display quick synopsis rather than the whole thing */
if (minus_s) {
continue;
}
/* If there are alias names, show them */
do {
if (**alias == '\0')
alias++;
} while (*alias);
}
/* An empty line after the last line of output */
}
return (ELFEDIT_CMDRET_NONE);
}
/*
* Command completion function for sys:help
*/
/*ARGSUSED*/
static void
int num_opt)
{
/*
* The arguments can be any module or command. Supplying the
* commands implicitly supplies the modules too.
*/
}
/*
* Implementation of sys:load
*/
/*ARGSUSED*/
static elfedit_cmdret_t
{
switch (getopt_ret->gor_idmask) {
case SYS_OPT_F_ALL:
break;
}
}
/* For each remaining argument, load them individually */
/* Is it a directory? Load everything in it */
} else { /* Not a directory. Normal load */
}
}
return (0);
}
/*
* Command completion function for sys:load
*/
/*ARGSUSED*/
static void
int num_opt)
{
/*
* Module names. Note that this causes elfedit to load all
* of the modules, which probably makes the current load
* operation unnecessary. This could be improved, but I don't
* see it as worth the complexity. Explicit load calls are
* rare, and the user will usually not use command completion.
*/
}
/*
* Implementation of sys:quit
*/
/*ARGSUSED*/
static elfedit_cmdret_t
{
int force = 0;
const char *file;
int fd;
switch (getopt_ret->gor_idmask) {
case SYS_OPT_F_FORCE:
force = 1;
break;
}
}
if (argc != 0)
/*
* If session is not READONLY, then refuse to quit if file
* needs flushing and -f option was not used.
*/
!force)
}
elfedit_exit(0);
/*NOTREACHED*/
return (0);
}
/*
* Implementation of sys:status
*/
/*ARGSUSED*/
static elfedit_cmdret_t
{
const char *s;
size_t i;
if (argc > 0)
/*
* This command can produce an arbitrary amount of output, so
* run a pager.
*/
/* Files */
} else {
}
/* Option Variables */
/* Module Load Path */
/* Currently Loaded Modules */
}
return (ELFEDIT_CMDRET_NONE);
}
/*
* Implementation of sys:set
*/
/*ARGSUSED*/
static elfedit_cmdret_t
{
switch (**argv) {
case 'a':
case 'A':
else
break;
case 'd':
case 'D':
else
break;
case 'o':
case 'O':
break;
default:
}
return (0);
}
/*
* Command completion function for sys:set
*/
/*ARGSUSED*/
static void
int num_opt)
{
const char *s;
/*
* This command doesn't accept options, so num_opt should be
* 0. This is a defensive measure, in case that should change.
*/
return;
return;
}
/* We're dealing with the second argument, the value */
s = argv[0];
return;
switch (*s) {
case 'a': /* Booleans */
case 'A':
case 'd':
case 'D':
case 'w':
case 'W':
/* The second argument is a boolean */
/* The numbers are not symbolic, but we want them in the list */
break;
case 'o': /* Output style */
case 'O':
break;
}
}
/*
* Implementation of sys:unload
*/
/*ARGSUSED*/
static elfedit_cmdret_t
{
int do_all = 0;
switch (getopt_ret->gor_idmask) {
case SYS_OPT_F_ALL:
do_all = 1;
break;
}
}
/*
* If -a is specified, unload everything except builtins. Don't
* allow plain arguments in this case because there is nothing
* left to unload after -a.
*/
if (do_all) {
if (argc > 0)
/*
* Until we run out of non-builtin modules, take the first
* one from the list and unload it. Each removal alters
* the list, so we always start at the beginning, but this
* is efficient since we always remove the first available item
*/
/* If we made it to the end, then the list is empty */
break;
}
return (0);
}
/* Unload each module individually */
return (0);
}
/*
* Command completion function for sys:unload
*/
/*ARGSUSED*/
static void
int num_opt)
{
/*
* Module names. Don't allow elfedit to load all the modules,
* as the only modules we want to unload are those already
* in memory.
*/
}
/*
* Implementation of sys:write
*/
/*ARGSUSED2*/
static elfedit_cmdret_t
{
const char *file;
int fd;
if (argc != 0)
elf_errmsg(elf_errno()));
/*
* An update has succeeded for this file, so revoke the need
* to unlink it on exit.
*/
}
return (ELFEDIT_CMDRET_FLUSH);
}
/*ARGSUSED*/
{
/* sys:help */
NULL };
static elfedit_cmd_optarg_t opt_help[] = {
/* MSG_INTL(MSG_SYS_OPTDESC_HELP_S) */
SYS_OPT_F_SYNOPSIS, 0 },
{ NULL }
};
static elfedit_cmd_optarg_t arg_help[] = {
{ MSG_ORIG(MSG_STR_ARG),
/* MSG_INTL(MSG_ARGDESC_HELP_ARG) */
{ NULL }
};
/* sys:load */
static const char *name_load[] = {
static elfedit_cmd_optarg_t opt_load[] = {
/* MSG_INTL(MSG_SYS_OPTDESC_LOAD_A) */
SYS_OPT_F_ALL, 0 },
{ NULL }
};
static elfedit_cmd_optarg_t arg_load[] = {
/* MSG_INTL(MSG_ARGDESC_LOAD_MODNAME) */
{ NULL }
};
/* sys:quit */
NULL };
static elfedit_cmd_optarg_t opt_quit[] = {
/* MSG_INTL(MSG_SYS_OPTDESC_QUIT_F) */
SYS_OPT_F_FORCE, 0 },
{ NULL }
};
/* sys:status */
static const char *name_status[] = {
/* sys:set */
static const char *name_set[] = {
static elfedit_cmd_optarg_t arg_set[] = {
/* MSG_INTL(MSG_ARGDESC_SET_OPTION) */
/* MSG_INTL(MSG_ARGDESC_SET_VALUE) */
{ NULL }
};
/* sys:unload */
static const char *name_unload[] = {
static elfedit_cmd_optarg_t opt_unload[] = {
/* MSG_INTL(MSG_SYS_OPTDESC_UNLOAD_A) */
SYS_OPT_F_ALL, 0},
{ NULL }
};
static elfedit_cmd_optarg_t arg_unload[] = {
/* MSG_INTL(MSG_ARGDESC_UNLOAD_MODNAME) */
{ NULL }
};
/* sys:write */
NULL };
static elfedit_cmd_t cmds[] = {
/* sym:help */
{ (elfedit_cmd_func_t *)cmd_help,
/* MSG_INTL(MSG_SYS_DESC_HELP) */
/* MSG_INTL(MSG_SYS_HELP_HELP) */
/* sym:load */
{ (elfedit_cmd_func_t *)cmd_load,
/* MSG_INTL(MSG_SYS_DESC_LOAD) */
/* MSG_INTL(MSG_SYS_HELP_LOAD) */
/* sym:quit */
/* MSG_INTL(MSG_SYS_DESC_QUIT) */
/* MSG_INTL(MSG_SYS_HELP_QUIT) */
/* sym:status */
/* MSG_INTL(MSG_SYS_DESC_STATUS) */
/* MSG_INTL(MSG_SYS_HELP_STATUS) */
/* sym:set */
{ (elfedit_cmd_func_t *)cmd_set,
/* MSG_INTL(MSG_SYS_DESC_SET) */
/* MSG_INTL(MSG_SYS_HELP_SET) */
/* sym:unload */
{ (elfedit_cmd_func_t *)cmd_unload,
/* MSG_INTL(MSG_SYS_DESC_UNLOAD) */
/* MSG_INTL(MSG_SYS_HELP_UNLOAD) */
opt_unload, arg_unload },
/* sym:write */
/* MSG_INTL(MSG_SYS_DESC_WRITE) */
/* MSG_INTL(MSG_SYS_HELP_WRITE) */
{ NULL }
};
static elfedit_module_t module = {
/* MSG_INTL(MSG_MOD_SYS_DESC) */
NULL, /* next */
NULL, /* Didn't dlopen() it, so NULL handle */
NULL /* Didn't dlopen() it, so no file path */
};
return (&moddef);
}