From: Tollef Fog Heen Date: Sun, 20 Apr 2014 06:14:39 +0000 (+0200) Subject: Imported Upstream version 3.8 X-Git-Tag: upstream/3.8^0 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8fc0db97d0c38350027ffc92a32f923f50570924;p=sash Imported Upstream version 3.8 --- diff --git a/CHANGES b/CHANGES index 4179511..c87d6d5 100644 --- 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. diff --git a/Makefile b/Makefile index bd8358e..a231ae8 100644 --- 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 7794d75..154f1f7 100644 --- 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 diff --git a/cmd_ar.c b/cmd_ar.c index 0f8d585..6c6181e 100644 --- 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. * @@ -32,22 +32,22 @@ */ 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; diff --git a/cmd_chattr.c b/cmd_chattr.c index 5fc43c2..df50c22 100644 --- a/cmd_chattr.c +++ b/cmd_chattr.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. * @@ -12,7 +12,15 @@ #include #include -#include + +/* + * These were used for old linux versions. + * #include + * #include + */ + +#include + #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 diff --git a/cmd_dd.c b/cmd_dd.c index 9708924..80338b6 100644 --- 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; } diff --git a/cmd_ed.c b/cmd_ed.c index 11d6850..e935c0d 100644 --- 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) { diff --git a/cmd_file.c b/cmd_file.c index 695e9c0..caf2a30 100644 --- a/cmd_file.c +++ b/cmd_file.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. * @@ -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; } diff --git a/cmd_find.c b/cmd_find.c index 48f9d01..fde9006 100644 --- a/cmd_find.c +++ b/cmd_find.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. * @@ -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; } diff --git a/cmd_grep.c b/cmd_grep.c index 504d9d4..b9e0821 100644 --- a/cmd_grep.c +++ b/cmd_grep.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. * @@ -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; } diff --git a/cmd_gzip.c b/cmd_gzip.c index 895d3cf..6bcec11 100644 --- a/cmd_gzip.c +++ b/cmd_gzip.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. * @@ -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; } diff --git a/cmd_ls.c b/cmd_ls.c index 7b9c8ee..20d28f7 100644 --- 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); diff --git a/cmd_tar.c b/cmd_tar.c index 42bed3d..5dd5f21 100644 --- 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 ec85539..8e530db 100644 --- 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. * @@ -21,8 +21,19 @@ #include #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 +#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 da57e19..8c61b9b 100644 --- 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 ee444a6..8c15711 100644 --- 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 0107604..b0ed254 100644 --- 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 7c4dcef..aa2a4ff 100644 --- 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, ×); + checkStatus("utime", utime(destName, ×)); } 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 */