static int dd_writech(struct dd_s *dd) { uint8_t *buffer = dd->buffer; uint16_t written ; ssize_t nbytes; /* Is the out buffer full (or is this the last one)? */ written = 0; do { nbytes = write(DD_OUTFD, buffer, dd->sectsize - written); if (nbytes < 0) { FAR struct nsh_vtbl_s *vtbl = dd->vtbl; nsh_output(vtbl, g_fmtcmdfailed, g_dd, "write", NSH_ERRNO_OF(-nbytes)); return ERROR; } written += nbytes; buffer += nbytes; } while (written < dd->sectsize); return OK; }
static int dd_writeblk(struct dd_s *dd) { ssize_t nbytes; off_t offset = (dd->sector - dd->skip) * dd->sectsize; /* Write the sector at the specified offset */ nbytes = bchlib_write(DD_OUTHANDLE, (char*)dd->buffer, offset, dd->sectsize); if (nbytes < 0) { /* bchlib_write return -EFBIG on attempts to write past the end of * the device. */ if (nbytes == -EFBIG) { dd->eof = true; /* Set end-of-file */ } else { FAR struct nsh_vtbl_s *vtbl = dd->vtbl; nsh_output(vtbl, g_fmtcmdfailed, g_dd, "bshlib_write", NSH_ERRNO_OF(-nbytes)); return ERROR; } } return OK; }
int nsh_session(FAR struct console_stdio_s *pstate) { int ret; DEBUGASSERT(pstate); /* Present a greeting */ printf("%s", g_nshgreeting); /* Then enter the command line parsing loop */ for (;;) { /* For the case of debugging the USB console... dump collected USB trace data */ #ifdef CONFIG_NSH_USBDEV_TRACE nsh_usbtrace(); #endif /* Display the prompt string */ printf("%s", g_nshprompt); /* Get the next line of input. readline() returns EOF on end-of-file * or any read failure. */ #ifdef CONFIG_NSH_CLE ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, stdin, stdout); #else ret = std_readline(pstate->cn_line, CONFIG_NSH_LINELEN); #endif if (ret != EOF) { /* Parse process the command */ (void)nsh_parse(&pstate->cn_vtbl, pstate->cn_line); } /* Readline normally returns the number of characters read, * but will return EOF on end of file or if an error occurs. * EOF will cause the session to terminate. */ else { printf(g_fmtcmdfailed, "nsh_session", "readline", NSH_ERRNO_OF(-ret)); return EXIT_SUCCESS; } } /* We do not get here, but this is necessary to keep some compilers happy. * But others will complain that this code is not reachable. */ return EXIT_SUCCESS; }
int cmd_userdel(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { int ret; ret = passwd_deluser(argv[1]); if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "passwd_deluser", NSH_ERRNO_OF(-ret)); return ERROR; } return OK; }
static int dd_readblk(struct dd_s *dd) { ssize_t nbytes; off_t offset = dd->sector * dd->sectsize; nbytes = bchlib_read(DD_INHANDLE, (char*)dd->buffer, offset, dd->sectsize); if (nbytes < 0) { FAR struct nsh_vtbl_s *vtbl = dd->vtbl; nsh_output(vtbl, g_fmtcmdfailed, g_dd, "bshlib_read", NSH_ERRNO_OF(-nbytes)); return ERROR; } /* bchlib_read return 0 on attempts to write past the end of the device. */ dd->nbytes = nbytes; dd->eof = (nbytes == 0); return OK; }
static inline int dd_infopen(const char *name, struct dd_s *dd) { FAR struct nsh_vtbl_s *vtbl = dd->vtbl; int ret; int type; /* Get the type of the input file */ type = dd_filetype(name); if (type < 0) { nsh_output(vtbl, g_fmtcmdfailed, g_dd, "stat", NSH_ERRNO_OF(-type)); return type; } /* Open the input file */ if (!type) { DD_INFD = open(name, O_RDONLY); if (DD_INFD < 0) { nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO); return ERROR; } dd->infread = dd_readch; /* Character oriented read */ dd->infclose = dd_infclosech; } else { ret = bchlib_setup(name, true, &DD_INHANDLE); if (ret < 0) { return ERROR; } dd->infread = dd_readblk; dd->infclose = dd_infcloseblk; } return OK; }
static int dd_readch(struct dd_s *dd) { uint8_t *buffer = dd->buffer; ssize_t nbytes; dd->nbytes = 0; do { nbytes = read(DD_INFD, buffer, dd->sectsize - dd->nbytes); if (nbytes < 0) { FAR struct nsh_vtbl_s *vtbl = dd->vtbl; nsh_output(vtbl, g_fmtcmdfailed, g_dd, "read", NSH_ERRNO_OF(-nbytes)); return ERROR; } dd->nbytes += nbytes; buffer += nbytes; } while (dd->nbytes < dd->sectsize && nbytes > 0); dd->eof |= (dd->nbytes == 0); return OK; }
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 nsh_session(FAR struct console_stdio_s *pstate) { FAR struct nsh_vtbl_s *vtbl; int ret; DEBUGASSERT(pstate); vtbl = &pstate->cn_vtbl; #ifdef CONFIG_NSH_CONSOLE_LOGIN /* Login User and Password Check */ if (nsh_login(pstate) != OK) { nsh_exit(vtbl, 1); return -1; /* nsh_exit does not return */ } #endif /* CONFIG_NSH_CONSOLE_LOGIN */ /* Present a greeting and possibly a Message of the Day (MOTD) */ fputs(g_nshgreeting, pstate->cn_outstream); #ifdef CONFIG_NSH_MOTD # ifdef CONFIG_NSH_PLATFORM_MOTD /* Output the platform message of the day */ platform_motd(vtbl->iobuffer, IOBUFFERSIZE); fprintf(pstate->cn_outstream, "%s\n", vtbl->iobuffer); # else /* Output the fixed message of the day */ fprintf(pstate->cn_outstream, "%s\n", g_nshmotd); # endif #endif fflush(pstate->cn_outstream); /* Execute the login script */ #ifdef CONFIG_NSH_ROMFSRC (void)nsh_loginscript(vtbl); #endif /* Then enter the command line parsing loop */ for (;;) { /* For the case of debugging the USB console... dump collected USB trace data */ #ifdef CONFIG_NSH_USBDEV_TRACE nsh_usbtrace(); #endif /* Display the prompt string */ fputs(g_nshprompt, pstate->cn_outstream); fflush(pstate->cn_outstream); /* Get the next line of input. readline() returns EOF on end-of-file * or any read failure. */ #ifdef CONFIG_NSH_CLE ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate), OUTSTREAM(pstate)); #else ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate), OUTSTREAM(pstate)); #endif if (ret != EOF) { /* Parse process the command */ (void)nsh_parse(vtbl, pstate->cn_line); fflush(pstate->cn_outstream); } /* Readline normally returns the number of characters read, * but will return EOF on end of file or if an error occurs. * EOF will cause the session to terminate. */ else { fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_session", "readline", NSH_ERRNO_OF(-ret)); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } } /* We do not get here, but this is necessary to keep some compilers happy. * But others will complain that this code is not reachable. */ return EXIT_SUCCESS; }
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 <loop-device> * losetup [-o <offset>] [-r] <loop-device> <filename> * * 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; }
static int cat_common(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, FAR const char *filename) { char buffer[IOBUFFERSIZE]; int fd; int ret = OK; /* Open the file for reading */ fd = open(filename, O_RDONLY); if (fd < 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); return ERROR; } /* And just dump it byte for byte into stdout */ for (;;) { int nbytesread = read(fd, buffer, IOBUFFERSIZE); /* Check for read errors */ if (nbytesread < 0) { int errval = errno; /* EINTR is not an error (but will stop stop the cat) */ #ifndef CONFIG_DISABLE_SIGNALS if (errval == EINTR) { nsh_output(vtbl, g_fmtsignalrecvd, cmd); } else #endif { nsh_output(vtbl, g_fmtcmdfailed, cmd, "read", NSH_ERRNO_OF(errval)); } 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) { int errval = errno; /* EINTR is not an error (but will stop stop the cat) */ #ifndef CONFIG_DISABLE_SIGNALS if (errval == EINTR) { nsh_output(vtbl, g_fmtsignalrecvd, cmd); } else #endif { nsh_output(vtbl, g_fmtcmdfailed, cmd, "write", NSH_ERRNO); } ret = ERROR; break; } else { nbyteswritten += n; } } } /* Otherwise, it is the end of file */ else { break; } } (void)close(fd); return ret; }
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; }
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); }
int nsh_consolemain(int argc, char *argv[]) { FAR struct console_stdio_s *pstate = nsh_newconsole(); int ret; DEBUGASSERT(pstate); /* If we are using a USB serial console, then we will have to wait for the * USB to be connected to the host. */ #ifdef HAVE_USB_CONSOLE ret = nsh_usbconsole(); DEBUGASSERT(ret == OK); #endif /* Present a greeting */ fputs(g_nshgreeting, pstate->cn_outstream); fflush(pstate->cn_outstream); /* Execute the startup script */ #ifdef CONFIG_NSH_ROMFSETC (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH); #endif /* Then enter the command line parsing loop */ for (;;) { /* For the case of debugging the USB console... dump collected USB trace data */ nsh_usbtrace(); /* Display the prompt string */ fputs(g_nshprompt, pstate->cn_outstream); fflush(pstate->cn_outstream); /* Get the next line of input */ ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate), OUTSTREAM(pstate)); if (ret > 0) { /* Parse process the command */ (void)nsh_parse(&pstate->cn_vtbl, pstate->cn_line); fflush(pstate->cn_outstream); } /* Readline normally returns the number of characters read, * but will return 0 on end of file or a negative value * if an error occurs. Either will cause the session to * terminate. */ else { fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_consolemain", "readline", NSH_ERRNO_OF(-ret)); nsh_exit(&pstate->cn_vtbl, 1); } } /* Clean up. We do not get here, but this is necessary to keep some * compilers happy. But others will complain that this code is not * reachable. */ nsh_exit(&pstate->cn_vtbl, 0); return OK; }
int cmd_hexdump(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { uint8_t buffer[IOBUFFERSIZE]; char msg[32]; off_t position; int fd; int ret = OK; #ifdef CONFIG_NSH_CMDOPT_HEXDUMP off_t skip = 0; off_t count = 0xfffffff; off_t dumpbytes; int x; #endif /* Open the file for reading */ fd = open(argv[1], O_RDONLY); if (fd < 0) { nsh_output(vtbl, g_fmtcmdfailed, "hexdump", "open", NSH_ERRNO); return ERROR; } #ifdef CONFIG_NSH_CMDOPT_HEXDUMP for (x = 2; x < argc; x++) { if (strncmp(argv[x], "skip=", 5) == 0) { skip = atoi(&argv[x][5]); } else if (strncmp(argv[x], "count=", 6) == 0) { count = atoi(&argv[x][6]); } } #endif position = 0; for (;;) { int nbytesread = read(fd, buffer, IOBUFFERSIZE); /* Check for read errors */ if (nbytesread < 0) { int errval = errno; nsh_output(vtbl, g_fmtcmdfailed, "hexdump", "read", NSH_ERRNO_OF(errval)); ret = ERROR; break; } else if (nbytesread > 0) { #ifdef CONFIG_NSH_CMDOPT_HEXDUMP if (position < skip) { /* Skip bytes until we reach the skip point */ position += nbytesread; if (position > skip) { dumpbytes = position - skip; if (dumpbytes > count) { dumpbytes = count; } snprintf(msg, sizeof(msg), "%s at %08x", argv[1], skip); nsh_dumpbuffer(vtbl, msg, &buffer[nbytesread - (position-skip)], dumpbytes); if (count > dumpbytes) { count -= dumpbytes; } else { break; } } /* Don't print if we are in skip mode */ continue; } /* Limit dumpbuffer to count if less than a full buffer needed */ if (nbytesread > count) { nbytesread = count; } #endif snprintf(msg, sizeof(msg), "%s at %08x", argv[1], position); nsh_dumpbuffer(vtbl, msg, buffer, nbytesread); position += nbytesread; #ifdef CONFIG_NSH_CMDOPT_HEXDUMP if (count > nbytesread) { count -= nbytesread; } else { break; } #endif } else { break; // EOF } } (void)close(fd); return ret; }
static int cat_common(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, FAR const char *filename) { FAR char *buffer; int fd; int ret = OK; /* Open the file for reading */ fd = open(filename, O_RDONLY); if (fd < 0) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); return ERROR; } buffer = (FAR char *)malloc(IOBUFFERSIZE); if(buffer == NULL) { nsh_output(vtbl, g_fmtcmdfailed, cmd, "malloc", NSH_ERRNO); return ERROR; } /* And just dump it byte for byte into stdout */ for (;;) { int nbytesread = read(fd, buffer, IOBUFFERSIZE); /* Check for read errors */ if (nbytesread < 0) { int errval = errno; /* EINTR is not an error (but will stop stop the cat) */ #ifndef CONFIG_DISABLE_SIGNALS if (errval == EINTR) { nsh_output(vtbl, g_fmtsignalrecvd, cmd); } else #endif { nsh_output(vtbl, g_fmtcmdfailed, cmd, "read", NSH_ERRNO_OF(errval)); } 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) { int errval = errno; /* EINTR is not an error (but will stop stop the cat) */ #ifndef CONFIG_DISABLE_SIGNALS if (errval == EINTR) { nsh_output(vtbl, g_fmtsignalrecvd, cmd); } else #endif { nsh_output(vtbl, g_fmtcmdfailed, cmd, "write", NSH_ERRNO); } ret = ERROR; break; } else { nbyteswritten += n; } } } /* Otherwise, it is the end of file */ else { break; } } /* Make sure that the following NSH prompt appears on a new line. If the * file ends in a newline, then this will print an extra blank line * before the prompt, but that is preferable to the case where there is * no newline and the NSH prompt appears on the same line as the cat'ed * file. */ nsh_output(vtbl, "\n"); /* Close the input file and return the result */ (void)close(fd); free(buffer); return ret; }