From addae32212c5c7650148aadd422478bbffa66d7c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 10 Jan 2014 16:15:14 -0600 Subject: NSH parser: Separate logic that executes a command into a separate function --- apps/nshlib/nsh_parse.c | 821 ++++++++++++++++++++++++------------------------ 1 file changed, 415 insertions(+), 406 deletions(-) (limited to 'apps/nshlib/nsh_parse.c') diff --git a/apps/nshlib/nsh_parse.c b/apps/nshlib/nsh_parse.c index 061aec65e..3a944261a 100644 --- a/apps/nshlib/nsh_parse.c +++ b/apps/nshlib/nsh_parse.c @@ -229,6 +229,305 @@ static inline struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl, } #endif +/**************************************************************************** + * Name: nsh_saveresult + ****************************************************************************/ + +static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result) +{ + struct nsh_parser_s *np = &vtbl->np; + +#ifndef CONFIG_NSH_DISABLESCRIPT + if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF) + { + np->np_fail = false; + np->np_st[np->np_ndx].ns_ifcond = result; + return OK; + } + else +#endif + { + np->np_fail = result; + return result ? ERROR : OK; + } +} + +/**************************************************************************** + * Name: nsh_argument + ****************************************************************************/ + +static int nsh_execute(FAR struct nsh_vtbl_s *vtbl, + int argc, FAR char *argv[], + FAR const char *redirfile, int oflags) +{ + int fd = -1; + int ret; + + /* 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 does 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 built-in + * command was successfully started (although it may not have ran + * successfully). So certainly it is not an NSH command. + */ + + /* Save the result: success if 0; failure if 1 */ + + return nsh_saveresult(vtbl, ret != OK); + } + + /* No, not a file name command (or, at least, we were unable to start a + * program of that name). Maybe it is a built-in application or an NSH + * command. + */ + +#endif + + /* Does this command correspond to a built-in 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 built-in + * command was successfully started (although it may not have ran + * successfully). So certainly it is not an NSH command. + */ + + /* 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 + * built-in 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); + if (fd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "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, argv[0], "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, argv[0], "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", argv[0], 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_command will return: + * + * -1 (ERRROR) if the command was unsuccessful + * 0 (OK) if the command was successful + */ + + ret = nsh_command(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); +} + /**************************************************************************** * Name: nsh_argument ****************************************************************************/ @@ -348,7 +647,7 @@ static char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr) } /* Not a built-in? Return the value of the environment variable - * with this name + * with this name. */ else @@ -544,29 +843,6 @@ errout: } #endif -/**************************************************************************** - * Name: nsh_saveresult - ****************************************************************************/ - -static inline int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result) -{ - struct nsh_parser_s *np = &vtbl->np; - -#ifndef CONFIG_NSH_DISABLESCRIPT - if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF) - { - np->np_fail = false; - np->np_st[np->np_ndx].ns_ifcond = result; - return OK; - } - else -#endif - { - np->np_fail = result; - return result ? ERROR : OK; - } -} - /**************************************************************************** * Name: nsh_nice ****************************************************************************/ @@ -610,440 +886,173 @@ static inline int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, } } - /* Return the real command name */ - - *ppcmd = cmd; - } - } - - return OK; -} -#endif - -/**************************************************************************** - * Name: nsh_parse_command - * - * Description: - * This function parses and executes one NSH command from the command line. - * - ****************************************************************************/ - -static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR 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 - * 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 does 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 built-in - * 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 file name command (or, at least, we were unable to start a - * program of that name). Maybe it is a built-in application or an NSH - * command. - */ - -#endif - - /* Does this command correspond to a built-in 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 built-in - * 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 */ + /* Return the real command name */ - if (redirfile) - { - nsh_freefullpath(redirfile); + *ppcmd = cmd; } + } + + return OK; +} #endif - /* Save the result: success if 0; failure if 1 */ +/**************************************************************************** + * Name: nsh_parse_command + * + * Description: + * This function parses and executes one NSH command from the command line. + * + ****************************************************************************/ - return nsh_saveresult(vtbl, ret != OK); - } +static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR 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; +#endif + int argc; + int ret; - /* No, not a built in command (or, at least, we were unable to start a - * built-in command of that name). Treat it like an NSH command. - */ + /* 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 - /* Redirected output? */ + vtbl->np.np_redirect = false; +#endif - 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. - */ + /* Parse out the command at the beginning of the line */ - fd = open(redirfile, oflags, 0666); - nsh_freefullpath(redirfile); - redirfile = NULL; + saveptr = cmdline; + cmd = nsh_argument(vtbl, &saveptr); - if (fd < 0) - { - nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); - goto errout; - } + /* Handler if-then-else-fi */ + +#ifndef CONFIG_NSH_DISABLESCRIPT + if (nsh_ifthenelse(vtbl, &cmd, &saveptr) != 0) + { + return nsh_saveresult(vtbl, true); } #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. - */ + /* Handle nice */ #ifndef CONFIG_NSH_DISABLEBG - if (vtbl->np.np_bg) + if (nsh_nice(vtbl, &cmd, &saveptr) != 0) { - 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); - } + return nsh_saveresult(vtbl, true); + } #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; - } + /* Check if any command was provided -OR- if command processing is + * currently disabled. + */ - /* Set up the thread attributes */ +#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. + */ - (void)pthread_attr_init(&attr); - (void)pthread_attr_setschedpolicy(&attr, SCHED_NSH); - (void)pthread_attr_setschedparam(&attr, ¶m); + return OK; + } - /* Execute the command as a separate thread at the appropriate priority */ + /* 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 + * argv[argc-1]: Possibly '&' + * argv[argc]: NULL terminating pointer + * + * Maximum size is CONFIG_NSH_MAXARGUMENTS+5 + */ - ret = pthread_create(&thread, &attr, nsh_child, (pthread_addr_t)args); - if (ret != 0) + argv[0] = cmd; + for (argc = 1; argc < MAX_ARGV_ENTRIES-1; argc++) + { + argv[argc] = nsh_argument(vtbl, &saveptr); + if (!argv[argc]) { - nsh_output(vtbl, g_fmtcmdfailed, cmd, "pthread_create", NSH_ERRNO_OF(ret)); - nsh_releaseargs(args); - nsh_release(bkgvtbl); - goto errout; + break; } + } - /* Detach from the pthread since we are not going to join with it. - * Otherwise, we would have a memory leak. - */ + argv[argc] = NULL; - (void)pthread_detach(thread); + /* Check if the command should run in background */ - nsh_output(vtbl, "%s [%d:%d]\n", cmd, thread, param.sched_priority); +#ifndef CONFIG_NSH_DISABLEBG + if (argc > 1 && strcmp(argv[argc-1], "&") == 0) + { + vtbl->np.np_bg = true; + argv[argc-1] = NULL; + argc--; } - else #endif - { + #if CONFIG_NFILE_STREAMS > 0 - uint8_t save[SAVE_SIZE]; + /* Check if the output was re-directed using > or >> */ - /* Handle redirection of output via a file descriptor */ + if (argc > 2) + { + /* Check for redirection to a new file */ - if (vtbl->np.np_redirect) + if (strcmp(argv[argc-2], g_redirect1) == 0) { - nsh_redirect(vtbl, fd, save); + vtbl->np.np_redirect = true; + oflags = O_WRONLY|O_CREAT|O_TRUNC; + redirfile = nsh_getfullpath(vtbl, argv[argc-1]); + argc -= 2; } -#endif - /* Then execute the command in "foreground" -- i.e., while the user waits - * for the next prompt. nsh_command will return: - * - * -1 (ERRROR) if the command was unsuccessful - * 0 (OK) if the command was successful - */ - - ret = nsh_command(vtbl, argc, argv); - -#if CONFIG_NFILE_STREAMS > 0 - /* Restore the original output. Undirect will close the redirection - * file descriptor. - */ + /* Check for redirection by appending to an existing file */ - if (vtbl->np.np_redirect) + else if (strcmp(argv[argc-2], g_redirect2) == 0) { - nsh_undirect(vtbl, save); + vtbl->np.np_redirect = true; + oflags = O_WRONLY|O_CREAT|O_APPEND; + redirfile = nsh_getfullpath(vtbl, argv[argc-1]); + argc -= 2; } + } #endif - /* Mark errors so that it is possible to test for non-zero return values - * in nsh scripts. - */ + /* Check if the maximum number of arguments was exceeded */ - if (ret < 0) - { - goto errout; - } + if (argc > CONFIG_NSH_MAXARGUMENTS) + { + nsh_output(vtbl, g_fmttoomanyargs, cmd); } - /* Return success if the command succeeded (or at least, starting of the - * command task succeeded). - */ + /* Then execute the command */ - return nsh_saveresult(vtbl, false); + ret = nsh_execute(vtbl, argc, argv, redirfile, oflags); + + /* Free any allocated resources */ -#ifndef CONFIG_NSH_DISABLEBG -errout_with_redirect: #if CONFIG_NFILE_STREAMS > 0 - if (vtbl->np.np_redirect) + /* Free the redirected output file path */ + + if (redirfile) { - close(fd); + nsh_freefullpath(redirfile); } #endif -#endif -errout: - return nsh_saveresult(vtbl, true); + return ret; } /**************************************************************************** -- cgit v1.2.3