summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2008-08-23 15:16:10 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2008-08-23 15:16:10 +0000
commit872cf9f99f8b6e2a64781c0c6bc8aee6e35f5cb7 (patch)
tree27c66a47011dea19170420a26a954591f02e8c53
parentb588aaaa96a83162f43a4ea409be382a01aa3812 (diff)
downloadpx4-nuttx-872cf9f99f8b6e2a64781c0c6bc8aee6e35f5cb7.tar.gz
px4-nuttx-872cf9f99f8b6e2a64781c0c6bc8aee6e35f5cb7.tar.bz2
px4-nuttx-872cf9f99f8b6e2a64781c0c6bc8aee6e35f5cb7.zip
Added ch and pwd to NSH
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@841 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog2
-rw-r--r--nuttx/Documentation/NuttX.html6
-rw-r--r--nuttx/examples/README.txt2
-rw-r--r--nuttx/examples/nsh/nsh.h25
-rw-r--r--nuttx/examples/nsh/nsh_envcmds.c198
-rw-r--r--nuttx/examples/nsh/nsh_fscmds.c337
-rw-r--r--nuttx/examples/nsh/nsh_main.c17
-rw-r--r--nuttx/lib/Makefile7
-rw-r--r--nuttx/lib/lib_chdir.c88
-rw-r--r--nuttx/lib/lib_cwdsem.c86
-rw-r--r--nuttx/lib/lib_getcwd.c79
-rw-r--r--nuttx/lib/lib_internal.h10
12 files changed, 593 insertions, 264 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index d756a2bd1..abb52498f 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/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/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index 05c44e37e..c67009fd0 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
- <p>Last Updated: August 22, 2008</p>
+ <p>Last Updated: August 23, 2008</p>
</td>
</tr>
</table>
@@ -1052,6 +1052,10 @@ nuttx-0.3.13 2008-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
* 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 &lt;spudmonkey@racsa.co.cr&gt;
diff --git a/nuttx/examples/README.txt b/nuttx/examples/README.txt
index 9f12b592e..6012d2087 100644
--- a/nuttx/examples/README.txt
+++ b/nuttx/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/nuttx/examples/nsh/nsh.h b/nuttx/examples/nsh/nsh.h
index 33f6d3d4d..7ee0d7192 100644
--- a/nuttx/examples/nsh/nsh.h
+++ b/nuttx/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/nuttx/examples/nsh/nsh_envcmds.c b/nuttx/examples/nsh/nsh_envcmds.c
index 7c8ece414..f8bedc461 100644
--- a/nuttx/examples/nsh/nsh_envcmds.c
+++ b/nuttx/examples/nsh/nsh_envcmds.c
@@ -42,7 +42,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
+#include <libgen.h>
#include <errno.h>
#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
****************************************************************************/
@@ -72,10 +80,188 @@
****************************************************************************/
/****************************************************************************
+ * 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
****************************************************************************/
@@ -96,6 +282,18 @@ int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
}
/****************************************************************************
+ * 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/nuttx/examples/nsh/nsh_fscmds.c b/nuttx/examples/nsh/nsh_fscmds.c
index 144cea9a4..8610b157d 100644
--- a/nuttx/examples/nsh/nsh_fscmds.c
+++ b/nuttx/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);
-
- /* Check for read errors */
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
+ }
+ else
+ {
+ /* And just dump it byte for byte into stdout */
- 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)
{
- nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO);
- ret = ERROR;
- break;
- }
- }
+ /* EINTR is not an error */
- /* Check for data successfully read */
+ if (errno != EINTR)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO);
+ ret = ERROR;
+ break;
+ }
+ }
- else if (nbytesread > 0)
- {
- int nbyteswritten = 0;
+ /* Check for data successfully read */
- while (nbyteswritten < nbytesread)
+ else if (nbytesread > 0)
{
- int n = write(1, buffer, nbytesread);
- if (n < 0)
- {
- /* EINTR is not an error */
+ int nbyteswritten = 0;
- if (errno != EINTR)
+ while (nbyteswritten < nbytesread)
+ {
+ int n = write(1, buffer, nbytesread);
+ if (n < 0)
{
- nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO);
- ret = ERROR;
- break;
+ /* EINTR is not an error */
+
+ if (errno != EINTR)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO);
+ ret = ERROR;
+ break;
+ }
+ }
+ else
+ {
+ nbyteswritten += n;
}
- }
- else
- {
- nbyteswritten += n;
}
}
- }
- /* Otherwise, it is the end of file */
+ /* Otherwise, it is the end of file */
- else
- {
- break;
+ 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/nuttx/examples/nsh/nsh_main.c b/nuttx/examples/nsh/nsh_main.c
index 8cbf78ad9..e98ee7f2d 100644
--- a/nuttx/examples/nsh/nsh_main.c
+++ b/nuttx/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, "<path> [<path> [<path> ...]]" },
+#ifndef CONFIG_DISABLE_ENVIRON
+ { "cd", cmd_cd, 1, 2, "[<dir-path>|-|~|..]" },
+#endif
{ "cp", cmd_cp, 3, 3, "<source-path> <dest-path>" },
#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] <dir-path>" },
+ { "ls", cmd_ls, 1, 5, "[-lRs] <dir-path>" },
#endif
{ "mb", cmd_mb, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" },
#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, "<hex-address>[=<hex-value>][ <hex-byte-count>]" },
{ "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, "<name> <value>" },
#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, "<script-path>" },
-# endif /* CONFIG_NFILE_STREAMS */
+#endif /* CONFIG_NFILE_DESCRIPTORS && CONFIG_NFILE_STREAMS */
#ifndef CONFIG_DISABLE_SIGNALS
{ "sleep", cmd_sleep, 2, 2, "<sec>" },
#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/nuttx/lib/Makefile b/nuttx/lib/Makefile
index cf35a0541..a56cde66f 100644
--- a/nuttx/lib/Makefile
+++ b/nuttx/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/nuttx/lib/lib_chdir.c b/nuttx/lib/lib_chdir.c
index 008e923ec..0db29829d 100644
--- a/nuttx/lib/lib_chdir.c
+++ b/nuttx/lib/lib_chdir.c
@@ -40,6 +40,8 @@
#include <nuttx/config.h>
#include <sys/types.h>
+#include <sys/stat.h>
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -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;
+ }
+
+ /* Something exists here... is it a directory? */
- duppath = strdup(path);
+ if (!S_ISDIR(buf.st_mode))
+ {
+ err = ENOTDIR;
+ goto errout;
+ }
- /* Free any preceding cwd and set the previous to the cwd (this
- * is to support 'cd -' in NSH
+ /* 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/nuttx/lib/lib_cwdsem.c b/nuttx/lib/lib_cwdsem.c
deleted file mode 100644
index d06487890..000000000
--- a/nuttx/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 <spudmonkey@racsa.co.cr>
- *
- * 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 <nuttx/config.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <assert.h>
-#include <semaphore.h>
-#include <errno.h>
-
-/****************************************************************************
- * 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/nuttx/lib/lib_getcwd.c b/nuttx/lib/lib_getcwd.c
index a0db05c09..20f7cef48 100644
--- a/nuttx/lib/lib_getcwd.c
+++ b/nuttx/lib/lib_getcwd.c
@@ -40,12 +40,15 @@
#include <nuttx/config.h>
#include <sys/types.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#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;
-
- /* Verify input parameters */
-
- if (!buf || !size)
- {
- err = EINVAL;
- goto errout;
- }
-
- /* 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;
- }
-
- /* Verify that the cwd will fit into the user-provided buffer */
-
- if (strlen(ptr) + 1 > size)
- {
- err = ERANGE;
- goto errout_with_sem;
- }
-
- /* Copy the cwd to the user buffer */
-
- strcpy(buf, ptr);
- cwd_semgive();
- return buf;
-
-errout_with_sem:
- cwd_semgive();
-errout:
- errno = err;
- return NULL;
+ char *pwd;
+
+ /* Verify input parameters */
+
+ if (!buf || !size)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* If no working directory is defined, then default to the home directory */
+
+ pwd = getenv("PWD");
+ if (!pwd)
+ {
+ pwd = CONFIG_LIB_HOMEDIR;
+ }
+
+ /* Verify that the cwd will fit into the user-provided buffer */
+
+ if (strlen(pwd) + 1 > size)
+ {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ /* Copy the cwd to the user buffer */
+
+ strcpy(buf, pwd);
+ sched_unlock();
+ return buf;
}
-#endif /* CONFIG_NFILE_DESCRIPTORS */
+#endif /* CONFIG_NFILE_DESCRIPTORS && !CONFIG_DISABLE_ENVIRON */
diff --git a/nuttx/lib/lib_internal.h b/nuttx/lib/lib_internal.h
index 067b64c24..2f776321a 100644
--- a/nuttx/lib/lib_internal.h
+++ b/nuttx/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 */