]> err.no Git - sash/commitdiff
Imported Upstream version 3.8 upstream upstream/3.8
authorTollef Fog Heen <tfheen@err.no>
Sun, 20 Apr 2014 06:14:39 +0000 (08:14 +0200)
committerTollef Fog Heen <tfheen@err.no>
Sun, 20 Apr 2014 06:14:39 +0000 (08:14 +0200)
18 files changed:
CHANGES
Makefile
README
cmd_ar.c
cmd_chattr.c
cmd_dd.c
cmd_ed.c
cmd_file.c
cmd_find.c
cmd_grep.c
cmd_gzip.c
cmd_ls.c
cmd_tar.c
cmds.c
sash.1
sash.c
sash.h
utils.c

diff --git a/CHANGES b/CHANGES
index 4179511052ccaad295a15953a3668fb19140c737..c87d6d5cb320528c37fae3412da75298a56183af 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,20 @@
+These are the major changes from version 3.7 to version 3.8:
+
+The Makefile has been updated for several distribution's standards.
+The ext2_fs include file location has been changed.
+Some compiler warnings were fixed.
+
+The -ls command has the -n option to print numeric user and group ids.
+
+The -n option might be needed in case the unsuppressable dynamic
+linking used to lookup the names fails.
+
+The -chroot, -pivot_root, and -losetup commands have been added.
+
+The exit status for commands has been implemented (such as -exit).
+Thanks to Tollef Fog Heen for the patches.
+
+
 These are the major changes from version 3.6 to version 3.7:
 
 A few bugs in the dd command have been fixed.
index bd8358e534c1f52cfd5fb54397a3f7b31e7df4b9..a231ae815aa6474b89d87c0a0e51bc2d95f36889 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,30 +3,49 @@
 #
 # The HAVE_GZIP definition adds the -gzip and -gunzip commands.
 # The HAVE_LINUX_ATTR definition adds the -chattr and -lsattr commands.
+# The HAVE_LINUX_CHROOT definition adds the -chroot command.
+# The HAVE_LINUX_PIVOT definition adds the -pivot_root command.
+# The HAVE_LINUX_LOSETUP definition adds the -losetup command.
 # The HAVE_LINUX_MOUNT definition makes -mount and -umount work on Linux.
 # The HAVE_BSD_MOUNT definition makes -mount and -umount work on BSD.
 # The MOUNT_TYPE definition sets the default file system type for -mount.
 #
+# Note that the linker may show warnings about 'statically linked
+# programs' requiring getpwnam, getpwuid, getgrnam and getgrgid.
+# This is unavoidable since those routines use dynamic libraries anyway.
+# Sash will still run, but if there are shared library problems then
+# the user might have to be be careful when using the -chown, -chgrp,
+# and -ls commands.
+#
+
 HAVE_GZIP              = 1
 HAVE_LINUX_ATTR                = 1
+HAVE_LINUX_CHROOT      = 1
+HAVE_LINUX_LOSETUP     = 1
+HAVE_LINUX_PIVOT       = 1
 HAVE_LINUX_MOUNT       = 1
 HAVE_BSD_MOUNT         = 0
 MOUNT_TYPE             = '"ext3"'
 
+OPT = -O3
 
-CFLAGS = -O3 -Wall -Wmissing-prototypes \
+CFLAGS = $(OPT) -Wall -Wmissing-prototypes \
        -DHAVE_GZIP=$(HAVE_GZIP) \
        -DHAVE_LINUX_ATTR=$(HAVE_LINUX_ATTR) \
+       -DHAVE_LINUX_CHROOT=$(HAVE_LINUX_CHROOT) \
+       -DHAVE_LINUX_LOSETUP=$(HAVE_LINUX_LOSETUP) \
+       -DHAVE_LINUX_PIVOT=$(HAVE_LINUX_PIVOT) \
        -DHAVE_LINUX_MOUNT=$(HAVE_LINUX_MOUNT) \
        -DHAVE_BSD_MOUNT=$(HAVE_BSD_MOUNT) \
        -DMOUNT_TYPE=$(MOUNT_TYPE)
 
-LDFLAGS = -static -s
+LDFLAGS = -static
 LIBS = -lz
 
 
+DESTDIR =
 BINDIR = /bin
-MANDIR = /usr/man/man1
+MANDIR = /usr/man
 
 
 OBJS = sash.o cmds.o cmd_dd.o cmd_ed.o cmd_grep.o cmd_ls.o cmd_tar.o \
@@ -35,12 +54,13 @@ OBJS = sash.o cmds.o cmd_dd.o cmd_ed.o cmd_grep.o cmd_ls.o cmd_tar.o \
 
 sash:  $(OBJS)
        $(CC) $(LDFLAGS) -o sash $(OBJS) $(LIBS)
+       strip sash
 
 clean:
        rm -f $(OBJS) sash
 
 install: sash
-       cp sash $(BINDIR)/sash
-       cp sash.1 $(MANDIR)/sash.1
+       cp sash $(DESTDIR)/$(BINDIR)/sash
+       cp sash.1 $(DESTDIR)/$(MANDIR)/man1/sash.1
 
 $(OBJS):       sash.h
diff --git a/README b/README
index 7794d7526577133491e47f234e686996b40a7038..154f1f757276b6e83af64a566000d17ba533399e 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is release 3.7 of sash, my stand-alone shell for Linux or other systems.
+This is release 3.8 of sash, my stand-alone shell for Linux or other systems.
 
 The purpose of this program is to make system recovery possible in
 many cases where there are missing shared libraries or executables.
@@ -13,5 +13,5 @@ other UNIX-like systems.  In particular, dependencies on Linux file
 systems can be removed and the mount command can be configured.
 
 David I. Bell
-dbell@canb.auug.org.au
-12 January 2004
+dbell@tip.net.au
+8 March 2014
index 0f8d58512ee81e0c6fbbf14c105c89e46ea04523..6c6181e9223461c57d922dd9168b543a38382309 100644 (file)
--- a/cmd_ar.c
+++ b/cmd_ar.c
@@ -5,7 +5,7 @@
  * provided that this copyright notice remains intact.
  *
  * Modified:
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
  */
 typedef struct
 {
-       int             fd;             /* file reading archive from */
-       BOOL            eof;            /* end of file has been seen */
-       BOOL            rescan;         /* rescan the header just read */
-       unsigned char * nameTable;      /* long name table */
+       int     fd;             /* file reading archive from */
+       BOOL    eof;            /* end of file has been seen */
+       BOOL    rescan;         /* rescan the header just read */
+       char *  nameTable;      /* long name table */
 
        /*
         * Information about the current file read from the archive.
         * This is extracted from the latest member header read.
         */
-       char *          name;           /* current file name */
-       time_t          date;           /* date of file */
-       uid_t           uid;            /* user id */
-       gid_t           gid;            /* group id */
-       mode_t          mode;           /* file protection */
-       off_t           size;           /* file size */
-       int             pad;            /* padding to next header */
+       char *  name;           /* current file name */
+       time_t  date;           /* date of file */
+       uid_t   uid;            /* user id */
+       gid_t   gid;            /* group id */
+       mode_t  mode;           /* file protection */
+       off_t   size;           /* file size */
+       int     pad;            /* padding to next header */
 } Archive;
 
 
@@ -76,7 +76,7 @@ static BOOL   getNumber(const char * s, unsigned base, int max_digits,
                        unsigned long * ul);
 
 
-void
+int
 do_ar(int argc, const char ** argv)
 {
        const char *    options;
@@ -85,8 +85,10 @@ do_ar(int argc, const char ** argv)
        BOOL            doTable;
        BOOL            doPrint;
        BOOL            verbose;
+       int             r;
        Archive         arch;
 
+       r = 0;
        verbose = FALSE;
        doExtract = FALSE;
        doTable = FALSE;
@@ -96,7 +98,7 @@ do_ar(int argc, const char ** argv)
        {
                fprintf(stderr, "Too few arguments for ar\n");
 
-               return;
+               return 1;
        }
 
        /*
@@ -137,12 +139,12 @@ do_ar(int argc, const char ** argv)
                case 'd': case 'm': case 'q': case 'r':
                        fprintf(stderr, "Writing ar files is not supported\n");
 
-                       return;
+                       return 1;
 
                default:
                        fprintf(stderr, "Unknown ar flag: %c\n", *options);
 
-                       return;
+                       return 1;
                }
        }
 
@@ -151,7 +153,7 @@ do_ar(int argc, const char ** argv)
                fprintf(stderr,
                        "Exactly one of 'x', 'p' or 't' must be specified\n");
 
-               return;
+               return 1;
        }
 
        /*
@@ -160,13 +162,13 @@ do_ar(int argc, const char ** argv)
        initArchive(&arch);
 
        if (!openArchive(archiveName, &arch))
-               return;
+               return 1;
 
        /*
         * Read the first special member of the archive.
         */
        if (!readSpecialMember(&arch))
-               return;
+               return 1;
 
        /*
         * Read all of the normal members of the archive.
@@ -237,16 +239,22 @@ do_ar(int argc, const char ** argv)
                        }
 
                        if (!success)
+                       {
+                               r = 1;
                                break;
+                       }
                }
                else
                {
                        fprintf(stderr, "Oops -- I don't know what to do\n");
+                       r = 1;
                        break;
                }
        }
 
        closeArchive(&arch);
+
+       return r;
 }
 
 
@@ -275,8 +283,8 @@ createFile(const Archive * arch)
         * specifying the mode in the open() call, because that mode is
         * munged by the umask.
         */
-       (void) fchmod(fd, arch->mode);
-       (void) fchown(fd, arch->uid, arch->gid);
+       checkStatus("fchmod", fchmod(fd, arch->mode));
+       checkStatus("fchown", fchown(fd, arch->uid, arch->gid));
 
        return fd;
 }
@@ -949,8 +957,8 @@ skipMember(const Archive * arch)
 static BOOL
 writeFile(const Archive * arch, int outfd)
 {
-       unsigned char   buf[BUF_SIZE];
-       off_t           n;
+       char    buf[BUF_SIZE];
+       off_t   n;
 
        n = arch->size;
 
index 5fc43c250f9ddebb602772db74166f964f303bf5..df50c2282004e24727915e2620309b2390d3585b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
 
 #include <sys/ioctl.h>
 #include <sys/types.h>
-#include <linux/ext2_fs.h>
+
+/*
+ * These were used for old linux versions.
+ * #include <linux/fs.h>
+ * #include <linux/ext2_fs.h>
+ */
+
+#include <ext2fs/ext2_fs.h>
+
 
 #include "sash.h"
 
@@ -21,7 +29,7 @@
  * The chattr command.
  * This can turn on or off the immutable and append-only ext2 flags.
  */
-void
+int
 do_chattr(int argc, const char ** argv)
 {
        const char *    fileName;
@@ -32,7 +40,9 @@ do_chattr(int argc, const char ** argv)
        int             oldFlags;
        int             newFlags;
        int             fd;
+       int             r;
 
+       r = 0;
        argc--;
        argv++;
 
@@ -74,7 +84,7 @@ do_chattr(int argc, const char ** argv)
                                        fprintf(stderr, "Unknown flag '%c'\n",
                                                options[-1]);
 
-                                       return;
+                                       return 1;
                        }
                }
        }
@@ -86,14 +96,14 @@ do_chattr(int argc, const char ** argv)
        {
                fprintf(stderr, "No attributes specified\n");
 
-               return;
+               return 1;
        }
 
        if ((onFlags & offFlags) != 0)
        {
                fprintf(stderr, "Inconsistent attributes specified\n");
 
-               return;
+               return 1;
        }
 
        /*
@@ -103,7 +113,7 @@ do_chattr(int argc, const char ** argv)
        {
                fprintf(stderr, "No files specified for setting attributes\n");
 
-               return;
+               return 1;
        }
 
        /*
@@ -121,7 +131,7 @@ do_chattr(int argc, const char ** argv)
                if (fd < 0)
                {
                        perror(fileName);
-
+                       r = 1;
                        continue;
                }
 
@@ -131,7 +141,7 @@ do_chattr(int argc, const char ** argv)
                if (ioctl(fd, EXT2_IOC_GETFLAGS, &oldFlags) < 0)
                {
                        perror(fileName);
-
+                       r = 1;
                        (void) close(fd);
 
                        continue;
@@ -161,7 +171,7 @@ do_chattr(int argc, const char ** argv)
                if (ioctl(fd, EXT2_IOC_SETFLAGS, &newFlags) < 0)
                {
                        perror(fileName);
-
+                       r = 1;
                        (void) close(fd);
 
                        continue;
@@ -172,6 +182,8 @@ do_chattr(int argc, const char ** argv)
                 */
                (void) close(fd);
        }
+
+       return r;
 }
 
 
@@ -179,15 +191,17 @@ do_chattr(int argc, const char ** argv)
  * The lsattr command.
  * This lists the immutable and append-only ext2 flags.
  */
-void
+int
 do_lsattr(int argc, const char ** argv)
 {
        const char *    fileName;
+       int             r;
        int             fd;
        int             status;
        int             flags;
        char            string[4];
 
+       r = 0;
        argc--;
        argv++;
 
@@ -206,7 +220,7 @@ do_lsattr(int argc, const char ** argv)
                if (fd < 0)
                {
                        perror(fileName);
-
+                       r = 1;
                        continue;
                }
 
@@ -223,6 +237,7 @@ do_lsattr(int argc, const char ** argv)
                if (status < 0)
                {
                        perror(fileName);
+                       r = 1;
 
                        continue;
                }
@@ -240,6 +255,8 @@ do_lsattr(int argc, const char ** argv)
                 */
                printf("%s  %s\n", string, fileName);
        }
+
+       return r;
 }
 
 #endif
index 9708924bb7926fe06c9e9163827420ffe6cbf929..80338b69ea8f76f52ddc560acd6ae5e4742f50cb 100644 (file)
--- a/cmd_dd.c
+++ b/cmd_dd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -40,7 +40,7 @@ static const PARAM    params[] =
 static long    getNum(const char * cp);
 
 
-void
+int
 do_dd(int argc, const char ** argv)
 {
        const char *    str;
@@ -62,6 +62,7 @@ do_dd(int argc, const char ** argv)
        long            outPartial;
        char *          buf;
        char            localBuf[BUF_SIZE];
+       int             r;
 
        inFile = NULL;
        outFile = NULL;
@@ -69,6 +70,7 @@ do_dd(int argc, const char ** argv)
        skipVal = 0;
        blockSize = 512;
        count = -1;
+       r = 0;
 
        while (--argc > 0)
        {
@@ -79,7 +81,7 @@ do_dd(int argc, const char ** argv)
                {
                        fprintf(stderr, "Bad dd argument\n");
 
-                       return;
+                       return 1;
                }
 
                *cp++ = '\0';
@@ -97,7 +99,7 @@ do_dd(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Multiple input files illegal\n");
 
-                                       return;
+                                       return 1;
                                }
        
                                inFile = cp;
@@ -108,7 +110,7 @@ do_dd(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Multiple output files illegal\n");
 
-                                       return;
+                                       return 1;
                                }
 
                                outFile = cp;
@@ -121,7 +123,7 @@ do_dd(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Bad block size value\n");
 
-                                       return;
+                                       return 1;
                                }
 
                                break;
@@ -133,7 +135,7 @@ do_dd(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Bad count value\n");
 
-                                       return;
+                                       return 1;
                                }
 
                                break;
@@ -145,7 +147,7 @@ do_dd(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Bad seek value\n");
 
-                                       return;
+                                       return 1;
                                }
 
                                break;
@@ -157,7 +159,7 @@ do_dd(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Bad skip value\n");
 
-                                       return;
+                                       return 1;
                                }
 
                                break;
@@ -165,7 +167,7 @@ do_dd(int argc, const char ** argv)
                        default:
                                fprintf(stderr, "Unknown dd parameter\n");
 
-                               return;
+                               return 1;
                }
        }
 
@@ -173,14 +175,14 @@ do_dd(int argc, const char ** argv)
        {
                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 @@ do_dd(int argc, const char ** argv)
                {
                        fprintf(stderr, "Cannot allocate buffer\n");
 
-                       return;
+                       return 1;
                }
        }
 
@@ -211,7 +213,7 @@ do_dd(int argc, const char ** argv)
                if (buf != localBuf)
                        free(buf);
 
-               return;
+               return 1;
        }
 
        outFd = creat(outFile, 0666);
@@ -224,7 +226,7 @@ do_dd(int argc, const char ** argv)
                if (buf != localBuf)
                        free(buf);
 
-               return;
+               return 1;
        }
 
        if (skipVal)
@@ -238,12 +240,14 @@ do_dd(int argc, const char ** argv)
                                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 @@ do_dd(int argc, const char ** argv)
                if (lseek(outFd, seekVal * blockSize, 0) < 0)
                {
                        perror(outFile);
-
+                       r = 1;
                        goto cleanup;
                }
        }
@@ -274,6 +278,7 @@ do_dd(int argc, const char ** argv)
                if (intFlag)
                {
                        fprintf(stderr, "Interrupted\n");
+                       r = 1;
                        goto cleanup;
                }
 
@@ -284,6 +289,7 @@ do_dd(int argc, const char ** argv)
                        if (outCc < 0)
                        {
                                perror(outFile);
+                               r = 1;
                                goto cleanup;
                        }
 
@@ -303,7 +309,10 @@ cleanup:
        close(inFd);
 
        if (close(outFd) < 0)
+       {
                perror(outFile);
+               r = 1;
+       }
 
        if (buf != localBuf)
                free(buf);
@@ -311,6 +320,8 @@ cleanup:
        printf("%ld+%ld records in\n", inFull, inPartial);
 
        printf("%ld+%ld records out\n", outFull, outPartial);
+
+       return r;
 }
 
 
index 11d6850f2418bf1ca73de36fc02235c8af908d54..e935c0dc187096d6f66d288beacce23fb30b559d 100644 (file)
--- a/cmd_ed.c
+++ b/cmd_ed.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -60,11 +60,11 @@ static      LEN     findString
        (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 @@ do_ed(int argc, const char ** argv)
                        fprintf(stderr, "No memory\n");
                        termEdit();
 
-                       return;
+                       return 1;
                }
 
                if (!readLines(fileName, 1))
                {
                        termEdit();
 
-                       return;
+                       return 1;
                }
 
                if (lastNum)
@@ -94,6 +94,7 @@ do_ed(int argc, const char ** argv)
        doCommands();
 
        termEdit();
+       return 0;
 }
 
 
@@ -281,7 +282,10 @@ doCommands(void)
                                fflush(stdout);
 
                                buf[0] = '\0';
-                               fgets(buf, sizeof(buf), stdin);
+
+                               if (fgets(buf, sizeof(buf), stdin) == NULL)
+                                       return;
+
                                cp = buf;
 
                                while (isBlank(*cp))
@@ -1111,10 +1115,10 @@ writeLines(const char * file, NUM num1, NUM num2)
 static BOOL
 printLines(NUM num1, NUM num2, BOOL expandFlag)
 {
-       const LINE *            lp;
-       const unsigned char *   cp;
-       int                     ch;
-       LEN                     count;
+       const LINE *    lp;
+       const char *    cp;
+       int             ch;
+       LEN             count;
 
        if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
        {
@@ -1132,7 +1136,7 @@ printLines(NUM num1, NUM num2, BOOL expandFlag)
        {
                if (!expandFlag)
                {
-                       write(STDOUT, lp->data, lp->len);
+                       tryWrite(STDOUT, lp->data, lp->len);
                        setCurNum(num1++);
                        lp = lp->next;
 
@@ -1151,7 +1155,7 @@ printLines(NUM num1, NUM num2, BOOL expandFlag)
 
                while (count-- > 0)
                {
-                       ch = *cp++;
+                       ch = *cp++ & 0xff;
 
                        if (ch & 0x80)
                        {
index 695e9c01b448cc9d660652326bde7eb770031b09..caf2a30382ca3e2f8428f7648df65a4bec61bb37 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -17,7 +17,7 @@
 static const char *    checkFile(const char * name);
 
 
-void
+int
 do_file(int argc, const char ** argv)
 {
        const char *    name;
@@ -37,6 +37,8 @@ do_file(int argc, const char ** argv)
 
                printf("%s: %s\n", name, info);
        }
+
+       return 0;
 }
 
 
index 48f9d012665619c8dc4808708ac3b13552175f73..fde9006083938528f1abfbe544e266660b334ac8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -46,7 +46,7 @@ static        BOOL    testFile(const char * fullName, const struct stat * statBuf);
  * Find files from the specified directory path.
  * This is limited to just printing their file names.
  */
-void
+int
 do_find(int argc, const char ** argv)
 {
        const char *    cp;
@@ -65,7 +65,7 @@ do_find(int argc, const char ** argv)
        {
                fprintf(stderr, "No path specified\n");
 
-               return;
+               return 1;
        }
 
        path = *argv++;
@@ -84,7 +84,7 @@ do_find(int argc, const char ** argv)
                        {
                                fprintf(stderr, "Missing type string\n");
 
-                               return;
+                               return 1;
                        }
 
                        argc--;
@@ -96,7 +96,7 @@ do_find(int argc, const char ** argv)
                        {
                                fprintf(stderr, "Missing file name\n");
 
-                               return;
+                               return 1;
                        }
 
                        argc--;
@@ -108,7 +108,7 @@ do_find(int argc, const char ** argv)
                        {
                                fprintf(stderr, "Missing file size\n");
 
-                               return;
+                               return 1;
                        }
 
                        argc--;
@@ -123,7 +123,7 @@ do_find(int argc, const char ** argv)
                        {
                                fprintf(stderr, "Bad file size specified\n");
 
-                               return;
+                               return 1;
                        }
                }
                else
@@ -133,7 +133,7 @@ do_find(int argc, const char ** argv)
                        else
                                fprintf(stderr, "Unknown option\n");
 
-                       return;
+                       return 1;
                }
        }
 
@@ -146,14 +146,14 @@ do_find(int argc, const char ** argv)
                fprintf(stderr, "Cannot stat \"%s\": %s\n", path,
                        strerror(errno));
 
-               return;
+               return 1;
        }
 
        if (!S_ISDIR(statBuf.st_mode))
        {
                fprintf(stderr, "Path \"%s\" is not a directory\n", path);
 
-               return;
+               return 1;
        }
 
        /*
@@ -171,6 +171,8 @@ do_find(int argc, const char ** argv)
         * Now examine the files in the directory.
         */
        examineDirectory(path);
+
+       return 0;
 }
 
 
index 504d9d45a2939d5583a401dcccf9de6400bb20c2..b9e08212982b457bacce9d14b761e2b09e33fe8c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -15,7 +15,7 @@ static        BOOL    search
        (const char * string, const char * word, BOOL ignoreCase);
 
 
-void
+int
 do_grep(int argc, const char ** argv)
 {
        FILE *          fp;
@@ -27,7 +27,9 @@ do_grep(int argc, const char ** argv)
        BOOL            tellLine;
        long            line;
        char            buf[BUF_SIZE];
+       int             r;
 
+       r = 1;
        ignoreCase = FALSE;
        tellLine = FALSE;
 
@@ -52,7 +54,7 @@ do_grep(int argc, const char ** argv)
                        default:
                                fprintf(stderr, "Unknown option\n");
 
-                               return;
+                               return 1;
                }
        }
 
@@ -70,6 +72,7 @@ do_grep(int argc, const char ** argv)
                if (fp == NULL)
                {
                        perror(name);
+                       r = 1;
 
                        continue;
                }
@@ -82,7 +85,7 @@ do_grep(int argc, const char ** argv)
                        {
                                fclose(fp);
 
-                               return;
+                               return 1;
                        }
 
                        line++;
@@ -94,6 +97,7 @@ do_grep(int argc, const char ** argv)
 
                        if (search(buf, word, ignoreCase))
                        {
+                               r = 0;
                                if (tellName)
                                        printf("%s: ", name);
 
@@ -109,6 +113,8 @@ do_grep(int argc, const char ** argv)
 
                fclose(fp);
        }
+
+       return r;
 }
 
 
index 895d3cfb0c2452ab71c4c189bf2c49a1a6766797..6bcec11b2faf2bed85983fe24caf423ca31f4503 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -62,14 +62,16 @@ static const char * convertName
        (const CONVERT * table, const char * inFile);
 
 
-void
+int
 do_gzip(int argc, const char ** argv)
 {
        const char *    outPath;
        const char *    inFile;
        const char *    outFile;
        int             i;
+       int             r;
 
+       r = 0;
        argc--;
        argv++;
 
@@ -99,7 +101,7 @@ do_gzip(int argc, const char ** argv)
                        else
                                fprintf(stderr, "Illegal option\n");
 
-                       return;
+                       return 1;
                }
        }
        
@@ -120,7 +122,11 @@ do_gzip(int argc, const char ** argv)
                         * Try to compress the file.
                         */
                        if (!gzip(inFile, outFile))
+                       {
+                               r = 1;
+
                                continue;
+                       }
 
                        /*
                         * This was successful.
@@ -130,10 +136,12 @@ do_gzip(int argc, const char ** argv)
                        {
                                fprintf(stderr, "%s: %s\n", inFile,
                                        "Compressed ok but unlink failed");
+
+                               r = 1;
                        }
                }
 
-               return;
+               return r;
        }
 
        /*
@@ -145,11 +153,14 @@ do_gzip(int argc, const char ** argv)
        if (!isDirectory(outPath))
        {
                if (argc == 1)
-                       (void) gzip(*argv, outPath);
+                       r = !gzip(*argv, outPath);
                else
+               {
                        fprintf(stderr, "Exactly one input file is required\n");
+                       r = 1;
+               }
 
-               return;
+               return r;
        }
 
        /*
@@ -187,19 +198,24 @@ do_gzip(int argc, const char ** argv)
                /*
                 * Compress the input file without deleting the input file.
                 */
-               (void) gzip(inFile, outFile);
+               if (!gzip(inFile, outFile))
+                       r = 1;
        }
+
+       return r;
 }
 
 
-void
+int
 do_gunzip(int argc, const char ** argv)
 {
        const char *    outPath;
        const char *    inFile;
        const char *    outFile;
        int             i;
+       int             r;
 
+       r = 0;
        argc--;
        argv++;
 
@@ -229,7 +245,7 @@ do_gunzip(int argc, const char ** argv)
                        else
                                fprintf(stderr, "Illegal option\n");
 
-                       return;
+                       return 1;
                }
        }
        
@@ -251,6 +267,7 @@ do_gunzip(int argc, const char ** argv)
                        {
                                fprintf(stderr, "%s: %s\n", inFile,
                                        "missing compression extension");
+                               r = 1;
 
                                continue;
                        }
@@ -259,7 +276,10 @@ do_gunzip(int argc, const char ** argv)
                         * Try to uncompress the file.
                         */
                        if (!gunzip(inFile, outFile))
+                       {
+                               r = 1;
                                continue;
+                       }
 
                        /*
                         * This was successful.
@@ -269,10 +289,11 @@ do_gunzip(int argc, const char ** argv)
                        {
                                fprintf(stderr, "%s: %s\n", inFile,
                                        "Uncompressed ok but unlink failed");
+                               r = 1;
                        }
                }
 
-               return;
+               return r;
        }
 
        /*
@@ -283,9 +304,12 @@ do_gunzip(int argc, const char ** argv)
        if (isDevice(outPath))
        {
                while (!intFlag && (argc-- > 0))
-                       (void) gunzip(*argv++, outPath);
+               {
+                       if (!gunzip(*argv++, outPath))
+                               r = 1;
+               }
 
-               return;
+               return r;
        }
 
        /*
@@ -296,11 +320,11 @@ do_gunzip(int argc, const char ** argv)
        if (!isDirectory(outPath))
        {
                if (argc == 1)
-                       (void) gunzip(*argv, outPath);
+                       return !gunzip(*argv, outPath);
                else
                        fprintf(stderr, "Exactly one input file is required\n");
 
-               return;
+               return 1;
        }
 
        /*
@@ -338,8 +362,11 @@ do_gunzip(int argc, const char ** argv)
                /*
                 * Uncompress the input file without deleting the input file.
                 */
-               (void) gunzip(inFile, outFile);
+               if (!gunzip(inFile, outFile))
+                       r = 1;
        }
+
+       return r;
 }
 
 
index 7b9c8ee6c8a4e98257090c4c0b259a6ecccdf7a2..20d28f72dd32aa8f4534c6a189351afc8a09c74a 100644 (file)
--- a/cmd_ls.c
+++ b/cmd_ls.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -34,6 +34,7 @@
 #define        LSF_MULT        0x08
 #define        LSF_FLAG        0x10
 #define        LSF_COLUMN      0x20
+#define        LSF_NUMERIC     0x40
 
 
 /*
@@ -43,6 +44,16 @@ static       char ** list;
 static int     listSize;
 static int     listUsed;
 
+/*
+ * Cached user and group name data.
+ */
+static char    userName[12];
+static int     userId;
+static BOOL    userIdKnown;
+static char    groupName[12];
+static int     groupId;
+static BOOL    groupIdKnown;
+
 
 /*
  * Local procedures.
@@ -59,7 +70,7 @@ static        void    listAllFiles(int flags, int displayWidth);
 static void    clearListNames(void);
 
 
-void
+int
 do_ls(int argc, const char ** argv)
 {
        const char *    cp;
@@ -72,6 +83,7 @@ do_ls(int argc, const char ** argv)
        struct dirent * dp;
        char            fullName[PATH_LEN];
        struct  stat    statBuf;
+       int             r;
 
        static const char *     def[] = {"."};
 
@@ -80,6 +92,9 @@ do_ls(int argc, const char ** argv)
         */
        clearListNames();
 
+       userIdKnown = FALSE;
+       groupIdKnown = FALSE;
+
        displayWidth = 0;
        flags = 0;
 
@@ -97,6 +112,7 @@ do_ls(int argc, const char ** argv)
                while (*cp) switch (*cp++)
                {
                        case 'l':       flags |= LSF_LONG; break;
+                       case 'n':       flags |= LSF_NUMERIC; break;
                        case 'd':       flags |= LSF_DIR; break;
                        case 'i':       flags |= LSF_INODE; break;
                        case 'F':       flags |= LSF_FLAG; break;
@@ -105,14 +121,14 @@ do_ls(int argc, const char ** argv)
                        default:
                                fprintf(stderr, "Unknown option -%c\n", cp[-1]);
 
-                               return;
+                               return 1;
                }
        }
 
        /*
-        * If long listing is specified then turn off column listing.
+        * If long or numeric listing is specified then turn off column listing.
         */
-       if (flags & LSF_LONG)
+       if (flags & (LSF_LONG | LSF_NUMERIC))
                flags &= ~LSF_COLUMN;
 
        /*
@@ -153,7 +169,7 @@ do_ls(int argc, const char ** argv)
                if ((flags & LSF_DIR) || !isDirectory(argv[i]))
                {
                        if (!addListName(argv[i]))
-                               return;
+                               return 1;
                }
        }
 
@@ -167,7 +183,7 @@ do_ls(int argc, const char ** argv)
         * 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 +196,7 @@ do_ls(int argc, const char ** argv)
                if (LSTAT(name, &statBuf) < 0)
                {
                        perror(name);
+                       r = 1;
 
                        continue;
                }
@@ -226,7 +243,7 @@ do_ls(int argc, const char ** argv)
                        {
                                closedir(dirp);
 
-                               return;
+                               return 1;
                        }
                }
 
@@ -239,6 +256,8 @@ do_ls(int argc, const char ** argv)
                listAllFiles(flags, displayWidth);
                clearListNames();
        }
+
+       return r;
 }
 
 
@@ -359,12 +378,6 @@ listFile(
        int             flagChar;
        int             usedWidth;
        char            buf[PATH_LEN];
-       static  char    userName[12];
-       static  int     userId;
-       static  BOOL    userIdKnown;
-       static  char    groupName[12];
-       static  int     groupId;
-       static  BOOL    groupIdKnown;
 
        mode = statBuf->st_mode;
 
@@ -385,19 +398,22 @@ listFile(
        }
 
        /*
-        * Create the long status line if requested.
+        * Create the long or numeric status line if requested.
         */
-       if (flags & LSF_LONG)
+       if (flags & (LSF_LONG | LSF_NUMERIC))
        {
                strcpy(cp, modeString(mode));
                cp += strlen(cp);
 
-               sprintf(cp, "%3d ", statBuf->st_nlink);
+               sprintf(cp, "%3ld ", (long) statBuf->st_nlink);
                cp += strlen(cp);
 
                if (!userIdKnown || (statBuf->st_uid != userId))
                {
-                       pwd = getpwuid(statBuf->st_uid);
+                       if (flags & LSF_NUMERIC)
+                               pwd = 0;
+                       else
+                               pwd = getpwuid(statBuf->st_uid);
 
                        if (pwd)
                                strcpy(userName, pwd->pw_name);
@@ -413,7 +429,10 @@ listFile(
 
                if (!groupIdKnown || (statBuf->st_gid != groupId))
                {
-                       grp = getgrgid(statBuf->st_gid);
+                       if (flags & LSF_NUMERIC)
+                               grp = 0;
+                       else
+                               grp = getgrgid(statBuf->st_gid);
 
                        if (grp)
                                strcpy(groupName, grp->gr_name);
index 42bed3d4b8d210847befe8eed56b855c31612215..5dd5f21cc194bf534ad2d3188d8ca63cbce4c48f 100644 (file)
--- a/cmd_tar.c
+++ b/cmd_tar.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -87,12 +87,12 @@ static      ino_t           tarInode;
 /*
  * Local procedures to restore files from a tar file.
  */
-static void    readTarFile(int fileCount, const char ** fileTable);
-static void    readData(const char * cp, int count);
-static void    createPath(const char * name, int mode);
+static BOOL    readTarFile(int fileCount, const char ** fileTable);
+static BOOL    readData(const char * cp, int count);
+static BOOL    createPath(const char * name, int mode);
 static long    getOctal(const char * cp, int len);
 
-static void    readHeader(const TarHeader * hp,
+static BOOL    readHeader(const TarHeader * hp,
                        int fileCount, const char ** fileTable);
 
 
@@ -113,16 +113,17 @@ static    BOOL    wantFileName(const char * fileName,
 static void    writeHeader(const char * fileName,
                        const struct stat * statbuf);
 
-static void    writeTarFile(int fileCount, const char ** fileTable);
+static BOOL    writeTarFile(int fileCount, const char ** fileTable);
 static void    writeTarBlock(const char * buf, int len);
 static BOOL    putOctal(char * cp, int len, long value);
 
 
 
-void
+int
 do_tar(int argc, const char ** argv)
 {
        const char *    options;
+       BOOL            successFlag;
 
        argc--;
        argv++;
@@ -131,7 +132,7 @@ do_tar(int argc, const char ** argv)
        {
                fprintf(stderr, "Too few arguments for tar\n");
 
-               return;
+               return 1;
        }
 
        extractFlag = FALSE;
@@ -158,7 +159,7 @@ do_tar(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Only one 'f' option allowed\n");
 
-                                       return;
+                                       return 1;
                                }
 
                                tarName = *argv++;
@@ -185,7 +186,7 @@ do_tar(int argc, const char ** argv)
                        default:
                                fprintf(stderr, "Unknown tar flag '%c'\n", *options);
 
-                               return;
+                               return 1;
                }
        }
 
@@ -196,14 +197,14 @@ do_tar(int argc, const char ** argv)
        {
                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,20 +212,24 @@ do_tar(int argc, const char ** argv)
         * command line arguments as the list of files to process.
         */
        if (createFlag)
-               writeTarFile(argc, argv);
+               successFlag = writeTarFile(argc, argv);
        else
-               readTarFile(argc, argv);
+               successFlag = readTarFile(argc, argv);
+
+       return !successFlag;
 }
 
 
 /*
  * 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.
+ * Returns TRUE on success.
  */
-static void
+static BOOL
 readTarFile(int fileCount, const char ** fileTable)
 {
        const char *    cp;
+       BOOL            successFlag;
        int             cc;
        int             inCc;
        int             blockSize;
@@ -235,6 +240,8 @@ readTarFile(int fileCount, const char ** fileTable)
        warnedRoot = FALSE;
        eofFlag = FALSE;
        inHeader = TRUE;
+       successFlag = TRUE;
+
        inCc = 0;
        dataCc = 0;
        outFd = -1;
@@ -250,7 +257,7 @@ readTarFile(int fileCount, const char ** fileTable)
        {
                perror(tarName);
 
-               return;
+               return FALSE;
        }
 
        /*
@@ -272,6 +279,7 @@ readTarFile(int fileCount, const char ** fileTable)
                        if (inCc < 0)
                        {
                                perror(tarName);
+                               successFlag = FALSE;
 
                                goto done;
                        }
@@ -281,6 +289,7 @@ readTarFile(int fileCount, const char ** fileTable)
                                fprintf(stderr,
                                        "Unexpected end of file from \"%s\"",
                                        tarName);
+                               successFlag = FALSE;
 
                                goto done;
                        }
@@ -291,7 +300,8 @@ readTarFile(int fileCount, const char ** fileTable)
                 */
                if (inHeader)
                {
-                       readHeader((const TarHeader *) cp, fileCount, fileTable);
+                       if (!readHeader((const TarHeader *) cp, fileCount, fileTable))
+                               successFlag = FALSE;
 
                        cp += TAR_BLOCK_SIZE;
                        inCc -= TAR_BLOCK_SIZE;
@@ -309,7 +319,8 @@ readTarFile(int fileCount, const char ** fileTable)
                if (cc > dataCc)
                        cc = dataCc;
 
-               readData(cp, cc);
+               if (!readData(cp, cc))
+                       successFlag = FALSE;
 
                /*
                 * If the amount left isn't an exact multiple of the tar block
@@ -327,15 +338,20 @@ readTarFile(int fileCount, const char ** fileTable)
         * Check for an interrupt.
         */
        if (intFlag)
+       {
                fprintf(stderr, "Interrupted - aborting\n");
-
+               successFlag = FALSE;
+       }
 
 done:
        /*
         * Close the tar file if needed.
         */
        if ((tarFd >= 0) && (close(tarFd) < 0))
+       {
                perror(tarName);
+               successFlag = FALSE;
+       }
 
        /*
         * Close the output file if needed.
@@ -344,21 +360,22 @@ done:
         */
        if (outFd >= 0)
                (void) close(outFd);
+
+       return successFlag;
 }
 
 
 /*
  * Examine the header block that was just read.
  * This can specify the information for another file, or it can mark
- * the end of the tar file.
+ * the end of the tar file.  Returns TRUE on success.
  */
-static void
+static BOOL
 readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
 {
        int             mode;
        int             uid;
        int             gid;
-       int             checkSum;
        long            size;
        time_t          mtime;
        const char *    name;
@@ -377,12 +394,12 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
                for (cc = TAR_BLOCK_SIZE; cc > 0; cc--)
                {
                        if (*name++)
-                               return;
+                               return TRUE;
                }
 
                eofFlag = TRUE;
 
-               return;
+               return TRUE;
        }
 
        /*
@@ -394,7 +411,6 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
        gid = getOctal(hp->gid, sizeof(hp->gid));
        size = getOctal(hp->size, sizeof(hp->size));
        mtime = getOctal(hp->mtime, sizeof(hp->mtime));
-       checkSum = getOctal(hp->checkSum, sizeof(hp->checkSum));
 
        if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0))
        {
@@ -403,7 +419,7 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
 
                badHeader = TRUE;
 
-               return;
+               return FALSE;
        }
 
        badHeader = FALSE;
@@ -458,7 +474,7 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
 
                skipFileFlag = TRUE;
 
-               return;
+               return TRUE;
        }
 
        /*
@@ -487,7 +503,7 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
 
                printf("\n");
 
-               return;
+               return TRUE;
        }
 
        /*
@@ -499,37 +515,43 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
        if (hardLink)
        {
                if (link(hp->linkName, name) < 0)
+               {
                        perror(name);
+                       return FALSE;
+               }
 
-               return;
+               return TRUE;
        }
 
        if (softLink)
        {
 #ifdef S_ISLNK
                if (symlink(hp->linkName, name) < 0)
+               {
                        perror(name);
+
+                       return FALSE;
+               }
+
+               return TRUE;
 #else
                fprintf(stderr, "Cannot create symbolic links\n");
 #endif
-               return;
+               return FALSE;
        }
 
        /*
         * If the file is a directory, then just create the path.
         */
        if (S_ISDIR(mode))
-       {
-               createPath(name, mode);
-
-               return;
-       }
+               return createPath(name, mode);
 
        /*
         * There is a file to write.
         * First create the path to it if necessary with a default permission.
         */
-       createPath(name, 0777);
+       if (!createPath(name, 0777))
+               return FALSE;
 
        inHeader = (size == 0);
        dataCc = size;
@@ -544,7 +566,7 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
                perror(name);
                skipFileFlag = TRUE;
 
-               return;
+               return FALSE;
        }
 
        /*
@@ -555,13 +577,16 @@ readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
                (void) close(outFd);
                outFd = -1;
        }
+
+       return TRUE;
 }
 
 
 /*
  * Handle a data block of some specified size that was read.
+ * Returns TRUE on success.
  */
-static void
+static BOOL
 readData(const char * cp, int count)
 {
        /*
@@ -579,7 +604,7 @@ readData(const char * cp, int count)
         * skipped then do nothing more.
         */
        if (!extractFlag || skipFileFlag)
-               return;
+               return TRUE;
 
        /*
         * Write the data to the output file.
@@ -591,7 +616,7 @@ readData(const char * cp, int count)
                outFd = -1;
                skipFileFlag = TRUE;
 
-               return;
+               return FALSE;
        }
 
        /*
@@ -604,18 +629,25 @@ readData(const char * cp, int count)
                        perror(outName);
 
                outFd = -1;
+
+               return FALSE;
        }
+
+       return TRUE;
 }
 
 
 /*
  * Write a tar file containing the specified files.
+ * Returns TRUE on success.
  */
-static void
+static BOOL
 writeTarFile(int fileCount, const char ** fileTable)
 {
        struct  stat    statbuf;
+       BOOL            successFlag;
 
+       successFlag = TRUE;
        errorFlag = FALSE;
 
        /*
@@ -625,7 +657,7 @@ writeTarFile(int fileCount, const char ** fileTable)
        {
                fprintf(stderr, "No files specified to be saved\n");
 
-               return;
+               return FALSE;
        }
 
        /*
@@ -637,7 +669,7 @@ writeTarFile(int fileCount, const char ** fileTable)
        {
                perror(tarName);
 
-               return;
+               return FALSE;
        }
 
        /*
@@ -646,6 +678,7 @@ writeTarFile(int fileCount, const char ** fileTable)
        if (fstat(tarFd, &statbuf) < 0)
        {
                perror(tarName);
+               successFlag = FALSE;
 
                goto done;
        }
@@ -663,7 +696,10 @@ writeTarFile(int fileCount, const char ** fileTable)
        }
 
        if (intFlag)
+       {
                fprintf(stderr, "Interrupted - aborting archiving\n");
+               successFlag = FALSE;
+       }
 
        /*
         * Now write an empty block of zeroes to end the archive.
@@ -676,7 +712,12 @@ done:
         * Close the tar file and check for errors if it was opened.
         */
        if ((tarFd >= 0) && (close(tarFd) < 0))
+       {
                perror(tarName);
+               successFlag = FALSE;
+       }
+
+       return successFlag;
 }
 
 
@@ -1066,8 +1107,9 @@ writeTarBlock(const char * buf, int len)
  * the final component.  The mode is given for the final directory only,
  * while all previous ones get default protections.  Errors are not reported
  * here, as failures to restore files can be reported later.
+ * Returns TRUE on success.
  */
-static void
+static BOOL
 createPath(const char * name, int mode)
 {
        char *  cp;
@@ -1090,6 +1132,8 @@ createPath(const char * name, int mode)
 
                *cpOld = '/';
        }
+
+       return TRUE;
 }
 
 
diff --git a/cmds.c b/cmds.c
index ec85539e22006508f97d07dba5165981720cc0a8..8e530dbe4212278960d9fe0975fad1ffef4996ae 100644 (file)
--- a/cmds.c
+++ b/cmds.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
 #include <linux/fs.h>
 #endif
 
+/* Need to tell loop.h what the actual dev_t type is. */
+#undef dev_t
+#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
+#define dev_t unsigned int
+#else
+#define dev_t unsigned short
+#endif
+#include <linux/loop.h>
+#undef dev_t
+#define dev_t dev_t
+
 
-void
+int
 do_echo(int argc, const char ** argv)
 {
        BOOL    first;
@@ -39,10 +50,12 @@ do_echo(int argc, const char ** argv)
        }
 
        fputc('\n', stdout);
+
+       return 0;
 }
 
 
-void
+int
 do_pwd(int argc, const char ** argv)
 {
        char    buf[PATH_LEN];
@@ -51,14 +64,16 @@ do_pwd(int argc, const char ** argv)
        {
                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;
@@ -73,29 +88,42 @@ do_cd(int argc, const char ** argv)
                {
                        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;
@@ -113,7 +141,7 @@ do_mknod(int argc, const char ** argv)
        {
                fprintf(stderr, "Bad device type\n");
 
-               return;
+               return 1;
        }
 
        major = 0;
@@ -126,7 +154,7 @@ do_mknod(int argc, const char ** argv)
        {
                fprintf(stderr, "Bad major number\n");
 
-               return;
+               return 1;
        }
 
        minor = 0;
@@ -139,53 +167,113 @@ do_mknod(int argc, const char ** argv)
        {
                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
+#if HAVE_LINUX_PIVOT
+
+int
+do_pivot_root(int argc, const char ** argv)
+{
+       if (pivot_root(argv[1], argv[2]) < 0)
+       {
+               perror("pivot_root");
+
+               return 1;
+       }
+
+       return 0;
+}
+
+#endif
+
+
+#if HAVE_LINUX_CHROOT
+
+int
+do_chroot(int argc, const char ** argv)
+{
+       if (chroot(argv[1]) < 0)
+       {
+               perror("chroot");
+
+               return 1;
+       }
+
+       return 0;
+}
+
+#endif
+
+
+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];
 
@@ -196,7 +284,7 @@ do_chmod(int argc, const char ** argv)
        {
                fprintf(stderr, "Mode must be octal\n");
 
-               return;
+               return 1;
        }
 
        argc--;
@@ -205,21 +293,28 @@ do_chmod(int argc, const char ** argv)
        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))
@@ -233,16 +328,18 @@ do_chown(int argc, const char ** argv)
                {
                        fprintf(stderr, "Bad uid value\n");
 
-                       return;
+                       return 1;
                }
-       } else {
+       }
+       else
+       {
                pwd = getpwnam(cp);
 
                if (pwd == NULL)
                {
                        fprintf(stderr, "Unknown user name\n");
 
-                       return;
+                       return 1;
                }
 
                uid = pwd->pw_uid;
@@ -259,19 +356,24 @@ do_chown(int argc, const char ** argv)
                        (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))
@@ -285,7 +387,7 @@ do_chgrp(int argc, const char ** argv)
                {
                        fprintf(stderr, "Bad gid value\n");
 
-                       return;
+                       return 1;
                }
        }
        else
@@ -296,7 +398,7 @@ do_chgrp(int argc, const char ** argv)
                {
                        fprintf(stderr, "Unknown group name\n");
 
-                       return;
+                       return 1;
                }
 
                gid = grp->gr_gid;
@@ -313,18 +415,23 @@ do_chgrp(int argc, const char ** argv)
                        (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;
 
@@ -341,20 +448,35 @@ do_touch(int argc, const char ** argv)
                        continue;
                }
 
+               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);
@@ -363,7 +485,7 @@ do_mv(int argc, const char ** argv)
        {
                fprintf(stderr, "%s: not a directory\n", lastArg);
 
-               return;
+               return 1;
        }
 
        while (!intFlag && (argc-- > 2))
@@ -373,6 +495,7 @@ do_mv(int argc, const char ** argv)
                if (access(srcName, 0) < 0)
                {
                        perror(srcName);
+                       r = 1;
 
                        continue;
                }
@@ -388,26 +511,39 @@ do_mv(int argc, const char ** argv)
                if (errno != EXDEV)
                {
                        perror(destName);
+                       r = 1;
 
                        continue;
                }
 
                if (!copyFile(srcName, destName, TRUE))
+               {
+                       r = 1;
+
                        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] == '-')
        {
@@ -415,23 +551,30 @@ do_ln(int argc, const char ** argv)
                {
                        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;
        }
 
        /*
@@ -444,7 +587,7 @@ do_ln(int argc, const char ** argv)
        {
                fprintf(stderr, "%s: not a directory\n", lastArg);
 
-               return;
+               return 1;
        }
 
        while (argc-- > 2)
@@ -454,6 +597,7 @@ do_ln(int argc, const char ** argv)
                if (access(srcName, 0) < 0)
                {
                        perror(srcName);
+                       r = 1;
 
                        continue;
                }
@@ -466,21 +610,26 @@ do_ln(int argc, const char ** argv)
                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);
@@ -489,7 +638,7 @@ do_cp(int argc, const char ** argv)
        {
                fprintf(stderr, "%s: not a directory\n", lastArg);
 
-               return;
+               return 1;
        }
 
        while (!intFlag && (argc-- > 2))
@@ -500,12 +649,15 @@ do_cp(int argc, const char ** argv)
                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;
@@ -535,7 +687,7 @@ do_mount(int argc, const char ** argv)
                                {
                                        fprintf(stderr, "Missing file system type\n");
 
-                                       return;
+                                       return 1;
                                }
 
                                type = *argv++;
@@ -575,7 +727,7 @@ do_mount(int argc, const char ** argv)
                        default:
                                fprintf(stderr, "Unknown option\n");
 
-                               return;
+                               return 1;
                }
        }
 
@@ -583,14 +735,16 @@ do_mount(int argc, const char ** argv)
        {
                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;
@@ -600,56 +754,79 @@ do_mount(int argc, const char ** argv)
                struct      msdosfs_args msdosfs;
                void *      args;
 
-               if(!strcmp(type, "ffs") || !strcmp(type, "ufs")) {
+               if (!strcmp(type, "ffs") || !strcmp(type, "ufs"))
+               {
                        ufs.fspec = (char*) argv[0];
                        args = &ufs;
-               } else if(!strcmp(type, "adosfs")) {
+               }
+               else if (!strcmp(type, "adosfs"))
+               {
                        adosfs.fspec = (char*) argv[0];
                        adosfs.uid = 0;
                        adosfs.gid = 0;
                        args = &adosfs;
-               } else if(!strcmp(type, "cd9660")) {
+               }
+               else if (!strcmp(type, "cd9660"))
+               {
                        iso.fspec = (char*) argv[0];
                        args = &iso;
-               } else if(!strcmp(type, "mfs")) {
+               }
+               else if (!strcmp(type, "mfs"))
+               {
                        mfs.fspec = (char*) argv[0];
                        args = &mfs;
-               } else if(!strcmp(type, "msdos")) {
+               }
+               else if (!strcmp(type, "msdos"))
+               {
                        msdosfs.fspec = (char*) argv[0];
                        msdosfs.uid = 0;
                        msdosfs.gid = 0;
                        args = &msdosfs;
-               } else {
+               }
+               else
+               {
                        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;
                int             flags = 0;
 
                for (argc--, argv++;
-                   (argc > 0) && (**argv == '-');) {
+                   (argc > 0) && (**argv == '-');)
+               {
                        argc--;
                        str = *argv++;
 
-                       while (*++str) {
+                       while (*++str)
+{
                                switch (*str)
                                {
                                        case 'f':
@@ -660,13 +837,18 @@ do_umount(int argc, const char ** argv)
                }
 
                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;
@@ -680,19 +862,22 @@ do_cmp(int argc, const char ** argv)
        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) &&
@@ -700,14 +885,14 @@ do_cmp(int argc, const char ** argv)
        {
                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);
@@ -716,7 +901,7 @@ do_cmp(int argc, const char ** argv)
        {
                perror(argv[1]);
 
-               return;
+               return 1;
        }
 
        fd2 = open(argv[2], O_RDONLY);
@@ -726,7 +911,7 @@ do_cmp(int argc, const char ** argv)
                perror(argv[2]);
                close(fd1);
 
-               return;
+               return 1;
        }
 
        pos = 0;
@@ -741,6 +926,7 @@ do_cmp(int argc, const char ** argv)
                if (cc1 < 0)
                {
                        perror(argv[1]);
+                       r = 1;
                        goto closefiles;
                }
 
@@ -749,24 +935,28 @@ do_cmp(int argc, const char ** argv)
                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;
                }
 
@@ -784,6 +974,7 @@ do_cmp(int argc, const char ** argv)
                        pos++;
 
                printf("Files differ at byte position %ld\n", pos);
+               r = 1;
 
                goto closefiles;
        }
@@ -791,10 +982,12 @@ do_cmp(int argc, const char ** argv)
 closefiles:
        close(fd1);
        close(fd2);
+
+       return r;
 }
 
 
-void
+int
 do_more(int argc, const char ** argv)
 {
        FILE *          fp;
@@ -842,7 +1035,7 @@ do_more(int argc, const char ** argv)
                {
                        perror(name);
 
-                       return;
+                       return 1;
                }
 
                printf("<< %s >>\n", name);
@@ -897,7 +1090,7 @@ do_more(int argc, const char ** argv)
                                if (fp)
                                        fclose(fp);
 
-                               return;
+                               return 0;
                        }
 
                        ch = buf[0];
@@ -917,7 +1110,7 @@ do_more(int argc, const char ** argv)
                                case 'q':
                                        fclose(fp);
 
-                                       return;
+                                       return 0;
                        }
 
                        col = 0;
@@ -927,10 +1120,12 @@ do_more(int argc, const char ** argv)
                if (fp)
                        fclose(fp);
        }
+
+       return 0;
 }
 
 
-void
+int
 do_sum(int argc, const char ** argv)
 {
        const char *    name;
@@ -940,9 +1135,11 @@ do_sum(int argc, const char ** argv)
        int             i;
        unsigned long   checksum;
        char            buf[BUF_SIZE];
+       int             r;
 
        argc--;
        argv++;
+       r = 0;
 
        while (argc-- > 0)
        {
@@ -953,6 +1150,7 @@ do_sum(int argc, const char ** argv)
                if (fd < 0)
                {
                        perror(name);
+                       r = 1;
 
                        continue;
                }
@@ -977,6 +1175,7 @@ do_sum(int argc, const char ** argv)
                if (cc < 0)
                {
                        perror(name);
+                       r = 1;
 
                        (void) close(fd);
 
@@ -987,24 +1186,35 @@ do_sum(int argc, const char ** argv)
 
                printf("%05lu %s\n", checksum, name);
        }
+
+       return r;
 }
 
 
-void
+int
 do_exit(int argc, const char ** argv)
 {
+       int r = 0;
+
        if (getpid() == 1)
        {
                fprintf(stderr, "You are the INIT process!\n");
 
-               return;
+               return 1;
+       }
+
+       if (argc == 2)
+       {
+               r = atoi(argv[1]);
        }
 
-       exit(0);
+       exit(r);
+
+       return 1;
 }
 
 
-void
+int
 do_setenv(int argc, const char ** argv)
 {
        const char *    name;
@@ -1024,7 +1234,7 @@ do_setenv(int argc, const char ** argv)
        {
                fprintf(stderr, "Cannot allocate memory\n");
 
-               return;
+               return 1;
        }
 
        strcpy(str, name);
@@ -1032,10 +1242,12 @@ do_setenv(int argc, const char ** argv)
        strcat(str, value);
 
        putenv(str);
+
+       return 0;
 }
 
 
-void
+int
 do_printenv(int argc, const char ** argv)
 {
        const char **   env;
@@ -1049,7 +1261,7 @@ do_printenv(int argc, const char ** argv)
                while (*env)
                        printf("%s\n", *env++);
 
-               return;
+               return 0;
        }
 
        len = strlen(argv[1]);
@@ -1061,14 +1273,16 @@ do_printenv(int argc, const char ** argv)
                {
                        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;
@@ -1080,7 +1294,7 @@ do_umask(int argc, const char ** argv)
                umask(mask);
                printf("%03o\n", mask);
 
-               return;
+               return 0;
        }
 
        mask = 0;
@@ -1093,20 +1307,24 @@ do_umask(int argc, const char ** argv)
        {
                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] == '-')
@@ -1142,7 +1360,7 @@ do_kill(int argc, const char ** argv)
                        {
                                fprintf(stderr, "Unknown signal\n");
 
-                               return;
+                               return 1;
                        }
                }
 
@@ -1162,16 +1380,21 @@ do_kill(int argc, const char ** argv)
                {
                        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;
@@ -1180,6 +1403,7 @@ do_where(int argc, const char ** argv)
        char *          endPath;
        char *          fullPath;
        BOOL            found;
+       int             r;
 
        found = FALSE;
        program = argv[1];
@@ -1188,7 +1412,7 @@ do_where(int argc, const char ** argv)
        {
                fprintf(stderr, "Program name cannot include a path\n");
 
-               return;
+               return 1;
        }
 
        path = getenv("PATH");
@@ -1200,7 +1424,7 @@ do_where(int argc, const char ** argv)
        {
                fprintf(stderr, "Memory allocation failed\n");
 
-               return;
+               return 1;
        }
 
        /*
@@ -1240,7 +1464,10 @@ do_where(int argc, const char ** argv)
                if (access(fullPath, X_OK) < 0)
                {
                        if (errno != ENOENT)
-                               printf("%s: %s\n", fullPath, strerror(errno));
+                       {
+                               perror(fullPath);
+                               r = 1;
+                       }
 
                        continue;
                }
@@ -1250,7 +1477,86 @@ do_where(int argc, const char ** argv)
        }
 
        if (!found)
+       {
                printf("Program \"%s\" not found in PATH\n", program);
+               r = 1;
+       }
+
+       return r;
 }
 
+#if HAVE_LINUX_LOSETUP
+
+int
+do_losetup(int argc, const char ** argv)
+{
+       int loopfd;
+       int targfd;
+       struct loop_info loopInfo;
+
+       if (!strcmp(argv[1], "-d"))
+       {
+               loopfd = open(argv[2], O_RDWR);
+
+               if (loopfd < 0)
+               {
+                       fprintf(stderr, "Error opening %s: %s\n", argv[2], 
+                               strerror(errno));
+
+                       return 1;
+               }
+
+               if (ioctl(loopfd, LOOP_CLR_FD, 0))
+               {
+                       fprintf(stderr, "Error unassociating device: %s\n", 
+                               strerror(errno));
+
+                       return 1;
+               }
+       }
+
+       loopfd = open(argv[1], O_RDWR);
+
+       if (loopfd < 0)
+       {
+               fprintf(stderr, "Error opening %s: %s\n", argv[1], 
+                       strerror(errno));
+
+               return 1;
+       }
+
+       targfd = open(argv[2], O_RDWR);
+
+       if (targfd < 0)
+       {
+               fprintf(stderr, "Error opening %s: %s\n", argv[2], 
+                       strerror(errno));
+
+               return 1;
+       }
+
+       if (ioctl(loopfd, LOOP_SET_FD, targfd))
+       {
+               fprintf(stderr, "Error setting up loopback device: %s\n", 
+                       strerror(errno));
+
+               return 1;
+       }
+
+       memset(&loopInfo, 0, sizeof(loopInfo));
+       strcpy(loopInfo.lo_name, argv[2]);
+
+       if (ioctl(loopfd, LOOP_SET_STATUS, &loopInfo))
+       {
+               fprintf(stderr, "Error setting up loopback device: %s\n", 
+                       strerror(errno));
+
+               return 1;
+       }
+
+       return 0;
+}
+
+#endif
+
 /* END CODE */
diff --git a/sash.1 b/sash.1
index da57e197b52b6fa2b46d0dfd5da71d1b7a779839..8c61b9ba0d010f02a9e22644fc26f8ab7b1c28d3 100644 (file)
--- a/sash.1
+++ b/sash.1
@@ -22,11 +22,11 @@ is that many of the standard system commands are built-in to
 These built-in commands are:
 .PP
 .nf
-     -ar, -chattr, -chgrp, -chmod, -chown, -cmp, -cp,
-     -dd, -echo, -ed, -grep, -file, -find, -gunzip,
-     -gzip, -kill, -ln, -ls, -lsattr, -mkdir, -mknod,
-     -more, -mount, -mv, -printenv, -pwd, -rm, -rmdir,
-     -sum, -sync, -tar, -touch, -umount, -where
+     -ar, -chattr, -chgrp, -chmod, -chown, -chroot, -cmp,
+     -cp, -dd, -echo, -ed, -grep, -file, -find, -gunzip,
+     -gzip, -kill, -losetup, -ln, -ls, -lsattr, -mkdir,
+     -mknod, -more, -mount, -mv, -pivot_root, -printenv, -pwd,
+     -rm, -rmdir, -sum, -sync, -tar, -touch, -umount, -where
 .fi
 .PP
 These commands are generally similar to the standard programs with similar
@@ -138,6 +138,13 @@ Change the owner id for the specified list of files.  The
 can
 either be a user name, or a decimal value.
 .TP
+.B -chroot path
+Changes  the  root  directory to that specified in
+.I path.
+This directory
+will be used for path  names  beginning with /. The root directory is
+inherited by all children of the current process.
+.TP
 .B -cmp fileName1 fileName2
 Determines whether or not the specified file names have identical data.
 This says that the files are links to each other, are different sizes,
@@ -312,6 +319,20 @@ is a numeric value, or one of the special values HUP, INT,
 QUIT, KILL, TERM, STOP, CONT, USR1 or USR2.
 If no signal is specified then SIGTERM is used.
 .TP
+.B -losetup [-d] loopDev [file]
+Associates loopback devices with files on the system. If
+.I -d
+is not given,
+the loopback device
+.I loopDev
+is associated with
+.I file.
+If
+.I -d
+is given,
+.I loopDev
+is unassociated with the file it's currently configured for.
+.TP
 .B -ln [-s] srcName ... destName
 Links one or more files from the
 .I srcName
@@ -326,8 +347,9 @@ For symbolic links, only one srcName can be specified.
 .B -ls [-lidFC] fileName ...
 Display information about the specified list of file names.
 The normal listing is simply a list of file names, one per line.
-The options available are -l, -i, -d, and -F.
+The options available are -l, -n, -i, -d, and -F.
 The -l option produces a long listing giving the normal 'ls' information.
+The -n option is like -l except that numeric user and group ids are shown.
 The -i option displays the inode numbers of the files.
 The -d option displays information about a directory, instead of the
 files within it.
@@ -388,6 +410,13 @@ same names as the srcNames.  Renames are attempted first, but if
 this fails because of the files being on different filesystems,
 then copies and deletes are done instead.
 .TP
+.B -pivot_root newRoot putOld
+Moves the root file system of the current process to the directory
+.I putOld
+and makes
+.I newRoot
+the  new root file system of the current process.
+.TP
 .B -printenv [name]
 If
 .I name
@@ -545,6 +574,11 @@ to run at all, then you will have to resort to a system recovery floppy.
 .SH WARNINGS
 .B Sash
 should obviously be linked statically, otherwise its purpose is lost.
+Note that even if the rest of the program is linked statically, the
+password and group lookup routines in the C library can still be dynamic.
+For that reason, if there are problems then it might be necessary to
+only use numeric ids for the -chown and -chgrp commands and to use
+the -n option instead of -l for the -ls command.
 .PP
 Several other system commands might be necessary for system recovery,
 but aren't built-in to
@@ -552,6 +586,6 @@ but aren't built-in to
 .SH AUTHOR
 .nf
 David I. Bell
-dbell@canb.auug.org.au
-12 January 2004
+dbell@tip.net.au
+5 March 2014
 .fi
diff --git a/sash.c b/sash.c
index ee444a64bde402d82a47773088f33e9705e844e5..8c1571195e04fed46ad749d9a4590a24ac68bac9 100644 (file)
--- a/sash.c
+++ b/sash.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -15,7 +15,7 @@
 #include "sash.h"
 
 
-static const char * const      version = "3.7";
+static const char * const      version = "3.8";
 
 
 /*
@@ -31,7 +31,7 @@ static const char * const     version = "3.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;
@@ -107,6 +107,14 @@ static const CommandEntry  commandEntryTable[] =
                "srcName ... destName"
        },
 
+#ifdef HAVE_LINUX_CHROOT
+       {
+               "-chroot",      do_chroot,      2,      2,
+               "change root file system",
+               "new_root_dir"
+       },
+#endif
+
        {
                "-dd",          do_dd,          3,      INFINITE_ARGS,
                "Copy data between two files",
@@ -132,9 +140,9 @@ static const CommandEntry   commandEntryTable[] =
        },
 
        {
-               "exit",         do_exit,        1,      1,
+               "exit",         do_exit,        1,      2,
                "Exit from sash",
-               ""
+               "[exit value]"
        },
 
        {
@@ -181,6 +189,14 @@ static const CommandEntry  commandEntryTable[] =
                "[-sig] pid ..."
        },
 
+#ifdef HAVE_LINUX_LOSETUP
+       {
+               "-losetup",     do_losetup,     3,      3,
+               "Associate a loopback device with a file",
+               "[-d] device\n       -losetup device filename"
+       },
+#endif
+
        {
                "-ln",          do_ln,          3,      INFINITE_ARGS,
                "Link one fileName to another",
@@ -237,6 +253,14 @@ static const CommandEntry  commandEntryTable[] =
                "srcName ... destName"
        },
 
+#ifdef HAVE_LINUX_PIVOT
+       {
+               "-pivot_root",  do_pivot_root,  3,      3,
+               "pivot the root file system",
+               "new_dir old_dir"
+       },
+#endif
+
        {
                "-printenv",    do_printenv,    1,      2,
                "Print environment variables",
@@ -375,14 +399,15 @@ static    char *  prompt;
  */
 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);
 static Alias * findAlias(const char * name);
+static void    expandVariable(char * name);
 
 
 /*
@@ -399,12 +424,14 @@ main(int argc, const char ** argv)
        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 +446,18 @@ main(int argc, const char ** argv)
 
                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 +480,18 @@ main(int argc, const char ** 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.
@@ -504,9 +550,7 @@ main(int argc, const char ** argv)
         */
        if (singleCommand)
        {
-               command(singleCommand);
-
-               return 0;
+               return command(singleCommand);
        }
 
        /*
@@ -541,9 +585,8 @@ main(int argc, const char ** argv)
        /*
         * Read commands from stdin or from a command file.
         */
-       readFile(commandFile);
+       return readFile(commandFile);
 
-       return 0;
 }
 
 
@@ -551,19 +594,20 @@ main(int argc, const char ** argv)
  * 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;
@@ -576,7 +620,7 @@ readFile(const char * name)
                {
                        perror(name);
 
-                       return;
+                       return 1;
                }
        }
 
@@ -594,7 +638,7 @@ readFile(const char * name)
                        fclose(fp);
                        sourceCount--;
 
-                       return;
+                       return 1;
                }
        
                if (fgets(buf, CMD_LEN - 1, fp) == NULL)
@@ -619,7 +663,7 @@ readFile(const char * name)
 
                buf[cc] = '\0';
 
-               command(buf);
+               r = command(buf);
        }
 
        if (ferror(fp))
@@ -636,6 +680,8 @@ readFile(const char * name)
                fclose(fp);
 
        sourceCount--;
+
+       return r;
 }
 
 
@@ -644,7 +690,7 @@ readFile(const char * name)
  * 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;
@@ -670,7 +716,7 @@ command(const char * cmd)
         * 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
@@ -701,18 +747,23 @@ command(const char * cmd)
                cmd = newCommand;
        }
 
+       /*
+        * Expand simple environment variables
+        */
+       while (strstr(cmd, "$(")) expandVariable((char *)cmd);
+
        /*
         * Now look for the command in the builtin table, and execute
         * 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);
 }
 
 
@@ -787,9 +838,10 @@ tryBuiltIn(const char * cmd)
 
 /*
  * Execute the specified command either by forking and executing
- * the program ourself, or else by using the shell.
+ * the program ourself, or else by using the shell.  Returns the
+ * exit status, or -1 if the program cannot be executed at all.
  */
-static void
+static int
 runCmd(const char * cmd)
 {
        const char *    cp;
@@ -833,11 +885,7 @@ runCmd(const char * cmd)
         * command using the shell.
         */
        if (magic)
-       {
-               system(cmd);
-
-               return;
-       }
+               return trySystem(cmd);
 
        /*
         * No magic characters were in the command, so we can do the fork
@@ -849,7 +897,7 @@ runCmd(const char * cmd)
        {
                perror("fork failed");
 
-               return;
+               return -1;
        }
 
        /*
@@ -874,14 +922,18 @@ runCmd(const char * cmd)
        {
                fprintf(stderr, "Error from waitpid: %s", strerror(errno));
 
-               return;
+               return -1;
        }
 
        if (WIFSIGNALED(status))
        {
                fprintf(stderr, "pid %ld: killed by signal %d\n",
                        (long) pid, WTERMSIG(status));
+
+               return -1;
        }
+
+       return WEXITSTATUS(status);
 }
 
 
@@ -911,8 +963,12 @@ childProcess(const char * cmd)
         */
        if (!makeArgs(cmd, &argc, &argv))
        {
-               system(cmd);
-               exit(0);
+               int status = trySystem(cmd);
+
+               if (status == -1)
+                       exit(99);
+
+               exit(status);
        }
 
        /*
@@ -926,8 +982,12 @@ childProcess(const char * cmd)
         */
        if (errno == ENOEXEC)
        {
-               system(cmd);
-               exit(0);
+               int status = trySystem(cmd);
+
+               if (status == -1)
+                       exit(99);
+
+               exit(status);
        }
 
        /*
@@ -938,7 +998,7 @@ childProcess(const char * cmd)
 }
 
 
-void
+int
 do_help(int argc, const char ** argv)
 {
        const CommandEntry *    entry;
@@ -963,7 +1023,7 @@ do_help(int argc, const char ** argv)
                                printf("usage: %s %s\n", entry->name,
                                        entry->usage);
 
-                               return;
+                               return 0;
                        }
                }
        }
@@ -980,10 +1040,12 @@ do_help(int argc, const char ** argv)
                        printf("%-10s %s\n", entry->name, entry->usage);
                }
        }
+
+       return 0;
 }
 
 
-void
+int
 do_alias(int argc, const char ** argv)
 {
        const char *    name;
@@ -999,7 +1061,7 @@ do_alias(int argc, const char ** argv)
                for (alias = aliasTable; count-- > 0; alias++)
                        printf("%s\t%s\n", alias->name, alias->value);
 
-               return;
+               return 0;
        }
 
        name = argv[1];
@@ -1011,20 +1073,24 @@ do_alias(int argc, const char ** argv)
                if (alias)
                        printf("%s\n", alias->value);
                else
+               {
                        fprintf(stderr, "Alias \"%s\" is not defined\n", name);
 
-               return; 
+                       return 1;
+               }
+
+               return 0;       
        }
 
        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);
 
@@ -1032,7 +1098,7 @@ do_alias(int argc, const char ** argv)
        {
                fprintf(stderr, "No memory for alias value\n");
 
-               return;
+               return 1;
        }
 
        strcpy(value, buf);
@@ -1044,7 +1110,7 @@ do_alias(int argc, const char ** argv)
                free(alias->value);
                alias->value = value;
 
-               return;
+               return 0;
        }
 
        if ((aliasCount % ALIAS_ALLOC) == 0)
@@ -1064,7 +1130,7 @@ do_alias(int argc, const char ** argv)
                        free(value);
                        fprintf(stderr, "No memory for alias table\n");
 
-                       return;
+                       return 1;
                }
 
                aliasTable = alias;
@@ -1079,12 +1145,14 @@ do_alias(int argc, const char ** argv)
                free(value);
                fprintf(stderr, "No memory for alias name\n");
 
-               return;
+               return 1;
        }
 
        strcpy(alias->name, name);
        alias->value = value;
        aliasCount++;
+
+       return 0;
 }
 
 
@@ -1092,7 +1160,7 @@ do_alias(int argc, const char ** argv)
  * 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;
@@ -1113,6 +1181,8 @@ do_aliasall(int argc, const char **argv)
 
                do_alias(3, newArgv);
        }
+
+       return 0;
 }
 
 
@@ -1138,27 +1208,20 @@ findAlias(const char * name)
 }
 
 
-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;
 
        name = argv[1];
 
-       if (access(name, 4))
-       {
-               perror(name);
-
-               return;
-       }
-
        while (--sourceCount >= 0)
        {
                if (sourcefiles[sourceCount] != stdin)
@@ -1168,18 +1231,20 @@ do_exec(int argc, const char ** argv)
        argv[argc] = NULL;
 
        execvp(name, (char **) argv + 1);
-       exit(1);
+       perror(name);
+
+       return 1;
 }
 
 
-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);
 
@@ -1187,7 +1252,7 @@ do_prompt(int argc, const char ** argv)
        {
                fprintf(stderr, "No memory for prompt\n");
 
-               return;
+               return 1;
        }
 
        strcpy(cp, buf);
@@ -1197,10 +1262,12 @@ do_prompt(int argc, const char ** argv)
                free(prompt);
 
        prompt = cp;
+
+       return 0;
 }
 
 
-void
+int
 do_unalias(int argc, const char ** argv)
 {
        Alias * alias;
@@ -1218,6 +1285,8 @@ do_unalias(int argc, const char ** argv)
                alias->name = aliasTable[aliasCount].name;
                alias->value = aliasTable[aliasCount].value;    
        }
+
+       return 0;
 }
 
 
@@ -1234,7 +1303,7 @@ showPrompt(void)
        if (prompt)
                cp = prompt;
 
-       write(STDOUT, cp, strlen(cp));
+       tryWrite(STDOUT, cp, strlen(cp));
 }      
 
 
@@ -1246,7 +1315,7 @@ catchInt(int val)
        intFlag = TRUE;
 
        if (intCrlf)
-               write(STDOUT, "\n", 1);
+               tryWrite(STDOUT, "\n", 1);
 }
 
 
@@ -1258,7 +1327,7 @@ catchQuit(int val)
        intFlag = TRUE;
 
        if (intCrlf)
-               write(STDOUT, "\n", 1);
+               tryWrite(STDOUT, "\n", 1);
 }
 
 
@@ -1270,9 +1339,35 @@ 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]\n");
+       fprintf(stderr, "Usage: sash [-a] [-q] [-f fileName] [-c command] [-p prompt] [-i]\n");
 
        exit(1);
 }
 
+
+/*
+ * Expand one environment variable: Syntax $(VAR)
+ */
+static void
+expandVariable(char * cmd)
+{
+       char    tmp[CMD_LEN];
+       char    *cp;
+       char    *ep;
+
+       strcpy(tmp, cmd);
+       cp = strstr(tmp, "$(");
+       if (cp) {
+               *cp++ = '\0';
+               strcpy(cmd, tmp);
+               ep = ++cp;
+               while (*ep && (*ep != ')')) ep++;
+               if (*ep == ')') *ep++ = '\0';
+               cp = getenv(cp);
+               if (cp) strcat(cmd, cp);
+               strcat(cmd, ep);
+       }
+       return;
+}
+
 /* END CODE */
diff --git a/sash.h b/sash.h
index 010760454dd8c15624e53a1521774a7f67388e3a..b0ed25469ceeb385707f50a7a75ee5394d06ec92 100644 (file)
--- a/sash.h
+++ b/sash.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -58,56 +58,69 @@ typedef     int     BOOL;
 /*
  * 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
+
+#if    HAVE_LINUX_CHROOT
+extern int     do_chroot(int argc, const char ** argv);
+#endif
+
+#if    HAVE_LINUX_LOSETUP
+extern int     do_losetup(int argc, const char ** argv);
+#endif
+
+#if    HAVE_LINUX_PIVOT
+extern int     do_pivot_root(int argc, const char ** argv);
+extern  int    pivot_root(const char *new_root, const char *put_old);
 #endif
 
 
@@ -122,8 +135,11 @@ extern     int             nameSort(const void * p1, const void * p2);
 extern char *          getChunk(int size);
 extern char *          chunkstrdup(const char *);
 extern void            freeChunks(void);
+extern int             trySystem(const char * cmd);
+extern void            tryWrite(int fd, const char * buf, int len);
 extern int             fullWrite(int fd, const char * buf, int len);
 extern int             fullRead(int fd, char * buf, int len);
+extern void            checkStatus(const char * name, int status);
 extern BOOL            match(const char * text, const char * pattern);
 
 extern const char *    buildName
diff --git a/utils.c b/utils.c
index 7c4dcefc7ef7368bd12b245b3fbe91f365500798..aa2a4ffafc065baed1a73a7bd75ab94bcedf73c3 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 by David I. Bell
+ * Copyright (c) 2014 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
@@ -244,7 +244,7 @@ copyFile(
                goto error_exit;
        }
 
-       (void) close(rfd);
+       checkStatus("close", close(rfd));
 
        if (close(wfd) < 0)
        {
@@ -255,14 +255,14 @@ copyFile(
 
        if (setModes)
        {
-               (void) chmod(destName, statBuf1.st_mode);
+               checkStatus("chmod", chmod(destName, statBuf1.st_mode));
 
-               (void) chown(destName, statBuf1.st_uid, statBuf1.st_gid);
+               checkStatus("chown", chown(destName, statBuf1.st_uid, statBuf1.st_gid));
 
                times.actime = statBuf1.st_atime;
                times.modtime = statBuf1.st_mtime;
 
-               (void) utime(destName, &times);
+               checkStatus("utime", utime(destName, &times));
        }
 
        return TRUE;
@@ -1029,6 +1029,26 @@ freeChunks(void)
 }
 
 
+/*
+ * Try writing data to the specified file descriptor.
+ * Only the first write error if any is printed.
+ * This is used when writing to STDOUT.
+ */
+void
+tryWrite(int fd, const char * cp, int len)
+{
+       static int failed = FALSE;
+
+       int status = fullWrite(fd, cp, len);
+
+       if ((status < 0) && !failed)
+       {
+               failed = TRUE;
+               perror("write");
+       }
+}
+
+
 /*
  * Write all of the supplied buffer out to a file.
  * This does multiple writes as necessary.
@@ -1090,4 +1110,35 @@ fullRead(int fd, char * buf, int len)
        return total;
 }
 
+
+/*
+ * Call system for the specified command and print an error
+ * message if the execution fails.  The exit status of the
+ * command is returned.
+ */
+int
+trySystem(const char * cmd)
+{
+       int status;
+
+       status = system(cmd);
+
+       if (status == -1)
+               fprintf(stderr, "Error starting command: %s\n", cmd);
+
+       return status;
+}
+
+
+/*
+ * Check the status for the most recent system call and complain
+ * if its value is -1 which indicates it failed.
+ */
+void
+checkStatus(const char * name, int status)
+{
+       if (status == -1)
+               perror(name);
+}
+
 /* END CODE */