From 3f2dfbb298cf7312f0fd1f1c54213e173451f7ae Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 23 Aug 2008 15:16:10 +0000 Subject: [PATCH] Added ch and pwd to NSH git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@841 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 2 + Documentation/NuttX.html | 6 +- examples/README.txt | 2 + examples/nsh/nsh.h | 25 +++ examples/nsh/nsh_envcmds.c | 198 +++++++++++++++++++++ examples/nsh/nsh_fscmds.c | 353 ++++++++++++++++++++++++++----------- examples/nsh/nsh_main.c | 17 +- lib/Makefile | 7 +- lib/lib_chdir.c | 88 +++++++-- lib/lib_cwdsem.c | 86 --------- lib/lib_getcwd.c | 63 +++---- lib/lib_internal.h | 10 -- 12 files changed, 593 insertions(+), 264 deletions(-) delete mode 100644 lib/lib_cwdsem.c diff --git a/ChangeLog b/ChangeLog index d756a2bd12..abb52498f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -420,5 +420,7 @@ * Add chdir() and getcwd() * Fix error in getopt() when called with argc==1 * Fix error in stat() when used on the root directory + * NSH: Add cd and pwd commands and current working directory to all NSH + commands that refer to paths. diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 05c44e37e7..c67009fd0a 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -8,7 +8,7 @@

NuttX RTOS

-

Last Updated: August 22, 2008

+

Last Updated: August 23, 2008

@@ -1052,6 +1052,10 @@ nuttx-0.3.13 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> * NSH now supports commands to inspect and modify memory * NSH cat command now supports multiple files on command line * Add chdir() and getcwd() + * Fix error in getopt() when called with argc==1 + * Fix error in stat() when used on the root directory + * NSH: Add cd and pwd commands and current working directory to all NSH + commands that refer to paths. pascal-0.1.3 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/examples/README.txt b/examples/README.txt index 9f12b592e0..6012d2087e 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -38,6 +38,7 @@ examples/nsh Command Depends on Configuration ---------- -------------------------- cat CONFIG_NFILE_DESCRIPTORS > 0 + cd !CONFIG_DISABLE_ENVIRON && CONFIG_NFILE_DESCRIPTORS > 0 cp CONFIG_NFILE_DESCRIPTORS > 0 echo -- exec -- @@ -51,6 +52,7 @@ examples/nsh mkfifo !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 mount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_FAT ps -- + pwd !CONFIG_DISABLE_ENVIRON && CONFIG_NFILE_DESCRIPTORS > 0 set !CONFIG_DISABLE_ENVIRON sleep !CONFIG_DISABLE_SIGNALS sh CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 diff --git a/examples/nsh/nsh.h b/examples/nsh/nsh.h index 33f6d3d4d4..7ee0d71923 100644 --- a/examples/nsh/nsh.h +++ b/examples/nsh/nsh.h @@ -100,6 +100,12 @@ #undef CONFIG_EXAMPLES_NSH_TELNETD_DUMPBUFFER #undef CONFIG_EXAMPLES_NSH_FULLPATH +/* Make sure that the home directory is defined */ + +#ifndef CONFIG_LIB_HOMEDIR +# define CONFIG_LIB_HOMEDIR "/" +#endif + #define nsh_clone(v) (v)->clone(v) #define nsh_addref(v) (v)->addref(v) #define nsh_release(v) (v)->release(v) @@ -116,6 +122,13 @@ #define SAVE_SIZE (sizeof(int) + sizeof(FILE*) + sizeof(boolean)) +/* Stubs used when working directory is not supported */ + +#if CONFIG_NFILE_DESCRIPTORS <= 0 || defined(CONFIG_DISABLE_ENVIRON) +# define nsh_getfullpath(v,p) (p) +# define nsh_freefullpath(p) +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -211,6 +224,14 @@ extern int nsh_consolemain(int argc, char *argv[]); extern int nsh_telnetmain(int argc, char *argv[]); #endif +/* Working directory support */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +extern FAR const char *nsh_getcwd(void); +extern char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath); +extern void nsh_freefullpath(char *relpath); +#endif + /* Shell command handlers */ extern int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); @@ -238,6 +259,10 @@ extern int cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); extern int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); # endif /* CONFIG_FS_FAT */ # endif /* !CONFIG_DISABLE_MOUNTPOINT */ +# if !defined(CONFIG_DISABLE_ENVIRON) + extern int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); + extern int cmd_pwd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif /* !CONFIG_DISABLE_MOUNTPOINT */ #endif /* CONFIG_NFILE_DESCRIPTORS */ #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 diff --git a/examples/nsh/nsh_envcmds.c b/examples/nsh/nsh_envcmds.c index 7c8ece414b..f8bedc461f 100644 --- a/examples/nsh/nsh_envcmds.c +++ b/examples/nsh/nsh_envcmds.c @@ -42,7 +42,9 @@ #include #include +#include #include +#include #include #include "nsh.h" @@ -63,6 +65,12 @@ * Private Data ****************************************************************************/ +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +static const char g_pwd[] = "PWD"; +static const char g_oldpwd[] = "OLDPWD"; +static const char g_home[] = CONFIG_LIB_HOMEDIR; +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -71,10 +79,188 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nsh_getwd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +static inline FAR const char *nsh_getwd(const char *wd) +{ + const char *val; + + /* If no working directory is defined, then default to the home directory */ + + val = getenv(wd); + if (!val) + { + val = g_home; + } + return val; +} +#endif + +/**************************************************************************** + * Name: nsh_getdirpath + ****************************************************************************/ + +static inline char *nsh_getdirpath(FAR struct nsh_vtbl_s *vtbl, + const char *dirpath, const char *relpath) +{ + char *alloc; + int len; + + /* Handle the special case where the dirpath is simply */ + + if (strcmp(dirpath, "/") == 0) + { + len = strlen(relpath) + 2; + alloc = (char*)malloc(len); + if (alloc) + { + sprintf(alloc, "/%s", relpath); + } + } + else + { + len = strlen(dirpath) + strlen(relpath) + 2; + alloc = (char*)malloc(len); + if (alloc) + { + sprintf(alloc, "%s/%s", dirpath, relpath); + } + } + + if (!alloc) + { + nsh_output(vtbl, g_fmtcmdoutofmemory, "nsh_getdirpath"); + } + return alloc; +} + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: nsh_getwd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +FAR const char *nsh_getcwd(void) +{ + return nsh_getwd(g_pwd); +} +#endif +/**************************************************************************** + * Name: nsh_getfullpath + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath) +{ + const char *wd; + + /* Handle some special cases */ + + if (!relpath || relpath[0] == '\0') + { + /* No relative path provided */ + + return strdup(g_home); + } + else if (relpath[0] == '/') + { + return strdup(relpath); + } + + /* Get the path to the current working directory */ + + wd = nsh_getcwd(); + + /* Fake the '.' directory */ + + if (strcmp(relpath, ".") == 0) + { + return strdup(wd); + } + + /* Return the full path */ + + return nsh_getdirpath(vtbl, wd, relpath); +} +#endif + +/**************************************************************************** + * Name: nsh_freefullpath + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +void nsh_freefullpath(char *relpath) +{ + if (relpath) + { + free(relpath); + } +} +#endif + +/**************************************************************************** + * Name: cmd_cd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + const char *path = argv[1]; + char *alloc = NULL; + char *fullpath = NULL; + int ret = OK; + + /* Check for special arguments */ + + if (argc < 2 || strcmp(path, "~") == 0) + { + path = g_home; + } + else if (strcmp(path, "-") == 0) + { + alloc = strdup(nsh_getwd(g_oldpwd)); + path = alloc; + } + else if (strcmp(path, "..") == 0) + { + alloc = strdup(nsh_getcwd()); + path = dirname(alloc); + } + else + { + fullpath = nsh_getfullpath(vtbl, path); + path = fullpath; + } + + /* Set the new workding directory */ + + if (chdir(path) != 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "chdir", NSH_ERRNO); + ret = ERROR; + } + + /* Free any memory that was allocated */ + + if (alloc) + { + free(alloc); + } + + if (fullpath) + { + nsh_freefullpath(fullpath); + } + return ret; +} +#endif + /**************************************************************************** * Name: cmd_echo ****************************************************************************/ @@ -95,6 +281,18 @@ int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) return OK; } +/**************************************************************************** + * Name: cmd_pwd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +int cmd_pwd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_output(vtbl, "%s\n", nsh_getcwd()); + return OK; +} +#endif + /**************************************************************************** * Name: cmd_set ****************************************************************************/ diff --git a/examples/nsh/nsh_fscmds.c b/examples/nsh/nsh_fscmds.c index 144cea9a47..8610b157dd 100644 --- a/examples/nsh/nsh_fscmds.c +++ b/examples/nsh/nsh_fscmds.c @@ -136,10 +136,10 @@ static void trim_dir(char *arg) } /**************************************************************************** - * Name: getdirpath + * Name: nsh_getdirpath ****************************************************************************/ -static char *getdirpath(const char *path, const char *file) +static char *nsh_getdirpath(const char *path, const char *file) { /* Handle the case where all that is left is '/' */ @@ -228,7 +228,7 @@ static int ls_handler(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, struct d if ((lsflags & (LSFLAGS_SIZE|LSFLAGS_LONG)) != 0) { struct stat buf; - char *fullpath = getdirpath(dirpath, entryp->d_name); + char *fullpath = nsh_getdirpath(dirpath, entryp->d_name); /* Yes, stat the file */ @@ -345,7 +345,7 @@ static int ls_recursive(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, struct /* Yes.. */ char *newpath; - newpath = getdirpath(dirpath, entryp->d_name); + newpath = nsh_getdirpath(dirpath, entryp->d_name); /* List the directory contents */ @@ -375,6 +375,7 @@ static int ls_recursive(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, struct int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { char buffer[IOBUFFERSIZE]; + char *fullpath; int fd; int i; int ret = OK; @@ -383,72 +384,81 @@ int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) for (i = 1; i < argc && ret == OK; i++) { - /* Open the file for reading */ + /* Get the fullpath to the file */ - fd = open(argv[1], O_RDONLY); - if (fd < 0) + fullpath = nsh_getfullpath(vtbl, argv[i]); + if (fullpath) { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); - ret = ERROR; - } - else - { - /* And just dump it byte for byte into stdout */ + /* Open the file for reading */ - for (;;) + fd = open(fullpath, O_RDONLY); + if (fd < 0) { - int nbytesread = read(fd, buffer, IOBUFFERSIZE); + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + } + else + { + /* And just dump it byte for byte into stdout */ - /* Check for read errors */ - - if (nbytesread < 0) + for (;;) { - /* EINTR is not an error */ + int nbytesread = read(fd, buffer, IOBUFFERSIZE); - if (errno != EINTR) + /* Check for read errors */ + + if (nbytesread < 0) + { + /* EINTR is not an error */ + + if (errno != EINTR) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); + ret = ERROR; + break; + } + } + + /* Check for data successfully read */ + + else if (nbytesread > 0) + { + int nbyteswritten = 0; + + while (nbyteswritten < nbytesread) + { + int n = write(1, buffer, nbytesread); + if (n < 0) + { + /* EINTR is not an error */ + + if (errno != EINTR) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO); + ret = ERROR; + break; + } + } + else + { + nbyteswritten += n; + } + } + } + + /* Otherwise, it is the end of file */ + + else { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); - ret = ERROR; break; } } - /* Check for data successfully read */ - - else if (nbytesread > 0) - { - int nbyteswritten = 0; - - while (nbyteswritten < nbytesread) - { - int n = write(1, buffer, nbytesread); - if (n < 0) - { - /* EINTR is not an error */ - - if (errno != EINTR) - { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO); - ret = ERROR; - break; - } - } - else - { - nbyteswritten += n; - } - } - } - - /* Otherwise, it is the end of file */ - - else - { - break; - } + (void)close(fd); } - (void)close(fd); + /* Free the allocated full path */ + + nsh_freefullpath(fullpath); } } return ret; @@ -463,25 +473,42 @@ int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { struct stat buf; - char *fullpath = NULL; - const char *wrpath = argv[2]; + char *srcpath = NULL; + char *destpath = NULL; + char *allocpath = NULL; int oflags = O_WRONLY|O_CREAT|O_TRUNC; int rdfd; int wrfd; int ret = ERROR; + /* Get the full path to the source file */ + + srcpath = nsh_getfullpath(vtbl, argv[1]); + if (!srcpath) + { + goto errout; + } + /* Open the source file for reading */ - rdfd = open(argv[1], O_RDONLY); + rdfd = open(srcpath, O_RDONLY); if (rdfd < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); - return ERROR; + goto errout_with_srcpath; + } + + /* Get the full path to the destination file or directory */ + + destpath = nsh_getfullpath(vtbl, argv[2]); + if (!destpath) + { + goto errout_with_rdfd; } /* Check if the destination is a directory */ - ret = stat(wrpath, &buf); + ret = stat(destpath, &buf); if (ret == 0) { /* Something exists here... is it a directory? */ @@ -494,15 +521,17 @@ int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) /* Construct the full path to the new file */ - fullpath = getdirpath(argv[2], basename(argv[1]) ); - if (!fullpath) + allocpath = nsh_getdirpath(argv[2], basename(argv[1]) ); + if (!allocpath) { nsh_output(vtbl, g_fmtcmdoutofmemory, argv[0]); - goto out_with_rdfd; + goto errout_with_destpath; } - /* Open then fullpath for writing */ - wrpath = fullpath; + /* Open then dest for writing */ + + nsh_freefullpath(destpath); + destpath = allocpath; } else if (!S_ISREG(buf.st_mode)) { @@ -514,11 +543,11 @@ int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) /* Now open the destination */ - wrfd = open(wrpath, oflags, 0666); + wrfd = open(destpath, oflags, 0666); if (wrfd < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); - goto out_with_fullpath; + goto errout_with_allocpath; } /* Now copy the file */ @@ -536,14 +565,14 @@ int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) /* End of file */ ret = OK; - goto out_with_wrfd; + goto errout_with_wrfd; } else if (nbytesread < 0 && errno != EINTR) { /* Read error */ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); - goto out_with_wrfd; + goto errout_with_wrfd; } } while (nbytesread <= 0); @@ -560,23 +589,36 @@ int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) /* Read error */ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO); - goto out_with_wrfd; + goto errout_with_wrfd; } } while (nbytesread > 0); } -out_with_wrfd: +errout_with_wrfd: close(wrfd); -out_with_fullpath: - if (fullpath) +errout_with_allocpath: + if (allocpath) { - free(fullpath); + free(allocpath); } -out_with_rdfd: +errout_with_destpath: + if (destpath && !allocpath) + { + nsh_freefullpath(destpath); + } + +errout_with_rdfd: close(rdfd); + +errout_with_srcpath: + if (srcpath) + { + nsh_freefullpath(srcpath); + } +errout: return ret; } #endif @@ -588,7 +630,9 @@ out_with_rdfd: #if CONFIG_NFILE_DESCRIPTORS > 0 int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { + const char *relpath; unsigned int lsflags = 0; + char *fullpath; int ret; /* Get the ls options */ @@ -617,29 +661,46 @@ int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) } } - /* There is one required arguments after the options */ + /* There may be one argument after the options */ if (optind + 1 < argc) { nsh_output(vtbl, g_fmttoomanyargs, argv[0]); return ERROR; } - else if (optind + 1 > argc) + else if (optind >= argc) { +#ifndef CONFIG_DISABLE_ENVIRON + relpath = nsh_getcwd(); +#else nsh_output(vtbl, g_fmtargrequired, argv[0]); return ERROR; +#endif + } + else + { + relpath = argv[optind]; + } + + /* Get the fullpath to the directory */ + + fullpath = nsh_getfullpath(vtbl, relpath); + if (!fullpath) + { + return ERROR; } /* List the directory contents */ - nsh_output(vtbl, "%s:\n", argv[optind]); - ret = foreach_direntry(vtbl, "ls", argv[optind], ls_handler, (void*)lsflags); + nsh_output(vtbl, "%s:\n", fullpath); + ret = foreach_direntry(vtbl, "ls", fullpath, ls_handler, (void*)lsflags); if (ret == OK && (lsflags & LSFLAGS_RECURSIVE) != 0) { /* Then recurse to list each directory within the directory */ - ret = foreach_direntry(vtbl, "ls", argv[optind], ls_recursive, (void*)lsflags); + ret = foreach_direntry(vtbl, "ls", fullpath, ls_recursive, (void*)lsflags); } + nsh_freefullpath(fullpath); return ret; } #endif @@ -651,10 +712,17 @@ int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { - int ret = mkdir(argv[1], 0777); - if (ret < 0) + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkdir", NSH_ERRNO); + ret = mkdir(fullpath, 0777); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkdir", NSH_ERRNO); + } + nsh_freefullpath(fullpath); } return ret; } @@ -668,10 +736,17 @@ int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { struct fat_format_s fmt = FAT_FORMAT_INITIALIZER; - int ret = mkfatfs(argv[1], &fmt); - if (ret < 0) - { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfatfs", NSH_ERRNO); + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = mkfatfs(fullpath, &fmt); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfatfs", NSH_ERRNO); + } + nsh_freefullpath(fullpath); } return ret; } @@ -684,10 +759,17 @@ int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { - int ret = mkfifo(argv[1], 0777); - if (ret < 0) + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfifo", NSH_ERRNO); + ret = mkfifo(fullpath, 0777); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfifo", NSH_ERRNO); + } + nsh_freefullpath(fullpath); } return ret; } @@ -701,8 +783,10 @@ int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #ifdef CONFIG_FS_FAT /* Need at least one filesytem in configuration */ int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { + char *source; + char *target; char *filesystem = 0; - int result; + int ret; /* Get the mount options */ @@ -739,13 +823,34 @@ int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) return ERROR; } + /* The source and target pathes might be relative to the current + * working directory. + */ + + source = nsh_getfullpath(vtbl, argv[optind]); + if (!source) + { + return ERROR; + } + + target = nsh_getfullpath(vtbl, argv[optind+1]); + if (!source) + { + nsh_freefullpath(source); + return ERROR; + } + /* Perform the mount */ - result = mount(argv[optind], argv[optind+1], filesystem, 0, NULL); - if ( result < 0) + + ret = mount(source, target, filesystem, 0, NULL); + if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO); } - return result; + + nsh_freefullpath(source); + nsh_freefullpath(target); + return ret; } #endif #endif @@ -757,10 +862,17 @@ int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { - int ret = unlink(argv[1]); - if (ret < 0) + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret; + + if (fullpath) { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "unlink", NSH_ERRNO); + ret = unlink(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "unlink", NSH_ERRNO); + } + nsh_freefullpath(fullpath); } return ret; } @@ -773,10 +885,17 @@ int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { - int ret = rmdir(argv[1]); - if (ret < 0) + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret; + + if (fullpath) { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rmdir", NSH_ERRNO); + ret = rmdir(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rmdir", NSH_ERRNO); + } + nsh_freefullpath(fullpath); } return ret; } @@ -789,11 +908,20 @@ int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { + char *fullpath; FILE *stream; char *buffer; char *pret; int ret = ERROR; + /* The path to the script may be relative to the current working directory */ + + fullpath = nsh_getfullpath(vtbl, argv[1]); + if (!fullpath) + { + return ERROR; + } + /* Get a reference to the common input buffer */ buffer = nsh_linebuffer(vtbl); @@ -801,10 +929,11 @@ int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { /* Open the file containing the script */ - stream = fopen(argv[1], "r"); + stream = fopen(fullpath, "r"); if (!stream) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "fopen", NSH_ERRNO); + nsh_freefullpath(fullpath); return ERROR; } @@ -831,6 +960,8 @@ int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) while (pret && ret == OK); fclose(stream); } + + nsh_freefullpath(fullpath); return ret; } #endif @@ -843,13 +974,21 @@ int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #ifdef CONFIG_FS_FAT /* Need at least one filesytem in configuration */ int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { - /* Perform the umount */ - int result = umount(argv[1]); - if (result < 0) + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret; + + if (fullpath) { - nsh_output(vtbl, g_fmtcmdfailed, argv[0], "umount", NSH_ERRNO); + /* Perform the umount */ + + ret = umount(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "umount", NSH_ERRNO); + } + nsh_freefullpath(fullpath); } - return result; + return ret; } #endif #endif diff --git a/examples/nsh/nsh_main.c b/examples/nsh/nsh_main.c index 8cbf78ad9d..e98ee7f2d0 100644 --- a/examples/nsh/nsh_main.c +++ b/examples/nsh/nsh_main.c @@ -91,6 +91,9 @@ static const struct cmdmap_s g_cmdmap[] = { #if CONFIG_NFILE_DESCRIPTORS > 0 { "cat", cmd_cat, 2, NSH_MAX_ARGUMENTS, " [ [ ...]]" }, +#ifndef CONFIG_DISABLE_ENVIRON + { "cd", cmd_cd, 1, 2, "[|-|~|..]" }, +#endif { "cp", cmd_cp, 3, 3, " " }, #endif #ifndef CONFIG_DISABLE_ENVIRON @@ -105,7 +108,7 @@ static const struct cmdmap_s g_cmdmap[] = { "ifconfig", cmd_ifconfig, 1, 1, NULL }, #endif #if CONFIG_NFILE_DESCRIPTORS > 0 - { "ls", cmd_ls, 2, 5, "[-lRs] " }, + { "ls", cmd_ls, 1, 5, "[-lRs] " }, #endif { "mb", cmd_mb, 2, 3, "[=][ ]" }, #if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 @@ -123,6 +126,9 @@ static const struct cmdmap_s g_cmdmap[] = #endif { "mw", cmd_mw, 2, 3, "[=][ ]" }, { "ps", cmd_ps, 1, 1, NULL }, +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) + { "pwd", cmd_pwd, 1, 1, NULL }, +#endif #ifndef CONFIG_DISABLE_ENVIRON { "set", cmd_set, 3, 3, " " }, #endif @@ -132,7 +138,7 @@ static const struct cmdmap_s g_cmdmap[] = #endif #if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 { "sh", cmd_sh, 2, 2, "" }, -# endif /* CONFIG_NFILE_STREAMS */ +#endif /* CONFIG_NFILE_DESCRIPTORS && CONFIG_NFILE_STREAMS */ #ifndef CONFIG_DISABLE_SIGNALS { "sleep", cmd_sleep, 2, 2, "" }, #endif /* CONFIG_DISABLE_SIGNALS */ @@ -847,7 +853,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) { vtbl->np.np_redirect = TRUE; oflags = O_WRONLY|O_CREAT|O_TRUNC; - redirfile = argv[argc-1]; + redirfile = nsh_getfullpath(vtbl, argv[argc-1]); argc -= 2; } @@ -857,7 +863,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) { vtbl->np.np_redirect = TRUE; oflags = O_WRONLY|O_CREAT|O_APPEND; - redirfile = argv[argc-1]; + redirfile = nsh_getfullpath(vtbl, argv[argc-1]); argc -= 2; } } @@ -873,6 +879,9 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) */ fd = open(redirfile, oflags, 0666); + nsh_freefullpath(redirfile); + redirfile = NULL; + if (fd < 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); diff --git a/lib/Makefile b/lib/Makefile index cf35a05419..a56cde66f0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -57,7 +57,7 @@ STDIO_SRCS = lib_printf.c lib_rawprintf.c lib_lowprintf.c lib_dbg.c \ lib_lowstream.c lib_nullstream.c lib_sscanf.c ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) -STDIO_SRCS += lib_rawstream.c lib_chdir.c lib_getcwd.c lib_cwdsem.c +STDIO_SRCS += lib_rawstream.c ifneq ($(CONFIG_NFILE_STREAMS),0) STDIO_SRCS += lib_fopen.c lib_fclose.c lib_fread.c lib_libfread.c lib_fseek.c \ lib_fgetc.c lib_fgets.c lib_gets.c lib_fwrite.c lib_libfwrite.c \ @@ -72,6 +72,11 @@ STDLIB_SRCS = lib_rand.c MATH_SRCS = lib_rint.c UNISTD_SRCS = lib_getopt.c +ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) +ifneq ($(CONFIG_DISABLE_ENVIRON),y) +UNISTD_SRCS += lib_chdir.c lib_getcwd.c +endif +endif NET_SRCS = lib_htons.c lib_htonl.c lib_inetntoa.c lib_etherntoa.c diff --git a/lib/lib_chdir.c b/lib/lib_chdir.c index 008e923eca..0db29829df 100644 --- a/lib/lib_chdir.c +++ b/lib/lib_chdir.c @@ -40,6 +40,8 @@ #include #include +#include + #include #include #include @@ -47,13 +49,35 @@ #include "lib_internal.h" +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) + /**************************************************************************** * Public Variables ****************************************************************************/ -#if CONFIG_NFILE_DESCRIPTORS > 0 -char *g_cwd = NULL; -char *g_prevcwd = NULL; +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: _trimdir + ****************************************************************************/ + +#if 0 +static inline void _trimdir(char *path) +{ + /* Skip any trailing '/' characters (unless it is also the leading '/') */ + + int len = strlen(path) - 1; + while (len > 0 && path[len] == '/') + { + path[len] = '\0'; + len--; + } +} +#else +# define _trimdir(p) +#endif /**************************************************************************** * Public Functions @@ -94,38 +118,64 @@ char *g_prevcwd = NULL; int chdir(FAR const char *path) { - char *duppath; + struct stat buf; + char *oldpwd; + char *alloc; + int err; + int ret; /* Verify the input parameters */ if (!path) { - errno = ENOENT; - return ERROR; + err = ENOENT; + goto errout; } /* Verify that 'path' refers to a directory */ - /* (To be provided) */ - /* Make a persistent copy of 'path' */ + ret = stat(path, &buf); + if (ret != 0) + { + err = ENOENT; + goto errout; + } - duppath = strdup(path); + /* Something exists here... is it a directory? */ - /* Free any preceding cwd and set the previous to the cwd (this - * is to support 'cd -' in NSH + if (!S_ISDIR(buf.st_mode)) + { + err = ENOTDIR; + goto errout; + } + + /* Yes, it is a directory. Remove any trailing '/' characters from the path */ + + _trimdir(path); + + /* Replace any preceding OLDPWD with the current PWD (this is to + * support 'cd -' in NSH) */ - cwd_semtake(); - if (g_prevcwd) + sched_lock(); + oldpwd = getenv("PWD"); + if (!oldpwd) { - free(g_prevcwd); + oldpwd = CONFIG_LIB_HOMEDIR; } - g_prevcwd = g_cwd; - /* Set the cwd to a persistent copy of the input 'path' */ + alloc = strdup(oldpwd); /* kludge needed because environment is realloc'ed */ + setenv("OLDPWD", alloc, TRUE); + free(alloc); - g_cwd = duppath; - cwd_semgive(); + /* Set the cwd to the input 'path' */ + + setenv("PWD", path, TRUE); + sched_unlock(); return OK; + +errout: + errno = err; + return ERROR; } -#endif /* CONFIG_NFILE_DESCRIPTORS */ +#endif /* CONFIG_NFILE_DESCRIPTORS && !CONFIG_DISABLE_ENVIRON */ diff --git a/lib/lib_cwdsem.c b/lib/lib_cwdsem.c deleted file mode 100644 index d064878903..0000000000 --- a/lib/lib_cwdsem.c +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** - * lib/lib_cwdsem.c - * - * Copyright (C) 2008 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name NuttX 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. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -#if CONFIG_NFILE_DESCRIPTORS > 0 -static sem_t g_cwdsem = { 1 }; - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: cwd_semtake - ****************************************************************************/ - -void cwd_semtake(void) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(&g_cwdsem) != 0) - { - /* The only case that an error should occr here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} -/**************************************************************************** - * Name: cwd_semgive - ****************************************************************************/ - -void cwd_semgive(void) -{ - /* Give the semaphore */ - - (void)sem_post(&g_cwdsem); -} -#endif /* CONFIG_NFILE_DESCRIPTORS */ diff --git a/lib/lib_getcwd.c b/lib/lib_getcwd.c index a0db05c094..20f7cef481 100644 --- a/lib/lib_getcwd.c +++ b/lib/lib_getcwd.c @@ -40,12 +40,15 @@ #include #include +#include #include #include #include #include "lib_internal.h" +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) + /**************************************************************************** * Definitions ****************************************************************************/ @@ -90,50 +93,38 @@ * ****************************************************************************/ -#if CONFIG_NFILE_DESCRIPTORS > 0 FAR char *getcwd(FAR char *buf, size_t size) { - const char *ptr; - int err; + char *pwd; - /* Verify input parameters */ + /* Verify input parameters */ - if (!buf || !size) - { - err = EINVAL; - goto errout; - } + if (!buf || !size) + { + errno = EINVAL; + return NULL; + } - /* If no working directory is defined, then default to the home directory */ + /* If no working directory is defined, then default to the home directory */ - cwd_semtake(); - if (g_cwd) - { - ptr = g_cwd; - } - else - { - ptr = CONFIG_LIB_HOMEDIR; - } + pwd = getenv("PWD"); + if (!pwd) + { + pwd = CONFIG_LIB_HOMEDIR; + } - /* Verify that the cwd will fit into the user-provided buffer */ + /* Verify that the cwd will fit into the user-provided buffer */ - if (strlen(ptr) + 1 > size) - { - err = ERANGE; - goto errout_with_sem; - } + if (strlen(pwd) + 1 > size) + { + errno = ERANGE; + return NULL; + } - /* Copy the cwd to the user buffer */ + /* Copy the cwd to the user buffer */ - strcpy(buf, ptr); - cwd_semgive(); - return buf; - -errout_with_sem: - cwd_semgive(); -errout: - errno = err; - return NULL; + strcpy(buf, pwd); + sched_unlock(); + return buf; } -#endif /* CONFIG_NFILE_DESCRIPTORS */ +#endif /* CONFIG_NFILE_DESCRIPTORS && !CONFIG_DISABLE_ENVIRON */ diff --git a/lib/lib_internal.h b/lib/lib_internal.h index 067b64c24e..2f776321a1 100644 --- a/lib/lib_internal.h +++ b/lib/lib_internal.h @@ -102,11 +102,6 @@ struct lib_rawstream_s * Public Variables ****************************************************************************/ -#if CONFIG_NFILE_DESCRIPTORS > 0 -extern char *g_cwd; /* Defined in lib_chdir.c */ -extern char *g_prevcwd; /* Defined in lib_chdir.c */ -#endif - /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -193,9 +188,4 @@ extern void lib_give_semaphore(FAR struct file_struct *stream); extern int lib_getbase(const char *nptr, const char **endptr); -/* Defined in lib_cwdsem.c */ - -extern void cwd_semtake(void); -extern void cwd_semgive(void); - #endif /* __LIB_INTERNAL_H */