Mercurial > ~dholland > hg > ag > index.cgi
diff insertsums/insertsums.c @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/insertsums/insertsums.c Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,226 @@ +/* + * AnaGram, A System for Syntax Directed Programming + * Copyright 2006 David A. Holland. All Rights Reserved. + * See the file COPYING for license and usage terms. + */ + +/* + * insertsums - patch checksum data block into binary + * usage: insertsums sums.dat sums.ctl + * + * The patch area is a region of size TARGETSIZE that the + * checksum program finds for us. We check to make sure it + * contains the right magic string before patching over it, + * just in case. + * + * Everything is XOR'd with PADBYTE as something of a paranoia + * measure against viruses. + * + * XXX the definitions of TARGETSIZE and TARGETLABEL should + * be shared with the AG code. PADBYTE too. + * + * This module is new code as of June 2006 and should be much more + * portable than the old stuff. + */ + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifndef O_BINARY +#define O_BINARY 0 +#define O_TEXT 0 +#endif + +#define TARGETSIZE 512 +#define TARGETLABEL "Checksum data:\n" +#define PADBYTE 0xae + + +static char info[TARGETSIZE]; +static const char *me; + +static const char label[] = TARGETLABEL; + +//////////////////////////////////////////////////////////// + +static void setme(const char *av0) { + me = strrchr(av0, '/'); + if (me) { + me++; + } + else { + me = av0; + } +} + +static void die(const char *fmt, ...) { + va_list ap; + fprintf(stderr, "%s: ", me); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + exit(EXIT_FAILURE); +} + +//////////////////////////////////////////////////////////// + +static int isnumber(const char *s) { + size_t i; + for (i=0; s[i]; i++) { + if (!isdigit((unsigned char) s[i])) { + return 0; + } + } + // protect against possible overflow, just in case + return i<10; +} + +//////////////////////////////////////////////////////////// + +static void putsums(const char *file, long offset) { + char buf[TARGETSIZE]; + ssize_t len; + int fd; + + fd = open(file, O_RDWR); + if (fd<0) { + die("%s: %s", file, strerror(errno)); + } + if (lseek(fd, offset, SEEK_SET)<0) { + die("%s: lseek: %s", file, strerror(errno)); + } + len = read(fd, buf, sizeof(buf)); + if (len < 0) { + die("%s: read: %s", file, strerror(errno)); + } + if ((size_t)len != TARGETSIZE) { + die("%s: read: short count (past EOF?)", file); + } + + if (memcmp(buf, label, strlen(label))!=0) { + die("%s: patch area label is missing", file); + } + + if (lseek(fd, offset, SEEK_SET)<0) { + die("%s: lseek: %s", file, strerror(errno)); + } + len = write(fd, info, sizeof(info)); + if (len < 0) { + die("%s: write: %s", file, strerror(errno)); + } + if ((size_t)len != TARGETSIZE) { + die("%s: write: short count", file); + } + if (close(fd)<0) { + die("%s: close: %s", file, strerror(errno)); + } + //printf("%s: patched %s\n", me, file); +} + +static void storesums(const char *ctlfile) { + char buf[128]; + FILE *f; + int lineno = 0; + + f = fopen(ctlfile, "rt"); + if (!f) { + die("%s: fopen failed", ctlfile); + } + + while (fgets(buf, sizeof(buf), f)) { + /* format is: pathname offset */ + char *words[3], *s; + int nwords = 0; + lineno++; + if (*buf=='#') { + continue; + } + for (s = strtok(buf, " \t\r\n"); s; s = strtok(NULL, " \t\r\n")) { + if (nwords >= 3) { + break; + } + words[nwords++] = s; + } + if (nwords != 2 || !isnumber(words[1])) { + die("%s: Invalid line %d", ctlfile, lineno); + } + putsums(words[0], atol(words[1])); + } + if (ferror(f)) { + die("%s: read error", ctlfile); + } + fclose(f); +} + +//////////////////////////////////////////////////////////// + +static void hidesums(void) { + size_t i; + for (i=strlen(label); i<sizeof(info); i++) { + info[i] = (char) (PADBYTE ^ (unsigned char)info[i]); + } +} + +//////////////////////////////////////////////////////////// + +static void loadsums(const char *sumpath) { + ssize_t readlen; + size_t loadpos, maxlen, infolen; + int fd; + + assert(strlen(label) < TARGETSIZE); + strcpy(info, label); + loadpos = strlen(info); + maxlen = sizeof(info) - loadpos; + + fd = open(sumpath, O_TEXT|O_RDONLY); + if (fd < 0) { + die("%s: %s", sumpath, strerror(errno)); + } + + readlen = read(fd, info+loadpos, maxlen); + if (readlen < 0) { + die("%s: read: %s", sumpath, strerror(errno)); + } + if (readlen == 0) { + die("%s: read: empty file?", sumpath); + } + close(fd); + + infolen = loadpos+readlen; + if (infolen >= sizeof(info)) { + die("%s: Too much information!", sumpath); /* :-) */ + } + + //printf("%s: %lu bytes prepared\n", me, (unsigned long) infolen); + + while (infolen < sizeof(info)) { + info[infolen++] = 0; + } +} + +//////////////////////////////////////////////////////////// + +static void usage(void) { + die("Usage: %s sums.dat sums.ctl", me); +} + +int main(int argc, char *argv[]) { + setme(argv[0]); + if (argc != 3) { + usage(); + } + + loadsums(argv[1]); + hidesums(); + storesums(argv[2]); + + return EXIT_SUCCESS; +}