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;
+}