+++ /dev/null
-Description: Upstream changes introduced in version 3.7-10
- This patch has been created by dpkg-source during the package build.
- Here's the last changelog entry, hopefully it gives details on why
- those changes were made:
- .
- sash (3.7-10) unstable; urgency=low
- .
- * Switch to 3.0 (quilt) as the source format and convert patches.
- * Fix up debian/patches/touch_error_handling to actually update the
- timestamp of the file, something that has been broken for more than
- ten years.
- * Add kFreeBSD build fixes from Axel Beckert. Closes: #565539
- * When exiting the shell, use the exit status of the last command as our
- exit status. Closes: #281728
- .
- The person named in the Author field signed this changelog entry.
-Author: Tollef Fog Heen <tfheen@debian.org>
-Bug-Debian: http://bugs.debian.org/281728
-Bug-Debian: http://bugs.debian.org/565539
-
----
-The information above should follow the Patch Tagging Guidelines, please
-checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
-are templates for supplementary fields that you might want to add:
-
-Origin: <vendor|upstream|other>, <url of original patch>
-Bug: <url in upstream bugtracker>
-Bug-Debian: http://bugs.debian.org/<bugnumber>
-Forwarded: <no|not-needed|url proving that it has been forwarded>
-Reviewed-By: <name and email of someone who approved the patch>
-Last-Update: <YYYY-MM-DD>
-
---- /dev/null
-+++ sash-3.7/sash.c.old
-@@ -0,0 +1,1289 @@
-+/*
-+ * Copyright (c) 2004 by David I. Bell
-+ * Permission is granted to use, distribute, or modify this source,
-+ * provided that this copyright notice remains intact.
-+ *
-+ * Stand-alone shell for system maintainance for Linux.
-+ * This program should NOT be built using shared libraries.
-+ */
-+
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <signal.h>
-+#include <errno.h>
-+
-+#include "sash.h"
-+
-+
-+static const char * const version = "3.7";
-+
-+
-+/*
-+ * The special maximum argument value which means that there is
-+ * no limit to the number of arguments on the command line.
-+ */
-+#define INFINITE_ARGS 0x7fffffff
-+
-+
-+/*
-+ * One entry of the command table.
-+ */
-+typedef struct
-+{
-+ const char * name;
-+ void (*func)(int argc, const char ** argv);
-+ int minArgs;
-+ int maxArgs;
-+ const char * description;
-+ const char * usage;
-+} CommandEntry;
-+
-+
-+/*
-+ * The table of built-in commands.
-+ * This is terminated wih an entry containing NULL values.
-+ */
-+static const CommandEntry commandEntryTable[] =
-+{
-+ {
-+ "alias", do_alias, 1, INFINITE_ARGS,
-+ "Define a command alias",
-+ "[name [command]]"
-+ },
-+
-+ {
-+ "aliasall", do_aliasall, 1, 1,
-+ "Define aliases for all of the build-in commands",
-+ ""
-+ },
-+
-+ {
-+ "-ar", do_ar, 3, INFINITE_ARGS,
-+ "Extract or list files from an AR file",
-+ "[txp]v arFileName fileName ..."
-+ },
-+
-+ {
-+ "cd", do_cd, 1, 2,
-+ "Change current directory",
-+ "[dirName]"
-+ },
-+
-+#if HAVE_LINUX_ATTR
-+ {
-+ "-chattr", do_chattr, 3, INFINITE_ARGS,
-+ "Change ext2 file attributes",
-+ "[+i] [-i] [+a] [-a] fileName ..."
-+ },
-+#endif
-+
-+ {
-+ "-chgrp", do_chgrp, 3, INFINITE_ARGS,
-+ "Change the group id of some files",
-+ "gid fileName ..."
-+ },
-+
-+ {
-+ "-chmod", do_chmod, 3, INFINITE_ARGS,
-+ "Change the protection of some files",
-+ "mode fileName ..."
-+ },
-+
-+ {
-+ "-chown", do_chown, 3, INFINITE_ARGS,
-+ "Change the owner id of some files",
-+ "uid fileName ..."
-+ },
-+
-+ {
-+ "-cmp", do_cmp, 3, 3,
-+ "Compare two files for equality",
-+ "fileName1 fileName2"
-+ },
-+
-+ {
-+ "-cp", do_cp, 3, INFINITE_ARGS,
-+ "Copy files",
-+ "srcName ... destName"
-+ },
-+
-+ {
-+ "-dd", do_dd, 3, INFINITE_ARGS,
-+ "Copy data between two files",
-+ "if=name of=name [bs=n] [count=n] [skip=n] [seek=n]"
-+ },
-+
-+ {
-+ "-echo", do_echo, 1, INFINITE_ARGS,
-+ "Echo the arguments",
-+ "[args] ..."
-+ },
-+
-+ {
-+ "-ed", do_ed, 1, 2,
-+ "Edit a fileName using simple line mode commands",
-+ "[fileName]"
-+ },
-+
-+ {
-+ "exec", do_exec, 2, INFINITE_ARGS,
-+ "Execute another program in place of this sash process",
-+ "fileName [args]"
-+ },
-+
-+ {
-+ "exit", do_exit, 1, 2,
-+ "Exit from sash",
-+ "[exit value]"
-+ },
-+
-+ {
-+ "-file", do_file, 1, INFINITE_ARGS,
-+ "Describe information about files",
-+ "fileName ..."
-+ },
-+
-+ {
-+ "-find", do_find, 2, INFINITE_ARGS,
-+ "Find files in a directory tree meeting some conditions",
-+ "dirName [-xdev] [-type chars] [-name pattern] [-size minSize]"
-+ },
-+
-+ {
-+ "-grep", do_grep, 3, INFINITE_ARGS,
-+ "Look for lines containing a word in some files",
-+ "[-in] word fileName ..."
-+ },
-+
-+#if HAVE_GZIP
-+ {
-+ "-gunzip", do_gunzip, 2, INFINITE_ARGS,
-+ "Uncompress files which were saved in GZIP or compress format",
-+ "fileName ... [-o outputPath]"
-+ },
-+
-+ {
-+ "-gzip", do_gzip, 2, INFINITE_ARGS,
-+ "Compress files into GZIP format",
-+ "fileName ... [-o outputPath]"
-+ },
-+#endif
-+
-+ {
-+ "help", do_help, 1, 2,
-+ "Print help about a command",
-+ "[word]"
-+ },
-+
-+ {
-+ "-kill", do_kill, 2, INFINITE_ARGS,
-+ "Send a signal to the specified process",
-+ "[-sig] pid ..."
-+ },
-+
-+ {
-+ "-ln", do_ln, 3, INFINITE_ARGS,
-+ "Link one fileName to another",
-+ "[-s] srcName ... destName"
-+ },
-+
-+ {
-+ "-ls", do_ls, 1, INFINITE_ARGS,
-+ "List information about files or directories",
-+ "[-lidFC] fileName ..."
-+ },
-+
-+#if HAVE_LINUX_ATTR
-+ {
-+ "-lsattr", do_lsattr, 2, INFINITE_ARGS,
-+ "List ext2 file attributes",
-+ "fileName ..."
-+ },
-+#endif
-+
-+ {
-+ "-mkdir", do_mkdir, 2, INFINITE_ARGS,
-+ "Create a directory",
-+ "dirName ..."
-+ },
-+
-+ {
-+ "-mknod", do_mknod, 5, 5,
-+ "Create a special type of file",
-+ "fileName type major minor"
-+ },
-+
-+ {
-+ "-more", do_more, 2, INFINITE_ARGS,
-+ "Type file contents page by page",
-+ "fileName ..."
-+ },
-+
-+ {
-+ "-mount", do_mount, 3, INFINITE_ARGS,
-+ "Mount or remount a filesystem on a directory",
-+#if HAVE_LINUX_MOUNT
-+ "[-t type] [-r] [-s] [-e] [-m] devName dirName"
-+#elif HAVE_BSD_MOUNT
-+ "[-t type] [-r] [-s] [-e] devName dirName"
-+#else
-+ "[-t type] devName dirName"
-+#endif
-+ },
-+
-+ {
-+ "-mv", do_mv, 3, INFINITE_ARGS,
-+ "Move or rename files",
-+ "srcName ... destName"
-+ },
-+
-+ {
-+ "-printenv", do_printenv, 1, 2,
-+ "Print environment variables",
-+ "[name]"
-+ },
-+
-+ {
-+ "prompt", do_prompt, 2, INFINITE_ARGS,
-+ "Set the prompt string for sash",
-+ "string"
-+ },
-+
-+ {
-+ "-pwd", do_pwd, 1, 1,
-+ "Print the current working directory",
-+ ""
-+ },
-+
-+ {
-+ "quit", do_exit, 1, 1,
-+ "Exit from sash",
-+ ""
-+ },
-+
-+ {
-+ "-rm", do_rm, 2, INFINITE_ARGS,
-+ "Remove the specified files",
-+ "fileName ..."
-+ },
-+
-+ {
-+ "-rmdir", do_rmdir, 2, INFINITE_ARGS,
-+ "Remove the specified empty directories",
-+ "dirName ..."
-+ },
-+
-+ {
-+ "setenv", do_setenv, 3, 3,
-+ "Set an environment variable value",
-+ "name value"
-+ },
-+
-+ {
-+ "source", do_source, 2, 2,
-+ "Read commands from the specified file",
-+ "fileName"
-+ },
-+
-+ {
-+ "-sum", do_sum, 2, INFINITE_ARGS,
-+ "Calculate checksums of the specified files",
-+ "fileName ..."
-+ },
-+
-+ {
-+ "-sync", do_sync, 1, 1,
-+ "Sync the disks to force cached data to them",
-+ ""
-+ },
-+
-+ {
-+ "-tar", do_tar, 2, INFINITE_ARGS,
-+ "Create, extract, or list files from a TAR file",
-+ "[cxtv]f tarFileName fileName ..."
-+ },
-+
-+ {
-+ "-touch", do_touch, 2, INFINITE_ARGS,
-+ "Update times or create the specified files",
-+ "fileName ..."
-+ },
-+
-+ {
-+ "umask", do_umask, 1, 2,
-+ "Set the umask value for file protections",
-+ "[mask]"
-+ },
-+
-+ {
-+#if HAVE_BSD_MOUNT
-+ "-umount", do_umount, 2, 3,
-+ "Unmount a filesystem",
-+ "[-f] fileName"
-+#else
-+ "-umount", do_umount, 2, 2,
-+ "Unmount a filesystem",
-+ "fileName"
-+#endif
-+ },
-+
-+ {
-+ "unalias", do_unalias, 2, 2,
-+ "Remove a command alias",
-+ "name"
-+ },
-+
-+ {
-+ "-where", do_where, 2, 2,
-+ "Type the location of a program",
-+ "program"
-+ },
-+
-+ {
-+ NULL, 0, 0, 0,
-+ NULL,
-+ NULL
-+ }
-+};
-+
-+
-+/*
-+ * The definition of an command alias.
-+ */
-+typedef struct
-+{
-+ char * name;
-+ char * value;
-+} Alias;
-+
-+
-+/*
-+ * Local data.
-+ */
-+static Alias * aliasTable;
-+static int aliasCount;
-+
-+static FILE * sourcefiles[MAX_SOURCE];
-+static int sourceCount;
-+
-+static BOOL intCrlf = TRUE;
-+static char * prompt;
-+
-+
-+/*
-+ * Local procedures.
-+ */
-+static void catchInt(int);
-+static void catchQuit(int);
-+static int readFile(const char * name);
-+static int command(const char * cmd);
-+static BOOL tryBuiltIn(const char * cmd);
-+static int runCmd(const char * cmd);
-+static void childProcess(const char * cmd);
-+static void showPrompt(void);
-+static void usage(void);
-+static Alias * findAlias(const char * name);
-+
-+
-+/*
-+ * Global interrupt flag.
-+ */
-+BOOL intFlag;
-+
-+
-+int
-+main(int argc, const char ** argv)
-+{
-+ const char * cp;
-+ const char * singleCommand;
-+ const char * commandFile;
-+ BOOL quietFlag;
-+ BOOL aliasFlag;
-+ BOOL interactiveFlag;
-+ char buf[PATH_LEN];
-+
-+ singleCommand = NULL;
-+ commandFile = NULL;
-+ quietFlag = FALSE;
-+ aliasFlag = FALSE;
-+ interactiveFlag = FALSE;
-+
-+ /*
-+ * Look for options.
-+ */
-+ argv++;
-+ argc--;
-+
-+ while ((argc > 0) && (**argv == '-'))
-+ {
-+ cp = *argv++ + 1;
-+ argc--;
-+
-+ while (*cp) switch (*cp++)
-+ {
-+ case '-':
-+ /*
-+ * Ignore. This is so that we can be
-+ * run from login.
-+ */
-+ break;
-+ case 'c':
-+ /*
-+ * Execute specified command.
-+ */
-+ if ((argc != 1) || singleCommand || interactiveFlag)
-+ usage();
-+
-+ singleCommand = *argv++;
-+ argc--;
-+
-+ break;
-+
-+ case 'f':
-+ /*
-+ * Execute commands from file.
-+ * This is used for sash script files.
-+ * The quiet flag is also set.
-+ */
-+ if ((argc != 1) || commandFile)
-+ usage();
-+
-+ quietFlag = TRUE;
-+ commandFile = *argv++;
-+ argc--;
-+
-+ break;
-+
-+ case 'i':
-+ /*
-+ * Be an interactive shell
-+ * ..is a no-op, but some contexts require this
-+ * ..interactiveFlag is to avoid -ic as a legacy
-+ */
-+ if (singleCommand)
-+ usage();
-+
-+ interactiveFlag = TRUE;
-+ break;
-+
-+ case 'p':
-+ /*
-+ * Set the prompt string.
-+ */
-+ if ((argc <= 0) || (**argv == '-'))
-+ usage();
-+
-+ if (prompt)
-+ free(prompt);
-+
-+ prompt = strdup(*argv++);
-+ argc--;
-+
-+ break;
-+
-+ case 'q':
-+ quietFlag = TRUE;
-+ break;
-+
-+ case 'a':
-+ aliasFlag = TRUE;
-+ break;
-+
-+ case 'h':
-+ case '?':
-+ usage();
-+ break;
-+
-+ default:
-+ fprintf(stderr, "Unknown option -%c\n", cp[-1]);
-+
-+ return 1;
-+ }
-+ }
-+
-+ /*
-+ * No more arguments are allowed.
-+ */
-+ if (argc > 0)
-+ usage();
-+
-+ /*
-+ * Default our path if it is not set.
-+ */
-+ if (getenv("PATH") == NULL)
-+ putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc");
-+
-+ /*
-+ * If the alias flag is set then define all aliases.
-+ */
-+ if (aliasFlag)
-+ do_aliasall(0, NULL);
-+
-+ /*
-+ * If we are to execute a single command, then do so and exit.
-+ */
-+ if (singleCommand)
-+ {
-+ return command(singleCommand);
-+ }
-+
-+ /*
-+ * Print a hello message unless we are told to be silent.
-+ */
-+ if (!quietFlag && isatty(STDIN))
-+ {
-+ printf("Stand-alone shell (version %s)\n", version);
-+
-+ if (aliasFlag)
-+ printf("Built-in commands are aliased to standard commands\n");
-+ }
-+
-+ signal(SIGINT, catchInt);
-+ signal(SIGQUIT, catchQuit);
-+
-+ /*
-+ * Execute the user's alias file if present.
-+ */
-+ cp = getenv("HOME");
-+
-+ if (cp)
-+ {
-+ strcpy(buf, cp);
-+ strcat(buf, "/");
-+ strcat(buf, ".aliasrc");
-+
-+ if ((access(buf, 0) == 0) || (errno != ENOENT))
-+ readFile(buf);
-+ }
-+
-+ /*
-+ * Read commands from stdin or from a command file.
-+ */
-+ return readFile(commandFile);
-+
-+}
-+
-+
-+/*
-+ * Read commands from the specified file.
-+ * A null name pointer indicates to read from stdin.
-+ */
-+static int
-+readFile(const char * name)
-+{
-+ FILE * fp;
-+ int cc;
-+ BOOL ttyFlag;
-+ char buf[CMD_LEN];
-+ int r = 0;
-+
-+ if (sourceCount >= MAX_SOURCE)
-+ {
-+ fprintf(stderr, "Too many source files\n");
-+
-+ return 1;
-+ }
-+
-+ fp = stdin;
-+
-+ if (name)
-+ {
-+ fp = fopen(name, "r");
-+
-+ if (fp == NULL)
-+ {
-+ perror(name);
-+
-+ return 1;
-+ }
-+ }
-+
-+ sourcefiles[sourceCount++] = fp;
-+
-+ ttyFlag = isatty(fileno(fp));
-+
-+ while (TRUE)
-+ {
-+ if (ttyFlag)
-+ showPrompt();
-+
-+ if (intFlag && !ttyFlag && (fp != stdin))
-+ {
-+ fclose(fp);
-+ sourceCount--;
-+
-+ return 1;
-+ }
-+
-+ if (fgets(buf, CMD_LEN - 1, fp) == NULL)
-+ {
-+ if (ferror(fp) && (errno == EINTR))
-+ {
-+ clearerr(fp);
-+
-+ continue;
-+ }
-+
-+ break;
-+ }
-+
-+ cc = strlen(buf);
-+
-+ if (buf[cc - 1] == '\n')
-+ cc--;
-+
-+ while ((cc > 0) && isBlank(buf[cc - 1]))
-+ cc--;
-+
-+ buf[cc] = '\0';
-+
-+ r = command(buf);
-+ }
-+
-+ if (ferror(fp))
-+ {
-+ perror("Reading command line");
-+
-+ if (fp == stdin)
-+ exit(1);
-+ }
-+
-+ clearerr(fp);
-+
-+ if (fp != stdin)
-+ fclose(fp);
-+
-+ sourceCount--;
-+ return r;
-+}
-+
-+
-+/*
-+ * Parse and execute one null-terminated command line string.
-+ * This breaks the command line up into words, checks to see if the
-+ * command is an alias, and expands wildcards.
-+ */
-+static int
-+command(const char * cmd)
-+{
-+ const char * endCmd;
-+ const Alias * alias;
-+ char newCommand[CMD_LEN];
-+ char cmdName[CMD_LEN];
-+
-+ /*
-+ * Rest the interrupt flag and free any memory chunks that
-+ * were allocated by the previous command.
-+ */
-+ intFlag = FALSE;
-+
-+ freeChunks();
-+
-+ /*
-+ * Skip leading blanks.
-+ */
-+ while (isBlank(*cmd))
-+ cmd++;
-+
-+ /*
-+ * If the command is empty or is a comment then ignore it.
-+ */
-+ if ((*cmd == '\0') || (*cmd == '#'))
-+ return 0;
-+
-+ /*
-+ * Look for the end of the command name and then copy the
-+ * command name to a buffer so we can null terminate it.
-+ */
-+ endCmd = cmd;
-+
-+ while (*endCmd && !isBlank(*endCmd))
-+ endCmd++;
-+
-+ memcpy(cmdName, cmd, endCmd - cmd);
-+
-+ cmdName[endCmd - cmd] = '\0';
-+
-+ /*
-+ * Search for the command name in the alias table.
-+ * If it is found, then replace the command name with
-+ * the alias value, and append the current command
-+ * line arguments to that.
-+ */
-+ alias = findAlias(cmdName);
-+
-+ if (alias)
-+ {
-+ strcpy(newCommand, alias->value);
-+ strcat(newCommand, endCmd);
-+
-+ cmd = newCommand;
-+ }
-+
-+ /*
-+ * Now look for the command in the builtin table, and execute
-+ * the command if found.
-+ */
-+ if (tryBuiltIn(cmd))
-+ return 0; /* This is a blatant lie */
-+
-+ /*
-+ * The command is not a built-in, so run the program along
-+ * the PATH list.
-+ */
-+ return runCmd(cmd);
-+}
-+
-+
-+/*
-+ * Try to execute a built-in command.
-+ * Returns TRUE if the command is a built in, whether or not the
-+ * command succeeds. Returns FALSE if this is not a built-in command.
-+ */
-+static BOOL
-+tryBuiltIn(const char * cmd)
-+{
-+ const char * endCmd;
-+ const CommandEntry * entry;
-+ int argc;
-+ const char ** argv;
-+ char cmdName[CMD_LEN];
-+
-+ /*
-+ * Look for the end of the command name and then copy the
-+ * command name to a buffer so we can null terminate it.
-+ */
-+ endCmd = cmd;
-+
-+ while (*endCmd && !isBlank(*endCmd))
-+ endCmd++;
-+
-+ memcpy(cmdName, cmd, endCmd - cmd);
-+
-+ cmdName[endCmd - cmd] = '\0';
-+
-+ /*
-+ * Search the command table looking for the command name.
-+ */
-+ for (entry = commandEntryTable; entry->name != NULL; entry++)
-+ {
-+ if (strcmp(entry->name, cmdName) == 0)
-+ break;
-+ }
-+
-+ /*
-+ * If the command is not a built-in, return indicating that.
-+ */
-+ if (entry->name == NULL)
-+ return FALSE;
-+
-+ /*
-+ * The command is a built-in.
-+ * Break the command up into arguments and expand wildcards.
-+ */
-+ if (!makeArgs(cmd, &argc, &argv))
-+ return TRUE;
-+
-+ /*
-+ * Give a usage string if the number of arguments is too large
-+ * or too small.
-+ */
-+ if ((argc < entry->minArgs) || (argc > entry->maxArgs))
-+ {
-+ fprintf(stderr, "usage: %s %s\n", entry->name, entry->usage);
-+
-+ return TRUE;
-+ }
-+
-+ /*
-+ * Call the built-in function with the argument list.
-+ */
-+ entry->func(argc, argv);
-+
-+ return TRUE;
-+}
-+
-+
-+/*
-+ * Execute the specified command either by forking and executing
-+ * the program ourself, or else by using the shell.
-+ */
-+static int
-+runCmd(const char * cmd)
-+{
-+ const char * cp;
-+ BOOL magic;
-+ pid_t pid;
-+ int status;
-+
-+ /*
-+ * Check the command for any magic shell characters
-+ * except for quoting.
-+ */
-+ magic = FALSE;
-+
-+ for (cp = cmd; *cp; cp++)
-+ {
-+ if ((*cp >= 'a') && (*cp <= 'z'))
-+ continue;
-+
-+ if ((*cp >= 'A') && (*cp <= 'Z'))
-+ continue;
-+
-+ if (isDecimal(*cp))
-+ continue;
-+
-+ if (isBlank(*cp))
-+ continue;
-+
-+ if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
-+ (*cp == '+') || (*cp == '=') || (*cp == '_') ||
-+ (*cp == ':') || (*cp == ',') || (*cp == '\'') ||
-+ (*cp == '"'))
-+ {
-+ continue;
-+ }
-+
-+ magic = TRUE;
-+ }
-+
-+ /*
-+ * If there were any magic characters used then run the
-+ * command using the shell.
-+ */
-+ if (magic)
-+ {
-+ return system(cmd);
-+ }
-+
-+ /*
-+ * No magic characters were in the command, so we can do the fork
-+ * and exec ourself.
-+ */
-+ pid = fork();
-+
-+ if (pid < 0)
-+ {
-+ perror("fork failed");
-+
-+ return -1;
-+ }
-+
-+ /*
-+ * If we are the child process, then go execute the program.
-+ */
-+ if (pid == 0)
-+ childProcess(cmd);
-+
-+ /*
-+ * We are the parent process.
-+ * Wait for the child to complete.
-+ */
-+ status = 0;
-+ intCrlf = FALSE;
-+
-+ while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR))
-+ ;
-+
-+ intCrlf = TRUE;
-+
-+ if (pid < 0)
-+ {
-+ fprintf(stderr, "Error from waitpid: %s", strerror(errno));
-+
-+ return -1;
-+ }
-+
-+ if (WIFSIGNALED(status))
-+ {
-+ fprintf(stderr, "pid %ld: killed by signal %d\n",
-+ (long) pid, WTERMSIG(status));
-+ }
-+ return WEXITSTATUS(status);
-+}
-+
-+
-+/*
-+ * Here as the child process to try to execute the command.
-+ * This is only called if there are no meta-characters in the command.
-+ * This procedure never returns.
-+ */
-+static void
-+childProcess(const char * cmd)
-+{
-+ const char ** argv;
-+ int argc;
-+
-+ /*
-+ * Close any extra file descriptors we have opened.
-+ */
-+ while (--sourceCount >= 0)
-+ {
-+ if (sourcefiles[sourceCount] != stdin)
-+ fclose(sourcefiles[sourceCount]);
-+ }
-+
-+ /*
-+ * Break the command line up into individual arguments.
-+ * If this fails, then run the shell to execute the command.
-+ */
-+ if (!makeArgs(cmd, &argc, &argv))
-+ {
-+ system(cmd);
-+ exit(0);
-+ }
-+
-+ /*
-+ * Try to execute the program directly.
-+ */
-+ execvp(argv[0], (char **) argv);
-+
-+ /*
-+ * The exec failed, so try to run the command using the shell
-+ * in case it is a shell script.
-+ */
-+ if (errno == ENOEXEC)
-+ {
-+ system(cmd);
-+ exit(0);
-+ }
-+
-+ /*
-+ * There was something else wrong, complain and exit.
-+ */
-+ perror(argv[0]);
-+ exit(1);
-+}
-+
-+
-+void
-+do_help(int argc, const char ** argv)
-+{
-+ const CommandEntry * entry;
-+ const char * str;
-+
-+ str = NULL;
-+
-+ if (argc == 2)
-+ str = argv[1];
-+
-+ /*
-+ * Check for an exact match, in which case describe the program.
-+ */
-+ if (str)
-+ {
-+ for (entry = commandEntryTable; entry->name; entry++)
-+ {
-+ if (strcmp(str, entry->name) == 0)
-+ {
-+ printf("%s\n", entry->description);
-+
-+ printf("usage: %s %s\n", entry->name,
-+ entry->usage);
-+
-+ return;
-+ }
-+ }
-+ }
-+
-+ /*
-+ * Print short information about commands which contain the
-+ * specified word.
-+ */
-+ for (entry = commandEntryTable; entry->name; entry++)
-+ {
-+ if ((str == NULL) || (strstr(entry->name, str) != NULL) ||
-+ (strstr(entry->usage, str) != NULL))
-+ {
-+ printf("%-10s %s\n", entry->name, entry->usage);
-+ }
-+ }
-+}
-+
-+
-+void
-+do_alias(int argc, const char ** argv)
-+{
-+ const char * name;
-+ char * value;
-+ Alias * alias;
-+ int count;
-+ char buf[CMD_LEN];
-+
-+ if (argc < 2)
-+ {
-+ count = aliasCount;
-+
-+ for (alias = aliasTable; count-- > 0; alias++)
-+ printf("%s\t%s\n", alias->name, alias->value);
-+
-+ return;
-+ }
-+
-+ name = argv[1];
-+
-+ if (argc == 2)
-+ {
-+ alias = findAlias(name);
-+
-+ if (alias)
-+ printf("%s\n", alias->value);
-+ else
-+ fprintf(stderr, "Alias \"%s\" is not defined\n", name);
-+
-+ return;
-+ }
-+
-+ if (strcmp(name, "alias") == 0)
-+ {
-+ fprintf(stderr, "Cannot alias \"alias\"\n");
-+
-+ return;
-+ }
-+
-+ if (!makeString(argc - 2, argv + 2, buf, CMD_LEN))
-+ return;
-+
-+ value = malloc(strlen(buf) + 1);
-+
-+ if (value == NULL)
-+ {
-+ fprintf(stderr, "No memory for alias value\n");
-+
-+ return;
-+ }
-+
-+ strcpy(value, buf);
-+
-+ alias = findAlias(name);
-+
-+ if (alias)
-+ {
-+ free(alias->value);
-+ alias->value = value;
-+
-+ return;
-+ }
-+
-+ if ((aliasCount % ALIAS_ALLOC) == 0)
-+ {
-+ count = aliasCount + ALIAS_ALLOC;
-+
-+ if (aliasTable)
-+ {
-+ alias = (Alias *) realloc(aliasTable,
-+ sizeof(Alias) * count);
-+ }
-+ else
-+ alias = (Alias *) malloc(sizeof(Alias) * count);
-+
-+ if (alias == NULL)
-+ {
-+ free(value);
-+ fprintf(stderr, "No memory for alias table\n");
-+
-+ return;
-+ }
-+
-+ aliasTable = alias;
-+ }
-+
-+ alias = &aliasTable[aliasCount];
-+
-+ alias->name = malloc(strlen(name) + 1);
-+
-+ if (alias->name == NULL)
-+ {
-+ free(value);
-+ fprintf(stderr, "No memory for alias name\n");
-+
-+ return;
-+ }
-+
-+ strcpy(alias->name, name);
-+ alias->value = value;
-+ aliasCount++;
-+}
-+
-+
-+/*
-+ * Build aliases for all of the built-in commands which start with a dash,
-+ * using the names without the dash.
-+ */
-+void
-+do_aliasall(int argc, const char **argv)
-+{
-+ const CommandEntry * entry;
-+ const char * name;
-+ const char * newArgv[4];
-+
-+ for (entry = commandEntryTable; entry->name; entry++)
-+ {
-+ name = entry->name;
-+
-+ if (*name != '-')
-+ continue;
-+
-+ newArgv[0] = "alias";
-+ newArgv[1] = name + 1;
-+ newArgv[2] = name;
-+ newArgv[3] = NULL;
-+
-+ do_alias(3, newArgv);
-+ }
-+}
-+
-+
-+/*
-+ * Look up an alias name, and return a pointer to it.
-+ * Returns NULL if the name does not exist.
-+ */
-+static Alias *
-+findAlias(const char * name)
-+{
-+ Alias * alias;
-+ int count;
-+
-+ count = aliasCount;
-+
-+ for (alias = aliasTable; count-- > 0; alias++)
-+ {
-+ if (strcmp(name, alias->name) == 0)
-+ return alias;
-+ }
-+
-+ return NULL;
-+}
-+
-+
-+void
-+do_source(int argc, const char ** argv)
-+{
-+ readFile(argv[1]);
-+}
-+
-+
-+void
-+do_exec(int argc, const char ** argv)
-+{
-+ const char * name;
-+
-+ name = argv[1];
-+
-+ while (--sourceCount >= 0)
-+ {
-+ if (sourcefiles[sourceCount] != stdin)
-+ fclose(sourcefiles[sourceCount]);
-+ }
-+
-+ argv[argc] = NULL;
-+
-+ execvp(name, (char **) argv + 1);
-+ perror(name);
-+}
-+
-+
-+void
-+do_prompt(int argc, const char ** argv)
-+{
-+ char * cp;
-+ char buf[CMD_LEN];
-+
-+ if (!makeString(argc - 1, argv + 1, buf, CMD_LEN))
-+ return;
-+
-+ cp = malloc(strlen(buf) + 2);
-+
-+ if (cp == NULL)
-+ {
-+ fprintf(stderr, "No memory for prompt\n");
-+
-+ return;
-+ }
-+
-+ strcpy(cp, buf);
-+ strcat(cp, " ");
-+
-+ if (prompt)
-+ free(prompt);
-+
-+ prompt = cp;
-+}
-+
-+
-+void
-+do_unalias(int argc, const char ** argv)
-+{
-+ Alias * alias;
-+
-+ while (--argc > 0)
-+ {
-+ alias = findAlias(*++argv);
-+
-+ if (alias == NULL)
-+ continue;
-+
-+ free(alias->name);
-+ free(alias->value);
-+ aliasCount--;
-+ alias->name = aliasTable[aliasCount].name;
-+ alias->value = aliasTable[aliasCount].value;
-+ }
-+}
-+
-+
-+/*
-+ * Display the prompt string.
-+ */
-+static void
-+showPrompt(void)
-+{
-+ const char * cp;
-+
-+ cp = "> ";
-+
-+ if (prompt)
-+ cp = prompt;
-+
-+ write(STDOUT, cp, strlen(cp));
-+}
-+
-+
-+static void
-+catchInt(int val)
-+{
-+ signal(SIGINT, catchInt);
-+
-+ intFlag = TRUE;
-+
-+ if (intCrlf)
-+ write(STDOUT, "\n", 1);
-+}
-+
-+
-+static void
-+catchQuit(int val)
-+{
-+ signal(SIGQUIT, catchQuit);
-+
-+ intFlag = TRUE;
-+
-+ if (intCrlf)
-+ write(STDOUT, "\n", 1);
-+}
-+
-+
-+/*
-+ * Print the usage information and quit.
-+ */
-+static void
-+usage(void)
-+{
-+ fprintf(stderr, "Stand-alone shell (version %s)\n", version);
-+ fprintf(stderr, "\n");
-+ fprintf(stderr, "Usage: sash [-a] [-q] [-f fileName] [-c command] [-p prompt] [-i]\n");
-+
-+ exit(1);
-+}
-+
-+/* END CODE */