From: David McCullough Date: Wed, 27 Feb 2008 11:41:32 +0000 (+0000) Subject: This patch allows elf2flt/flthdr's compression options to work in a wider X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=76e3e1d4d31a49e85b83bf15a8385da5df1d11f3;p=elf2flt.git This patch allows elf2flt/flthdr's compression options to work in a wider variety of environments (e.g. under MinGW/Win32), by linking with zlib rather than by using external gzip/gunzip executables. The cp binary isn't used any more either, and libiberty's make_temp_file() is used instead of mkstemp() as a more portable way of creating a temporary file. Also the compression logic is made somewhat clearer, IMO. Signed-off-by: Julian Brown Signed-off-by: Mike Frysinger --- diff --git a/Makefile.in b/Makefile.in index 2d225d4..f041890 100644 --- a/Makefile.in +++ b/Makefile.in @@ -11,7 +11,7 @@ CC = @CC@ CPU = @target_cpu@ TARGET = @target_alias@ CFLAGS = @CFLAGS@ -INCLUDES = @bfd_include_dir@ @binutils_include_dir@ +INCLUDES = @bfd_include_dir@ @binutils_include_dir@ @zlib_include_dir@ CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ @@ -50,11 +50,14 @@ PROGS = $(PROG_ELF2FLT) $(PROG_FLTHDR) all: $(PROGS) -$(PROG_ELF2FLT): elf2flt.c stubs.c Makefile - $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $(srcdir)/elf2flt.c $(srcdir)/stubs.c $(LIBS) +$(PROG_ELF2FLT): $(srcdir)/elf2flt.c compress.o $(srcdir)/stubs.c + $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) -$(PROG_FLTHDR): flthdr.c Makefile - $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $(srcdir)/flthdr.c $(LIBS) +$(PROG_FLTHDR): $(srcdir)/flthdr.c compress.o + $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +Makefile: $(srcdir)/Makefile.in + ./config.status $@ clean: -rm -f $(PROGS) *.$(OBJEXT) diff --git a/compress.c b/compress.c new file mode 100644 index 0000000..69abc6a --- /dev/null +++ b/compress.c @@ -0,0 +1,186 @@ +/* + * Helper functions to handle compression via zlib + * + * Copyright (C) 2007-2008 Julian Brown + * Copyright (C) 2008 Mike Frysinger + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include + +#include +#include "compress.h" + +/* Open an (uncompressed) file as a stream. Return 0 on success, 1 on + error. + NOTE: The MODE argument must remain valid for the lifetime of the stream, + because it is referred to by reopen_stream_compressed() if it is called. + String constants work fine. */ + +int +fopen_stream_u(stream *fp, const char *path, const char *mode) +{ + fp->u.filep = fopen(path, mode); + fp->type = (fp->u.filep) ? UNCOMPRESSED : INVALID; + fp->mode = mode; + return (fp->u.filep) ? 0 : 1; +} + +/* Read from stream. Return number of elements read. */ + +size_t +fread_stream(void *ptr, size_t size, size_t nmemb, stream *str) +{ + size_t read; + + switch (str->type) { + case UNCOMPRESSED: + read = fread(ptr, size, nmemb, str->u.filep); + break; + + case COMPRESSED: + read = gzread(str->u.gzfilep, ptr, size * nmemb) / size; + break; + + default: + abort(); + } + + return read; +} + +/* Write to stream. Return number of elements written. */ + +size_t +fwrite_stream(const void *ptr, size_t size, size_t nmemb, stream *str) +{ + size_t written; + + switch (str->type) { + case UNCOMPRESSED: + written = fwrite(ptr, size, nmemb, str->u.filep); + break; + + case COMPRESSED: + written = gzwrite(str->u.gzfilep, ptr, size * nmemb) / size; + break; + + default: + abort(); + } + + return written; +} + +/* Close stream. */ + +int +fclose_stream(stream *str) +{ + switch (str->type) { + case UNCOMPRESSED: + return fclose(str->u.filep); + + case COMPRESSED: + return gzclose(str->u.gzfilep); + + default: + abort(); + } + + return 0; +} + +int +ferror_stream(stream *str) +{ + switch (str->type) { + case UNCOMPRESSED: + return ferror(str->u.filep); + + case COMPRESSED: + { + const char *err; + int errno; + + err = gzerror(str->u.gzfilep, &errno); + if (errno == Z_OK || errno == Z_STREAM_END) + return 0; + else if (errno == Z_ERRNO) + return 1; + else { + fprintf(stderr, "%s\n", err); + return 1; + } + } + break; + + default: + abort(); + } + + return 0; +} + +/* Reopen a stream at the current file position. */ + +void +reopen_stream_compressed(stream *str) +{ + int fd; + long offset, roffset; + + /* Already a compressed stream, return immediately */ + if (str->type == COMPRESSED) + return; + + if (str->type == INVALID) + abort(); + + fd = fileno(str->u.filep); + /* Get current (buffered) file position. */ + offset = ftell(str->u.filep); + + /* Make sure there's nothing left in buffers. */ + fflush(str->u.filep); + + /* Reposition underlying FD. (Might be unnecessary?) */ + roffset = lseek(fd, offset, SEEK_SET); + + assert(roffset == offset); + + /* Reopen as compressed stream. */ + str->u.gzfilep = gzdopen(fd, str->mode); + gzsetparams(str->u.gzfilep, 9, Z_DEFAULT_STRATEGY); + str->type = COMPRESSED; +} + +void +transfer(stream *ifp, stream *ofp, int count) +{ + char cmd[1024]; + int n, num; + + while (count == -1 || count > 0) { + if (count == -1 || count > sizeof(cmd)) + num = sizeof(cmd); + else + num = count; + n = fread_stream(cmd, 1, num, ifp); + if (n == 0) + break; + if (fwrite_stream(cmd, n, 1, ofp) != 1) { + fprintf(stderr, "Write failed :-(\n"); + exit(1); + } + if (count != -1) + count -= n; + } + if (count > 0) { + fprintf(stderr, "Failed to transfer %d bytes\n", count); + exit(1); + } +} diff --git a/compress.h b/compress.h new file mode 100644 index 0000000..d27f708 --- /dev/null +++ b/compress.h @@ -0,0 +1,43 @@ +/* + * Helper functions to handle compression via zlib + * + * Copyright (C) 2007-2008 Julian Brown + * Copyright (C) 2008 Mike Frysinger + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __ELF2FLT_COMPRESS_H__ +#define __ELF2FLT_COMPRESS_H__ + +#include + +typedef enum +{ + INVALID, + UNCOMPRESSED, + COMPRESSED +} stream_type; + +/* Tagged union holding either a regular FILE* handle or a zlib gzFile + handle. */ +typedef struct +{ + stream_type type; + const char *mode; + union + { + FILE *filep; + gzFile gzfilep; + } u; +} stream; + +int fopen_stream_u(stream *fp, const char *path, const char *mode); +size_t fread_stream(void *ptr, size_t size, size_t nmemb, stream *str); +size_t fwrite_stream(const void *ptr, size_t size, size_t nmemb, stream *str); +int fclose_stream(stream *str); +int ferror_stream(stream *str); +void reopen_stream_compressed(stream *str); +void transfer(stream *ifp, stream *ofp, int count); + +#endif diff --git a/configure.in b/configure.in index d43b500..d6e9d44 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,12 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(elf2flt.c) +AC_ARG_WITH(zlib-prefix, + [ --with-zlib-prefix= path to installed zlib ], + [ ac_zlib_prefix=$withval ], + [ ac_zlib_prefix=NONE ] +) + AC_ARG_WITH(libbfd, [ --with-libbfd= path to libbfd.a library to use ], [ ac_libbfd=$withval ], @@ -63,6 +69,11 @@ if test "$ac_libbfd" = "NONE"; then else LIBS="$ac_libbfd $LIBS" fi +if test "$ac_zlib_prefix" = "NONE"; then + AC_CHECK_LIB(z, deflate) +else + LIBS="-L$ac_zlib_prefix/lib -lz $LIBS" +fi bfd_include_dir= if test "$ac_bfd_include_dir" != "NONE"; then @@ -74,6 +85,11 @@ if test "$ac_binutils_include_dir" != "NONE"; then binutils_include_dir="-I$ac_binutils_include_dir" fi +zlib_include_dir= +if test "$ac_zlib_prefix" != "NONE"; then + zlib_include_dir="-I$ac_zlib_prefix/include" +fi + binutils_ldscript_dir= if test "$ac_binutils_ldscript_dir" = "NONE"; then ac_binutils_ldscript_dir="\${TOOLDIR}/../${target_alias}/lib" @@ -126,6 +142,7 @@ AC_SUBST(target_os) AC_SUBST(target_vendor) AC_SUBST(bfd_include_dir) AC_SUBST(binutils_include_dir) +AC_SUBST(zlib_include_dir) AC_SUBST(binutils_ldscript_dir) AC_SUBST(got_check) AC_SUBST(emit_relocs) diff --git a/elf2flt.c b/elf2flt.c index 552710c..546305f 100644 --- a/elf2flt.c +++ b/elf2flt.c @@ -74,6 +74,7 @@ /* from uClinux-x.x.x/include/linux */ #include "flat.h" /* Binary flat header description */ +#include "compress.h" #ifdef TARGET_e1 #include @@ -143,7 +144,7 @@ int verbose = 0; /* extra output when running */ int pic_with_got = 0; /* do elf/got processing with PIC code */ int load_to_ram = 0; /* instruct loader to allocate everything into RAM */ int ktrace = 0; /* instruct loader output kernel trace on load */ -int compress = 0; /* 1 = compress everything, 2 = compress data only */ +int docompress = 0; /* 1 = compress everything, 2 = compress data only */ int use_resolved = 0; /* If true, get the value of symbol references from */ /* the program contents, not from the relocation table. */ /* In this case, the input ELF file must be already */ @@ -1768,7 +1769,7 @@ static void usage(void) /* Write NUM zeroes to STREAM. */ -static void write_zeroes (unsigned long num, FILE *stream) +static void write_zeroes (unsigned long num, stream *stream) { char zeroes[1024]; if (num > 0) { @@ -1776,11 +1777,11 @@ static void write_zeroes (unsigned long num, FILE *stream) work for stdio output files. */ memset(zeroes, 0x00, 1024); while (num > sizeof(zeroes)) { - fwrite(zeroes, sizeof(zeroes), 1, stream); + fwrite_stream(zeroes, sizeof(zeroes), 1, stream); num -= sizeof(zeroes); } if (num > 0) - fwrite(zeroes, num, 1, stream); + fwrite_stream(zeroes, num, 1, stream); } } @@ -1795,8 +1796,7 @@ int main(int argc, char *argv[]) int opt; int i; int stack; - char cmd[1024]; - FILE *gf = NULL; + stream gf; asymbol **symbol_table; long number_of_symbols; @@ -1818,8 +1818,6 @@ int main(int argc, char *argv[]) struct flat_hdr hdr; - int gf_is_pipe = 0; - program = argv[0]; progname = argv[0]; xmalloc_set_program_name(program); @@ -1853,10 +1851,10 @@ int main(int argc, char *argv[]) ktrace++; break; case 'z': - compress = 1; + docompress = 1; break; case 'd': - compress = 2; + docompress = 2; break; case 'p': pfile = optarg; @@ -2065,7 +2063,7 @@ int main(int argc, char *argv[]) | (load_to_ram ? FLAT_FLAG_RAM : 0) | (ktrace ? FLAT_FLAG_KTRACE : 0) | (pic_with_got ? FLAT_FLAG_GOTPIC : 0) - | (compress ? (compress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0) + | (docompress ? (docompress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0) ); hdr.build_date = htonl((unsigned long)time(NULL)); memset(hdr.filler, 0x00, sizeof(hdr.filler)); @@ -2094,54 +2092,32 @@ int main(int argc, char *argv[]) write(fd, &hdr, sizeof(hdr)); close(fd); - /* - * get the compression command ready - */ - sprintf(cmd, "gzip -f -9 >> %s", ofile); - -#define START_COMPRESSOR do { \ - if (gf) \ - if (gf_is_pipe) \ - pclose(gf); \ - else \ - fclose(gf); \ - if (!(gf = popen(cmd, "w" BINARY_FILE_OPTS))) { \ - fprintf(stderr, "Can't run cmd %s\n", cmd); \ - exit(4); \ - } \ - gf_is_pipe = 1; \ - } while (0) - - gf = fopen(ofile, "ab"); /* Add 'b' to support non-posix (ie windows) */ - if (!gf) { - fprintf(stderr, "Can't open file %s for writing\n", ofile); \ - exit(4); + if (fopen_stream_u(&gf, ofile, "a" BINARY_FILE_OPTS)) { + fprintf(stderr, "Can't open file %s for writing\n", ofile); + exit(4); } - if (compress == 1) - START_COMPRESSOR; + if (docompress == 1) + reopen_stream_compressed(&gf); /* Fill in any hole at the beginning of the text segment. */ if (verbose) - printf("ZERO before text len=0x%x\n", text_offs); - write_zeroes(text_offs, gf); + printf("ZERO before text len=0x%x\n", text_offs); + write_zeroes(text_offs, &gf); /* Write the text segment. */ - fwrite(text, text_len, 1, gf); + fwrite_stream(text, text_len, 1, &gf); - if (compress == 2) - START_COMPRESSOR; + if (docompress == 2) + reopen_stream_compressed(&gf); /* Write the data segment. */ - fwrite(data, data_len, 1, gf); + fwrite_stream(data, data_len, 1, &gf); if (reloc) - fwrite(reloc, reloc_len * 4, 1, gf); + fwrite_stream(reloc, reloc_len * 4, 1, &gf); - if(gf_is_pipe) - pclose(gf); - else - fclose(gf); + fclose_stream(&gf); exit(0); } diff --git a/flthdr.c b/flthdr.c index b1277ca..f3c54ab 100644 --- a/flthdr.c +++ b/flthdr.c @@ -15,6 +15,7 @@ #include #include /* exit() */ #include /* strcat(), strcpy() */ +#include /* macros for conversion between host and (internet) network byte order */ #ifndef WIN32 @@ -25,6 +26,9 @@ #define BINARY_FILE_OPTS "b" #endif +#include "compress.h" +#include + /* from uClinux-x.x.x/include/linux */ #include "flat.h" /* Binary flat header description */ @@ -39,57 +43,27 @@ char *program_name; -static char cmd[1024]; -static int print = 0, compress = 0, ramload = 0, stacksize = 0, ktrace = 0; - -/****************************************************************************/ +static int print = 0, docompress = 0, ramload = 0, stacksize = 0, ktrace = 0; -void -transferr(FILE *ifp, FILE *ofp, int count) -{ - int n, num; - - while (count == -1 || count > 0) { - if (count == -1 || count > sizeof(cmd)) - num = sizeof(cmd); - else - num = count; - n = fread(cmd, 1, num, ifp); - if (n == 0) - break; - if (fwrite(cmd, n, 1, ofp) != 1) { - fprintf(stderr, "Write failed :-(\n"); - exit(1); - } - if (count != -1) - count -= n; - } - if (count > 0) { - fprintf(stderr, "Failed to transferr %d bytes\n", count); - exit(1); - } -} - /****************************************************************************/ void process_file(char *ifile, char *ofile) { int old_flags, old_stack, new_flags, new_stack; - FILE *ifp, *ofp; - int ofp_is_pipe = 0; + stream ifp, ofp; struct flat_hdr old_hdr, new_hdr; - char tfile[256]; - char tfile2[256]; + char *tfile, tmpbuf[256]; + int input_error, output_error; - *tfile = *tfile2 = '\0'; + *tmpbuf = '\0'; - if ((ifp = fopen(ifile, "r" BINARY_FILE_OPTS)) == NULL) { + if (fopen_stream_u(&ifp, ifile, "r" BINARY_FILE_OPTS)) { fprintf(stderr, "Cannot open %s\n", ifile); return; } - if (fread(&old_hdr, sizeof(old_hdr), 1, ifp) != 1) { + if (fread_stream(&old_hdr, sizeof(old_hdr), 1, &ifp) != 1) { fprintf(stderr, "Cannot read header of %s\n", ifile); return; } @@ -103,13 +77,13 @@ process_file(char *ifile, char *ofile) new_stack = old_stack = ntohl(old_hdr.stack_size); new_hdr = old_hdr; - if (compress == 1) { + if (docompress == 1) { new_flags |= FLAT_FLAG_GZIP; new_flags &= ~FLAT_FLAG_GZDATA; - } else if (compress == 2) { + } else if (docompress == 2) { new_flags |= FLAT_FLAG_GZDATA; new_flags &= ~FLAT_FLAG_GZIP; - } else if (compress < 0) + } else if (docompress < 0) new_flags &= ~(FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA); if (ramload > 0) @@ -163,13 +137,13 @@ process_file(char *ifile, char *ofile) printf("-----------------------------------------------------------\n"); first = 0; } - *tfile = '\0'; - strcat(tfile, (old_flags & FLAT_FLAG_KTRACE) ? "k" : ""); - strcat(tfile, (old_flags & FLAT_FLAG_RAM) ? "r" : ""); - strcat(tfile, (old_flags & FLAT_FLAG_GOTPIC) ? "p" : ""); - strcat(tfile, (old_flags & FLAT_FLAG_GZIP) ? "z" : + *tmpbuf = '\0'; + strcat(tmpbuf, (old_flags & FLAT_FLAG_KTRACE) ? "k" : ""); + strcat(tmpbuf, (old_flags & FLAT_FLAG_RAM) ? "r" : ""); + strcat(tmpbuf, (old_flags & FLAT_FLAG_GOTPIC) ? "p" : ""); + strcat(tmpbuf, (old_flags & FLAT_FLAG_GZIP) ? "z" : ((old_flags & FLAT_FLAG_GZDATA) ? "d" : "")); - printf("-%-3.3s ", tfile); + printf("-%-3.3s ", tmpbuf); printf("%3d ", ntohl(old_hdr.rev)); printf("%6d ", text=ntohl(old_hdr.data_start)-sizeof(struct flat_hdr)); printf("%6d ", data=ntohl(old_hdr.data_end)-ntohl(old_hdr.data_start)); @@ -205,106 +179,74 @@ process_file(char *ifile, char *ofile) new_hdr.flags = htonl(new_flags); new_hdr.stack_size = htonl(new_stack); - strcpy(tfile, "/tmp/flatXXXXXX"); - mkstemp(tfile); - if ((ofp = fopen(tfile, "w" BINARY_FILE_OPTS)) == NULL) { + tfile = make_temp_file("flthdr"); + + if (fopen_stream_u(&ofp, tfile, "w" BINARY_FILE_OPTS)) { fprintf(stderr, "Failed to open %s for writing\n", tfile); unlink(tfile); - unlink(tfile2); exit(1); } - if (fwrite(&new_hdr, sizeof(new_hdr), 1, ofp) != 1) { + /* Copy header (always uncompressed). */ + if (fwrite_stream(&new_hdr, sizeof(new_hdr), 1, &ofp) != 1) { fprintf(stderr, "Failed to write to %s\n", tfile); unlink(tfile); - unlink(tfile2); exit(1); } - /* - * get ourselves a fully uncompressed copy of the text/data/relocs - * so that we can manipulate it more easily - */ - if (old_flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { - FILE *tfp; - - strcpy(tfile2, "/tmp/flat2XXXXXX"); - mkstemp(tfile2); - - if (old_flags & FLAT_FLAG_GZDATA) { - tfp = fopen(tfile2, "w" BINARY_FILE_OPTS); - if (!tfp) { - fprintf(stderr, "Failed to open %s for writing\n", tfile2); - exit(1); - } - transferr(ifp, tfp, ntohl(old_hdr.data_start) - - sizeof(struct flat_hdr)); - fclose(tfp); - } - - sprintf(cmd, "gunzip >> %s", tfile2); - tfp = popen(cmd, "w" BINARY_FILE_OPTS); - if(!tfp) { - perror("popen"); - exit(1); - } - transferr(ifp, tfp, -1); - pclose(tfp); - - fclose(ifp); - ifp = fopen(tfile2, "r" BINARY_FILE_OPTS); - if (!ifp) { - fprintf(stderr, "Failed to open %s for reading\n", tfile2); - unlink(tfile); - unlink(tfile2); - exit(1); - } - } + /* Whole input file (including text) is compressed: start decompressing + now. */ + if (old_flags & FLAT_FLAG_GZIP) + reopen_stream_compressed(&ifp); + /* Likewise, output file is compressed. Start compressing now. */ if (new_flags & FLAT_FLAG_GZIP) { printf("zflat %s --> %s\n", ifile, ofile); - fclose(ofp); - sprintf(cmd, "gzip -9 -f >> %s", tfile); - ofp = popen(cmd, "w" BINARY_FILE_OPTS); - ofp_is_pipe = 1; - } else if (new_flags & FLAT_FLAG_GZDATA) { - printf("zflat-data %s --> %s\n", ifile, ofile); - transferr(ifp, ofp, ntohl(new_hdr.data_start) - - sizeof(struct flat_hdr)); - fclose(ofp); - sprintf(cmd, "gzip -9 -f >> %s", tfile); - ofp = popen(cmd, "w" BINARY_FILE_OPTS); - ofp_is_pipe = 1; + reopen_stream_compressed(&ofp); } - if (!ofp) { /* can only happen if using gzip/gunzip */ - fprintf(stderr, "Can't run cmd %s\n", cmd); - unlink(tfile); - unlink(tfile2); - exit(1); + transfer(&ifp, &ofp, + ntohl(old_hdr.data_start) - sizeof(struct flat_hdr)); + + /* Only data and relocs were compressed in input. Start decompressing + from here. */ + if (old_flags & FLAT_FLAG_GZDATA) + reopen_stream_compressed(&ifp); + + /* Only data/relocs to be compressed in output. Start compressing + from here. */ + if (new_flags & FLAT_FLAG_GZDATA) { + printf("zflat-data %s --> %s\n", ifile, ofile); + reopen_stream_compressed(&ofp); } - transferr(ifp, ofp, -1); - - if (ferror(ifp) || ferror(ofp)) { + transfer(&ifp, &ofp, -1); + + input_error = ferror_stream(&ifp); + output_error = ferror_stream(&ofp); + + if (input_error || output_error) { fprintf(stderr, "Error on file pointer%s%s\n", - ferror(ifp) ? " input" : "", ferror(ofp) ? " output" : ""); + input_error ? " input" : "", + output_error ? " output" : ""); unlink(tfile); - unlink(tfile2); exit(1); } - fclose(ifp); - if (ofp_is_pipe) - pclose(ofp); - else - fclose(ofp); + fclose_stream(&ifp); + fclose_stream(&ofp); + + /* Copy temporary file to output location. */ + fopen_stream_u(&ifp, tfile, "r" BINARY_FILE_OPTS); + fopen_stream_u(&ofp, ofile, "w" BINARY_FILE_OPTS); + + transfer(&ifp, &ofp, -1); + + fclose_stream(&ifp); + fclose_stream(&ofp); - /* cheat a little here to preserve file permissions */ - sprintf(cmd, "cp %s %s", tfile, ofile); - system(cmd); unlink(tfile); - unlink(tfile2); + free(tfile); } /****************************************************************************/ @@ -343,9 +285,9 @@ main(int argc, char *argv[]) while ((c = getopt(argc, argv, "pdzZrRkKs:o:")) != EOF) { switch (c) { case 'p': print = 1; break; - case 'z': compress = 1; break; - case 'd': compress = 2; break; - case 'Z': compress = -1; break; + case 'z': docompress = 1; break; + case 'd': docompress = 2; break; + case 'Z': docompress = -1; break; case 'r': ramload = 1; break; case 'R': ramload = -1; break; case 'k': ktrace = 1; break; @@ -366,8 +308,8 @@ main(int argc, char *argv[]) if (ofile && argc - optind > 1) usage("-o can only be used with a single file"); - - if (!print && !compress && !ramload && !stacksize) /* no args == print */ + + if (!print && !docompress && !ramload && !stacksize) /* no args == print */ print = argc - optind; /* greater than 1 is short format */ for (c = optind; c < argc; c++) {