view insertsums/insertsums.c @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -0400
parents 13d2b8934445
children
line wrap: on
line source

/*
 * 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;
}