From 058e81edfdee203f2143b3f0910aa957a7f8da48 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 18 Mar 2011 19:46:25 +0000 Subject: Move NSH to apps/ as library git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3393 42af7a65-404d-4744-a932-0658087f49c3 --- apps/nshlib/nsh_fscmds.c | 1341 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1341 insertions(+) create mode 100644 apps/nshlib/nsh_fscmds.c (limited to 'apps/nshlib/nsh_fscmds.c') diff --git a/apps/nshlib/nsh_fscmds.c b/apps/nshlib/nsh_fscmds.c new file mode 100644 index 000000000..4a471e65f --- /dev/null +++ b/apps/nshlib/nsh_fscmds.c @@ -0,0 +1,1341 @@ +/**************************************************************************** + * apps/nshlib/nsh_fscmds.c + * + * Copyright (C) 2007-2009, 2011 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 + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# include +# include +# if !defined(CONFIG_DISABLE_MOUNTPOINT) +# ifdef CONFIG_FS_READABLE /* Need at least one filesytem in configuration */ +# include +# include +# endif +# ifdef CONFIG_FS_FAT +# include +# endif +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define LSFLAGS_SIZE 1 +#define LSFLAGS_LONG 2 +#define LSFLAGS_RECURSIVE 4 + +/* The size of the I/O buffer may be specified in the + * configs/defconfig file -- provided that it is at least as + * large as PATH_MAX. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifdef CONFIG_EXAMPLES_NSH_FILEIOSIZE +# if CONFIG_EXAMPLES_NSH_FILEIOSIZE > (PATH_MAX + 1) +# define IOBUFFERSIZE CONFIG_EXAMPLES_NSH_FILEIOSIZE +# else +# define IOBUFFERSIZE (PATH_MAX + 1) +# endif +# else +# define IOBUFFERSIZE 1024 +# endif +# else +# define IOBUFFERSIZE (PATH_MAX + 1) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef int (*direntry_handler_t)(FAR struct nsh_vtbl_s *, const char *, struct dirent *, void *); + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Common buffer for file I/O. Note the use of this common buffer precludes + * multiple copies of NSH running concurrently. It should be allocated per + * NSH instance and retained in the "vtbl" as is done for the telnet + * connection. + */ + +static char g_iobuffer[IOBUFFERSIZE]; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: trim_dir + ****************************************************************************/ + +static void trim_dir(char *arg) +{ + /* Skip any trailing '/' characters (unless it is also the leading '/') */ + + int len = strlen(arg) - 1; + while (len > 0 && arg[len] == '/') + { + arg[len] = '\0'; + len--; + } +} + +/**************************************************************************** + * Name: nsh_getdirpath + ****************************************************************************/ + +static char *nsh_getdirpath(const char *path, const char *file) +{ + /* Handle the case where all that is left is '/' */ + + if (strcmp(path, "/") == 0) + { + sprintf(g_iobuffer, "/%s", file); + } + else + { + sprintf(g_iobuffer, "%s/%s", path, file); + } + + g_iobuffer[PATH_MAX] = '\0'; + return strdup(g_iobuffer); +} + +/**************************************************************************** + * Name: foreach_direntry + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +static int foreach_direntry(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *dirpath, + direntry_handler_t handler, void *pvarg) +{ + DIR *dirp; + int ret = OK; + + /* Trim trailing '/' from directory names */ + +#ifdef CONFIG_EXAMPLES_NSH_FULLPATH + trim_dir(arg); +#endif + + /* Open the directory */ + + dirp = opendir(dirpath); + + if (!dirp) + { + /* Failed to open the directory */ + + nsh_output(vtbl, g_fmtnosuch, cmd, "directory", dirpath); + return ERROR; + } + + /* Read each directory entry */ + + for (;;) + { + struct dirent *entryp = readdir(dirp); + if (!entryp) + { + /* Finished with this directory */ + + break; + } + + /* Call the handler with this directory entry */ + + if (handler(vtbl, dirpath, entryp, pvarg) < 0) + { + /* The handler reported a problem */ + + ret = ERROR; + break; + } + } + + closedir(dirp); + return ret; +} +#endif + +/**************************************************************************** + * Name: ls_specialdir + ****************************************************************************/ + +static inline int ls_specialdir(const char *dir) +{ + /* '.' and '..' directories are not listed like normal directories */ + + return (strcmp(dir, ".") == 0 || strcmp(dir, "..") == 0); +} + +/**************************************************************************** + * Name: ls_handler + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +static int ls_handler(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, struct dirent *entryp, void *pvarg) +{ + unsigned int lsflags = (unsigned int)pvarg; + int ret; + + /* Check if any options will require that we stat the file */ + + if ((lsflags & (LSFLAGS_SIZE|LSFLAGS_LONG)) != 0) + { + struct stat buf; + char *fullpath = nsh_getdirpath(dirpath, entryp->d_name); + + /* Yes, stat the file */ + + ret = stat(fullpath, &buf); + free(fullpath); + if (ret != 0) + { + nsh_output(vtbl, g_fmtcmdfailed, "ls", "stat", NSH_ERRNO); + return ERROR; + } + + if ((lsflags & LSFLAGS_LONG) != 0) + { + char details[] = "----------"; + if (S_ISDIR(buf.st_mode)) + { + details[0]='d'; + } + else if (S_ISCHR(buf.st_mode)) + { + details[0]='c'; + } + else if (S_ISBLK(buf.st_mode)) + { + details[0]='b'; + } + + if ((buf.st_mode & S_IRUSR) != 0) + { + details[1]='r'; + } + + if ((buf.st_mode & S_IWUSR) != 0) + { + details[2]='w'; + } + + if ((buf.st_mode & S_IXUSR) != 0) + { + details[3]='x'; + } + + if ((buf.st_mode & S_IRGRP) != 0) + { + details[4]='r'; + } + + if ((buf.st_mode & S_IWGRP) != 0) + { + details[5]='w'; + } + + if ((buf.st_mode & S_IXGRP) != 0) + { + details[6]='x'; + } + + if ((buf.st_mode & S_IROTH) != 0) + { + details[7]='r'; + } + + if ((buf.st_mode & S_IWOTH) != 0) + { + details[8]='w'; + } + + if ((buf.st_mode & S_IXOTH) != 0) + { + details[9]='x'; + } + + nsh_output(vtbl, " %s", details); + } + + if ((lsflags & LSFLAGS_SIZE) != 0) + { + nsh_output(vtbl, "%8d", buf.st_size); + } + } + + /* then provide the filename that is common to normal and verbose output */ + +#ifdef CONFIG_EXAMPLES_NSH_FULLPATH + nsh_output(vtbl, " %s/%s", arg, entryp->d_name); +#else + nsh_output(vtbl, " %s", entryp->d_name); +#endif + + if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name)) + { + nsh_output(vtbl, "/\n"); + } + else + { + nsh_output(vtbl, "\n"); + } + return OK; +} +#endif + +/**************************************************************************** + * Name: ls_recursive + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +static int ls_recursive(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, + struct dirent *entryp, void *pvarg) +{ + int ret = OK; + + /* Is this entry a directory (and not one of the special directories, . and ..)? */ + + if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name)) + { + /* Yes.. */ + + char *newpath; + newpath = nsh_getdirpath(dirpath, entryp->d_name); + + /* List the directory contents */ + + nsh_output(vtbl, "%s:\n", newpath); + + /* Traverse the directory */ + + ret = foreach_direntry(vtbl, "ls", newpath, ls_handler, pvarg); + if (ret == 0) + { + /* Then recurse to list each directory within the directory */ + + ret = foreach_direntry(vtbl, "ls", newpath, ls_recursive, pvarg); + free(newpath); + } + } + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_cat + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_CAT +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; + + /* Loop for each file name on the command line */ + + for (i = 1; i < argc && ret == OK; i++) + { + /* Get the fullpath to the file */ + + fullpath = nsh_getfullpath(vtbl, argv[i]); + if (fullpath) + { + /* Open the file for reading */ + + fd = open(fullpath, O_RDONLY); + if (fd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + } + else + { + /* And just dump it byte for byte into stdout */ + + for (;;) + { + int nbytesread = read(fd, buffer, IOBUFFERSIZE); + + /* Check for read errors */ + + if (nbytesread < 0) + { + /* EINTR is not an error (but will stop stop the cat) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + 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) + { + ssize_t n = nsh_write(vtbl, buffer, nbytesread); + if (n < 0) + { + /* EINTR is not an error (but will stop stop the cat) */ + + #ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + 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); + } + + /* Free the allocated full path */ + + nsh_freefullpath(fullpath); + } + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_cp + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_CP +int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct stat buf; + 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(srcpath, O_RDONLY); + if (rdfd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + 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(destpath, &buf); + if (ret == 0) + { + /* Something exists here... is it a directory? */ + + if (S_ISDIR(buf.st_mode)) + { + /* Yes, it is a directory. Remove any trailing '/' characters from the path */ + + trim_dir(argv[2]); + + /* Construct the full path to the new file */ + + allocpath = nsh_getdirpath(argv[2], basename(argv[1]) ); + if (!allocpath) + { + nsh_output(vtbl, g_fmtcmdoutofmemory, argv[0]); + goto errout_with_destpath; + } + + /* Open then dest for writing */ + + nsh_freefullpath(destpath); + destpath = allocpath; + } + else if (!S_ISREG(buf.st_mode)) + { + /* Maybe it is a driver? */ + + oflags = O_WRONLY; + } + } + + /* Now open the destination */ + + wrfd = open(destpath, oflags, 0666); + if (wrfd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + goto errout_with_allocpath; + } + + /* Now copy the file */ + + for (;;) + { + int nbytesread; + int nbyteswritten; + + do + { + nbytesread = read(rdfd, g_iobuffer, IOBUFFERSIZE); + if (nbytesread == 0) + { + /* End of file */ + + ret = OK; + goto errout_with_wrfd; + } + else if (nbytesread < 0) + { + /* EINTR is not an error (but will still stop the copy) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + /* Read error */ + + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); + } + goto errout_with_wrfd; + } + } + while (nbytesread <= 0); + + do + { + nbyteswritten = write(wrfd, g_iobuffer, nbytesread); + if (nbyteswritten >= 0) + { + nbytesread -= nbyteswritten; + } + else + { + /* EINTR is not an error (but will still stop the copy) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + /* Read error */ + + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO); + } + goto errout_with_wrfd; + } + } + while (nbytesread > 0); + } + +errout_with_wrfd: + close(wrfd); + +errout_with_allocpath: + if (allocpath) + { + free(allocpath); + } + +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 +#endif + +/**************************************************************************** + * Name: cmd_losetup + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_LOSETUP +int cmd_losetup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *loopdev = NULL; + char *filepath = NULL; + bool teardown = false; + bool readonly = false; + off_t offset = 0; + bool badarg = false; + int ret = ERROR; + int option; + + /* Get the losetup options: Two forms are supported: + * + * losetup -d + * losetup [-o ] [-r] + * + * NOTE that the -o and -r options are accepted with the -d option, but + * will be ignored. + */ + + while ((option = getopt(argc, argv, "d:o:r")) != ERROR) + { + switch (option) + { + case 'd': + loopdev = nsh_getfullpath(vtbl, optarg); + teardown = true; + break; + + case 'o': + offset = atoi(optarg); + break; + + case 'r': + readonly = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + goto errout_with_paths; + } + + /* If this is not a tear down operation, then additional command line + * parameters are required. + */ + + if (!teardown) + { + /* There must be two arguments on the command line after the options */ + + if (optind + 1 < argc) + { + loopdev = nsh_getfullpath(vtbl, argv[optind]); + optind++; + + filepath = nsh_getfullpath(vtbl, argv[optind]); + optind++; + } + else + { + nsh_output(vtbl, g_fmtargrequired, argv[0]); + goto errout_with_paths; + } + } + + /* There should be nothing else on the command line */ + + if (optind < argc) + { + nsh_output(vtbl, g_fmttoomanyargs, argv[0]); + goto errout_with_paths; + } + + /* Perform the teardown operation */ + + if (teardown) + { + /* Tear down the loop device. */ + + ret = loteardown(loopdev); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "loteardown", NSH_ERRNO_OF(-ret)); + goto errout_with_paths; + } + } + else + { + /* Set up the loop device */ + + ret = losetup(loopdev, filepath, 512, offset, readonly); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "losetup", NSH_ERRNO_OF(-ret)); + goto errout_with_paths; + } + } + + /* Free memory */ + +errout_with_paths: + if (loopdev) + { + free(loopdev); + } + + if (filepath) + { + free(filepath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_ls + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_LS +int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + const char *relpath; + unsigned int lsflags = 0; + char *fullpath; + bool badarg = false; + int ret; + + /* Get the ls options */ + + int option; + while ((option = getopt(argc, argv, "lRs")) != ERROR) + { + switch (option) + { + case 'l': + lsflags |= (LSFLAGS_SIZE|LSFLAGS_LONG); + break; + + case 'R': + lsflags |= LSFLAGS_RECURSIVE; + break; + + case 's': + lsflags |= LSFLAGS_SIZE; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There may be one argument after the options */ + + if (optind + 1 < argc) + { + nsh_output(vtbl, g_fmttoomanyargs, argv[0]); + return ERROR; + } + 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", 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", fullpath, ls_recursive, (void*)lsflags); + } + nsh_freefullpath(fullpath); + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkdir + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKDIR +int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = mkdir(fullpath, 0777); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkdir", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkfatfs + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_FAT) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFATFS +int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct fat_format_s fmt = FAT_FORMAT_INITIALIZER; + 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; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkfifo + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFIFO +int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = mkfifo(fullpath, 0777); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfifo", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkrd + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKRD +int cmd_mkrd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + const char *fmt; + uint8_t *buffer; + uint32_t nsectors; + bool badarg = false; + int sectsize = 512; + int minor = 0; + int ret; + + /* Get the mount options */ + + int option; + while ((option = getopt(argc, argv, ":m:s:")) != ERROR) + { + switch (option) + { + case 'm': + minor = atoi(optarg); + if (minor < 0 || minor > 255) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + break; + + case 's': + sectsize = atoi(optarg); + if (minor < 0 || minor > 16384) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There should be exactly on parameter left on the command-line */ + + if (optind == argc-1) + { + nsectors = (uint32_t)atoi(argv[optind]); + } + else if (optind >= argc) + { + fmt = g_fmttoomanyargs; + goto errout_with_fmt; + } + else + { + fmt = g_fmtargrequired; + goto errout_with_fmt; + } + + /* Allocate the memory backing up the ramdisk */ + + buffer = (uint8_t*)malloc(sectsize * nsectors); + if (!buffer) + { + fmt = g_fmtcmdoutofmemory; + goto errout_with_fmt; + } + +#ifdef CONFIG_DEBUG_VERBOSE + memset(buffer, 0, sectsize * nsectors); +#endif + dbg("RAMDISK at %p\n", buffer); + + /* Then register the ramdisk */ + + ret = ramdisk_register(minor, buffer, nsectors, sectsize, true); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "ramdisk_register", NSH_ERRNO_OF(-ret)); + free(buffer); + return ERROR; + } + return ret; + +errout_with_fmt: + nsh_output(vtbl, fmt, argv[0]); + return ERROR; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mount + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MOUNT +int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *source; + char *target; + char *filesystem = 0; + bool badarg = false; + int ret; + + /* Get the mount options */ + + int option; + while ((option = getopt(argc, argv, ":t:")) != ERROR) + { + switch (option) + { + case 't': + filesystem = optarg; + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There are two required arguments after the options */ + + if (optind + 2 < argc) + { + nsh_output(vtbl, g_fmttoomanyargs, argv[0]); + return ERROR; + } + else if (optind + 2 > argc) + { + nsh_output(vtbl, g_fmtargrequired, argv[0]); + 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 */ + + ret = mount(source, target, filesystem, 0, NULL); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO); + } + + nsh_freefullpath(source); + nsh_freefullpath(target); + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_rm + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_RM +int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = unlink(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "unlink", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_rmdir + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_RMDIR +int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = rmdir(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rmdir", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: nsh_script + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT) +int nsh_script(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *path) +{ + 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, path); + if (!fullpath) + { + return ERROR; + } + + /* Get a reference to the common input buffer */ + + buffer = nsh_linebuffer(vtbl); + if (buffer) + { + /* Open the file containing the script */ + + stream = fopen(fullpath, "r"); + if (!stream) + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "fopen", NSH_ERRNO); + nsh_freefullpath(fullpath); + return ERROR; + } + + /* Loop, processing each command line in the script file (or + * until an error occurs) + */ + + do + { + /* Get the next line of input from the file*/ + + fflush(stdout); + pret = fgets(buffer, CONFIG_EXAMPLES_NSH_LINELEN, stream); + if (pret) + { + /* Parse process the command. NOTE: this is recursive... + * we got to cmd_sh via a call to nsh_parse. So some + * considerable amount of stack may be used. + */ + + ret = nsh_parse(vtbl, buffer); + } + } + while (pret && ret == OK); + fclose(stream); + } + + nsh_freefullpath(fullpath); + return ret; +} +#endif + +/**************************************************************************** + * Name: cmd_sh + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_SH +int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + return nsh_script(vtbl, argv[0], argv[1]); +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_umount + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE) +#ifndef CONFIG_EXAMPLES_NSH_DISABLE_UMOUNT +int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + /* Perform the umount */ + + ret = umount(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "umount", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif -- cgit v1.2.3