Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3365 → Rev 3366

/trunk/uspace/app/bdsh/scli.h
14,7 → 14,5
} cliuser_t;
 
extern unsigned int cli_set_prompt(cliuser_t *usr);
extern int cli_init(cliuser_t *usr);
extern void cli_finit(cliuser_t *usr);
 
#endif
/trunk/uspace/app/bdsh/input.c
46,7 → 46,7
/* More than a macro than anything */
void cli_restricted(char *cmd)
{
cli_verbose("%s is not available in %s mode\n", cmd,
printf("%s is not available in %s mode\n", cmd,
cli_interactive ? "interactive" : "non-interactive");
 
return;
/trunk/uspace/app/bdsh/cmds/modules/quit/quit.c
35,9 → 35,8
#include "cmds.h"
 
static char *cmdname = "quit";
unsigned int cli_quit = 0;
 
extern volatile int cli_lasterror;
extern volatile unsigned int cli_quit;
extern const char *progname;
 
void * help_cmd_quit(unsigned int level)
/trunk/uspace/app/bdsh/cmds/modules/help/help.c
40,7 → 40,6
 
static char *cmdname = "help";
extern const char *progname;
extern unsigned int cli_interactive;
 
#define HELP_IS_MODULE 1
#define HELP_IS_BUILTIN 0
126,10 → 125,8
}
}
 
printf("%sAvailable commands are:\n", cli_interactive ? "\n " : "");
if (cli_interactive)
printf(
" ------------------------------------------------------------\n");
printf("\n Available commands are:\n");
printf(" ------------------------------------------------------------\n");
 
/* First, show a list of built in commands that are available in this mode */
for (cmd = builtins; cmd->name != NULL; cmd++, i++) {
155,11 → 152,8
}
}
 
/* Provide a little more information and inform them of history / line
* editing features if they are present */
if (cli_interactive)
printf("\n Try %s %s for more information on how `%s' works.\n\n",
cmdname, cmdname, cmdname);
printf("\n Try %s %s for more information on how `%s' works.\n\n",
cmdname, cmdname, cmdname);
 
return CMD_SUCCESS;
}
/trunk/uspace/app/bdsh/cmds/modules/README
1,8 → 1,15
Modules are commands or full programs (anything can be made into a module that can return
int type) should go here. Note, modules do not update the structures containing user info
such as the working directory, euid, etc.
Modules are commands or full programs (anything can be made into a module
that can return int type) should go here. Note, modules do not (can not)
update or read cliuser_t.
 
Stuff that needs to write to the user structures contained in scli.h should be made as
built-in commands, not modules.
Stuff that needs to write to the user structures contained in scli.h should
be made as built-in commands, not modules, but there are very few times when
you would want to do that.
 
See the README file in the bdsh root directory for a quick overview of how to
write a new command, or convert an existig stand-alone program into a module
for BDSH.
 
 
 
 
/trunk/uspace/app/bdsh/cmds/builtins/README
4,13 → 4,18
 
Examples of what should be a built-in and not a module would be:
 
cd (the cwd needs to be updated)
prompt (the prompt needs to be updated)
enable (the euid needs to be updated)
cd (cliuser_t->cwd needs to be updated)
 
In the future, more user preferences will be set via built-in commands,
such as the formatting of the prompt string (HelenOS doesn't yet have
an environment, much less PS*, even if it did we'd likely do it a little
differently).
 
.... etc.
 
Anything that does _not_ need to write to this structure should be included
as a module, not a built in.
Anything that does _not_ need to use this structure should be included
as a module, not a built in. If you want to include a new command, there
is a 99% chance that you want it to be a module.
 
For now, a skeleton directory of stuff that will exist lives here.
 
 
/trunk/uspace/app/bdsh/errors.c
38,18 → 38,19
#include "errors.h"
#include "errstr.h"
 
volatile int cli_errno = CL_EOK;
extern volatile unsigned int cli_quit;
 
/* Error printing, translation and handling functions */
 
volatile int cli_lasterr = 0;
extern volatile unsigned int cli_verbocity;
 
/* Look up errno in cl_errors and return the corresponding string.
* Return NULL if not found */
char *err2str(int errno)
static char *err2str(int err)
{
 
if (NULL != cl_errors[errno])
return cl_errors[errno];
if (NULL != cl_errors[err])
return cl_errors[err];
 
return (char *)NULL;
}
58,7 → 59,7
* its corresponding human readable string. If errno > 0, raise the
* cli_quit int that tells the main program loop to exit immediately */
 
void cli_error(int errno, const char *fmt, ...)
void cli_error(int err, const char *fmt, ...)
{
va_list vargs;
va_start(vargs, fmt);
65,31 → 66,22
vprintf(fmt, vargs);
va_end(vargs);
 
if (NULL != err2str(errno))
printf(" (%s)\n", err2str(errno));
if (NULL != err2str(err))
printf(" (%s)\n", err2str(err));
else
printf(" (Unknown Error %d)\n", errno);
printf(" (Unknown Error %d)\n", err);
 
if (errno < 0)
exit(EXIT_FAILURE);
/* If fatal, raise cli_quit so that we try to exit
* gracefully. This will break the main loop and
* invoke the destructor */
if (err == CL_EFATAL)
cli_quit = 1;
 
return;
 
}
 
/* Just a smart printf(), print the string only if cli_verbocity is high */
void cli_verbose(const char *fmt, ...)
{
if (cli_verbocity) {
va_list vargs;
 
printf("[*] ");
va_start(vargs, fmt);
vprintf(fmt, vargs);
va_end(vargs);
printf("\n");
}
return;
}
 
 
 
 
/trunk/uspace/app/bdsh/util.c
52,6 → 52,8
#include "errors.h"
#include "util.h"
 
extern volatile int cli_errno;
 
/* some platforms do not have strdup, implement it here.
* Returns a pointer to an allocated string or NULL on failure */
char * cli_strdup(const char *s1)
59,9 → 61,12
size_t len = strlen(s1) + 1;
void *ret = malloc(len);
 
if (ret == NULL)
if (ret == NULL) {
cli_errno = CL_ENOMEM;
return (char *) NULL;
}
 
cli_errno = CL_EOK;
return (char *) memcpy(ret, s1, len);
}
 
79,54 → 84,108
 
*s1 = realloc(*s1, len);
 
if (*s1 == NULL)
if (*s1 == NULL) {
cli_errno = CL_ENOMEM;
return -1;
}
 
memset(*s1, 0, sizeof(*s1));
memcpy(*s1, s2, len);
cli_errno = CL_EOK;
return (int) len;
}
 
/* An asprintf() for concantenating paths. Allocates the system PATH_MAX value,
* expands the formatted string and re-sizes the block s1 points to accordingly.
/* An asprintf() for formatting paths, similar to asprintf() but ensures
* the returned allocated string is <= PATH_MAX. On failure, an attempt
* is made to return the original string (if not null) unmodified.
*
* Returns the length of the new s1 on success, -1 on failure. On failure, an
* attempt is made to return s1 unmodified for sanity, in this case 0 is returned.
* to indicate that s1 was not modified.
* Returns: Length of the new string on success, 0 if the string was handed
* back unmodified, -1 on failure. On failure, cli_errno is set.
*
* FIXME: ugly hack to get around asprintf(), if you use this, CHECK ITS VALUE! */
* We do not use POSIX_PATH_MAX, as it is typically much smaller than the
* PATH_MAX defined by the kernel.
*
* Use this like:
* if (1 > cli_psprintf(&char, "%s/%s", foo, bar)) {
* cli_error(cli_errno, "Failed to format path");
* stop_what_your_doing_as_your_out_of_memory();
* }
*/
 
int cli_psprintf(char **s1, const char *fmt, ...)
{
va_list ap;
size_t needed, base = PATH_MAX + 1;
int skipped = 0;
char *orig = NULL;
char *tmp = (char *) malloc(base);
 
if (NULL == tmp)
/* Don't even touch s1, not enough memory */
if (NULL == tmp) {
cli_errno = CL_ENOMEM;
return -1;
}
 
char *orig = *s1;
/* If re-allocating s1, save a copy in case we fail */
if (NULL != *s1)
orig = cli_strdup(*s1);
 
/* Print the string to tmp so we can determine the size that
* we actually need */
memset(tmp, 0, sizeof(tmp));
va_start(ap, fmt);
vsnprintf(tmp, base, fmt, ap);
/* vsnprintf will return the # of bytes not written */
skipped = vsnprintf(tmp, base, fmt, ap);
va_end(ap);
 
/* realloc/alloc s1 to be just the size that we need */
needed = strlen(tmp) + 1;
*s1 = realloc(*s1, needed);
 
if (NULL == *s1) {
/* No string lived here previously, or we failed to
* make a copy of it, either way there's nothing we
* can do. */
if (NULL == *orig) {
cli_errno = CL_ENOMEM;
return -1;
}
/* We can't even allocate enough size to restore the
* saved copy, just give up */
*s1 = realloc(*s1, strlen(orig) + 1);
if (NULL == *s1) {
free(tmp);
free(orig);
cli_errno = CL_ENOMEM;
return -1;
}
/* Give the string back as we found it */
memset(*s1, 0, sizeof(*s1));
memcpy(*s1, orig, strlen(orig) + 1);
free(tmp);
free(orig);
cli_errno = CL_ENOMEM;
return 0;
}
 
/* Ok, great, we have enough room */
memset(*s1, 0, sizeof(*s1));
memcpy(*s1, tmp, needed);
free(tmp);
 
/* Free tmp only if s1 was reallocated instead of allocated */
if (NULL != orig)
free(orig);
 
if (skipped) {
/* s1 was bigger than PATH_MAX when expanded, however part
* of the string was printed. Tell the caller not to use it */
cli_errno = CL_ETOOBIG;
return -1;
}
 
/* Success! */
cli_errno = CL_EOK;
return (int) needed;
}
136,8 → 195,10
char *spanp, *tok;
int c, sc;
 
if (s == NULL && (s = *last) == NULL)
if (s == NULL && (s = *last) == NULL) {
cli_errno = CL_EFAIL;
return (NULL);
}
 
cont:
c = *s++;
/trunk/uspace/app/bdsh/errors.h
2,7 → 2,7
#define ERRORS_H
 
/* Various error levels */
#define CL_EFATAL -1
#define CL_EFATAL -1
#define CL_EOK 0
#define CL_EFAIL 1
#define CL_EBUSY 2
12,8 → 12,11
#define CL_ENOTSUP 6
#define CL_EEXEC 7
#define CL_EEXISTS 8
#define CL_ETOOBIG 9
 
extern char *err2str(int);
/* Just like 'errno' */
extern volatile int cli_errno;
 
extern void cli_error(int, const char *, ...);
extern void cli_verbose(const char *, ...);
 
#endif
/trunk/uspace/app/bdsh/exec.c
65,7 → 65,7
* cmd as it was presented */
char *find_command(char *cmd)
{
char *path_orig, *path_tok;
char *path_tok;
char *path[PATH_MAX];
int n = 0, i = 0;
size_t x = strlen(cmd) + 2;
76,9 → 76,9
if (-1 != try_access(cmd)) {
return (char *) cmd;
}
path_orig = PATH;
path_tok = cli_strdup(path_orig);
 
path_tok = cli_strdup(PATH);
 
/* Extract the PATH env to a path[] array */
path[n] = cli_strtok(path_tok, PATH_DELIM);
while (NULL != path[n]) {
/trunk/uspace/app/bdsh/errstr.h
13,8 → 13,11
"Method Not Supported",
"Bad command or file name",
"Entry already exists",
"Object too large",
NULL
};
 
static char *err2str(int);
 
#endif
 
/trunk/uspace/app/bdsh/scli.c
42,11 → 42,9
/* See scli.h */
static cliuser_t usr;
 
/* Modified by the 'quit' module, which is compiled before this */
extern unsigned int cli_quit;
 
/* Globals that are modified during start-up that modules/builtins should
* be aware of. */
/* Globals that are modified during start-up that modules/builtins
* should be aware of. */
volatile unsigned int cli_quit = 0;
volatile unsigned int cli_interactive = 1;
volatile unsigned int cli_verbocity = 1;
 
54,8 → 52,13
* (change to your liking in configure.ac and re-run autoconf) */
const char *progname = PACKAGE_NAME;
 
/* These are not exposed, even to builtins */
static int cli_init(cliuser_t *usr);
static void cli_finit(cliuser_t *usr);
 
/* (re)allocates memory to store the current working directory, gets
* and updates the current working directory, formats the prompt string */
* and updates the current working directory, formats the prompt
* string */
unsigned int cli_set_prompt(cliuser_t *usr)
{
usr->prompt = (char *) realloc(usr->prompt, PATH_MAX);
77,15 → 80,16
if (NULL == usr->cwd)
snprintf(usr->cwd, PATH_MAX, "(unknown)");
 
snprintf(usr->prompt,
PATH_MAX,
"%s # ",
usr->cwd);
if (1 < cli_psprintf(&usr->prompt, "%s # ", usr->cwd)) {
cli_error(cli_errno, "Failed to set prompt");
return 1;
}
 
return 0;
}
 
int cli_init(cliuser_t *usr)
/* Constructor */
static int cli_init(cliuser_t *usr)
{
usr->line = (char *) NULL;
usr->name = "root";
98,7 → 102,7
}
 
/* Destructor */
void cli_finit(cliuser_t *usr)
static void cli_finit(cliuser_t *usr)
{
if (NULL != usr->line)
free(usr->line);