HAVE_BSD_MOUNT = 0
MOUNT_TYPE = '"ext3"'
-DEFS = -DHAVE_GZIP=$(HAVE_GZIP) \
+
+CFLAGS = -O3 -Wall -Wmissing-prototypes \
+ -DHAVE_GZIP=$(HAVE_GZIP) \
-DHAVE_LINUX_ATTR=$(HAVE_LINUX_ATTR) \
-DHAVE_LINUX_MOUNT=$(HAVE_LINUX_MOUNT) \
-DHAVE_BSD_MOUNT=$(HAVE_BSD_MOUNT) \
-DMOUNT_TYPE=$(MOUNT_TYPE)
-CFLAGS = -O3 -Wall -Wmissing-prototypes -g $(DEFS)
LDFLAGS = -static -s
LIBS = -lz
cp sash $(BINDIR)/sash
cp sash.1 $(MANDIR)/sash.1
-%.o: %.c
- $(CC) $(CFLAGS) $(DEFS) -c $<
-
$(OBJS): sash.h
#include <sys/ioctl.h>
#include <sys/types.h>
-#include <ext2fs/ext2_fs.h>
+#include <linux/ext2_fs.h>
#include "sash.h"
if (fd >= 0)
{
close(fd);
- } else {
- perror(name);
+
+ continue;
}
+
+ if (utime(name, &now) < 0)
+ perror(name);
}
}
void
do_exit(int argc, const char ** argv)
{
- int r = 0;
if (getpid() == 1)
{
fprintf(stderr, "You are the INIT process!\n");
return;
}
- if (argc == 2)
- {
- r = atoi(argv[1]);
- }
- exit(r);
+
+ exit(0);
}
+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
+
+ -- Tollef Fog Heen <tfheen@debian.org> Sun, 04 Apr 2010 10:25:57 +0200
+
sash (3.7-9) unstable; urgency=low
* Drop dependency on lockfile-progs, no longer needed.
Priority: optional
Maintainer: Tollef Fog Heen <tfheen@debian.org>
Standards-Version: 3.8.0
-Build-Depends: zlib1g-dev (>= 1:1.2.2-7), debhelper (>= 7), e2fslibs-dev
+Build-Depends: zlib1g-dev (>= 1:1.2.2-7), debhelper (>= 7),
+ e2fslibs-dev [!kfreebsd-amd64 !kfreebsd-i386],
+ kfreebsd-kernel-headers [kfreebsd-amd64 kfreebsd-i386]
Package: sash
Architecture: any
--- /dev/null
+Index: sash-3.7/cmds.c
+===================================================================
+--- sash-3.7.orig/cmds.c 2010-04-04 11:45:33.864951850 +0200
++++ sash-3.7/cmds.c 2010-04-04 12:29:17.184954241 +0200
+@@ -26,7 +26,7 @@
+ #endif
+
+
+-void
++int
+ do_echo(int argc, const char ** argv)
+ {
+ BOOL first;
+@@ -43,10 +43,11 @@
+ }
+
+ fputc('\n', stdout);
++ return 0;
+ }
+
+
+-void
++int
+ do_pwd(int argc, const char ** argv)
+ {
+ char buf[PATH_LEN];
+@@ -55,14 +56,15 @@
+ {
+ fprintf(stderr, "Cannot get current directory\n");
+
+- return;
++ return 1;
+ }
+
+ printf("%s\n", buf);
++ return 0;
+ }
+
+
+-void
++int
+ do_cd(int argc, const char ** argv)
+ {
+ const char * path;
+@@ -77,29 +79,38 @@
+ {
+ fprintf(stderr, "No HOME environment variable\n");
+
+- return;
++ return 1;
+ }
+ }
+
+ if (chdir(path) < 0)
++ {
+ perror(path);
++ return 1;
++ }
++ return 0;
+ }
+
+
+-void
++int
+ do_mkdir(int argc, const char ** argv)
+ {
++ int r = 0;
+ while (argc-- > 1)
+ {
+ if (mkdir(argv[1], 0777) < 0)
++ {
+ perror(argv[1]);
++ r = 1;
++ }
+
+ argv++;
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_mknod(int argc, const char ** argv)
+ {
+ const char * cp;
+@@ -117,7 +128,7 @@
+ {
+ fprintf(stderr, "Bad device type\n");
+
+- return;
++ return 1;
+ }
+
+ major = 0;
+@@ -130,7 +141,7 @@
+ {
+ fprintf(stderr, "Bad major number\n");
+
+- return;
++ return 1;
+ }
+
+ minor = 0;
+@@ -143,53 +154,70 @@
+ {
+ fprintf(stderr, "Bad minor number\n");
+
+- return;
++ return 1;
+ }
+
+ if (mknod(argv[1], mode, major * 256 + minor) < 0)
++ {
+ perror(argv[1]);
++ return 1;
++ }
++ return 0;
+ }
+
+
+-void
++int
+ do_rmdir(int argc, const char ** argv)
+ {
++ int r = 0;
+ while (argc-- > 1)
+ {
+ if (rmdir(argv[1]) < 0)
++ {
+ perror(argv[1]);
++ r = 1;
++ }
+
+ argv++;
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_sync(int argc, const char ** argv)
+ {
+ sync();
++ return 0;
+ }
+
+
+-void
++int
+ do_rm(int argc, const char ** argv)
+ {
++ int r = 0;
+ while (argc-- > 1)
+ {
+ if (unlink(argv[1]) < 0)
++ {
+ perror(argv[1]);
++ r = 1;
++ }
+
+ argv++;
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_chmod(int argc, const char ** argv)
+ {
+ const char * cp;
+ int mode;
++ int r;
+
++ r = 0;
+ mode = 0;
+ cp = argv[1];
+
+@@ -200,7 +228,7 @@
+ {
+ fprintf(stderr, "Mode must be octal\n");
+
+- return;
++ return 1;
+ }
+
+ argc--;
+@@ -209,21 +237,27 @@
+ while (argc-- > 1)
+ {
+ if (chmod(argv[1], mode) < 0)
++ {
+ perror(argv[1]);
++ r = 1;
++ }
+
+ argv++;
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_chown(int argc, const char ** argv)
+ {
+ const char * cp;
+ int uid;
+ struct passwd * pwd;
+ struct stat statBuf;
++ int r;
+
++ r = 0;
+ cp = argv[1];
+
+ if (isDecimal(*cp))
+@@ -237,7 +271,7 @@
+ {
+ fprintf(stderr, "Bad uid value\n");
+
+- return;
++ return 1;
+ }
+ } else {
+ pwd = getpwnam(cp);
+@@ -246,7 +280,7 @@
+ {
+ fprintf(stderr, "Unknown user name\n");
+
+- return;
++ return 1;
+ }
+
+ uid = pwd->pw_uid;
+@@ -263,19 +297,23 @@
+ (chown(*argv, uid, statBuf.st_gid) < 0))
+ {
+ perror(*argv);
++ r = 1;
+ }
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_chgrp(int argc, const char ** argv)
+ {
+ const char * cp;
+ int gid;
+ struct group * grp;
+ struct stat statBuf;
++ int r;
+
++ r = 0;
+ cp = argv[1];
+
+ if (isDecimal(*cp))
+@@ -289,7 +327,7 @@
+ {
+ fprintf(stderr, "Bad gid value\n");
+
+- return;
++ return 1;
+ }
+ }
+ else
+@@ -300,7 +338,7 @@
+ {
+ fprintf(stderr, "Unknown group name\n");
+
+- return;
++ return 1;
+ }
+
+ gid = grp->gr_gid;
+@@ -317,18 +355,22 @@
+ (chown(*argv, statBuf.st_uid, gid) < 0))
+ {
+ perror(*argv);
++ r = 1;
+ }
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_touch(int argc, const char ** argv)
+ {
+ const char * name;
+ int fd;
+ struct utimbuf now;
++ int r;
+
++ r = 0;
+ time(&now.actime);
+ now.modtime = now.actime;
+
+@@ -347,23 +389,30 @@
+
+ if (errno != EEXIST) {
+ perror(name);
++ r = 1;
+ continue;
+ }
+
+ if (utime(name, &now) < 0)
++ {
+ perror(name);
++ r = 1;
++ }
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_mv(int argc, const char ** argv)
+ {
+ const char * srcName;
+ const char * destName;
+ const char * lastArg;
+ BOOL dirFlag;
++ int r;
+
++ r = 0;
+ lastArg = argv[argc - 1];
+
+ dirFlag = isDirectory(lastArg);
+@@ -372,7 +421,7 @@
+ {
+ fprintf(stderr, "%s: not a directory\n", lastArg);
+
+- return;
++ return 1;
+ }
+
+ while (!intFlag && (argc-- > 2))
+@@ -382,6 +431,7 @@
+ if (access(srcName, 0) < 0)
+ {
+ perror(srcName);
++ r = 1;
+
+ continue;
+ }
+@@ -397,6 +447,7 @@
+ if (errno != EXDEV)
+ {
+ perror(destName);
++ r = 1;
+
+ continue;
+ }
+@@ -405,18 +456,25 @@
+ continue;
+
+ if (unlink(srcName) < 0)
++ {
+ perror(srcName);
++ r = 1;
++ }
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_ln(int argc, const char ** argv)
+ {
+ const char * srcName;
+ const char * destName;
+ const char * lastArg;
+ BOOL dirFlag;
++ int r;
++
++ r = 0;
+
+ if (argv[1][0] == '-')
+ {
+@@ -424,23 +482,27 @@
+ {
+ fprintf(stderr, "Unknown option\n");
+
+- return;
++ return 1;
+ }
+
+ if (argc != 4)
+ {
+ fprintf(stderr, "Wrong number of arguments for symbolic link\n");
+
+- return;
++ return 1;
+ }
+
+ #ifdef S_ISLNK
+ if (symlink(argv[2], argv[3]) < 0)
++ {
+ perror(argv[3]);
++ return 1;
++ }
++ return 0;
+ #else
+ fprintf(stderr, "Symbolic links are not allowed\n");
++ return 1;
+ #endif
+- return;
+ }
+
+ /*
+@@ -453,7 +515,7 @@
+ {
+ fprintf(stderr, "%s: not a directory\n", lastArg);
+
+- return;
++ return 1;
+ }
+
+ while (argc-- > 2)
+@@ -463,6 +525,7 @@
+ if (access(srcName, 0) < 0)
+ {
+ perror(srcName);
++ r = 1;
+
+ continue;
+ }
+@@ -475,21 +538,25 @@
+ if (link(srcName, destName) < 0)
+ {
+ perror(destName);
++ r = 1;
+
+ continue;
+ }
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_cp(int argc, const char ** argv)
+ {
+ const char * srcName;
+ const char * destName;
+ const char * lastArg;
+ BOOL dirFlag;
++ int r;
+
++ r = 0;
+ lastArg = argv[argc - 1];
+
+ dirFlag = isDirectory(lastArg);
+@@ -498,7 +565,7 @@
+ {
+ fprintf(stderr, "%s: not a directory\n", lastArg);
+
+- return;
++ return 1;
+ }
+
+ while (!intFlag && (argc-- > 2))
+@@ -509,12 +576,14 @@
+ if (dirFlag)
+ destName = buildName(destName, srcName);
+
+- (void) copyFile(srcName, destName, FALSE);
++ if (!copyFile(srcName, destName, FALSE))
++ r = 1;
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_mount(int argc, const char ** argv)
+ {
+ const char * str;
+@@ -544,7 +613,7 @@
+ {
+ fprintf(stderr, "Missing file system type\n");
+
+- return;
++ return 1;
+ }
+
+ type = *argv++;
+@@ -584,7 +653,7 @@
+ default:
+ fprintf(stderr, "Unknown option\n");
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -592,14 +661,16 @@
+ {
+ fprintf(stderr, "Wrong number of arguments for mount\n");
+
+- return;
++ return 1;
+ }
+
+ #if HAVE_LINUX_MOUNT
+
+- if (mount(argv[0], argv[1], type, flags, 0) < 0)
+- perror("mount failed");
+-
++ if (mount(argv[0], argv[1], type, flags, 0) < 0)
++ {
++ perror("mount failed");
++ return 1;
++ }
+ #elif HAVE_BSD_MOUNT
+ {
+ struct ufs_args ufs;
+@@ -622,22 +693,29 @@
+ fprintf(stderr, "Unknown filesystem type: %s", type);
+ fprintf(stderr,
+ "Supported: ffs ufs adosfs cd9660 mfs msdos\n");
+- return;
++ return 1;
+ }
+
+ if (mount(type, argv[1], flags, args) < 0)
+- perror(argv[0]);
++ {
++ perror(argv[0]);
++ return 1;
++ }
+ }
+ #endif
++ return 0;
+ }
+
+
+-void
++int
+ do_umount(int argc, const char ** argv)
+ {
+ #if HAVE_LINUX_MOUNT
+ if (umount(argv[1]) < 0)
++ {
+ perror(argv[1]);
++ return 1;
++ }
+ #elif HAVE_BSD_MOUNT
+ {
+ const char * str;
+@@ -659,13 +737,17 @@
+ }
+
+ if (unmount(argv[0], flags) < 0)
++ {
+ perror(argv[0]);
++ return 1;
++ }
+ }
+ #endif
++ return 0;
+ }
+
+
+-void
++int
+ do_cmp(int argc, const char ** argv)
+ {
+ int fd1;
+@@ -679,19 +761,22 @@
+ char buf2[BUF_SIZE];
+ struct stat statBuf1;
+ struct stat statBuf2;
++ int r;
++
++ r = 0;
+
+ if (stat(argv[1], &statBuf1) < 0)
+ {
+ perror(argv[1]);
+
+- return;
++ return 1;
+ }
+
+ if (stat(argv[2], &statBuf2) < 0)
+ {
+ perror(argv[2]);
+
+- return;
++ return 1;
+ }
+
+ if ((statBuf1.st_dev == statBuf2.st_dev) &&
+@@ -699,14 +784,14 @@
+ {
+ printf("Files are links to each other\n");
+
+- return;
++ return 0;
+ }
+
+ if (statBuf1.st_size != statBuf2.st_size)
+ {
+ printf("Files are different sizes\n");
+
+- return;
++ return 1;
+ }
+
+ fd1 = open(argv[1], O_RDONLY);
+@@ -715,7 +800,7 @@
+ {
+ perror(argv[1]);
+
+- return;
++ return 1;
+ }
+
+ fd2 = open(argv[2], O_RDONLY);
+@@ -725,7 +810,7 @@
+ perror(argv[2]);
+ close(fd1);
+
+- return;
++ return 1;
+ }
+
+ pos = 0;
+@@ -740,6 +825,7 @@
+ if (cc1 < 0)
+ {
+ perror(argv[1]);
++ r = 1;
+ goto closefiles;
+ }
+
+@@ -748,24 +834,28 @@
+ if (cc2 < 0)
+ {
+ perror(argv[2]);
++ r = 1;
+ goto closefiles;
+ }
+
+ if ((cc1 == 0) && (cc2 == 0))
+ {
+ printf("Files are identical\n");
++ r = 0;
+ goto closefiles;
+ }
+
+ if (cc1 < cc2)
+ {
+ printf("First file is shorter than second\n");
++ r = 1;
+ goto closefiles;
+ }
+
+ if (cc1 > cc2)
+ {
+ printf("Second file is shorter than first\n");
++ r = 1;
+ goto closefiles;
+ }
+
+@@ -783,6 +873,7 @@
+ pos++;
+
+ printf("Files differ at byte position %ld\n", pos);
++ r = 1;
+
+ goto closefiles;
+ }
+@@ -790,10 +881,11 @@
+ closefiles:
+ close(fd1);
+ close(fd2);
++ return r;
+ }
+
+
+-void
++int
+ do_more(int argc, const char ** argv)
+ {
+ FILE * fp;
+@@ -841,7 +933,7 @@
+ {
+ perror(name);
+
+- return;
++ return 1;
+ }
+
+ printf("<< %s >>\n", name);
+@@ -896,7 +988,7 @@
+ if (fp)
+ fclose(fp);
+
+- return;
++ return 0;
+ }
+
+ ch = buf[0];
+@@ -916,7 +1008,7 @@
+ case 'q':
+ fclose(fp);
+
+- return;
++ return 0;
+ }
+
+ col = 0;
+@@ -926,10 +1018,11 @@
+ if (fp)
+ fclose(fp);
+ }
++ return 0;
+ }
+
+
+-void
++int
+ do_sum(int argc, const char ** argv)
+ {
+ const char * name;
+@@ -939,9 +1032,11 @@
+ int i;
+ unsigned long checksum;
+ char buf[BUF_SIZE];
++ int r;
+
+ argc--;
+ argv++;
++ r = 0;
+
+ while (argc-- > 0)
+ {
+@@ -952,6 +1047,7 @@
+ if (fd < 0)
+ {
+ perror(name);
++ r = 1;
+
+ continue;
+ }
+@@ -976,6 +1072,7 @@
+ if (cc < 0)
+ {
+ perror(name);
++ r = 1;
+
+ (void) close(fd);
+
+@@ -986,10 +1083,11 @@
+
+ printf("%05lu %s\n", checksum, name);
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_exit(int argc, const char ** argv)
+ {
+ int r = 0;
+@@ -997,17 +1095,18 @@
+ {
+ fprintf(stderr, "You are the INIT process!\n");
+
+- return;
++ return 1;
+ }
+ if (argc == 2)
+ {
+ r = atoi(argv[1]);
+ }
+ exit(r);
++ return r;
+ }
+
+
+-void
++int
+ do_setenv(int argc, const char ** argv)
+ {
+ const char * name;
+@@ -1027,7 +1126,7 @@
+ {
+ fprintf(stderr, "Cannot allocate memory\n");
+
+- return;
++ return 1;
+ }
+
+ strcpy(str, name);
+@@ -1035,10 +1134,11 @@
+ strcat(str, value);
+
+ putenv(str);
++ return 0;
+ }
+
+
+-void
++int
+ do_printenv(int argc, const char ** argv)
+ {
+ const char ** env;
+@@ -1052,7 +1152,7 @@
+ while (*env)
+ printf("%s\n", *env++);
+
+- return;
++ return 0;
+ }
+
+ len = strlen(argv[1]);
+@@ -1064,14 +1164,15 @@
+ {
+ printf("%s\n", &env[0][len+1]);
+
+- return;
++ return 0;
+ }
+ env++;
+ }
++ return 0;
+ }
+
+
+-void
++int
+ do_umask(int argc, const char ** argv)
+ {
+ const char * cp;
+@@ -1083,7 +1184,7 @@
+ umask(mask);
+ printf("%03o\n", mask);
+
+- return;
++ return 0;
+ }
+
+ mask = 0;
+@@ -1096,20 +1197,24 @@
+ {
+ fprintf(stderr, "Bad umask value\n");
+
+- return;
++ return 1;
+ }
+
+ umask(mask);
++ return 0;
++
+ }
+
+
+-void
++int
+ do_kill(int argc, const char ** argv)
+ {
+ const char * cp;
+ int sig;
+ int pid;
++ int r;
+
++ r = 0;
+ sig = SIGTERM;
+
+ if (argv[1][0] == '-')
+@@ -1145,7 +1250,7 @@
+ {
+ fprintf(stderr, "Unknown signal\n");
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -1165,16 +1270,20 @@
+ {
+ fprintf(stderr, "Non-numeric pid\n");
+
+- return;
++ return 1;
+ }
+
+ if (kill(pid, sig) < 0)
++ {
+ perror(*argv);
++ r = 1;
++ }
+ }
++ return r;
+ }
+
+
+-void
++int
+ do_where(int argc, const char ** argv)
+ {
+ const char * program;
+@@ -1183,6 +1292,7 @@
+ char * endPath;
+ char * fullPath;
+ BOOL found;
++ int r;
+
+ found = FALSE;
+ program = argv[1];
+@@ -1191,7 +1301,7 @@
+ {
+ fprintf(stderr, "Program name cannot include a path\n");
+
+- return;
++ return 1;
+ }
+
+ path = getenv("PATH");
+@@ -1203,7 +1313,7 @@
+ {
+ fprintf(stderr, "Memory allocation failed\n");
+
+- return;
++ return 1;
+ }
+
+ /*
+@@ -1243,7 +1353,10 @@
+ if (access(fullPath, X_OK) < 0)
+ {
+ if (errno != ENOENT)
+- printf("%s: %s\n", fullPath, strerror(errno));
++ {
++ perror(fullPath);
++ r = 1;
++ }
+
+ continue;
+ }
+@@ -1253,7 +1366,11 @@
+ }
+
+ if (!found)
++ {
+ printf("Program \"%s\" not found in PATH\n", program);
++ r = 1;
++ }
++ return r;
+ }
+
+ /* END CODE */
+Index: sash-3.7/sash.h
+===================================================================
+--- sash-3.7.orig/sash.h 2010-04-04 11:45:33.888951646 +0200
++++ sash-3.7/sash.h 2010-04-04 11:46:22.112949938 +0200
+@@ -58,56 +58,56 @@
+ /*
+ * Built-in command functions.
+ */
+-extern void do_alias(int argc, const char ** argv);
+-extern void do_aliasall(int argc, const char ** argv);
+-extern void do_cd(int argc, const char ** argv);
+-extern void do_exec(int argc, const char ** argv);
+-extern void do_exit(int argc, const char ** argv);
+-extern void do_prompt(int argc, const char ** argv);
+-extern void do_source(int argc, const char ** argv);
+-extern void do_umask(int argc, const char ** argv);
+-extern void do_unalias(int argc, const char ** argv);
+-extern void do_help(int argc, const char ** argv);
+-extern void do_ln(int argc, const char ** argv);
+-extern void do_cp(int argc, const char ** argv);
+-extern void do_mv(int argc, const char ** argv);
+-extern void do_rm(int argc, const char ** argv);
+-extern void do_chmod(int argc, const char ** argv);
+-extern void do_mkdir(int argc, const char ** argv);
+-extern void do_rmdir(int argc, const char ** argv);
+-extern void do_mknod(int argc, const char ** argv);
+-extern void do_chown(int argc, const char ** argv);
+-extern void do_chgrp(int argc, const char ** argv);
+-extern void do_sum(int argc, const char ** argv);
+-extern void do_sync(int argc, const char ** argv);
+-extern void do_printenv(int argc, const char ** argv);
+-extern void do_more(int argc, const char ** argv);
+-extern void do_cmp(int argc, const char ** argv);
+-extern void do_touch(int argc, const char ** argv);
+-extern void do_ls(int argc, const char ** argv);
+-extern void do_dd(int argc, const char ** argv);
+-extern void do_tar(int argc, const char ** argv);
+-extern void do_ar(int argc, const char ** argv);
+-extern void do_mount(int argc, const char ** argv);
+-extern void do_umount(int argc, const char ** argv);
+-extern void do_setenv(int argc, const char ** argv);
+-extern void do_pwd(int argc, const char ** argv);
+-extern void do_echo(int argc, const char ** argv);
+-extern void do_kill(int argc, const char ** argv);
+-extern void do_grep(int argc, const char ** argv);
+-extern void do_file(int argc, const char ** argv);
+-extern void do_find(int argc, const char ** argv);
+-extern void do_ed(int argc, const char ** argv);
+-extern void do_where(int argc, const char ** argv);
++extern int do_alias(int argc, const char ** argv);
++extern int do_aliasall(int argc, const char ** argv);
++extern int do_cd(int argc, const char ** argv);
++extern int do_exec(int argc, const char ** argv);
++extern int do_exit(int argc, const char ** argv);
++extern int do_prompt(int argc, const char ** argv);
++extern int do_source(int argc, const char ** argv);
++extern int do_umask(int argc, const char ** argv);
++extern int do_unalias(int argc, const char ** argv);
++extern int do_help(int argc, const char ** argv);
++extern int do_ln(int argc, const char ** argv);
++extern int do_cp(int argc, const char ** argv);
++extern int do_mv(int argc, const char ** argv);
++extern int do_rm(int argc, const char ** argv);
++extern int do_chmod(int argc, const char ** argv);
++extern int do_mkdir(int argc, const char ** argv);
++extern int do_rmdir(int argc, const char ** argv);
++extern int do_mknod(int argc, const char ** argv);
++extern int do_chown(int argc, const char ** argv);
++extern int do_chgrp(int argc, const char ** argv);
++extern int do_sum(int argc, const char ** argv);
++extern int do_sync(int argc, const char ** argv);
++extern int do_printenv(int argc, const char ** argv);
++extern int do_more(int argc, const char ** argv);
++extern int do_cmp(int argc, const char ** argv);
++extern int do_touch(int argc, const char ** argv);
++extern int do_ls(int argc, const char ** argv);
++extern int do_dd(int argc, const char ** argv);
++extern int do_tar(int argc, const char ** argv);
++extern int do_ar(int argc, const char ** argv);
++extern int do_mount(int argc, const char ** argv);
++extern int do_umount(int argc, const char ** argv);
++extern int do_setenv(int argc, const char ** argv);
++extern int do_pwd(int argc, const char ** argv);
++extern int do_echo(int argc, const char ** argv);
++extern int do_kill(int argc, const char ** argv);
++extern int do_grep(int argc, const char ** argv);
++extern int do_file(int argc, const char ** argv);
++extern int do_find(int argc, const char ** argv);
++extern int do_ed(int argc, const char ** argv);
++extern int do_where(int argc, const char ** argv);
+
+ #if HAVE_GZIP
+-extern void do_gzip(int argc, const char ** argv);
+-extern void do_gunzip(int argc, const char ** argv);
++extern int do_gzip(int argc, const char ** argv);
++extern int do_gunzip(int argc, const char ** argv);
+ #endif
+
+ #if HAVE_LINUX_ATTR
+-extern void do_lsattr(int argc, const char ** argv);
+-extern void do_chattr(int argc, const char ** argv);
++extern int do_lsattr(int argc, const char ** argv);
++extern int do_chattr(int argc, const char ** argv);
+ #endif
+
+
+Index: sash-3.7/sash.c
+===================================================================
+--- sash-3.7.orig/sash.c 2010-04-04 11:45:33.876960339 +0200
++++ sash-3.7/sash.c 2010-04-04 11:46:22.116952745 +0200
+@@ -31,7 +31,7 @@
+ typedef struct
+ {
+ const char * name;
+- void (*func)(int argc, const char ** argv);
++ int (*func)(int argc, const char ** argv);
+ int minArgs;
+ int maxArgs;
+ const char * description;
+@@ -375,10 +375,10 @@
+ */
+ static void catchInt(int);
+ static void catchQuit(int);
+-static void readFile(const char * name);
+-static void command(const char * cmd);
+-static BOOL tryBuiltIn(const char * cmd);
+-static void runCmd(const char * cmd);
++static int readFile(const char * name);
++static int command(const char * cmd);
++static int tryBuiltIn(const char * cmd);
++static int runCmd(const char * cmd);
+ static void childProcess(const char * cmd);
+ static void showPrompt(void);
+ static void usage(void);
+@@ -571,19 +571,20 @@
+ * Read commands from the specified file.
+ * A null name pointer indicates to read from stdin.
+ */
+-static void
++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;
++ return 1;
+ }
+
+ fp = stdin;
+@@ -596,7 +597,7 @@
+ {
+ perror(name);
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -614,7 +615,7 @@
+ fclose(fp);
+ sourceCount--;
+
+- return;
++ return 1;
+ }
+
+ if (fgets(buf, CMD_LEN - 1, fp) == NULL)
+@@ -639,7 +640,7 @@
+
+ buf[cc] = '\0';
+
+- command(buf);
++ r = command(buf);
+ }
+
+ if (ferror(fp))
+@@ -656,6 +657,7 @@
+ fclose(fp);
+
+ sourceCount--;
++ return r;
+ }
+
+
+@@ -664,13 +666,14 @@
+ * This breaks the command line up into words, checks to see if the
+ * command is an alias, and expands wildcards.
+ */
+-static void
++static int
+ command(const char * cmd)
+ {
+ const char * endCmd;
+ const Alias * alias;
+ char newCommand[CMD_LEN];
+ char cmdName[CMD_LEN];
++ int r = -1;
+
+ /*
+ * Rest the interrupt flag and free any memory chunks that
+@@ -690,7 +693,7 @@
+ * If the command is empty or is a comment then ignore it.
+ */
+ if ((*cmd == '\0') || (*cmd == '#'))
+- return;
++ return 0;
+
+ /*
+ * Look for the end of the command name and then copy the
+@@ -725,14 +728,15 @@
+ * Now look for the command in the builtin table, and execute
+ * the command if found.
+ */
+- if (tryBuiltIn(cmd))
+- return;
++ r = tryBuiltIn(cmd);
++ if (r >= 0)
++ return r;
+
+ /*
+ * The command is not a built-in, so run the program along
+ * the PATH list.
+ */
+- runCmd(cmd);
++ return runCmd(cmd);
+ }
+
+
+@@ -741,7 +745,7 @@
+ * 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
++static int
+ tryBuiltIn(const char * cmd)
+ {
+ const char * endCmd;
+@@ -776,14 +780,14 @@
+ * If the command is not a built-in, return indicating that.
+ */
+ if (entry->name == NULL)
+- return FALSE;
++ return -1;
+
+ /*
+ * The command is a built-in.
+ * Break the command up into arguments and expand wildcards.
+ */
+ if (!makeArgs(cmd, &argc, &argv))
+- return TRUE;
++ return 0;
+
+ /*
+ * Give a usage string if the number of arguments is too large
+@@ -793,15 +797,13 @@
+ {
+ fprintf(stderr, "usage: %s %s\n", entry->name, entry->usage);
+
+- return TRUE;
++ return 0;
+ }
+
+ /*
+ * Call the built-in function with the argument list.
+ */
+- entry->func(argc, argv);
+-
+- return TRUE;
++ return entry->func(argc, argv);
+ }
+
+
+@@ -809,7 +811,7 @@
+ * Execute the specified command either by forking and executing
+ * the program ourself, or else by using the shell.
+ */
+-static void
++static int
+ runCmd(const char * cmd)
+ {
+ const char * cp;
+@@ -854,9 +856,7 @@
+ */
+ if (magic)
+ {
+- system(cmd);
+-
+- return;
++ return system(cmd);
+ }
+
+ /*
+@@ -869,7 +869,7 @@
+ {
+ perror("fork failed");
+
+- return;
++ return -1;
+ }
+
+ /*
+@@ -894,7 +894,7 @@
+ {
+ fprintf(stderr, "Error from waitpid: %s", strerror(errno));
+
+- return;
++ return -1;
+ }
+
+ if (WIFSIGNALED(status))
+@@ -902,6 +902,7 @@
+ fprintf(stderr, "pid %ld: killed by signal %d\n",
+ (long) pid, WTERMSIG(status));
+ }
++ return WEXITSTATUS(status);
+ }
+
+
+@@ -958,7 +959,7 @@
+ }
+
+
+-void
++int
+ do_help(int argc, const char ** argv)
+ {
+ const CommandEntry * entry;
+@@ -983,7 +984,7 @@
+ printf("usage: %s %s\n", entry->name,
+ entry->usage);
+
+- return;
++ return 0;
+ }
+ }
+ }
+@@ -1000,10 +1001,11 @@
+ printf("%-10s %s\n", entry->name, entry->usage);
+ }
+ }
++ return 0;
+ }
+
+
+-void
++int
+ do_alias(int argc, const char ** argv)
+ {
+ const char * name;
+@@ -1019,7 +1021,7 @@
+ for (alias = aliasTable; count-- > 0; alias++)
+ printf("%s\t%s\n", alias->name, alias->value);
+
+- return;
++ return 0;
+ }
+
+ name = argv[1];
+@@ -1029,22 +1031,26 @@
+ alias = findAlias(name);
+
+ if (alias)
++ {
+ printf("%s\n", alias->value);
++ return 0;
++ }
+ else
++ {
+ fprintf(stderr, "Alias \"%s\" is not defined\n", name);
+-
+- return;
++ return 1;
++ }
+ }
+
+ if (strcmp(name, "alias") == 0)
+ {
+ fprintf(stderr, "Cannot alias \"alias\"\n");
+
+- return;
++ return 1;
+ }
+
+ if (!makeString(argc - 2, argv + 2, buf, CMD_LEN))
+- return;
++ return -1;
+
+ value = malloc(strlen(buf) + 1);
+
+@@ -1052,7 +1058,7 @@
+ {
+ fprintf(stderr, "No memory for alias value\n");
+
+- return;
++ return 1;
+ }
+
+ strcpy(value, buf);
+@@ -1064,7 +1070,7 @@
+ free(alias->value);
+ alias->value = value;
+
+- return;
++ return 0;
+ }
+
+ if ((aliasCount % ALIAS_ALLOC) == 0)
+@@ -1084,7 +1090,7 @@
+ free(value);
+ fprintf(stderr, "No memory for alias table\n");
+
+- return;
++ return 1;
+ }
+
+ aliasTable = alias;
+@@ -1099,12 +1105,13 @@
+ free(value);
+ fprintf(stderr, "No memory for alias name\n");
+
+- return;
++ return 1;
+ }
+
+ strcpy(alias->name, name);
+ alias->value = value;
+ aliasCount++;
++ return 0;
+ }
+
+
+@@ -1112,12 +1119,13 @@
+ * Build aliases for all of the built-in commands which start with a dash,
+ * using the names without the dash.
+ */
+-void
++int
+ do_aliasall(int argc, const char **argv)
+ {
+ const CommandEntry * entry;
+ const char * name;
+ const char * newArgv[4];
++ int r;
+
+ for (entry = commandEntryTable; entry->name; entry++)
+ {
+@@ -1131,8 +1139,13 @@
+ newArgv[2] = name;
+ newArgv[3] = NULL;
+
+- do_alias(3, newArgv);
++ r = do_alias(3, newArgv);
++ if (r != 0)
++ {
++ return r;
++ }
+ }
++ return 0;
+ }
+
+
+@@ -1158,14 +1171,14 @@
+ }
+
+
+-void
++int
+ do_source(int argc, const char ** argv)
+ {
+- readFile(argv[1]);
++ return readFile(argv[1]);
+ }
+
+
+-void
++int
+ do_exec(int argc, const char ** argv)
+ {
+ const char * name;
+@@ -1182,17 +1195,18 @@
+
+ execvp(name, (char **) argv + 1);
+ perror(name);
++ return 127;
+ }
+
+
+-void
++int
+ do_prompt(int argc, const char ** argv)
+ {
+ char * cp;
+ char buf[CMD_LEN];
+
+ if (!makeString(argc - 1, argv + 1, buf, CMD_LEN))
+- return;
++ return 1;
+
+ cp = malloc(strlen(buf) + 2);
+
+@@ -1200,7 +1214,7 @@
+ {
+ fprintf(stderr, "No memory for prompt\n");
+
+- return;
++ return 1;
+ }
+
+ strcpy(cp, buf);
+@@ -1210,10 +1224,11 @@
+ free(prompt);
+
+ prompt = cp;
++ return 0;
+ }
+
+
+-void
++int
+ do_unalias(int argc, const char ** argv)
+ {
+ Alias * alias;
+@@ -1231,6 +1246,7 @@
+ alias->name = aliasTable[aliasCount].name;
+ alias->value = aliasTable[aliasCount].value;
+ }
++ return 0;
+ }
+
+
+Index: sash-3.7/cmd_dd.c
+===================================================================
+--- sash-3.7.orig/cmd_dd.c 2010-04-04 12:29:35.236953933 +0200
++++ sash-3.7/cmd_dd.c 2010-04-04 12:32:57.081955729 +0200
+@@ -40,7 +40,7 @@
+ static long getNum(const char * cp);
+
+
+-void
++int
+ do_dd(int argc, const char ** argv)
+ {
+ const char * str;
+@@ -62,6 +62,7 @@
+ long outPartial;
+ char * buf;
+ char localBuf[BUF_SIZE];
++ int r;
+
+ inFile = NULL;
+ outFile = NULL;
+@@ -69,6 +70,7 @@
+ skipVal = 0;
+ blockSize = 512;
+ count = -1;
++ r = 0;
+
+ while (--argc > 0)
+ {
+@@ -79,7 +81,7 @@
+ {
+ fprintf(stderr, "Bad dd argument\n");
+
+- return;
++ return 1;
+ }
+
+ *cp++ = '\0';
+@@ -97,7 +99,7 @@
+ {
+ fprintf(stderr, "Multiple input files illegal\n");
+
+- return;
++ return 1;
+ }
+
+ inFile = cp;
+@@ -108,7 +110,7 @@
+ {
+ fprintf(stderr, "Multiple output files illegal\n");
+
+- return;
++ return 1;
+ }
+
+ outFile = cp;
+@@ -121,7 +123,7 @@
+ {
+ fprintf(stderr, "Bad block size value\n");
+
+- return;
++ return 1;
+ }
+
+ break;
+@@ -133,7 +135,7 @@
+ {
+ fprintf(stderr, "Bad count value\n");
+
+- return;
++ return 1;
+ }
+
+ break;
+@@ -145,7 +147,7 @@
+ {
+ fprintf(stderr, "Bad seek value\n");
+
+- return;
++ return 1;
+ }
+
+ break;
+@@ -157,7 +159,7 @@
+ {
+ fprintf(stderr, "Bad skip value\n");
+
+- return;
++ return 1;
+ }
+
+ break;
+@@ -165,7 +167,7 @@
+ default:
+ fprintf(stderr, "Unknown dd parameter\n");
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -173,14 +175,14 @@
+ {
+ fprintf(stderr, "No input file specified\n");
+
+- return;
++ return 1;
+ }
+
+ if (outFile == NULL)
+ {
+ fprintf(stderr, "No output file specified\n");
+
+- return;
++ return 1;
+ }
+
+ buf = localBuf;
+@@ -193,7 +195,7 @@
+ {
+ fprintf(stderr, "Cannot allocate buffer\n");
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -211,7 +213,7 @@
+ if (buf != localBuf)
+ free(buf);
+
+- return;
++ return 1;
+ }
+
+ outFd = creat(outFile, 0666);
+@@ -224,7 +226,7 @@
+ if (buf != localBuf)
+ free(buf);
+
+- return;
++ return 1;
+ }
+
+ if (skipVal)
+@@ -238,12 +240,14 @@
+ if (inCc < 0)
+ {
+ perror(inFile);
++ r = 1;
+ goto cleanup;
+ }
+
+ if (inCc == 0)
+ {
+ fprintf(stderr, "End of file while skipping\n");
++ r = 1;
+ goto cleanup;
+ }
+ }
+@@ -255,7 +259,7 @@
+ if (lseek(outFd, seekVal * blockSize, 0) < 0)
+ {
+ perror(outFile);
+-
++ r = 1;
+ goto cleanup;
+ }
+ }
+@@ -274,6 +278,7 @@
+ if (intFlag)
+ {
+ fprintf(stderr, "Interrupted\n");
++ r = 1;
+ goto cleanup;
+ }
+
+@@ -284,6 +289,7 @@
+ if (outCc < 0)
+ {
+ perror(outFile);
++ r = 1;
+ goto cleanup;
+ }
+
+@@ -303,7 +309,10 @@
+ close(inFd);
+
+ if (close(outFd) < 0)
++ {
+ perror(outFile);
++ r = 1;
++ }
+
+ if (buf != localBuf)
+ free(buf);
+@@ -311,6 +320,7 @@
+ printf("%ld+%ld records in\n", inFull, inPartial);
+
+ printf("%ld+%ld records out\n", outFull, outPartial);
++ return r;
+ }
+
+
+Index: sash-3.7/cmd_ed.c
+===================================================================
+--- sash-3.7.orig/cmd_ed.c 2010-04-04 12:33:11.076954419 +0200
++++ sash-3.7/cmd_ed.c 2010-04-04 12:34:01.244953056 +0200
+@@ -60,11 +60,11 @@
+ (const LINE * lp, const char * str, LEN len, LEN offset);
+
+
+-void
++int
+ do_ed(int argc, const char ** argv)
+ {
+ if (!initEdit())
+- return;
++ return 1;
+
+ if (argc > 1)
+ {
+@@ -75,14 +75,14 @@
+ fprintf(stderr, "No memory\n");
+ termEdit();
+
+- return;
++ return 1;
+ }
+
+ if (!readLines(fileName, 1))
+ {
+ termEdit();
+
+- return;
++ return 1;
+ }
+
+ if (lastNum)
+@@ -94,6 +94,7 @@
+ doCommands();
+
+ termEdit();
++ return 0;
+ }
+
+
+Index: sash-3.7/cmd_grep.c
+===================================================================
+--- sash-3.7.orig/cmd_grep.c 2010-04-04 12:34:30.320951181 +0200
++++ sash-3.7/cmd_grep.c 2010-04-04 12:38:36.524986801 +0200
+@@ -15,7 +15,7 @@
+ (const char * string, const char * word, BOOL ignoreCase);
+
+
+-void
++int
+ do_grep(int argc, const char ** argv)
+ {
+ FILE * fp;
+@@ -27,7 +27,9 @@
+ BOOL tellLine;
+ long line;
+ char buf[BUF_SIZE];
++ int r;
+
++ r = 1;
+ ignoreCase = FALSE;
+ tellLine = FALSE;
+
+@@ -52,7 +54,7 @@
+ default:
+ fprintf(stderr, "Unknown option\n");
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -70,6 +72,7 @@
+ if (fp == NULL)
+ {
+ perror(name);
++ r = 1;
+
+ continue;
+ }
+@@ -82,7 +85,7 @@
+ {
+ fclose(fp);
+
+- return;
++ return 1;
+ }
+
+ line++;
+@@ -94,6 +97,7 @@
+
+ if (search(buf, word, ignoreCase))
+ {
++ r = 0;
+ if (tellName)
+ printf("%s: ", name);
+
+@@ -109,6 +113,7 @@
+
+ fclose(fp);
+ }
++ return r;
+ }
+
+
+Index: sash-3.7/cmd_ls.c
+===================================================================
+--- sash-3.7.orig/cmd_ls.c 2010-04-04 12:38:46.364975686 +0200
++++ sash-3.7/cmd_ls.c 2010-04-04 12:40:32.424951492 +0200
+@@ -59,7 +59,7 @@
+ static void clearListNames(void);
+
+
+-void
++int
+ do_ls(int argc, const char ** argv)
+ {
+ const char * cp;
+@@ -72,6 +72,7 @@
+ struct dirent * dp;
+ char fullName[PATH_LEN];
+ struct stat statBuf;
++ int r;
+
+ static const char * def[] = {"."};
+
+@@ -105,7 +106,7 @@
+ default:
+ fprintf(stderr, "Unknown option -%c\n", cp[-1]);
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -153,7 +154,7 @@
+ if ((flags & LSF_DIR) || !isDirectory(argv[i]))
+ {
+ if (!addListName(argv[i]))
+- return;
++ return 1;
+ }
+ }
+
+@@ -167,7 +168,7 @@
+ * If directories were being listed as themselves, then we are done.
+ */
+ if (flags & LSF_DIR)
+- return;
++ return r;
+
+ /*
+ * Now iterate over the file names processing the directories.
+@@ -180,6 +181,7 @@
+ if (LSTAT(name, &statBuf) < 0)
+ {
+ perror(name);
++ r = 1;
+
+ continue;
+ }
+@@ -226,7 +228,7 @@
+ {
+ closedir(dirp);
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -239,6 +241,7 @@
+ listAllFiles(flags, displayWidth);
+ clearListNames();
+ }
++ return r;
+ }
+
+
+Index: sash-3.7/cmd_tar.c
+===================================================================
+--- sash-3.7.orig/cmd_tar.c 2010-04-04 12:40:41.588964080 +0200
++++ sash-3.7/cmd_tar.c 2010-04-04 12:41:56.960954363 +0200
+@@ -119,7 +119,7 @@
+
+
+
+-void
++int
+ do_tar(int argc, const char ** argv)
+ {
+ const char * options;
+@@ -131,7 +131,7 @@
+ {
+ fprintf(stderr, "Too few arguments for tar\n");
+
+- return;
++ return 1;
+ }
+
+ extractFlag = FALSE;
+@@ -158,7 +158,7 @@
+ {
+ fprintf(stderr, "Only one 'f' option allowed\n");
+
+- return;
++ return 1;
+ }
+
+ tarName = *argv++;
+@@ -185,7 +185,7 @@
+ default:
+ fprintf(stderr, "Unknown tar flag '%c'\n", *options);
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -196,14 +196,14 @@
+ {
+ fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
+
+- return;
++ return 1;
+ }
+
+ if (tarName == NULL)
+ {
+ fprintf(stderr, "The 'f' flag must be specified\n");
+
+- return;
++ return 1;
+ }
+
+ /*
+@@ -211,9 +211,9 @@
+ * command line arguments as the list of files to process.
+ */
+ if (createFlag)
+- writeTarFile(argc, argv);
++ return writeTarFile(argc, argv);
+ else
+- readTarFile(argc, argv);
++ return readTarFile(argc, argv);
+ }
+
+
+@@ -221,7 +221,7 @@
+ * Read a tar file and extract or list the specified files within it.
+ * If the list is empty than all files are extracted or listed.
+ */
+-static void
++static int
+ readTarFile(int fileCount, const char ** fileTable)
+ {
+ const char * cp;
+@@ -250,7 +250,7 @@
+ {
+ perror(tarName);
+
+- return;
++ return 1;
+ }
+
+ /*
--- /dev/null
+Index: sash-3.7/Makefile
+===================================================================
+--- sash-3.7.orig/Makefile 2010-04-04 10:13:55.176949485 +0200
++++ sash-3.7/Makefile 2010-04-04 10:14:03.300968030 +0200
+@@ -13,13 +13,12 @@
+ HAVE_BSD_MOUNT = 0
+ MOUNT_TYPE = '"ext3"'
+
+-
+-CFLAGS = -O3 -Wall -Wmissing-prototypes \
+- -DHAVE_GZIP=$(HAVE_GZIP) \
++DEFS = -DHAVE_GZIP=$(HAVE_GZIP) \
+ -DHAVE_LINUX_ATTR=$(HAVE_LINUX_ATTR) \
+ -DHAVE_LINUX_MOUNT=$(HAVE_LINUX_MOUNT) \
+ -DHAVE_BSD_MOUNT=$(HAVE_BSD_MOUNT) \
+ -DMOUNT_TYPE=$(MOUNT_TYPE)
++CFLAGS = -O3 -Wall -Wmissing-prototypes -g $(DEFS)
+
+ LDFLAGS = -static -s
+ LIBS = -lz
+@@ -43,4 +42,7 @@
+ cp sash $(BINDIR)/sash
+ cp sash.1 $(MANDIR)/sash.1
+
++%.o: %.c
++ $(CC) $(CFLAGS) $(DEFS) -c $<
++
+ $(OBJS): sash.h
--- /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 */
--- /dev/null
+Subject: Use includes from e2fslibs rather than the kernel
+From: Tollef Fog Heen <tfheen@debian.org>
+Bug-Debian: #223203
+Last-updated: 2010-04-04
+Index: sash-3.7/cmd_chattr.c
+===================================================================
+--- sash-3.7.orig/cmd_chattr.c 2010-04-04 10:40:52.644957438 +0200
++++ sash-3.7/cmd_chattr.c 2010-04-04 10:41:11.084974379 +0200
+@@ -12,7 +12,7 @@
+
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+-#include <linux/ext2_fs.h>
++#include <ext2fs/ext2_fs.h>
+
+ #include "sash.h"
+
--- /dev/null
+Subject: Let exit have an optional argument
+From: Tollef Fog Heen <tfheen@debian.org>
+Last-updated: 2010-04-04
+Index: sash-3.7/cmds.c
+===================================================================
+--- sash-3.7.orig/cmds.c 2002-07-22 00:28:19.000000000 +0200
++++ sash-3.7/cmds.c 2010-04-04 10:58:51.604971262 +0200
+@@ -993,14 +993,18 @@
+ void
+ do_exit(int argc, const char ** argv)
+ {
++ int r = 0;
+ if (getpid() == 1)
+ {
+ fprintf(stderr, "You are the INIT process!\n");
+
+ return;
+ }
+-
+- exit(0);
++ if (argc == 2)
++ {
++ r = atoi(argv[1]);
++ }
++ exit(r);
+ }
+
+
+Index: sash-3.7/sash.c
+===================================================================
+--- sash-3.7.orig/sash.c 2004-01-14 06:08:03.000000000 +0100
++++ sash-3.7/sash.c 2010-04-04 10:58:51.604971262 +0200
+@@ -132,9 +132,9 @@
+ },
+
+ {
+- "exit", do_exit, 1, 1,
++ "exit", do_exit, 1, 2,
+ "Exit from sash",
+- ""
++ "[exit value]"
+ },
+
+ {
--- /dev/null
+Index: sash-3.7/sash.c
+===================================================================
+--- sash-3.7.orig/sash.c 2010-04-04 14:56:47.964954627 +0200
++++ sash-3.7/sash.c 2010-04-04 14:57:03.932954934 +0200
+@@ -375,10 +375,10 @@
+ */
+ static void catchInt(int);
+ static void catchQuit(int);
+-static void readFile(const char * name);
+-static void command(const char * cmd);
++static int readFile(const char * name);
++static int command(const char * cmd);
+ static BOOL tryBuiltIn(const char * cmd);
+-static void runCmd(const char * cmd);
++static int runCmd(const char * cmd);
+ static void childProcess(const char * cmd);
+ static void showPrompt(void);
+ static void usage(void);
+@@ -524,9 +524,7 @@
+ */
+ if (singleCommand)
+ {
+- command(singleCommand);
+-
+- return 0;
++ return command(singleCommand);
+ }
+
+ /*
+@@ -561,9 +559,8 @@
+ /*
+ * Read commands from stdin or from a command file.
+ */
+- readFile(commandFile);
++ return readFile(commandFile);
+
+- return 0;
+ }
+
+
+@@ -571,19 +568,20 @@
+ * Read commands from the specified file.
+ * A null name pointer indicates to read from stdin.
+ */
+-static void
++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;
++ return 1;
+ }
+
+ fp = stdin;
+@@ -596,7 +594,7 @@
+ {
+ perror(name);
+
+- return;
++ return 1;
+ }
+ }
+
+@@ -614,7 +612,7 @@
+ fclose(fp);
+ sourceCount--;
+
+- return;
++ return 1;
+ }
+
+ if (fgets(buf, CMD_LEN - 1, fp) == NULL)
+@@ -639,7 +637,7 @@
+
+ buf[cc] = '\0';
+
+- command(buf);
++ r = command(buf);
+ }
+
+ if (ferror(fp))
+@@ -656,6 +654,7 @@
+ fclose(fp);
+
+ sourceCount--;
++ return r;
+ }
+
+
+@@ -664,7 +663,7 @@
+ * This breaks the command line up into words, checks to see if the
+ * command is an alias, and expands wildcards.
+ */
+-static void
++static int
+ command(const char * cmd)
+ {
+ const char * endCmd;
+@@ -690,7 +689,7 @@
+ * If the command is empty or is a comment then ignore it.
+ */
+ if ((*cmd == '\0') || (*cmd == '#'))
+- return;
++ return 0;
+
+ /*
+ * Look for the end of the command name and then copy the
+@@ -726,13 +725,13 @@
+ * the command if found.
+ */
+ if (tryBuiltIn(cmd))
+- return;
++ return 0; /* This is a blatant lie */
+
+ /*
+ * The command is not a built-in, so run the program along
+ * the PATH list.
+ */
+- runCmd(cmd);
++ return runCmd(cmd);
+ }
+
+
+@@ -809,7 +808,7 @@
+ * Execute the specified command either by forking and executing
+ * the program ourself, or else by using the shell.
+ */
+-static void
++static int
+ runCmd(const char * cmd)
+ {
+ const char * cp;
+@@ -854,9 +853,7 @@
+ */
+ if (magic)
+ {
+- system(cmd);
+-
+- return;
++ return system(cmd);
+ }
+
+ /*
+@@ -869,7 +866,7 @@
+ {
+ perror("fork failed");
+
+- return;
++ return -1;
+ }
+
+ /*
+@@ -894,7 +891,7 @@
+ {
+ fprintf(stderr, "Error from waitpid: %s", strerror(errno));
+
+- return;
++ return -1;
+ }
+
+ if (WIFSIGNALED(status))
+@@ -902,6 +899,7 @@
+ fprintf(stderr, "pid %ld: killed by signal %d\n",
+ (long) pid, WTERMSIG(status));
+ }
++ return WEXITSTATUS(status);
+ }
+
+
--- /dev/null
+Subject: Don't check permissions before trying to execute a command
+From: Unknown
+Last-updated: 2010-04-04
+Index: sash-3.7/sash.c
+===================================================================
+--- sash-3.7.orig/sash.c 2010-04-04 10:12:57.228978742 +0200
++++ sash-3.7/sash.c 2010-04-04 10:13:04.008985124 +0200
+@@ -1172,13 +1172,6 @@
+
+ name = argv[1];
+
+- if (access(name, 4))
+- {
+- perror(name);
+-
+- return;
+- }
+-
+ while (--sourceCount >= 0)
+ {
+ if (sourcefiles[sourceCount] != stdin)
+@@ -1188,7 +1181,7 @@
+ argv[argc] = NULL;
+
+ execvp(name, (char **) argv + 1);
+- exit(1);
++ perror(name);
+ }
+
+
--- /dev/null
+Subject: Build fixes for Debian GNU/kFreeBSD
+From: Axel Beckert <abe@debian.org>
+Bug-Debian: #565539
+Last-updated: 2010-04-04
+Index: sash-3.7/Makefile
+===================================================================
+--- sash-3.7.orig/Makefile 2010-04-04 11:13:36.005953632 +0200
++++ sash-3.7/Makefile 2010-04-04 11:38:19.300955689 +0200
+@@ -9,9 +9,16 @@
+ #
+ HAVE_GZIP = 1
+ HAVE_LINUX_ATTR = 1
++ifeq (Linux,$(shell uname -s))
+ HAVE_LINUX_MOUNT = 1
+ HAVE_BSD_MOUNT = 0
+ MOUNT_TYPE = '"ext3"'
++endif
++ifeq (kFreeBSD,$(shell uname -s))
++HAVE_LINUX_MOUNT = 0
++HAVE_BSD_MOUNT = 1
++MOUNT_TYPE = '"ufs"'
++endif
+
+ DEFS = -DHAVE_GZIP=$(HAVE_GZIP) \
+ -DHAVE_LINUX_ATTR=$(HAVE_LINUX_ATTR) \
+Index: sash-3.7/cmds.c
+===================================================================
+--- sash-3.7.orig/cmds.c 2010-04-04 11:13:36.025952857 +0200
++++ sash-3.7/cmds.c 2010-04-04 11:37:59.160966064 +0200
+@@ -19,6 +19,10 @@
+
+ #if HAVE_LINUX_MOUNT
+ #include <linux/fs.h>
++#elif HAVE_BSD_MOUNT
++#include <ufs/ufs/ufsmount.h>
++#include <fs/cd9660/cd9660_mount.h>
++#include <fs/msdosfs/msdosfsmount.h>
+ #endif
+
+
+@@ -599,26 +603,16 @@
+ #elif HAVE_BSD_MOUNT
+ {
+ struct ufs_args ufs;
+- struct adosfs_args adosfs;
+ struct iso_args iso;
+- struct mfs_args mfs;
+ struct msdosfs_args msdosfs;
+ void * args;
+
+ if(!strcmp(type, "ffs") || !strcmp(type, "ufs")) {
+ ufs.fspec = (char*) argv[0];
+ args = &ufs;
+- } else if(!strcmp(type, "adosfs")) {
+- adosfs.fspec = (char*) argv[0];
+- adosfs.uid = 0;
+- adosfs.gid = 0;
+- args = &adosfs;
+ } else if(!strcmp(type, "cd9660")) {
+ iso.fspec = (char*) argv[0];
+ args = &iso;
+- } else if(!strcmp(type, "mfs")) {
+- mfs.fspec = (char*) argv[0];
+- args = &mfs;
+ } else if(!strcmp(type, "msdos")) {
+ msdosfs.fspec = (char*) argv[0];
+ msdosfs.uid = 0;
--- /dev/null
+Subject: Add -i option
+From: Michael Meskes <meskes@debian.org>
+Bug-Debian: #19656
+Last-updated: 2010-04-04
+Index: sash-3.7/sash.c
+===================================================================
+--- sash-3.7.orig/sash.c 2010-04-04 10:35:51.268950839 +0200
++++ sash-3.7/sash.c 2010-04-04 10:36:42.572973204 +0200
+@@ -399,12 +399,14 @@
+ 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.
+@@ -419,11 +421,17 @@
+
+ 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)
++ if ((argc != 1) || singleCommand || interactiveFlag)
+ usage();
+
+ singleCommand = *argv++;
+@@ -446,6 +454,18 @@
+
+ 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.
+@@ -1263,7 +1290,7 @@
+ {
+ fprintf(stderr, "Stand-alone shell (version %s)\n", version);
+ fprintf(stderr, "\n");
+- fprintf(stderr, "Usage: sash [-a] [-q] [-f fileName] [-c command] [-p prompt]\n");
++ fprintf(stderr, "Usage: sash [-a] [-q] [-f fileName] [-c command] [-p prompt] [-i]\n");
+
+ exit(1);
+ }
--- /dev/null
+exit_with_argument
+e2fslibs_chattr_include
+touch_error_handling
+interactive_flag
+fix_exec
+buildsystem
+freebsd_build
+exit_with_command_status
+debian-changes-3.7-10
--- /dev/null
+Subject: Correct error message when touching non-existent file in non-writeable directory
+From: Tollef Fog Heen <tfheen@debian.org>, Raul Miller <moth@debian.org>
+Bug-Debian: #43428
+Last-updated: 2010-04-04
+Index: sash-3.7/cmds.c
+===================================================================
+--- sash-3.7.orig/cmds.c 2010-04-04 10:58:51.000000000 +0200
++++ sash-3.7/cmds.c 2010-04-04 11:04:55.185955708 +0200
+@@ -341,6 +341,11 @@
+ continue;
+ }
+
++ if (errno != EEXIST) {
++ perror(name);
++ continue;
++ }
++
+ if (utime(name, &now) < 0)
+ perror(name);
+ }
--- /dev/null
+3.0 (quilt)
},
{
- "exit", do_exit, 1, 2,
+ "exit", do_exit, 1, 1,
"Exit from sash",
- "[exit value]"
+ ""
},
{
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.
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)
+ if ((argc != 1) || singleCommand)
usage();
singleCommand = *argv++;
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.
name = argv[1];
+ if (access(name, 4))
+ {
+ perror(name);
+
+ return;
+ }
+
while (--sourceCount >= 0)
{
if (sourcefiles[sourceCount] != stdin)
argv[argc] = NULL;
execvp(name, (char **) argv + 1);
- perror(name);
+ exit(1);
}
{
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");
+ fprintf(stderr, "Usage: sash [-a] [-q] [-f fileName] [-c command] [-p prompt]\n");
exit(1);
}