Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>

void
error(char* fmt, ...)
{
        va_list arg;
        char *e, s[256];

        va_start(arg, fmt);
        e = seprint(s, s+sizeof(s), "%s: ", argv0);
        e = vseprint(e, s+sizeof(s), fmt, arg);
        e = seprint(e, s+sizeof(s), "\n");
        va_end(arg);

        write(2, s, e-s);
}

static void
usage(void)
{
        error("usage: %s -o ofile file\n\t%s file ...\n", argv0, argv0);
        exits("usage");
}

static int
strip(char* file, char* out)
{
        Dir *dir;
        int fd, i;
        Fhdr fhdr;
        Exec *exec;
        ulong mode;
        void *data;
        vlong length;

        if((fd = open(file, OREAD)) < 0){
                error("%s: open: %r", file);
                return 1;
        }

        if(!crackhdr(fd, &fhdr)){
                error("%s: %r", file);
                close(fd);
                return 1;
        }
        for(i = MIN_MAGIC; i <= MAX_MAGIC; i++){
                if(fhdr.magic == _MAGIC(0, i) || fhdr.magic == _MAGIC(HDR_MAGIC, i))
                        break;
        }
        if(i > MAX_MAGIC){
                error("%s: not a recognizeable binary", file);
                close(fd);
                return 1;
        }

        if((dir = dirfstat(fd)) == nil){
                error("%s: stat: %r", file);
                close(fd);
                return 1;
        }

        length = fhdr.datoff+fhdr.datsz;
        if(length == dir->length){
                if(out == nil){ /* nothing to do */
                        error("%s: already stripped", file);
                        free(dir);
                        close(fd);
                        return 0;
                }
        }
        if(length > dir->length){
                error("%s: strange length", file);
                close(fd);
                free(dir);
                return 1;
        }

        mode = dir->mode;
        free(dir);

        if((data = malloc(length)) == nil){
                error("%s: malloc failure", file);
                close(fd);
                return 1;
        }
        seek(fd, 0LL, 0);
        if(read(fd, data, length) != length){
                error("%s: read: %r", file);
                close(fd);
                free(data);
                return 1;
        }
        close(fd);

        exec = data;
        exec->syms = 0;
        exec->spsz = 0;
        exec->pcsz = 0;

        if(out == nil){
                if(remove(file) < 0) {
                        error("%s: remove: %r", file);
                        free(data);
                        return 1;
                }
                out = file;
        }
        if((fd = create(out, OWRITE, mode)) < 0){
                error("%s: create: %r", out);
                free(data);
                return 1;
        }
        if(write(fd, data, length) != length){
                error("%s: write: %r", out);
                close(fd);
                free(data);
                return 1;
        }
        close(fd);
        free(data);

        return 0;
}

void
main(int argc, char* argv[])
{
        int r;
        char *p;

        p = nil;

        ARGBEGIN{
        default:
                usage();
                break;
        case 'o':
                p = ARGF();
                if(p == nil)
                        usage();
                break;
        }ARGEND;

        switch(argc){
        case 0:
                usage();
                return;
        case 1:
                if(p != nil){
                        r = strip(*argv, p);
                        break;
                }
                /*FALLTHROUGH*/
        default:
                r = 0;
                while(argc > 0){
                        r |= strip(*argv, nil);
                        argc--;
                        argv++;
                }
                break;
        }

        if(r)
                exits("error");
        exits(0);
}