|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- /*
- Copyright (c) 2012, Broadcom Europe Ltd
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the copyright holder nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- /*****************************************************************************
- *
- * This file provides a generic command line interface which allows
- * vcos internals to be manipulated and/or displayed.
- *
- *****************************************************************************/
-
- /* ---- Include Files ---------------------------------------------------- */
-
- #include "interface/vcos/vcos.h"
-
- #ifdef HAVE_VCOS_VERSION
- #include "interface/vcos/vcos_build_info.h"
- #endif
-
- #ifdef _VIDEOCORE
- #include "vcfw/logging/logging.h"
- #endif
-
- /* ---- Public Variables ------------------------------------------------- */
-
- /* ---- Private Constants and Types -------------------------------------- */
-
- #define VCOS_LOG_CATEGORY (&vcos_cmd_log_category)
- VCOS_LOG_CAT_T vcos_cmd_log_category;
-
- /* ---- Private Variables ------------------------------------------------ */
-
- static struct VCOS_CMD_GLOBALS_T
- {
- VCOS_MUTEX_T lock;
- VCOS_ONCE_T initialized;
-
- unsigned num_cmd_entries;
- unsigned num_cmd_alloc;
- VCOS_CMD_T *cmd_entry;
-
- VCOS_LOG_CAT_T *log_category;
- } cmd_globals;
-
- #ifdef HAVE_VCOS_VERSION
- /* Keep the static strings in the image from being dropped by
- * the linker.
- */
- extern const char *vcos_get_build_strings(unsigned id);
- const char *(*vcos_keep_static_strings)(unsigned);
- #endif
-
- /* ---- Private Function Prototypes -------------------------------------- */
-
- static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param );
-
- /* ---- Functions ------------------------------------------------------- */
-
- /*****************************************************************************
- *
- * Walks through the commands looking for a particular command
- *
- *****************************************************************************/
-
- static VCOS_CMD_T *find_cmd( VCOS_CMD_T *cmd_entry, const char *name )
- {
- VCOS_CMD_T *scan_entry = cmd_entry;
-
- while ( scan_entry->name != NULL )
- {
- if ( vcos_strcmp( scan_entry->name, name ) == 0 )
- {
- return scan_entry;
- }
- scan_entry++;
- }
-
- return NULL;
- }
-
- /*****************************************************************************
- *
- * Saves away
- * each line individually.
- *
- *****************************************************************************/
-
- void vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category )
- {
- cmd_globals.log_category = log_category;
- }
-
- /*****************************************************************************
- *
- * Walks through a buffer containing newline separated lines, and logs
- * each line individually.
- *
- *****************************************************************************/
-
- static void cmd_log_results( VCOS_CMD_PARAM_T *param )
- {
- char *start;
- char *end;
-
- start = end = param->result_buf;
-
- while ( *start != '\0' )
- {
- while (( *end != '\0' ) && ( *end != '\n' ))
- end++;
-
- if ( *end == '\n' )
- {
- *end++ = '\0';
- }
-
- if ( cmd_globals.log_category != NULL )
- {
- if ( vcos_is_log_enabled( cmd_globals.log_category, VCOS_LOG_INFO ))
- {
- vcos_log_impl( cmd_globals.log_category, VCOS_LOG_INFO, "%s", start );
- }
- }
- else
- {
- vcos_log_info( "%s", start );
- }
-
- start = end;
- }
-
- /* Since we logged the buffer, reset the pointer back to the beginning. */
-
- param->result_ptr = param->result_buf;
- param->result_buf[0] = '\0';
- }
-
- /*****************************************************************************
- *
- * Since we may have limited output space, we create a generic routine
- * which tries to use the result space, but will switch over to using
- * logging if the output is too large.
- *
- *****************************************************************************/
-
- void vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args )
- {
- int bytes_written;
- int bytes_remaining;
-
- bytes_remaining = (int)(param->result_size - ( param->result_ptr - param->result_buf ));
-
- bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
-
- if ( cmd_globals.log_category != NULL )
- {
- /* We're going to log each line as we encounter it. If the buffer
- * doesn't end in a newline, then we'll wait for one first.
- */
-
- if ( (( bytes_written + 1 ) >= bytes_remaining )
- || ( param->result_ptr[ bytes_written - 1 ] == '\n' ))
- {
- cmd_log_results( param );
- }
- else
- {
- param->result_ptr += bytes_written;
- }
- }
- else
- {
- if (( bytes_written + 1 ) >= bytes_remaining )
- {
- /* Output doesn't fit - switch over to logging */
-
- param->use_log = 1;
-
- *param->result_ptr = '\0'; /* Zap the partial line that didn't fit above. */
-
- cmd_log_results( param ); /* resets result_ptr */
-
- bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
- }
- param->result_ptr += bytes_written;
- }
- }
-
- /*****************************************************************************
- *
- * Prints the output.
- *
- *****************************************************************************/
-
- void vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
- {
- va_list args;
-
- va_start( args, fmt );
- vcos_cmd_vprintf( param, fmt, args );
- va_end( args );
- }
-
- /*****************************************************************************
- *
- * Prints the arguments which were on the command line prior to ours.
- *
- *****************************************************************************/
-
- static void print_argument_prefix( VCOS_CMD_PARAM_T *param )
- {
- int arg_idx;
-
- for ( arg_idx = 0; ¶m->argv_orig[arg_idx] != param->argv; arg_idx++ )
- {
- vcos_cmd_printf( param, "%s ", param->argv_orig[arg_idx] );
- }
- }
-
- /*****************************************************************************
- *
- * Prints an error message, prefixed by the command chain required to get
- * to where we're at.
- *
- *****************************************************************************/
-
- void vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
- {
- va_list args;
-
- print_argument_prefix( param );
-
- va_start( args, fmt );
- vcos_cmd_vprintf( param, fmt, args );
- va_end( args );
- vcos_cmd_printf( param, "\n" );
- }
-
- /****************************************************************************
- *
- * usage - prints command usage for an array of commands.
- *
- ***************************************************************************/
-
- static void usage( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
- {
- int cmd_idx;
- int nameWidth = 0;
- int argsWidth = 0;
- VCOS_CMD_T *scan_entry;
-
- vcos_cmd_printf( param, "Usage: " );
- print_argument_prefix( param );
- vcos_cmd_printf( param, "command [args ...]\n" );
- vcos_cmd_printf( param, "\n" );
- vcos_cmd_printf( param, "Where command is one of the following:\n" );
-
- for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
- {
- int aw;
- int nw;
-
- scan_entry = &cmd_entry[cmd_idx];
-
- nw = vcos_strlen( scan_entry->name );
- aw = vcos_strlen( scan_entry->args );
-
- if ( nw > nameWidth )
- {
- nameWidth = nw;
- }
- if ( aw > argsWidth )
- {
- argsWidth = aw;
- }
- }
-
- for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
- {
- scan_entry = &cmd_entry[cmd_idx];
-
- vcos_cmd_printf( param, " %-*s %-*s - %s\n",
- nameWidth, scan_entry->name,
- argsWidth, scan_entry->args,
- scan_entry->descr );
- }
- }
-
- /****************************************************************************
- *
- * Prints the usage for the current command.
- *
- ***************************************************************************/
-
- void vcos_cmd_usage( VCOS_CMD_PARAM_T *param )
- {
- VCOS_CMD_T *cmd_entry;
-
- cmd_entry = param->cmd_entry;
-
- if ( cmd_entry->sub_cmd_entry != NULL )
- {
- /* This command is command with sub-commands */
-
- usage( param, param->cmd_entry->sub_cmd_entry );
- }
- else
- {
- vcos_cmd_printf( param, "Usage: " );
- print_argument_prefix( param );
- vcos_cmd_printf( param, "%s %s - %s\n",
- param->argv[0],
- param->cmd_entry->args,
- param->cmd_entry->descr );
- }
- }
-
- /*****************************************************************************
- *
- * Command to print out the help
- *
- * This help command is only called from the main menu.
- *
- *****************************************************************************/
-
- static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param )
- {
- VCOS_CMD_T *found_entry;
-
- #if 0
- {
- int arg_idx;
-
- vcos_log_trace( "%s: argc = %d", __func__, param->argc );
- for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
- {
- vcos_log_trace( "%s: argv[%d] = '%s'", __func__, arg_idx, param->argv[arg_idx] );
- }
- }
- #endif
-
- /* If there is an argument after the word help, then we want to print
- * help for that command.
- */
-
- if ( param->argc == 1 )
- {
- if ( param->cmd_parent_entry == cmd_globals.cmd_entry )
- {
- /* Bare help - print the command usage for the root */
-
- usage( param, cmd_globals.cmd_entry );
- return VCOS_SUCCESS;
- }
-
- /* For all other cases help requires an argument */
-
- vcos_cmd_error( param, "%s requires an argument", param->argv[0] );
- return VCOS_EINVAL;
- }
-
- /* We were given an argument. */
-
- if (( found_entry = find_cmd( param->cmd_parent_entry, param->argv[1] )) != NULL )
- {
- /* Make it look like the command that was specified is the one that's
- * currently running
- */
-
- param->cmd_entry = found_entry;
- param->argv[0] = param->argv[1];
- param->argv++;
- param->argc--;
-
- vcos_cmd_usage( param );
- return VCOS_SUCCESS;
- }
-
- vcos_cmd_error( param, "- unrecognized command: '%s'", param->argv[1] );
- return VCOS_ENOENT;
- }
-
- /*****************************************************************************
- *
- * Command to print out the version/build information.
- *
- *****************************************************************************/
-
- #ifdef HAVE_VCOS_VERSION
-
- static VCOS_STATUS_T version_cmd( VCOS_CMD_PARAM_T *param )
- {
- static const char* copyright = "Copyright (c) 2011 Broadcom";
-
- vcos_cmd_printf( param, "%s %s\n%s\nversion %s\nhost %s",
- vcos_get_build_date(),
- vcos_get_build_time(),
- copyright,
- vcos_get_build_version(),
- vcos_get_build_hostname() );
-
- return VCOS_SUCCESS;
- }
-
- #endif
-
- /*****************************************************************************
- *
- * Internal commands
- *
- *****************************************************************************/
-
- static VCOS_CMD_T cmd_help = { "help", "[command]", help_cmd, NULL, "Prints command help information" };
-
- #ifdef HAVE_VCOS_VERSION
- static VCOS_CMD_T cmd_version = { "version", "", version_cmd, NULL, "Prints build/version information" };
- #endif
-
- /*****************************************************************************
- *
- * Walks the command table and executes the commands
- *
- *****************************************************************************/
-
- static VCOS_STATUS_T execute_cmd( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
- {
- const char *cmdStr;
- VCOS_CMD_T *found_entry;
-
- #if 0
- {
- int arg_idx;
-
- vcos_cmd_printf( param, "%s: argc = %d", __func__, param->argc );
- for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
- {
- vcos_cmd_printf( param, " argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
- }
- vcos_cmd_printf( param, "\n" );
- }
- #endif
-
- if ( param->argc <= 1 )
- {
- /* No command specified */
-
- vcos_cmd_error( param, "%s - no command specified", param->argv[0] );
- return VCOS_EINVAL;
- }
-
- /* argv[0] is the command/program that caused us to get invoked, so we strip
- * it off.
- */
-
- param->argc--;
- param->argv++;
- param->cmd_parent_entry = cmd_entry;
-
- /* Not the help command, scan for the command and execute it. */
-
- cmdStr = param->argv[0];
-
- if (( found_entry = find_cmd( cmd_entry, cmdStr )) != NULL )
- {
- if ( found_entry->sub_cmd_entry != NULL )
- {
- return execute_cmd( param, found_entry->sub_cmd_entry );
- }
-
- param->cmd_entry = found_entry;
- return found_entry->cmd_fn( param );
- }
-
- /* Unrecognized command - check to see if it was the help command */
-
- if ( vcos_strcmp( cmdStr, cmd_help.name ) == 0 )
- {
- return help_cmd( param );
- }
-
- vcos_cmd_error( param, "- unrecognized command: '%s'", cmdStr );
- return VCOS_ENOENT;
- }
-
- /*****************************************************************************
- *
- * Initializes the command line parser.
- *
- *****************************************************************************/
-
- static void vcos_cmd_init( void )
- {
- vcos_mutex_create( &cmd_globals.lock, "vcos_cmd" );
-
- cmd_globals.num_cmd_entries = 0;
- cmd_globals.num_cmd_alloc = 0;
- cmd_globals.cmd_entry = NULL;
-
- #ifdef HAVE_VCOS_VERSION
- vcos_keep_static_strings = vcos_get_build_strings;
- #endif
- }
-
- /*****************************************************************************
- *
- * Shuts down the command line parser.
- *
- *****************************************************************************/
-
- void vcos_cmd_shutdown( void )
- {
- vcos_mutex_delete( &cmd_globals.lock );
-
- vcos_free( cmd_globals.cmd_entry );
- cmd_globals.cmd_entry = NULL;
- }
-
- /*****************************************************************************
- *
- * Command line processor.
- *
- *****************************************************************************/
-
- VCOS_STATUS_T vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf )
- {
- VCOS_STATUS_T rc = VCOS_EINVAL;
- VCOS_CMD_PARAM_T param;
-
- vcos_once( &cmd_globals.initialized, vcos_cmd_init );
-
- param.argc = argc;
- param.argv = param.argv_orig = argv;
-
- param.use_log = 0;
- param.result_size = result_size;
- param.result_ptr = result_buf;
- param.result_buf = result_buf;
-
- result_buf[0] = '\0';
-
- vcos_mutex_lock( &cmd_globals.lock );
-
- rc = execute_cmd( ¶m, cmd_globals.cmd_entry );
-
- if ( param.use_log )
- {
- cmd_log_results( ¶m );
- vcos_snprintf( result_buf, result_size, "results logged" );
- }
- else
- if ( cmd_globals.log_category != NULL )
- {
- if ( result_buf[0] != '\0' )
- {
- /* There is a partial line still buffered. */
-
- vcos_cmd_printf( ¶m, "\n" );
- }
- }
-
- vcos_mutex_unlock( &cmd_globals.lock );
-
- return rc;
- }
-
- /*****************************************************************************
- *
- * Registers a command entry with the command line processor
- *
- *****************************************************************************/
-
- VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry )
- {
- VCOS_STATUS_T rc;
- VCOS_UNSIGNED new_num_cmd_alloc;
- VCOS_CMD_T *new_cmd_entry;
- VCOS_CMD_T *old_cmd_entry;
- VCOS_CMD_T *scan_entry;
-
- vcos_once( &cmd_globals.initialized, vcos_cmd_init );
-
- vcos_assert( cmd_entry != NULL );
- vcos_assert( cmd_entry->name != NULL );
-
- vcos_log_trace( "%s: cmd '%s'", __FUNCTION__, cmd_entry->name );
-
- vcos_assert( cmd_entry->args != NULL );
- vcos_assert(( cmd_entry->cmd_fn != NULL ) || ( cmd_entry->sub_cmd_entry != NULL ));
- vcos_assert( cmd_entry->descr != NULL );
-
- /* We expect vcos_cmd_init to be called before vcos_logging_init, so we
- * need to defer registering our logging category until someplace
- * like right here.
- */
-
- if ( vcos_cmd_log_category.name == NULL )
- {
- /*
- * If you're using the command interface, you pretty much always want
- * log messages from this file to show up. So we change the default
- * from ERROR to be the more reasonable INFO level.
- */
-
- vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO);
- vcos_log_register("vcos_cmd", &vcos_cmd_log_category);
-
- /* We register a help command so that it shows up in the usage. */
-
- vcos_cmd_register( &cmd_help );
- #ifdef HAVE_VCOS_VERSION
- vcos_cmd_register( &cmd_version );
- #endif
- }
-
- vcos_mutex_lock( &cmd_globals.lock );
-
- if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc )
- {
- if ( cmd_globals.num_cmd_alloc == 0 )
- {
- /* We haven't allocated a table yet */
- }
-
- /* The number 8 is rather arbitrary. */
-
- new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8;
-
- /* The + 1 is to ensure that we always have a NULL entry at the end. */
-
- new_cmd_entry = (VCOS_CMD_T *)vcos_calloc( new_num_cmd_alloc + 1, sizeof( *cmd_entry ), "vcos_cmd_entries" );
- if ( new_cmd_entry == NULL )
- {
- rc = VCOS_ENOMEM;
- goto out;
- }
- memcpy( new_cmd_entry, cmd_globals.cmd_entry, cmd_globals.num_cmd_entries * sizeof( *cmd_entry ));
- cmd_globals.num_cmd_alloc = new_num_cmd_alloc;
- old_cmd_entry = cmd_globals.cmd_entry;
- cmd_globals.cmd_entry = new_cmd_entry;
- vcos_free( old_cmd_entry );
- }
-
- if ( cmd_globals.num_cmd_entries == 0 )
- {
- /* This is the first command being registered */
-
- cmd_globals.cmd_entry[0] = *cmd_entry;
- }
- else
- {
- /* Keep the list in alphabetical order. We start at the end and work backwards
- * shuffling entries up one until we find an insertion point.
- */
-
- for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1];
- scan_entry >= cmd_globals.cmd_entry; scan_entry-- )
- {
- if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 )
- {
- /* We found an insertion point. */
-
- break;
- }
-
- scan_entry[1] = scan_entry[0];
- }
- scan_entry[1] = *cmd_entry;
- }
- cmd_globals.num_cmd_entries++;
-
- rc = VCOS_SUCCESS;
-
- out:
-
- vcos_mutex_unlock( &cmd_globals.lock );
- return rc;
- }
-
- /*****************************************************************************
- *
- * Registers multiple commands.
- *
- *****************************************************************************/
-
- VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry )
- {
- VCOS_STATUS_T status;
-
- while ( cmd_entry->name != NULL )
- {
- if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS )
- {
- return status;
- }
- cmd_entry++;
- }
- return VCOS_SUCCESS;
- }
-
|