748 lines
21 KiB
C
748 lines
21 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_shellalias.c,v $ $Revision: 1.3 $
|
|
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_shellalias.c,v $
|
|
* $Author: lob $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelius@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
#include "ipcom_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_SHELL_C
|
|
|
|
#if defined(IPCOM_USE_ALIAS) && IPCOM_USE_SHELL == IPCOM_SHELL_IPCOM
|
|
|
|
/* Ipcom include files */
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include "ipcom_clib.h"
|
|
#include "ipcom_err.h"
|
|
#include "ipcom_os.h"
|
|
#include "ipcom_syslog.h"
|
|
#include "ipcom_sock.h"
|
|
#include "ipcom_strlib.h"
|
|
#include "ipcom_shell.h"
|
|
#include "ipcom_sysvar.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
struct Ipcom_shellalias_alias
|
|
{
|
|
Ipcom_list next;
|
|
|
|
char *name; /* Name of this alias */
|
|
char *cmd; /* Command string */
|
|
|
|
int argc; /* Number of arguments */
|
|
char **argv; /* Stored arguments */
|
|
|
|
Ip_bool locked; /* Parsed alias */
|
|
};
|
|
|
|
struct Ipcom_shellalias_config
|
|
{
|
|
char *name;
|
|
char *cmd;
|
|
};
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC int ipcom_shellalias_set(char *name, char *cmd);
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
static Ipcom_list ipcom_shellalias_head;
|
|
|
|
/* Alias expansion is done:
|
|
* If the first word of the command is an alias, it will be expanded, unless
|
|
* that particular alias has already been used in this expansion. Recursive
|
|
* expansion of aliases do not allows that the same alias is referenced twice.
|
|
*
|
|
* If no substitution is involved, the arguments passed in the command will
|
|
* be appended to the expanded alias'ed command. If substitution is involved,
|
|
* the arguments will be inserted where the substitution specifies, and
|
|
* not anywhere else.
|
|
*
|
|
* If a command is prepended with \, the backslash will be removed by the
|
|
* the alias expansion mechanism and then the expansion will terminate, allowing
|
|
* the command to pass through without any expansion.
|
|
*
|
|
* Subsitution understands the following directives:
|
|
* !^ - First argument [Argument 1].
|
|
* !$ - Last argument [Argument 'argc - 1']
|
|
* !-y - Argument range 0 - y
|
|
* !x- - Argument range x - 'argc - 2'. Note that !$ is not included.
|
|
* !x-y - Argument range x -y .
|
|
* !- - Argument range 0 - 'argc - 2'. Note that !$ is not included.
|
|
* !* - Same as !^-$ with the exception that if it does not match any
|
|
* arguments, it will be silently discarded whereas the other
|
|
* substitutions require a match.
|
|
* !n - Argument n
|
|
* !n* - Same as !n-$ with the exception that if no arguments match the
|
|
* the substitution it will be silenty discarded.
|
|
*/
|
|
|
|
/* Pre defined aliases */
|
|
static struct Ipcom_shellalias_config ipcom_shellalias_config[] =
|
|
{
|
|
#ifdef IPCOM_SHELLALIAS_EXAMPLE
|
|
/* First argument expands !1, if there exists any more arguments, they will
|
|
* be expanded in !2*, otherwise it'' be empty */
|
|
{ "qos6", "qos -6 !1 policy !2*" },
|
|
/* Invoke alias qos6 with the appropriate command */
|
|
{ "ql", "qos6 list" },
|
|
{ "qg", "qos6 get" },
|
|
/* Short for route */
|
|
{ "r", "route" },
|
|
/* Show a specific routing table */
|
|
{ "rt", "r show -T" },
|
|
{ "ftp6", "ftp 3ffe:302:111:3::10" },
|
|
/* Ping a specific host, prepend address with any arguments */
|
|
{ "p6", "ping6 !* 3ffe:302:111:1::3" },
|
|
#endif /* IPCOM_SHELLALIAS_EXAMPLE */
|
|
{ IP_NULL, IP_NULL }
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_init
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipcom_shellalias_init(void *unused)
|
|
{
|
|
int i;
|
|
(void)unused;
|
|
|
|
ipcom_list_init(&ipcom_shellalias_head);
|
|
|
|
for (i = 0; ipcom_shellalias_config[i].name != IP_NULL; i++)
|
|
ipcom_shellalias_set(ipcom_shellalias_config[i].name, ipcom_shellalias_config[i].cmd);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_setup
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipcom_shellalias_setup()
|
|
{
|
|
Ip_err err;
|
|
static Ipcom_once_t once = IPCOM_ONCE_INIT;
|
|
|
|
err = ipcom_once(&once, ipcom_shellalias_init, IP_NULL);
|
|
if (err != IPCOM_SUCCESS)
|
|
return err;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_find
|
|
*===========================================================================
|
|
* Description: Find a given alias based on name.
|
|
* Parameters: name - The alias name.
|
|
* Returns: The alias if found.
|
|
*
|
|
*/
|
|
IP_STATIC struct Ipcom_shellalias_alias *
|
|
ipcom_shellalias_find(const char *name)
|
|
{
|
|
struct Ipcom_shellalias_alias *alias;
|
|
|
|
/* Go through the aliases */
|
|
for (alias = IPCOM_LIST_FIRST(&ipcom_shellalias_head);
|
|
alias != IP_NULL;
|
|
alias = IPCOM_LIST_NEXT(&alias->next))
|
|
{
|
|
if (name == IP_NULL)
|
|
{
|
|
int i;
|
|
ipcom_printf("%-15s\t'", alias->name);
|
|
for (i = 0; i < alias->argc; i++)
|
|
{
|
|
ipcom_printf("%s%s",
|
|
alias->argv[i],
|
|
(i == alias->argc - 1)? "" : " ");
|
|
}
|
|
ipcom_printf("'"IP_LF);
|
|
}
|
|
/* Did it match? */
|
|
else if (ipcom_strcmp(alias->name, name) == 0)
|
|
{
|
|
/* Return it */
|
|
return alias;
|
|
}
|
|
}
|
|
|
|
/* No go */
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_remove
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_shellalias_remove(const char *name)
|
|
{
|
|
struct Ipcom_shellalias_alias *alias = ipcom_shellalias_find(name);
|
|
|
|
/* We did locate it */
|
|
if (alias != IP_NULL)
|
|
{
|
|
/* Remove it from the list */
|
|
ipcom_list_remove(&alias->next);
|
|
|
|
/* Free any allocated name */
|
|
ipcom_free(alias->name);
|
|
|
|
/* Free the command */
|
|
ipcom_free(alias->cmd);
|
|
|
|
/* Kill the vector */
|
|
ipcom_free(alias->argv);
|
|
|
|
/* Free the structure */
|
|
ipcom_free(alias);
|
|
|
|
/* Found it */
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* No such entry */
|
|
return -IP_ERRNO_ENOENT;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_remove
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_shellalias_set(char *name,
|
|
char *cmd)
|
|
{
|
|
struct Ipcom_shellalias_alias *alias;
|
|
|
|
if (ipcom_strcmp(name, "alias") == 0 ||
|
|
ipcom_strcmp(name, "unalias") == 0)
|
|
return -IPCOM_ERR_INVALID_ARG;
|
|
|
|
/* Remove any old references */
|
|
ipcom_shellalias_remove(name);
|
|
|
|
/* Allocate a new alias structure */
|
|
alias = ipcom_calloc(1, sizeof(*alias));
|
|
|
|
/* Could we allocate? */
|
|
if (alias != IP_NULL)
|
|
{
|
|
Ip_err retval;
|
|
int argc;
|
|
char **argv = IP_NULL;
|
|
|
|
/* Allocate the name */
|
|
alias->name = ipcom_strdup(name);
|
|
if (alias->name == IP_NULL)
|
|
goto fail;
|
|
|
|
/* Allocate the command */
|
|
alias->cmd = ipcom_strdup(cmd);
|
|
if (alias->cmd == IP_NULL)
|
|
goto fail;
|
|
|
|
/* Parse the string */
|
|
retval = ipcom_parse_argstr(alias->cmd, (int *)&argc, &argv);
|
|
switch(retval)
|
|
{
|
|
case IPCOM_SUCCESS:
|
|
break;
|
|
|
|
case IPCOM_ERR_INVALID_ARG:
|
|
ipcom_printf("Unmatched string delimiters"IP_LF);
|
|
goto fail;
|
|
|
|
case IPCOM_ERR_FAILED:
|
|
default:
|
|
goto fail;
|
|
}
|
|
|
|
/* Store */
|
|
alias->argv = argv;
|
|
alias->argc = argc;
|
|
|
|
/* Link the alias into the major list */
|
|
ipcom_list_insert_first(&ipcom_shellalias_head, &alias->next);
|
|
|
|
/* Success */
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* No memory */
|
|
return -IP_ERRNO_ENOMEM;
|
|
|
|
fail:
|
|
/* Did we manage to allocate the name? */
|
|
if (alias->name != IP_NULL)
|
|
ipcom_free(alias->name);
|
|
|
|
/* Free the stored command */
|
|
if (alias->cmd != IP_NULL)
|
|
ipcom_free(alias->cmd);
|
|
|
|
/* Free the vector */
|
|
if (alias->argv != IP_NULL)
|
|
ipcom_free(alias->argv);
|
|
|
|
/* Free the structure */
|
|
ipcom_free(alias);
|
|
return -IP_ERRNO_ENOMEM;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_list
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_shellalias_list()
|
|
{
|
|
/* Dump */
|
|
ipcom_shellalias_find(IP_NULL);
|
|
|
|
/* Don't bother */
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_substitute
|
|
*===========================================================================
|
|
* Description: Determines what substitutins should be made
|
|
* Parameters: argc - Old argc
|
|
* argv - Old argv
|
|
* alias - The alias we're working with
|
|
* nargv - The new alias argv string
|
|
* Returns: >= 0 The total number of arguments, < 0 error code
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_shellalias_substitute(int argc,
|
|
char **argv,
|
|
struct Ipcom_shellalias_alias *alias,
|
|
char **nargv)
|
|
{
|
|
int nargc = 0;
|
|
int i;
|
|
Ip_bool subst = IP_FALSE;
|
|
|
|
/* Do hunt for substitutions */
|
|
for (i = 0; i < alias->argc; i++)
|
|
{
|
|
char *ptr = alias->argv[i];
|
|
long start;
|
|
long end;
|
|
Ip_bool wildcard = IP_FALSE;
|
|
|
|
/* Substitution? */
|
|
if (*ptr++ == '!')
|
|
{
|
|
/* See what kind of substitution we're dealing with */
|
|
switch (*ptr)
|
|
{
|
|
case '\0':
|
|
/* Just a simple '!' */
|
|
break;
|
|
case '^':
|
|
start = 1;
|
|
ptr++;
|
|
goto parse_range;
|
|
case '$':
|
|
start = argc - 1;
|
|
end = argc - 1;
|
|
goto substitute_range;
|
|
case '*':
|
|
wildcard = IP_TRUE;
|
|
start = 1;
|
|
end = argc - 1;
|
|
goto substitute_range;
|
|
case '-':
|
|
/* This is a -number subtitution, which indicates 0 - num substitution. */
|
|
start = 0;
|
|
goto parse_range;
|
|
default:
|
|
if (ipcom_isdigit(*ptr))
|
|
{
|
|
/* Resolve */
|
|
start = ipcom_strtol(ptr, &ptr, 10);
|
|
|
|
parse_range:
|
|
/* Is it a range or a single value? */
|
|
if (*ptr == '-')
|
|
{
|
|
ptr++;
|
|
|
|
/* It's a range */
|
|
if (*ptr == '\0')
|
|
end = argc - 2;
|
|
else if (*ptr == '$')
|
|
end = argc - 1;
|
|
else if (ipcom_isdigit(*ptr))
|
|
{
|
|
/* Resolve */
|
|
end = ipcom_strtol(ptr, &ptr, 10);
|
|
}
|
|
else
|
|
{
|
|
ipcom_printf("alias: [%s] !x- - substitution requested, but argument following '-' is erronous"IP_LF,
|
|
alias->name);
|
|
return -IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
}
|
|
else if (*ptr == '*')
|
|
{
|
|
wildcard = IP_TRUE;
|
|
end = argc - 1;
|
|
}
|
|
else
|
|
end = start;
|
|
|
|
substitute_range:
|
|
/* OK */
|
|
subst = IP_TRUE;
|
|
|
|
/* Verify if we've gotten the required arguments */
|
|
if (start < 0 || start >= argc)
|
|
{
|
|
/* We've gotten a wildcard match, but we aint got the arguments. Continue */
|
|
if (wildcard)
|
|
continue;
|
|
|
|
ipcom_printf("alias: [%s] !x - substitution requested, but insufficient arguments supplied"IP_LF,
|
|
alias->name);
|
|
return -IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
/* Verify that we have the required number of arguments */
|
|
if (end >= argc)
|
|
{
|
|
ipcom_printf("alias: [%s] !x-y - substitution requested, but insufficient arguments supplied"IP_LF,
|
|
alias->name);
|
|
return -IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
/* Sanity that start <= end */
|
|
if (end < start)
|
|
{
|
|
ipcom_printf("alias: [%s] !x-y - substitution requested, but x > y"IP_LF,
|
|
alias->name);
|
|
return -IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
|
|
/* Go through the arugments */
|
|
for (; start <= end; start++)
|
|
{
|
|
if (nargv != IP_NULL)
|
|
nargv[nargc] = argv[start];
|
|
|
|
nargc++;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nargv != IP_NULL)
|
|
nargv[nargc] = alias->argv[i];
|
|
nargc++;
|
|
}
|
|
|
|
/* No substitutions? */
|
|
if (subst == IP_FALSE)
|
|
{
|
|
/* Add all arguments to the end of the command */
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (nargv != IP_NULL)
|
|
nargv[nargc] = argv[i];
|
|
|
|
nargc++;
|
|
}
|
|
}
|
|
|
|
|
|
/* Return the number of arguments */
|
|
return nargc;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_alias
|
|
*===========================================================================
|
|
* Description: Add an alias.
|
|
* Parameters: argc - The number of arguments
|
|
* argv - The arguments.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_shellalias_alias(int argc, char **argv)
|
|
{
|
|
Ip_err err;
|
|
|
|
if ((err = ipcom_shellalias_setup()) != IPCOM_SUCCESS)
|
|
return err;
|
|
|
|
if (argc == 1)
|
|
{
|
|
/* List all aliases */
|
|
return ipcom_shellalias_list();
|
|
}
|
|
else if (argc != 3)
|
|
{
|
|
ipcom_printf("alias: syntax: alias name \"cmd\""IP_LF);
|
|
return -1;
|
|
}
|
|
|
|
|
|
return ipcom_shellalias_set(argv[1], argv[2]);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_alias
|
|
*===========================================================================
|
|
* Description: Add an alias.
|
|
* Parameters: argc - The number of arguments
|
|
* argv - The arguments.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_shellalias_unalias(int argc, char **argv)
|
|
{
|
|
Ip_err err;
|
|
|
|
if ((err = ipcom_shellalias_setup()) != IPCOM_SUCCESS)
|
|
return err;
|
|
|
|
if (argc != 2)
|
|
{
|
|
ipcom_printf("unalias: syntax: unalias name"IP_LF);
|
|
return -1;
|
|
}
|
|
|
|
/* Remove this partiuclar alias */
|
|
return ipcom_shellalias_remove(argv[1]);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shellalias_expand
|
|
*===========================================================================
|
|
* Description: Expand a command
|
|
* Parameters: argc - The number of arguments
|
|
* argv - The arguments.
|
|
* Returns: IPCOM_SUCCESS if successful.
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_shellalias_expand(int *argc, char ***argv)
|
|
{
|
|
char **aargv = *argv;
|
|
int aargc = *argc;
|
|
struct Ipcom_shellalias_alias *alias;
|
|
char **nargv = IP_NULL;
|
|
int nargc = 0;
|
|
int ret;
|
|
Ip_err err;
|
|
|
|
/* Setup */
|
|
if ((err = ipcom_shellalias_setup()) != IPCOM_SUCCESS)
|
|
return err;
|
|
|
|
/* Don't expand if it begins with a '\' */
|
|
if (aargv[0][0] == '\\')
|
|
{
|
|
aargv[0]++;
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* Locate */
|
|
alias = ipcom_shellalias_find(aargv[0]);
|
|
|
|
/* Nothing to do? */
|
|
if (alias == IP_NULL)
|
|
return IPCOM_SUCCESS;
|
|
|
|
/* Do not attempt to recursively parse the same alias */
|
|
if (alias->locked)
|
|
return IPCOM_SUCCESS;
|
|
|
|
/* Lock this alias */
|
|
alias->locked = IP_TRUE;
|
|
|
|
/* Verify the substitutions */
|
|
if ((nargc = ipcom_shellalias_substitute(aargc,aargv,alias,IP_NULL)) < 0)
|
|
{
|
|
alias->locked = IP_FALSE;
|
|
return nargc;
|
|
}
|
|
|
|
/* We located an alias. We need to reallocate the vector so that we
|
|
* can insert all arguments in the current command after the arguments
|
|
* added by the alias */
|
|
nargv = ipcom_malloc(sizeof(char *) * (nargc + 1));
|
|
|
|
/* Failed to reallocate vector? */
|
|
if (nargv == IP_NULL)
|
|
{
|
|
alias->locked = IP_FALSE;
|
|
return -IP_ERRNO_ENOMEM;
|
|
}
|
|
|
|
/* NULL Terminate, some commands require this */
|
|
nargv[nargc] = IP_NULL;
|
|
|
|
/* Perform the previously calculated subistitutions */
|
|
ipcom_shellalias_substitute(aargc,aargv,alias,nargv);
|
|
|
|
/* Free previous argument vector */
|
|
ipcom_free(*argv);
|
|
|
|
/* Set new command vector */
|
|
*argv = nargv;
|
|
*argc = nargc;
|
|
|
|
#if 0
|
|
for (ret = 0; ret < nargc; ret++)
|
|
ipcom_printf("%s ", nargv[ret]);
|
|
ipcom_printf(IP_LF);
|
|
#endif
|
|
|
|
/* Do recursively expand */
|
|
ret = ipcom_shellalias_expand(argc, argv);
|
|
|
|
/* Lock this alias */
|
|
alias->locked = IP_FALSE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
#else
|
|
int ipcom_shellalias_empty_file;
|
|
#endif /* defined(IPCOM_USE_ALIAS) && IPCOM_USE_SHELL == IPCOM_SHELL_IPCOM */
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|