Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev HEAD → Rev 3461

/trunk/uspace/app/bdsh/util.c
1,4 → 1,7
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> - All rights reserved
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
* Copyright (C) 1998 by Wes Peters <wes@softweyr.com>
* Copyright (c) 1988, 1993 The Regents of the University of California.
* All rights reserved by all copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
27,6 → 30,18
* POSSIBILITY OF SUCH DAMAGE.
*/
 
/* NOTES:
* 1 - Various functions were adapted from FreeBSD (copyright holders noted above)
* these functions are identified with comments.
*
* 2 - Some of these have since appeared in libc. They remain here for various
* reasons, such as the eventual integration of garbage collection for things
* that allocate memory and don't automatically free it.
*
* 3 - Things that expect a pointer to an allocated string do _no_ sanity checking
* if developing on a simulator with no debugger, take care :)
*/
 
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
39,6 → 54,190
 
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)
{
size_t len = strlen(s1) + 1;
void *ret = malloc(len);
 
if (ret == NULL) {
cli_errno = CL_ENOMEM;
return (char *) NULL;
}
 
cli_errno = CL_EOK;
return (char *) memcpy(ret, s1, len);
}
 
/*
* Take a previously allocated string (s1), re-size it to accept s2 and copy
* the contents of s2 into s1.
* Return -1 on failure, or the length of the copied string on success.
*/
int cli_redup(char **s1, const char *s2)
{
size_t len = strlen(s2) + 1;
 
if (! len)
return -1;
 
*s1 = realloc(*s1, len);
 
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 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: Length of the new string on success, 0 if the string was handed
* back unmodified, -1 on failure. On failure, cli_errno is set.
*
* 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);
 
/* Don't even touch s1, not enough memory */
if (NULL == tmp) {
cli_errno = CL_ENOMEM;
return -1;
}
 
/* 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 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;
}
/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
char * cli_strtok_r(char *s, const char *delim, char **last)
{
char *spanp, *tok;
int c, sc;
 
if (s == NULL && (s = *last) == NULL) {
cli_errno = CL_EFAIL;
return (NULL);
}
 
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
 
if (c == 0) { /* no non-delimiter characters */
*last = NULL;
return (NULL);
}
 
tok = s - 1;
 
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = '\0';
*last = s;
return (tok);
}
} while (sc != 0);
}
}
 
/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
char * cli_strtok(char *s, const char *delim)
{
static char *last;
 
return (cli_strtok_r(s, delim, &last));
}
 
/* Count and return the # of elements in an array */
unsigned int cli_count_args(char **args)
{
74,7 → 273,10
if (NULL == usr->cwd)
snprintf(usr->cwd, PATH_MAX, "(unknown)");
 
asprintf(&usr->prompt, "%s # ", usr->cwd);
if (1 < cli_psprintf(&usr->prompt, "%s # ", usr->cwd)) {
cli_error(cli_errno, "Failed to set prompt");
return 1;
}
 
return 0;
}
/trunk/uspace/app/bdsh/exec.c
71,7 → 71,7
char *path_tok;
char *path[PATH_MAX];
int n = 0, i = 0;
size_t x = str_size(cmd) + 2;
size_t x = strlen(cmd) + 2;
 
found = (char *)malloc(PATH_MAX);
 
80,18 → 80,18
return (char *) cmd;
}
 
path_tok = str_dup(PATH);
path_tok = cli_strdup(PATH);
 
/* Extract the PATH env to a path[] array */
path[n] = strtok(path_tok, PATH_DELIM);
path[n] = cli_strtok(path_tok, PATH_DELIM);
while (NULL != path[n]) {
if ((str_size(path[n]) + x ) > PATH_MAX) {
if ((strlen(path[n]) + x ) > PATH_MAX) {
cli_error(CL_ENOTSUP,
"Segment %d of path is too large, search ends at segment %d",
n, n-1);
break;
}
path[++n] = strtok(NULL, PATH_DELIM);
path[++n] = cli_strtok(NULL, PATH_DELIM);
}
 
/* We now have n places to look for the command */
112,27 → 112,18
unsigned int try_exec(char *cmd, char **argv)
{
task_id_t tid;
task_exit_t texit;
char *tmp;
int retval;
 
tmp = str_dup(find_command(cmd));
tmp = cli_strdup(find_command(cmd));
free(found);
 
tid = task_spawn((const char *)tmp, argv);
tid = task_spawn((const char *)tmp, (const char **)argv);
free(tmp);
 
if (tid == 0) {
cli_error(CL_EEXEC, "Cannot spawn `%s'.", cmd);
cli_error(CL_EEXEC, "Can not spawn %s", cmd);
return 1;
} else {
return 0;
}
task_wait(tid, &texit, &retval);
if (texit != TASK_EXIT_NORMAL) {
printf("Command failed (unexpectedly terminated).\n");
} else if (retval != 0) {
printf("Command failed (return value %d).\n", retval);
}
 
return 0;
}
/trunk/uspace/app/bdsh/cmds/modules/kcon/kcon.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/kcon/entry.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/kcon/kcon.c
File deleted
/trunk/uspace/app/bdsh/cmds/modules/kcon/kcon_def.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mv/mv.c
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mv/mv_def.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mv/entry.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mv/mv.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/bdd/entry.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/bdd/bdd.c
File deleted
/trunk/uspace/app/bdsh/cmds/modules/bdd/bdd_def.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/bdd/bdd.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mount/mount_def.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mount/entry.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mount/mount.h
File deleted
/trunk/uspace/app/bdsh/cmds/modules/mount/mount.c
File deleted
/trunk/uspace/app/bdsh/cmds/modules/cp/cp.c
30,10 → 30,6
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <fcntl.h>
#include "config.h"
#include "util.h"
#include "errors.h"
41,191 → 37,37
#include "cp.h"
#include "cmds.h"
 
#define CP_VERSION "0.0.1"
#define CP_DEFAULT_BUFLEN 1024
static char *cmdname = "cp";
 
static const char *cmdname = "cp";
 
static struct option const long_options[] = {
{ "buffer", required_argument, 0, 'b' },
{ "force", no_argument, 0, 'f' },
{ "recursive", no_argument, 0, 'r' },
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'v' },
{ "verbose", no_argument, 0, 'V' },
{ 0, 0, 0, 0 }
};
 
static int strtoint(const char *s1)
{
long t1;
 
if (-1 == (t1 = strtol(s1, (char **) NULL, 10)))
return -1;
 
if (t1 <= 0)
return -1;
 
return (int) t1;
}
 
static int64_t copy_file(const char *src, const char *dest,
size_t blen, int vb)
{
int fd1, fd2, bytes = 0;
off_t total = 0;
int64_t copied = 0;
char *buff = NULL;
 
if (vb)
printf("Copying %s to %s\n", src, dest);
 
if (-1 == (fd1 = open(src, O_RDONLY))) {
printf("Unable to open source file %s\n", src);
return -1;
}
 
if (-1 == (fd2 = open(dest, O_CREAT))) {
printf("Unable to open destination file %s\n", dest);
close(fd1);
return -1;
}
 
total = lseek(fd1, 0, SEEK_END);
 
if (vb)
printf("%d bytes to copy\n", total);
 
lseek(fd1, 0, SEEK_SET);
 
if (NULL == (buff = (char *) malloc(blen))) {
printf("Unable to allocate enough memory to read %s\n",
src);
copied = -1;
goto out;
}
 
for (;;) {
ssize_t res;
 
bytes = read(fd1, buff, blen);
if (bytes <= 0)
break;
copied += bytes;
res = bytes;
do {
/*
* Theoretically, it may not be enough to call write()
* only once. Also the previous read() may have
* returned less data than requested.
*/
bytes = write(fd2, buff, res);
if (bytes < 0)
goto err;
res -= bytes;
} while (res > 0);
 
/* TODO: re-insert assert() once this is stand alone,
* removed as abort() exits the entire shell
*/
if (res != 0) {
printf("\n%d more bytes than actually exist were copied\n", res);
goto err;
}
}
 
if (bytes < 0) {
err:
printf("\nError copying %s, (%d)\n", src, bytes);
copied = bytes;
}
 
out:
close(fd1);
close(fd2);
if (buff)
free(buff);
return copied;
}
 
/* Dispays help for cp in various levels */
void help_cmd_cp(unsigned int level)
{
static char helpfmt[] =
"Usage: %s [options] <source> <dest>\n"
"Options: (* indicates not yet implemented)\n"
" -h, --help A short option summary\n"
" -v, --version Print version information and exit\n"
"* -V, --verbose Be annoyingly noisy about what's being done\n"
"* -f, --force Do not complain when <dest> exists\n"
"* -r, --recursive Copy entire directories\n"
" -b, --buffer ## Set the read buffer size to ##\n"
"Currently, %s is under development, some options may not work.\n";
if (level == HELP_SHORT) {
printf("`%s' copies files and directories\n", cmdname);
} else {
help_cmd_cp(HELP_SHORT);
printf(helpfmt, cmdname, cmdname);
}
 
printf("This is the %s help for '%s'.\n",
level ? EXT_HELP : SHORT_HELP, cmdname);
return;
}
 
/* Main entry point for cp, accepts an array of arguments */
int cmd_cp(char **argv)
{
unsigned int argc, buffer = 0, verbose = 0;
int c, opt_ind;
int64_t ret;
unsigned int argc;
unsigned int i;
 
argc = cli_count_args(argv);
/* Count the arguments */
for (argc = 0; argv[argc] != NULL; argc ++);
 
for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
c = getopt_long(argc, argv, "hvVfrb:", long_options, &opt_ind);
switch (c) {
case 'h':
help_cmd_cp(1);
return CMD_SUCCESS;
case 'v':
printf("%d\n", CP_VERSION);
return CMD_SUCCESS;
case 'V':
verbose = 1;
break;
case 'f':
break;
case 'r':
break;
case 'b':
if (-1 == (buffer = strtoint(optarg))) {
printf("%s: Invalid buffer specification, "
"(should be a number greater than zero)\n",
cmdname);
return CMD_FAILURE;
}
if (verbose)
printf("Buffer = %d\n", buffer);
break;
}
}
printf("%s %s\n", TEST_ANNOUNCE, cmdname);
printf("%d arguments passed to %s", argc - 1, cmdname);
 
if (buffer == 0)
buffer = CP_DEFAULT_BUFLEN;
 
argc -= optind;
 
if (argc != 2) {
printf("%s: invalid number of arguments. Try %s --help\n",
cmdname, cmdname);
return CMD_FAILURE;
if (argc < 2) {
printf("\n");
return CMD_SUCCESS;
}
 
ret = copy_file(argv[optind], argv[optind + 1], buffer, verbose);
printf(":\n");
for (i = 1; i < argc; i++)
printf("[%d] -> %s\n", i, argv[i]);
 
if (verbose)
printf("%d bytes copied\n", ret);
 
if (ret >= 0)
return CMD_SUCCESS;
else
return CMD_FAILURE;
return CMD_SUCCESS;
}
 
/trunk/uspace/app/bdsh/cmds/modules/cp/cp_def.h
3,5 → 3,6
"Copy files and directories",
&cmd_cp,
&help_cmd_cp,
0
},
 
/trunk/uspace/app/bdsh/cmds/modules/sleep/sleep_def.h
3,5 → 3,6
"Pause for given time interval (in seconds)",
&cmd_sleep,
&help_cmd_sleep,
0
},
 
/trunk/uspace/app/bdsh/cmds/modules/modules.h
18,9 → 18,9
/* Prototypes for each module's entry (help/exec) points */
 
#include "help/entry.h"
#include "quit/entry.h"
#include "mkdir/entry.h"
#include "rm/entry.h"
#include "bdd/entry.h"
#include "cat/entry.h"
#include "touch/entry.h"
#include "ls/entry.h"
27,9 → 27,6
#include "pwd/entry.h"
#include "sleep/entry.h"
#include "cp/entry.h"
#include "mv/entry.h"
#include "mount/entry.h"
#include "kcon/entry.h"
 
/* Each .def function fills the module_t struct with the individual name, entry
* point, help entry point, etc. You can use config.h to control what modules
37,9 → 34,9
 
module_t modules[] = {
#include "help/help_def.h"
#include "quit/quit_def.h"
#include "mkdir/mkdir_def.h"
#include "rm/rm_def.h"
#include "bdd/bdd_def.h"
#include "cat/cat_def.h"
#include "touch/touch_def.h"
#include "ls/ls_def.h"
46,10 → 43,6
#include "pwd/pwd_def.h"
#include "sleep/sleep_def.h"
#include "cp/cp_def.h"
#include "mv/mv_def.h"
#include "mount/mount_def.h"
#include "kcon/kcon_def.h"
 
{NULL, NULL, NULL, NULL}
};
 
/trunk/uspace/app/bdsh/cmds/modules/quit/quit.c
0,0 → 1,55
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
* 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 original program's authors 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 OWNER 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.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include "entry.h"
#include "quit.h"
#include "cmds.h"
 
static char *cmdname = "quit";
 
extern volatile unsigned int cli_quit;
extern const char *progname;
 
void help_cmd_quit(unsigned int level)
{
printf("Type `%s' to exit %s\n", cmdname, progname);
return;
}
 
/* Quits the program and returns the status of whatever command
* came before invoking 'quit' */
int cmd_quit(char *argv[])
{
/* Inform that we're outta here */
cli_quit = 1;
return CMD_SUCCESS;
}
/trunk/uspace/app/bdsh/cmds/modules/quit/entry.h
0,0 → 1,10
#ifndef QUIT_ENTRY_H_
#define QUIT_ENTRY_H_
 
/* Entry points for the quit command */
extern void help_cmd_quit(unsigned int);
extern int cmd_quit(char *[]);
 
#endif
 
 
/trunk/uspace/app/bdsh/cmds/modules/quit/quit_def.h
0,0 → 1,14
{
"quit",
"Exit the console",
&cmd_quit,
&help_cmd_quit,
-1
},
{
"exit",
NULL,
&cmd_quit,
&help_cmd_quit,
-1
},
/trunk/uspace/app/bdsh/cmds/modules/quit/quit.h
0,0 → 1,6
#ifndef QUIT_H
#define QUIT_H
 
/* Prototypes for the quit command (excluding entry points) */
 
#endif
/trunk/uspace/app/bdsh/cmds/modules/touch/touch.c
37,7 → 37,6
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>
 
#include "config.h"
#include "errors.h"
80,7 → 79,7
}
 
for (i = 1; i < argc; i ++) {
buff = str_dup(argv[i]);
buff = cli_strdup(argv[i]);
dirp = opendir(buff);
if (dirp) {
cli_error(CL_ENOTSUP, "%s is a directory", buff);
/trunk/uspace/app/bdsh/cmds/modules/touch/touch_def.h
3,5 → 3,6
"Create files or update access times",
&cmd_touch,
&help_cmd_touch,
0
},
 
/trunk/uspace/app/bdsh/cmds/modules/mkdir/mkdir.c
37,7 → 37,6
#include <sys/stat.h>
#include <getopt.h>
#include <stdarg.h>
#include <string.h>
 
#include "config.h"
#include "errors.h"
94,7 → 93,7
 
/* Its a good idea to allocate path, plus we (may) need a copy of
* path to tokenize if parents are specified */
if (NULL == (tmp = str_dup(path))) {
if (NULL == (tmp = cli_strdup(path))) {
cli_error(CL_ENOMEM, "%s: path too big?", cmdname);
return 1;
}
129,9 → 128,9
absolute = 1;
 
/* TODO: Canonify the path prior to tokenizing it, see below */
dirs[i] = strtok(tmp, "/");
dirs[i] = cli_strtok(tmp, "/");
while (dirs[i] && i < 255)
dirs[++i] = strtok(NULL, "/");
dirs[++i] = cli_strtok(NULL, "/");
 
if (NULL == dirs[0])
return 1;
150,7 → 149,7
while (dirs[i] != NULL) {
/* Sometimes make or scripts conjoin odd paths. Account for something
* like this: ../../foo/bar/../foo/foofoo/./bar */
if (!str_cmp(dirs[i], "..") || !str_cmp(dirs[i], ".")) {
if (!strcmp(dirs[i], "..") || !strcmp(dirs[i], ".")) {
if (0 != (chdir(dirs[i]))) {
cli_error(CL_EFAIL, "%s: impossible path: %s",
cmdname, path);
/trunk/uspace/app/bdsh/cmds/modules/mkdir/mkdir_def.h
3,6 → 3,14
"Create new directories",
&cmd_mkdir,
&help_cmd_mkdir,
0
},
 
{
"md",
NULL,
&cmd_mkdir,
&help_cmd_mkdir,
0
},
 
/trunk/uspace/app/bdsh/cmds/modules/cat/cat.c
87,8 → 87,7
off_t total = 0;
char *buff = NULL;
 
fd = open(fname, O_RDONLY);
if (fd < 0) {
if (-1 == (fd = open(fname, O_RDONLY))) {
printf("Unable to open %s\n", fname);
return 1;
}
104,11 → 103,13
}
 
do {
memset(buff, 0, sizeof(buff));
bytes = read(fd, buff, blen);
if (bytes > 0) {
count += bytes;
buff[bytes] = '\0';
printf("%s", buff);
if (bytes < blen)
buff[bytes] = '\0';
printf(buff);
reads++;
}
} while (bytes > 0);
/trunk/uspace/app/bdsh/cmds/modules/cat/cat_def.h
3,5 → 3,6
"Show the contents of a file",
&cmd_cat,
&help_cmd_cat,
0
},
 
/trunk/uspace/app/bdsh/cmds/modules/help/help.c
107,7 → 107,7
}
 
if (argc == 3) {
if (!str_cmp("extended", argv[2]))
if (!strcmp("extended", argv[2]))
level = HELP_LONG;
else
level = HELP_SHORT;
133,11 → 133,13
 
/* First, show a list of built in commands that are available in this mode */
for (cmd = builtins; cmd->name != NULL; cmd++, i++) {
if (!builtin_is_restricted(i)) {
if (is_builtin_alias(cmd->name))
printf(" %-16s\tAlias for `%s'\n", cmd->name,
alias_for_builtin(cmd->name));
else
printf(" %-16s\t%s\n", cmd->name, cmd->desc);
}
}
 
i = 0;
144,11 → 146,13
 
/* Now, show a list of module commands that are available in this mode */
for (mod = modules; mod->name != NULL; mod++, i++) {
if (!module_is_restricted(i)) {
if (is_module_alias(mod->name))
printf(" %-16s\tAlias for `%s'\n", mod->name,
alias_for_module(mod->name));
else
printf(" %-16s\t%s\n", mod->name, mod->desc);
}
}
 
printf("\n Try %s %s for more information on how `%s' works.\n\n",
/trunk/uspace/app/bdsh/cmds/modules/help/help_def.h
3,4 → 3,5
"Show help for commands",
&cmd_help,
&help_cmd_help,
0
},
/trunk/uspace/app/bdsh/cmds/modules/pwd/pwd.c
30,7 → 30,6
 
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
 
#include "config.h"
#include "errors.h"
/trunk/uspace/app/bdsh/cmds/modules/pwd/pwd_def.h
3,4 → 3,5
"Prints the current working directory",
&cmd_pwd,
&help_cmd_pwd,
-1
},
/trunk/uspace/app/bdsh/cmds/modules/ls/ls.c
50,9 → 50,30
 
static char *cmdname = "ls";
 
static unsigned int ls_scope(const char *path)
{
int fd;
DIR *dirp;
 
dirp = opendir(path);
if (dirp) {
closedir(dirp);
return LS_DIR;
}
 
fd = open(path, O_RDONLY);
if (fd > 0) {
close(fd);
return LS_FILE;
}
 
return LS_BOGUS;
}
 
static void ls_scan_dir(const char *d, DIR *dirp)
{
struct dirent *dp;
unsigned int scope;
char *buff;
 
if (! dirp)
69,7 → 90,20
/* Don't worry if inserting a double slash, this will be fixed by
* absolutize() later with subsequent calls to open() or readdir() */
snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name);
ls_print(dp->d_name, buff);
scope = ls_scope(buff);
switch (scope) {
case LS_DIR:
ls_print_dir(dp->d_name);
break;
case LS_FILE:
ls_print_file(dp->d_name);
break;
case LS_BOGUS:
/* Odd chance it was deleted from the time readdir() found
* it and the time that it was scoped */
printf("ls: skipping bogus node %s\n", dp->d_name);
break;
}
}
 
free(buff);
77,7 → 111,7
return;
}
 
/* ls_print currently does nothing more than print the entry.
/* ls_print_* currently does nothing more than print the entry.
* in the future, we will likely pass the absolute path, and
* some sort of ls_options structure that controls how each
* entry is printed and what is printed about it.
84,23 → 118,17
*
* Now we just print basic DOS style lists */
 
static void ls_print(const char *name, const char *pathname)
static void ls_print_dir(const char *d)
{
struct stat s;
int rc;
printf("%-40s\t<DIR>\n", d);
 
if (rc = stat(pathname, &s)) {
/* Odd chance it was deleted from the time readdir() found it */
printf("ls: skipping bogus node %s\n", pathname);
printf("rc=%d\n", rc);
return;
}
if (s.is_file)
printf("%-40s\t%llu\n", name, (long long) s.size);
else
printf("%-40s\n", name);
return;
}
 
static void ls_print_file(const char *f)
{
printf("%-40s\n", f);
 
return;
}
 
120,7 → 148,7
int cmd_ls(char **argv)
{
unsigned int argc;
struct stat s;
unsigned int scope;
char *buff;
DIR *dirp;
 
136,19 → 164,21
if (argc == 1)
getcwd(buff, PATH_MAX);
else
str_cpy(buff, PATH_MAX, argv[1]);
strncpy(buff, argv[1], PATH_MAX);
 
if (stat(buff, &s)) {
scope = ls_scope(buff);
 
switch (scope) {
case LS_BOGUS:
cli_error(CL_ENOENT, buff);
free(buff);
return CMD_FAILURE;
}
 
if (s.is_file) {
ls_print(buff, buff);
} else {
case LS_FILE:
ls_print_file(buff);
break;
case LS_DIR:
dirp = opendir(buff);
if (!dirp) {
if (! dirp) {
/* May have been deleted between scoping it and opening it */
cli_error(CL_EFAIL, "Could not stat %s", buff);
free(buff);
156,6 → 186,7
}
ls_scan_dir(buff, dirp);
closedir(dirp);
break;
}
 
free(buff);
/trunk/uspace/app/bdsh/cmds/modules/ls/ls_def.h
3,4 → 3,14
"List files and directories",
&cmd_ls,
&help_cmd_ls,
0
},
 
{
"dir",
NULL,
&cmd_ls,
&help_cmd_ls,
0
},
 
/trunk/uspace/app/bdsh/cmds/modules/ls/ls.h
9,7 → 9,8
 
static unsigned int ls_scope(const char *);
static void ls_scan_dir(const char *, DIR *);
static void ls_print(const char *, const char *);
static void ls_print_dir(const char *);
static void ls_print_file(const char *);
 
#endif /* LS_H */
 
/trunk/uspace/app/bdsh/cmds/modules/rm/rm.c
33,9 → 33,8
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <assert.h>
#include <getopt.h>
#include <mem.h>
#include <string.h>
 
#include "config.h"
#include "errors.h"
218,13 → 217,9
 
i = optind;
while (NULL != argv[i]) {
len = str_size(argv[i]) + 2;
len = strlen(argv[i]) + 2;
buff = (char *) realloc(buff, len);
if (buff == NULL) {
printf("rm: out of memory\n");
ret = 1;
break;
}
assert(buff != NULL);
memset(buff, 0, sizeof(buff));
snprintf(buff, len, argv[i]);
 
/trunk/uspace/app/bdsh/cmds/modules/rm/rm_def.h
3,5 → 3,14
"Remove files and directories",
&cmd_rm,
&help_cmd_rm,
0
},
 
{
"del",
NULL,
&cmd_rm,
&help_cmd_rm,
0
},
 
/trunk/uspace/app/bdsh/cmds/modules/module_aliases.h
12,7 → 12,10
* the entry point being reached. */
 
char *mod_aliases[] = {
"ren", "mv",
"exit", "quit",
"md", "mkdir",
"del", "rm",
"dir", "ls",
NULL, NULL
};
 
/trunk/uspace/app/bdsh/cmds/mknewcmd
46,6 → 46,8
-e, --entry Entry function of the command (def: cmd_${def})
-h, --help-entry Entry function for command help (def: help_cmd_${def})
-a, --alias Alias (nickname) for this command (def: none)
-r, --restrict Restriction level (interactive, non-interactive, both)
(def: module is both, builtin is interactive only)
-t, --type Type of command (module or builtin) (def: module)
-H, --help This help summary
-V, --version Print $PROGNAME version and exit normally
65,7 → 67,8
$PROGNAME -n foo -d "Foo power" -a bar -r both -t module modules/foo
 
The example would generate a modular command named 'foo', which is also
reached by typing 'bar'.
reached by typing 'bar' and available in either interactive or noninteractive
mode.
 
Skeletal files do *not* depend on the autoconf generated "config.h" unless you
include it. This may or may not be desirable depending on your use.
94,6 → 97,7
"${CMDDESC}",
&${CMDENTRY},
&${HELPENTRY},
${CMDRESTRICT}
},
 
EOF
103,6 → 107,7
NULL,
&${CMDENTRY},
&${HELPENTRY},
${CMDRESTRICT}
},
 
EOF
162,7 → 167,7
#include "${CMDNAME}.h"
#include "cmds.h"
 
static const char *cmdname = "${CMDNAME}";
static char *cmdname = "${CMDNAME}";
 
/* Dispays help for ${CMDNAME} in various levels */
void ${HELPENTRY}(unsigned int level)
229,8 → 234,8
# We need at least one
[ $# = 0 ] && usage && exit 1;
 
TEMP=$(getopt -o n:d:e:h:a:t:HV \
--long name:,desc:,entry:,help-entry:,alias:,type:,help,version \
TEMP=$(getopt -o n:d:e:h:a:r:t:HV \
--long name:,desc:,entry:,help-entry:,alias:,restrict:,type:,help,version \
-- "$@") || {
echo "Try $PROGNAME --help for help"
}
264,6 → 269,11
shift 2
continue
;;
-r | --restrict)
CMDRESTRICT="$2"
shift 2
continue
;;
-t | --type)
CMDTYPE="$2"
shift 2
295,7 → 305,30
[ -n "$CMDTYPE" ] || CMDTYPE="module"
[ -n "$OUTDIR" ] || OUTDIR="${CMDTYPE}s/${CMDNAME}"
 
# Builtins typically only need to be available in interactive mode,
# set the default accordingly.
[ -n "$CMDRESTRICT" ] || {
[ "$CMDTYPE" = "module" ] && CMDRESTRICT="both"
[ "$CMDTYPE" = "builtin" ] && CMDRESTRICT="interactive"
}
 
# Set the restriction level as the structure expects to see it
case "$CMDRESTRICT" in
0 | both)
CMDRESTRICT="0"
;;
1 | non-interactive)
CMDRESTRICT="1"
;;
-1 | interactive)
CMDRESTRICT="-1"
;;
*)
usage
exit 1
;;
esac
 
# Do a little sanity
[ -d $OUTDIR ] && {
echo "$OUTDIR already exists, remove it to proceed."
/trunk/uspace/app/bdsh/cmds/builtins/exit/entry.h
File deleted
/trunk/uspace/app/bdsh/cmds/builtins/exit/exit.c
File deleted
/trunk/uspace/app/bdsh/cmds/builtins/exit/exit_def.h
File deleted
/trunk/uspace/app/bdsh/cmds/builtins/exit/exit.h
File deleted
/trunk/uspace/app/bdsh/cmds/builtins/cd/cd_def.h
3,4 → 3,12
"Change the current working directory",
&cmd_cd,
&help_cmd_cd,
-1
},
{
"chdir",
NULL,
&cmd_cd,
&help_cmd_cd,
-1
},
/trunk/uspace/app/bdsh/cmds/builtins/builtins.h
4,11 → 4,9
#include "config.h"
 
#include "cd/entry.h"
#include "exit/entry.h"
 
builtin_t builtins[] = {
#include "cd/cd_def.h"
#include "exit/exit_def.h"
{NULL, NULL, NULL, NULL}
};
 
/trunk/uspace/app/bdsh/cmds/builtins/builtin_aliases.h
4,6 → 4,7
/* See modules/module_aliases.h for an explanation of this file */
 
char *builtin_aliases[] = {
"chdir", "cd",
NULL, NULL
};
 
/trunk/uspace/app/bdsh/cmds/cmds.h
36,6 → 36,7
char *desc; /* Description of the command */
mod_entry_t entry; /* Command (exec) entry function */
mod_help_t help; /* Command (help) entry function */
int restricted; /* Restricts to interactive/non-interactive only */
} module_t;
 
/* Builtin structure, same as modules except different types of entry points */
/trunk/uspace/app/bdsh/cmds/mod_cmds.c
53,6 → 53,26
 
extern volatile unsigned int cli_interactive;
 
int module_is_restricted(int pos)
{
/* Restriction Levels:
* -1 -> Available only in interactive mode
* 0 -> Available in any mode
* 1 -> Available only in non-interactive mode */
 
module_t *mod = modules;
mod += pos;
/* We're interactive, and the module is OK to run */
if (cli_interactive && mod->restricted <= 0)
return 0;
/* We're not interactive, and the module is OK to run */
if (!cli_interactive && mod->restricted >= 0)
return 0;
 
/* Anything else is just a big fat no :) */
return 1;
}
 
/* Checks if an entry function matching command exists in modules[], if so
* its position in the array is returned */
int is_module(const char *command)
64,7 → 84,7
return -2;
 
for (mod = modules; mod->name != NULL; mod++, i++) {
if (!str_cmp(mod->name, command))
if (!strcmp(mod->name, command))
return i;
}
 
81,7 → 101,7
return -1;
 
for(i=0; mod_aliases[i] != NULL; i+=2) {
if (!str_cmp(mod_aliases[i], command))
if (!strcmp(mod_aliases[i], command))
return 1;
}
 
97,7 → 117,7
return (char *)NULL;
 
for(i=0; mod_aliases[i] != NULL; i++) {
if (!str_cmp(mod_aliases[i], command))
if (!strcmp(mod_aliases[i], command))
return (char *)mod_aliases[++i];
i++;
}
/trunk/uspace/app/bdsh/cmds/builtin_cmds.c
40,6 → 40,19
 
extern volatile unsigned int cli_interactive;
 
int builtin_is_restricted(int pos)
{
builtin_t *cmd = builtins;
cmd += pos;
 
if (cli_interactive && cmd->restricted <= 0)
return 0;
if (!cli_interactive && cmd->restricted >= 0)
return 0;
 
return 1;
}
 
int is_builtin(const char *command)
{
builtin_t *cmd;
49,7 → 62,7
return -2;
 
for (cmd = builtins; cmd->name != NULL; cmd++, i++) {
if (!str_cmp(cmd->name, command))
if (!strcmp(cmd->name, command))
return i;
}
 
64,7 → 77,7
return -1;
 
for(i=0; builtin_aliases[i] != NULL; i+=2) {
if (!str_cmp(builtin_aliases[i], command))
if (!strcmp(builtin_aliases[i], command))
return 1;
}
 
79,7 → 92,7
return (char *)NULL;
 
for(i=0; builtin_aliases[i] != NULL; i++) {
if (!str_cmp(builtin_aliases[i], command))
if (!strcmp(builtin_aliases[i], command))
return (char *)builtin_aliases[++i];
i++;
}
/trunk/uspace/app/bdsh/Makefile
30,18 → 30,25
# POSSIBILITY OF SUCH DAMAGE.
 
include ../../../version
include ../../Makefile.config
 
LIBC_PREFIX = ../../lib/libc
SOFTINT_PREFIX = ../../lib/softint
LIBBLOCK_PREFIX = ../../lib/libblock
 
include $(LIBC_PREFIX)/Makefile.toolchain
 
CFLAGS += -I../../srv/kbd/include -I$(LIBBLOCK_PREFIX)
CFLAGS += -I../../srv/kbd/include
 
LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBC_PREFIX)/libc.a
DEFS += -DRELEASE=$(RELEASE)
LIBS = $(LIBC_PREFIX)/libc.a
DEFS += -DRELEASE=\"$(RELEASE)\"
 
ifdef REVISION
DEFS += "-DREVISION=\"$(TIMESTAMP)\""
endif
 
ifdef TIMESTAMP
DEFS += "-DTIMESTAMP=\"$(TIMESTAMP)\""
endif
 
PROGRAM = bdsh
 
# Any directory that cleaning targets should know about
50,9 → 57,9
cmds/ \
cmds/modules/ \
cmds/modules/help/ \
cmds/modules/quit/ \
cmds/modules/mkdir/ \
cmds/modules/rm/ \
cmds/modules/bdd/ \
cmds/modules/cat/ \
cmds/modules/touch/ \
cmds/modules/ls/ \
59,18 → 66,14
cmds/modules/pwd/ \
cmds/modules/sleep/ \
cmds/modules/cp/ \
cmds/modules/mv/ \
cmds/modules/mount/ \
cmds/modules/kcon/ \
cmds/builtins/ \
cmds/builtins/exit/\
cmds/builtins/cd/
 
SOURCES = \
cmds/modules/help/help.c \
cmds/modules/quit/quit.c \
cmds/modules/mkdir/mkdir.c \
cmds/modules/rm/rm.c \
cmds/modules/bdd/bdd.c \
cmds/modules/cat/cat.c \
cmds/modules/touch/touch.c \
cmds/modules/ls/ls.c \
77,10 → 80,6
cmds/modules/pwd/pwd.c \
cmds/modules/sleep/sleep.c \
cmds/modules/cp/cp.c \
cmds/modules/mv/mv.c \
cmds/modules/mount/mount.c \
cmds/modules/kcon/kcon.c \
cmds/builtins/exit/exit.c \
cmds/builtins/cd/cd.c \
cmds/mod_cmds.c \
cmds/builtin_cmds.c \
113,7 → 112,7
@$(CC) -M $(CFLAGS) $(INC) $*.c > $*.d
 
$(PROGRAM): $(OBJECTS) $(LIBS)
$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(PROGRAM).map
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(PROGRAM).map
 
# Everything else is a phony target
.PHONY: all clean distclean depend disasm
/trunk/uspace/app/bdsh/scli.c
45,6 → 45,7
/* 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;
 
/* The official name of this program
/trunk/uspace/app/bdsh/util.h
3,6 → 3,13
 
#include "scli.h"
 
/* Internal string handlers */
extern char * cli_strdup(const char *);
extern int cli_redup(char **, const char *);
extern int cli_psprintf(char **, const char *, ...);
extern char * cli_strtok_r(char *, const char *, char **);
extern char * cli_strtok(char *, const char *);
 
/* Utility functions */
extern unsigned int cli_count_args(char **);
extern unsigned int cli_set_prompt(cliuser_t *usr);
/trunk/uspace/app/bdsh/input.c
32,12 → 32,7
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io/console.h>
#include <io/keycode.h>
#include <io/style.h>
#include <vfs/vfs.h>
#include <errno.h>
#include <bool.h>
#include <io/stream.h>
 
#include "config.h"
#include "util.h"
46,8 → 41,21
#include "errors.h"
#include "exec.h"
 
extern volatile unsigned int cli_interactive;
 
/* Not exposed in input.h */
static void cli_restricted(char *);
static void read_line(char *, int);
 
/* More than a macro than anything */
static void cli_restricted(char *cmd)
{
printf("%s is not available in %s mode\n", cmd,
cli_interactive ? "interactive" : "non-interactive");
 
return;
}
 
/* Tokenizes input from console, sees if the first word is a built-in, if so
* invokes the built-in entry point (a[0]) passing all arguments in a[] to
* the handler */
61,11 → 69,14
if (NULL == usr->line)
return CL_EFAIL;
 
tmp = str_dup(usr->line);
tmp = cli_strdup(usr->line);
 
cmd[n] = strtok(tmp, " ");
/* Break up what the user typed, space delimited */
 
/* TODO: Protect things in quotes / ticks, expand wildcards */
cmd[n] = cli_strtok(tmp, " ");
while (cmd[n] && n < WORD_MAX) {
cmd[++n] = strtok(NULL, " ");
cmd[++n] = cli_strtok(NULL, " ");
}
 
/* We have rubbish */
74,19 → 85,39
goto finit;
}
 
/* Its a builtin command ? */
/* Its a builtin command */
if ((i = (is_builtin(cmd[0]))) > -1) {
/* Its not available in this mode, see what try_exec() thinks */
if (builtin_is_restricted(i)) {
rc = try_exec(cmd[0], cmd);
if (rc)
/* No external matching it could be found, tell the
* user that the command does exist, but is not
* available in this mode. */
cli_restricted(cmd[0]);
goto finit;
}
/* Its a builtin, its available, run it */
rc = run_builtin(i, cmd, usr);
goto finit;
/* Its a module ? */
/* We repeat the same dance for modules */
} else if ((i = (is_module(cmd[0]))) > -1) {
if (module_is_restricted(i)) {
rc = try_exec(cmd[0], cmd);
if (rc)
cli_restricted(cmd[0]);
goto finit;
}
rc = run_module(i, cmd);
goto finit;
} else {
/* Its not a module or builtin, restricted or otherwise.
* See what try_exec() thinks of it and just pass its return
* value back to the caller */
rc = try_exec(cmd[0], cmd);
goto finit;
}
 
/* See what try_exec thinks of it */
rc = try_exec(cmd[0], cmd);
 
finit:
if (NULL != usr->line) {
free(usr->line);
98,46 → 129,31
return rc;
}
 
/* Borrowed from Jiri Svoboda's 'cli' uspace app */
static void read_line(char *buffer, int n)
{
console_event_t ev;
size_t offs, otmp;
wchar_t dec;
char c;
int chars;
 
offs = 0;
while (true) {
fflush(stdout);
if (!console_get_event(fphone(stdin), &ev))
chars = 0;
while (chars < n - 1) {
c = getchar();
if (c < 0)
return;
if (ev.type != KEY_PRESS)
continue;
if (ev.key == KC_ENTER || ev.key == KC_NENTER)
if (c == '\n')
break;
if (ev.key == KC_BACKSPACE) {
if (offs > 0) {
/*
* Back up until we reach valid start of
* character.
*/
while (offs > 0) {
--offs; otmp = offs;
dec = str_decode(buffer, &otmp, n);
if (dec != U_SPECIAL)
break;
}
if (c == '\b') {
if (chars > 0) {
putchar('\b');
--chars;
}
continue;
}
if (ev.c >= ' ') {
if (chr_encode(ev.c, buffer, &offs, n - 1) == EOK)
putchar(ev.c);
}
putchar(c);
buffer[chars++] = c;
}
putchar('\n');
buffer[offs] = '\0';
buffer[chars] = '\0';
}
 
/* TODO:
146,18 → 162,15
void get_input(cliuser_t *usr)
{
char line[INPUT_MAX];
size_t len = 0;
 
fflush(stdout);
console_set_style(fphone(stdout), STYLE_EMPHASIS);
printf("%s", usr->prompt);
fflush(stdout);
console_set_style(fphone(stdout), STYLE_NORMAL);
 
read_line(line, INPUT_MAX);
len = strlen(line);
/* Make sure we don't have rubbish or a C/R happy user */
if (str_cmp(line, "") == 0 || str_cmp(line, "\n") == 0)
if (len == 0 || line[0] == '\n')
return;
usr->line = str_dup(line);
usr->line = cli_strdup(line);
 
return;
}
/trunk/uspace/app/bdsh/AUTHORS
8,6 → 8,9
 
* Based on the HelenOS testing sub-system written by Martin Decky
 
* cli_strtok() and cli_strtok_r() (util.c) were adapted from the FreeBSD
strtok() and strtok_r() functions written by Wes Peters.
 
* read_line() (input.c) was written by Jiri Svoboda
 
Individual author copyrights are listed in the headers of each file.