int cmd_mv(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { char *oldpath; char *newpath; int ret; /* Get the full path to the old and new file paths */ oldpath = nsh_getfullpath(vtbl, argv[1]); if (!oldpath) { return ERROR; } newpath = nsh_getfullpath(vtbl, argv[2]); if (!newpath) { nsh_freefullpath(newpath); return ERROR; } /* Perform the mount */ ret = rename(oldpath, newpath); if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rename", NSH_ERRNO); } /* Free the file paths */ nsh_freefullpath(oldpath); nsh_freefullpath(newpath); return ret; }
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_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; }
int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { char *fullpath; 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) { ret = ERROR; } else { /* Dump the file to the console */ ret = cat_common(vtbl, argv[0], fullpath); /* Free the allocated full path */ nsh_freefullpath(fullpath); } } return ret; }
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 */ ret = chdir(path); if (ret != 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; }
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; }
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; }
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; }
int cmd_mksmartfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { char *fullpath = nsh_getfullpath(vtbl, argv[1]); int ret = ERROR; #ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS int nrootdirs = 1; #endif if (fullpath) { /* Test if number of root directories was supplied */ #ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS if (argc == 3) { nrootdirs = atoi(argv[2]); } if (nrootdirs > 8 || nrootdirs < 1) { nsh_output(vtbl, "Invalid number of root directories specified\n"); } else #endif { #ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS ret = mksmartfs(fullpath, nrootdirs); #else ret = mksmartfs(fullpath); #endif if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mksmartfs", NSH_ERRNO); } } nsh_freefullpath(fullpath); } return ret; }
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 paths 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 (!target) { 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; }
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; }
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; }
int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { FAR const char *source; FAR char *fullsource; FAR const char *target; FAR char *fulltarget; FAR const char *filesystem = NULL; bool badarg = false; int option; int ret; /* The mount command behaves differently if no parameters are provided */ #ifndef CONFIG_NUTTX_KERNEL if (argc < 2) { return mount_show(vtbl, argv[0]); } #endif /* Get the mount options. NOTE: getopt() is not thread safe nor re-entrant. * To keep its state proper for the next usage, it is necessary to parse to * the end of the line even if an error occurs. If an error occurs, this * logic just sets 'badarg' and continues. */ 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 may be one or two required arguments after the options: the source * and target paths. Some file systems do not require the source parameter * so if there is only one parameter left, it must be the target. */ if (optind >= argc) { nsh_output(vtbl, g_fmtargrequired, argv[0]); return ERROR; } source = NULL; target = argv[optind]; optind++; if (optind < argc) { source = target; target = argv[optind]; optind++; if (optind < argc) { nsh_output(vtbl, g_fmttoomanyargs, argv[0]); return ERROR; } } /* While the above parsing for the -t argument looks nice, the -t argument * not really optional. */ if (!filesystem) { nsh_output(vtbl, g_fmtargrequired, argv[0]); return ERROR; } /* The source and target paths might be relative to the current * working directory. */ fullsource = NULL; fulltarget = NULL; if (source) { fullsource = nsh_getfullpath(vtbl, source); if (!fullsource) { return ERROR; } } fulltarget = nsh_getfullpath(vtbl, target); if (!fulltarget) { ret = ERROR; goto errout; } /* Perform the mount */ ret = mount(fullsource, fulltarget, filesystem, 0, NULL); if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO); } errout: if (fullsource) { nsh_freefullpath(fullsource); } if (fulltarget) { nsh_freefullpath(fulltarget); } return ret; }
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; }
int cmd_nfsmount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { struct nfs_args data; FAR char *address; FAR char *lpath; FAR char *rpath; bool badarg = false; #ifdef CONFIG_NET_IPv6 FAR struct sockaddr_in6 *sin; struct in6_addr inaddr; #else FAR struct sockaddr_in *sin; struct in_addr inaddr; #endif int ret; /* If a bad argument was encountered, then return without processing the * command. */ if (badarg) { return ERROR; } /* The fist argument on the command line should be the NFS server IP address * in standard IPv4 (or IPv6) dot format. */ address = argv[1]; if (!address) { return ERROR; } /* The local mount point path (lpath) might be relative to the current working * directory. */ lpath = nsh_getfullpath(vtbl, argv[2]); if (!lpath) { return ERROR; } /* Get the remote mount point path */ rpath = argv[3]; /* Convert the IP address string into its binary form */ #ifdef CONFIG_NET_IPv6 ret = inet_pton(AF_INET6, address, &inaddr); #else ret = inet_pton(AF_INET, address, &inaddr); #endif if (ret != 1) { nsh_freefullpath(lpath); return ERROR; } /* Place all of the NFS arguements into the nfs_args structure */ memset(&data, 0, sizeof(data)); #ifdef CONFIG_NET_IPv6 sin = (FAR struct sockaddr_in6 *)&data.addr; sin->sin_family = AF_INET6; sin->sin_port = htons(NFS_PMAPPORT); memcpy(&sin->sin6_addr, &inaddr, sizeof(struct in6_addr)); data.addrlen = sizeof(struct sockaddr_in6); #else sin = (FAR struct sockaddr_in *)&data.addr; sin->sin_family = AF_INET; sin->sin_port = htons(NFS_PMAPPORT); sin->sin_addr = inaddr; data.addrlen = sizeof(struct sockaddr_in); #endif data.sotype = SOCK_DGRAM; data.path = rpath; data.flags = 0; /* 0=Use all defaults */ /* Perform the mount */ ret = mount(NULL, lpath, "nfs", 0, (FAR void *)&data); if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO); } /* We no longer need the allocated mount point path */ nsh_freefullpath(lpath); return ret; }
int cmd_cmp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { FAR char *path1 = NULL; FAR char *path2 = NULL; off_t total_read = 0; int fd1 = -1; int fd2 = -1; int ret = ERROR; /* Get the full path to the two files */ path1 = nsh_getfullpath(vtbl, argv[1]); if (!path1) { nsh_output(vtbl, g_fmtargrequired, argv[0]); goto errout; } path2 = nsh_getfullpath(vtbl, argv[2]); if (!path2) { nsh_output(vtbl, g_fmtargrequired, argv[0]); goto errout_with_path1; } /* Open the files for reading */ fd1 = open(path1, O_RDONLY); if (fd1 < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); goto errout_with_path2; } fd2 = open(path2, O_RDONLY); if (fd2 < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); goto errout_with_fd1; } /* The loop until we hit the end of file or find a difference in the two * files. */ for (;;) { char buf1[128]; char buf2[128]; /* Read the file data */ ssize_t nbytesread1 = read(fd1, buf1, sizeof(buf1)); ssize_t nbytesread2 = read(fd2, buf2, sizeof(buf2)); if (nbytesread1 < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); goto errout_with_fd2; } if (nbytesread2 < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); goto errout_with_fd2; } total_read += nbytesread1 > nbytesread2 ? nbytesread2 : nbytesread1; /* Compare the file data */ if (nbytesread1 != nbytesread2 || memcmp(buf1, buf2, nbytesread1) != 0) { nsh_output(vtbl, "files differ: byte %u\n", total_read); goto errout_with_fd2; } /* A partial read indicates the end of file (usually) */ if (nbytesread1 < (size_t)sizeof(buf1)) { break; } } /* The files are the same, i.e., the end of file was encountered * without finding any differences. */ ret = OK; errout_with_fd2: close(fd2); errout_with_fd1: close(fd1); errout_with_path2: nsh_freefullpath(path2); errout_with_path1: nsh_freefullpath(path1); errout: return ret; }
int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) { FAR char *argv[MAX_ARGV_ENTRIES]; FAR char *saveptr; FAR char *cmd; #if CONFIG_NFILE_STREAMS > 0 FAR char *redirfile = NULL; int oflags = 0; int fd = -1; #endif int argc; int ret; /* Initialize parser state */ memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *)); #ifndef CONFIG_NSH_DISABLEBG vtbl->np.np_bg = false; #endif #if CONFIG_NFILE_STREAMS > 0 vtbl->np.np_redirect = false; #endif /* Parse out the command at the beginning of the line */ saveptr = cmdline; cmd = nsh_argument(vtbl, &saveptr); /* Handler if-then-else-fi */ #ifndef CONFIG_NSH_DISABLESCRIPT if (nsh_ifthenelse(vtbl, &cmd, &saveptr) != 0) { goto errout; } #endif /* Handle nice */ #ifndef CONFIG_NSH_DISABLEBG if (nsh_nice(vtbl, &cmd, &saveptr) != 0) { goto errout; } #endif /* Check if any command was provided -OR- if command processing is * currently disabled. */ #ifndef CONFIG_NSH_DISABLESCRIPT if (!cmd || !nsh_cmdenabled(vtbl)) #else if (!cmd) #endif { /* An empty line is not an error and an unprocessed command cannot * generate an error, but neither should they change the last * command status. */ return OK; } /* Parse all of the arguments following the command name. The form * of argv is: * * argv[0]: The command name. * argv[1]: The beginning of argument (up to CONFIG_NSH_MAXARGUMENTS) * argv[argc-3]: Possibly '>' or '>>' * argv[argc-2]: Possibly <file> * argv[argc-1]: Possibly '&' * argv[argc]: NULL terminating pointer * * Maximum size is CONFIG_NSH_MAXARGUMENTS+5 */ argv[0] = cmd; for (argc = 1; argc < MAX_ARGV_ENTRIES-1; argc++) { argv[argc] = nsh_argument(vtbl, &saveptr); if (!argv[argc]) { break; } } argv[argc] = NULL; /* Check if the command should run in background */ #ifndef CONFIG_NSH_DISABLEBG if (argc > 1 && strcmp(argv[argc-1], "&") == 0) { vtbl->np.np_bg = true; argv[argc-1] = NULL; argc--; } #endif #if CONFIG_NFILE_STREAMS > 0 /* Check if the output was re-directed using > or >> */ if (argc > 2) { /* Check for redirection to a new file */ if (strcmp(argv[argc-2], g_redirect1) == 0) { vtbl->np.np_redirect = true; oflags = O_WRONLY|O_CREAT|O_TRUNC; redirfile = nsh_getfullpath(vtbl, argv[argc-1]); argc -= 2; } /* Check for redirection by appending to an existing file */ else if (strcmp(argv[argc-2], g_redirect2) == 0) { vtbl->np.np_redirect = true; oflags = O_WRONLY|O_CREAT|O_APPEND; redirfile = nsh_getfullpath(vtbl, argv[argc-1]); argc -= 2; } } #endif /* Check if the maximum number of arguments was exceeded */ if (argc > CONFIG_NSH_MAXARGUMENTS) { nsh_output(vtbl, g_fmttoomanyargs, cmd); } /* Does this command correspond to an application filename? * nsh_fileapp() returns: * * -1 (ERROR) if the application task corresponding to 'argv[0]' could not * be started (possibly because it doesn not exist). * 0 (OK) if the application task corresponding to 'argv[0]' was * and successfully started. If CONFIG_SCHED_WAITPID is * defined, this return value also indicates that the * application returned successful status (EXIT_SUCCESS) * 1 If CONFIG_SCHED_WAITPID is defined, then this return value * indicates that the application task was spawned successfully * but returned failure exit status. * * Note the priority if not effected by nice-ness. */ #ifdef CONFIG_NSH_FILE_APPS ret = nsh_fileapp(vtbl, argv[0], argv, redirfile, oflags); if (ret >= 0) { /* nsh_fileapp() returned 0 or 1. This means that the builtin * command was successfully started (although it may not have ran * successfully). So certainly it is not an NSH command. */ /* Free the redirected output file path */ if (redirfile) { nsh_freefullpath(redirfile); } /* Save the result: success if 0; failure if 1 */ return nsh_saveresult(vtbl, ret != OK); } /* No, not a built in command (or, at least, we were unable to start a * builtin command of that name). Treat it like an NSH command. */ #endif /* Does this command correspond to a builtin command? * nsh_builtin() returns: * * -1 (ERROR) if the application task corresponding to 'argv[0]' could not * be started (possibly because it doesn not exist). * 0 (OK) if the application task corresponding to 'argv[0]' was * and successfully started. If CONFIG_SCHED_WAITPID is * defined, this return value also indicates that the * application returned successful status (EXIT_SUCCESS) * 1 If CONFIG_SCHED_WAITPID is defined, then this return value * indicates that the application task was spawned successfully * but returned failure exit status. * * Note the priority if not effected by nice-ness. */ #if defined(CONFIG_NSH_BUILTIN_APPS) && (!defined(CONFIG_NSH_FILE_APPS) || !defined(CONFIG_FS_BINFS)) #if CONFIG_NFILE_STREAMS > 0 ret = nsh_builtin(vtbl, argv[0], argv, redirfile, oflags); #else ret = nsh_builtin(vtbl, argv[0], argv, NULL, 0); #endif if (ret >= 0) { /* nsh_builtin() returned 0 or 1. This means that the builtin * command was successfully started (although it may not have ran * successfully). So certainly it is not an NSH command. */ #if CONFIG_NFILE_STREAMS > 0 /* Free the redirected output file path */ if (redirfile) { nsh_freefullpath(redirfile); } #endif /* Save the result: success if 0; failure if 1 */ return nsh_saveresult(vtbl, ret != OK); } /* No, not a built in command (or, at least, we were unable to start a * builtin command of that name). Treat it like an NSH command. */ #endif #if CONFIG_NFILE_STREAMS > 0 /* Redirected output? */ if (vtbl->np.np_redirect) { /* Open the redirection file. This file will eventually * be closed by a call to either nsh_release (if the command * is executed in the background) or by nsh_undirect if the * command is executed in the foreground. */ fd = open(redirfile, oflags, 0666); nsh_freefullpath(redirfile); redirfile = NULL; if (fd < 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); goto errout; } } #endif /* Handle the case where the command is executed in background. * However is app is to be started as builtin new process will * be created anyway, so skip this step. */ #ifndef CONFIG_NSH_DISABLEBG if (vtbl->np.np_bg) { struct sched_param param; struct nsh_vtbl_s *bkgvtbl; struct cmdarg_s *args; pthread_attr_t attr; pthread_t thread; /* Get a cloned copy of the vtbl with reference count=1. * after the command has been processed, the nsh_release() call * at the end of nsh_child() will destroy the clone. */ bkgvtbl = nsh_clone(vtbl); if (!bkgvtbl) { goto errout_with_redirect; } /* Create a container for the command arguments */ args = nsh_cloneargs(bkgvtbl, fd, argc, argv); if (!args) { nsh_release(bkgvtbl); goto errout_with_redirect; } #if CONFIG_NFILE_STREAMS > 0 /* Handle redirection of output via a file descriptor */ if (vtbl->np.np_redirect) { (void)nsh_redirect(bkgvtbl, fd, NULL); } #endif /* Get the execution priority of this task */ ret = sched_getparam(0, ¶m); if (ret != 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "sched_getparm", NSH_ERRNO); nsh_releaseargs(args); nsh_release(bkgvtbl); goto errout; } /* Determine the priority to execute the command */ if (vtbl->np.np_nice != 0) { int priority = param.sched_priority - vtbl->np.np_nice; if (vtbl->np.np_nice < 0) { int max_priority = sched_get_priority_max(SCHED_NSH); if (priority > max_priority) { priority = max_priority; } } else { int min_priority = sched_get_priority_min(SCHED_NSH); if (priority < min_priority) { priority = min_priority; } } param.sched_priority = priority; } /* Set up the thread attributes */ (void)pthread_attr_init(&attr); (void)pthread_attr_setschedpolicy(&attr, SCHED_NSH); (void)pthread_attr_setschedparam(&attr, ¶m); /* Execute the command as a separate thread at the appropriate priority */ ret = pthread_create(&thread, &attr, nsh_child, (pthread_addr_t)args); if (ret != 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "pthread_create", NSH_ERRNO_OF(ret)); nsh_releaseargs(args); nsh_release(bkgvtbl); goto errout; } /* Detach from the pthread since we are not going to join with it. * Otherwise, we would have a memory leak. */ (void)pthread_detach(thread); nsh_output(vtbl, "%s [%d:%d]\n", cmd, thread, param.sched_priority); } else #endif { #if CONFIG_NFILE_STREAMS > 0 uint8_t save[SAVE_SIZE]; /* Handle redirection of output via a file descriptor */ if (vtbl->np.np_redirect) { nsh_redirect(vtbl, fd, save); } #endif /* Then execute the command in "foreground" -- i.e., while the user waits * for the next prompt. nsh_execute will return: * * -1 (ERRROR) if the command was unsuccessful * 0 (OK) if the command was successful */ ret = nsh_execute(vtbl, argc, argv); #if CONFIG_NFILE_STREAMS > 0 /* Restore the original output. Undirect will close the redirection * file descriptor. */ if (vtbl->np.np_redirect) { nsh_undirect(vtbl, save); } #endif /* Mark errors so that it is possible to test for non-zero return values * in nsh scripts. */ if (ret < 0) { goto errout; } } /* Return success if the command succeeded (or at least, starting of the * command task succeeded). */ return nsh_saveresult(vtbl, false); #ifndef CONFIG_NSH_DISABLEBG errout_with_redirect: #if CONFIG_NFILE_STREAMS > 0 if (vtbl->np.np_redirect) { close(fd); } #endif #endif errout: return nsh_saveresult(vtbl, true); }
static inline int unaryexpression(FAR struct nsh_vtbl_s *vtbl, char **argv) { struct stat buf; char *fullpath; int ret; /* -n STRING */ if (strcmp(argv[0], "-n") == 0) { /* Return true if the length of the string is non-zero */ return strlen(argv[1]) != 0 ? TEST_TRUE : TEST_FALSE; } /* -z STRING */ if (strcmp(argv[0], "-z") == 0) { /* Return true if the length of the string is zero */ return strlen(argv[1]) == 0 ? TEST_TRUE : TEST_FALSE; } /* All of the remaining assume that the following argument is the * path to a file. */ fullpath = nsh_getfullpath(vtbl, argv[1]); if (!fullpath) { return TEST_FALSE; } ret = stat(fullpath, &buf); nsh_freefullpath(fullpath); if (ret != 0) { /* The file does not exist (or another error occurred) -- return FALSE */ return TEST_FALSE; } /* -b FILE */ if (strcmp(argv[0], "-b") == 0) { /* Return true if the path is a block device */ return S_ISBLK(buf.st_mode) ? TEST_TRUE : TEST_FALSE; } /* -c FILE */ if (strcmp(argv[0], "-c") == 0) { /* Return true if the path is a character device */ return S_ISCHR(buf.st_mode) ? TEST_TRUE : TEST_FALSE; } /* -d FILE */ if (strcmp(argv[0], "-d") == 0) { /* Return true if the path is a directory */ return S_ISDIR(buf.st_mode) ? TEST_TRUE : TEST_FALSE; } /* -e FILE */ if (strcmp(argv[0], "-e") == 0) { /* Return true if the file exists */ return TEST_TRUE; } /* -f FILE */ if (strcmp(argv[0], "-f") == 0) { /* Return true if the path refers to a regular file */ return S_ISREG(buf.st_mode) ? TEST_TRUE : TEST_FALSE; } /* -r FILE */ if (strcmp(argv[0], "-r") == 0) { /* Return true if the file is readable */ return (buf.st_mode & (S_IRUSR|S_IRGRP|S_IROTH)) != 0 ? TEST_TRUE : TEST_FALSE; } /* -s FILE */ if (strcmp(argv[0], "-s") == 0) { /* Return true if the size of the file is greater than zero */ return buf.st_size > 0 ? TEST_TRUE : TEST_FALSE; } /* -w FILE */ if (strcmp(argv[0], "-w") == 0) { /* Return true if the file is write-able */ return (buf.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0 ? TEST_TRUE : TEST_FALSE; } /* Unrecognized operator */ return TEST_ERROR; }
int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) { FAR char *argv[MAX_ARGV_ENTRIES]; FAR char *saveptr; FAR char *cmd; FAR char *redirfile = NULL; int fd = -1; int oflags = 0; int argc; int ret; /* Initialize parser state */ memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *)); #ifndef CONFIG_NSH_DISABLEBG vtbl->np.np_bg = false; #endif vtbl->np.np_redirect = false; /* Parse out the command at the beginning of the line */ saveptr = cmdline; cmd = nsh_argument(vtbl, &saveptr); /* Handler if-then-else-fi */ #ifndef CONFIG_NSH_DISABLESCRIPT if (nsh_ifthenelse(vtbl, &cmd, &saveptr) != 0) { goto errout; } #endif /* Handle nice */ #ifndef CONFIG_NSH_DISABLEBG if (nsh_nice(vtbl, &cmd, &saveptr) != 0) { goto errout; } #endif /* Check if any command was provided -OR- if command processing is * currently disabled. */ #ifndef CONFIG_NSH_DISABLESCRIPT if (!cmd || !nsh_cmdenabled(vtbl)) #else if (!cmd) #endif { /* An empty line is not an error and an unprocessed command cannot * generate an error, but neither should they change the last * command status. */ return OK; } /* Parse all of the arguments following the command name. The form * of argv is: * * argv[0]: The command name. * argv[1]: The beginning of argument (up to NSH_MAX_ARGUMENTS) * argv[argc-3]: Possibly '>' or '>>' * argv[argc-2]: Possibly <file> * argv[argc-1]: Possibly '&' * argv[argc]: NULL terminating pointer * * Maximum size is NSH_MAX_ARGUMENTS+5 */ argv[0] = cmd; for (argc = 1; argc < MAX_ARGV_ENTRIES-1; argc++) { argv[argc] = nsh_argument(vtbl, &saveptr); if (!argv[argc]) { break; } } argv[argc] = NULL; /* Check if the command should run in background */ #ifndef CONFIG_NSH_DISABLEBG if (argc > 1 && strcmp(argv[argc-1], "&") == 0) { vtbl->np.np_bg = true; argv[argc-1] = NULL; argc--; } #endif /* Check if the output was re-directed using > or >> */ if (argc > 2) { /* Check for redirection to a new file */ if (strcmp(argv[argc-2], g_redirect1) == 0) { vtbl->np.np_redirect = true; oflags = O_WRONLY|O_CREAT|O_TRUNC; redirfile = nsh_getfullpath(vtbl, argv[argc-1]); argc -= 2; } /* Check for redirection by appending to an existing file */ else if (strcmp(argv[argc-2], g_redirect2) == 0) { vtbl->np.np_redirect = true; oflags = O_WRONLY|O_CREAT|O_APPEND; redirfile = nsh_getfullpath(vtbl, argv[argc-1]); argc -= 2; } } /* Redirected output? */ if (vtbl->np.np_redirect) { /* Open the redirection file. This file will eventually * be closed by a call to either nsh_release (if the command * is executed in the background) or by nsh_undirect if the * command is executed in the foreground. */ fd = open(redirfile, oflags, 0666); nsh_freefullpath(redirfile); redirfile = NULL; if (fd < 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); goto errout; } } /* Check if the maximum number of arguments was exceeded */ if (argc > NSH_MAX_ARGUMENTS) { nsh_output(vtbl, g_fmttoomanyargs, cmd); } /* Handle the case where the command is executed in background. * However is app is to be started as namedapp new process will * be created anyway, so skip this step. */ #ifndef CONFIG_NSH_DISABLEBG if (vtbl->np.np_bg #ifdef CONFIG_NSH_BUILTIN_APPS && namedapp_isavail(argv[0]) < 0 #endif ) { struct sched_param param; struct nsh_vtbl_s *bkgvtbl; struct cmdarg_s *args; pthread_attr_t attr; pthread_t thread; /* Get a cloned copy of the vtbl with reference count=1. * after the command has been processed, the nsh_release() call * at the end of nsh_child() will destroy the clone. */ bkgvtbl = nsh_clone(vtbl); if (!bkgvtbl) { goto errout_with_redirect; } /* Create a container for the command arguments */ args = nsh_cloneargs(bkgvtbl, fd, argc, argv); if (!args) { nsh_release(bkgvtbl); goto errout_with_redirect; } /* Handle redirection of output via a file descriptor */ if (vtbl->np.np_redirect) { (void)nsh_redirect(bkgvtbl, fd, NULL); } /* Get the execution priority of this task */ ret = sched_getparam(0, ¶m); if (ret != 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "sched_getparm", NSH_ERRNO); nsh_releaseargs(args); nsh_release(bkgvtbl); goto errout; } /* Determine the priority to execute the command */ if (vtbl->np.np_nice != 0) { int priority = param.sched_priority - vtbl->np.np_nice; if (vtbl->np.np_nice < 0) { int max_priority = sched_get_priority_max(SCHED_NSH); if (priority > max_priority) { priority = max_priority; } } else { int min_priority = sched_get_priority_min(SCHED_NSH); if (priority < min_priority) { priority = min_priority; } } param.sched_priority = priority; } /* Set up the thread attributes */ (void)pthread_attr_init(&attr); (void)pthread_attr_setschedpolicy(&attr, SCHED_NSH); (void)pthread_attr_setschedparam(&attr, ¶m); /* Execute the command as a separate thread at the appropriate priority */ ret = pthread_create(&thread, &attr, nsh_child, (pthread_addr_t)args); if (ret != 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "pthread_create", NSH_ERRNO_OF(ret)); nsh_releaseargs(args); nsh_release(bkgvtbl); goto errout; } nsh_output(vtbl, "%s [%d:%d]\n", cmd, thread, param.sched_priority); } else #endif { uint8_t save[SAVE_SIZE]; /* Handle redirection of output via a file descriptor */ if (vtbl->np.np_redirect) { nsh_redirect(vtbl, fd, save); } /* Then execute the command in "foreground" -- i.e., while the user waits * for the next prompt. nsh_execute will return: * * -1 (ERRROR) if the command was unsuccessful * 0 (OK) if the command was successful * 1 if an application task was spawned successfully, but * returned failure exit status. */ ret = nsh_execute(vtbl, argc, argv); /* Restore the original output. Undirect will close the redirection * file descriptor. */ if (vtbl->np.np_redirect) { nsh_undirect(vtbl, save); } /* Treat both errors and non-zero return codes as "errors" so that * it is possible to test for non-zero returns in nsh scripts. */ if (ret != OK) { goto errout; } } /* Return success if the command succeeded (or at least, starting of the * command task succeeded). */ return nsh_saveresult(vtbl, false); #ifndef CONFIG_NSH_DISABLEBG errout_with_redirect: if (vtbl->np.np_redirect) { close(fd); } #endif errout: return nsh_saveresult(vtbl, true); }
int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { struct fat_format_s fmt = FAT_FORMAT_INITIALIZER; FAR char *fullpath; bool badarg; int option; int ret = ERROR; /* mkfatfs [-F <fatsize>] <block-driver> */ badarg = false; while ((option = getopt(argc, argv, ":F:")) != ERROR) { switch (option) { case 'F': fmt.ff_fattype = atoi(optarg); if (fmt.ff_fattype != 0 && fmt.ff_fattype != 12 && fmt.ff_fattype != 16 && fmt.ff_fattype != 32) { 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 one parameter left on the command-line */ if (optind == argc-1) { fullpath = nsh_getfullpath(vtbl, argv[optind]); if (!fullpath) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "nsh_getfullpath", NSH_ERRNO); return ERROR; } } else if (optind >= argc) { nsh_output(vtbl, g_fmttoomanyargs, argv[0]); return ERROR; } else { nsh_output(vtbl, g_fmtargrequired, argv[0]); return ERROR; } /* Now format the FAT file system */ ret = mkfatfs(fullpath, &fmt); if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfatfs", NSH_ERRNO); } nsh_freefullpath(fullpath); return ret; }