Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!ll-xn!husc6!necntc!ncoast!allbery
From: tanner@ki4pv.UUCP
Newsgroups: comp.sources.misc
Subject: A File Patching Package
Message-ID: <2765@ncoast.UUCP>
Date: Thu, 2-Jul-87 20:14:34 EDT
Article-I.D.: ncoast.2765
Posted: Thu Jul 2 20:14:34 1987
Date-Received: Sat, 4-Jul-87 10:17:57 EDT
Sender: allbery@ncoast.UUCP
Lines: 873
Approved: allbery@ncoast.UUCP
X-Archive: comp.sources.misc/8707/5
: "un-pack me with /bin/sh"
# This shar file contains a file patcher known around here as "fddt".
# The "Makefile" is incredibly simple. The man page explains
# everything (hihi). I hand-shar'ed the thing, as I don't have a
# "shar" prog running here. It might unpack anyway. Try it, after
# inspecting for trojan horse droppings.
echo "unshar: x-fddt.1"
sed s/\^X-// > fddt.1 < Makefile < fddt.c <
X-#include
X-
X-#define SZ 0x0100 /* size of things */
X-
X- /* this program allows someone to apply patches to files
X- * of almost any type. it helps a lot if lseek() will work
X- * on the file, but it is not required if the file to be
X- * "patched" is a serial device which is really being fed
X- * a stream of bytes.
X- *
X- * usage:
X- * fddt [-rw]
X- * or:
X- * fddt [-w] -p old1=new1 old2=new2 ...
X- * where
X- * -r read-only; patches may not be applied
X- * -w write-only; old contents may not be displayed
X- * -p "patch" mode, starts at addr and applies patch
X- *
X- * once a file is selected for editing, the following commands
X- * will apply for interactive mode within the prog:
X- * d display data
X- * e enter new values
X- * f find data; will prompt for values
X- * q,x exit
X- * all commands take either one or two addresses (if no addr
X- * given, no work is done). the first addr is a starting addr;
X- * the second, if given, is an ending addr. default end is EOF.
X- * note that all addresses and data values are to be expressed
X- * in hex. new values being entered are entered as 1-byte hex
X- * values.
X- *
X- * patch mode is a way to non-interactively change values in the
X- * file being edited. see the man page.
X- *
X- * warning: if your unix does not have rdchk(), you may either
X- * provide a substitute with ioctl() or eliminate the line of
X- * code using it with a return(0) and just use ^C to interrupt
X- * commands. rdchk() appears new with SYS-3, replacing a V7
X- * ioctl() call.
X- *
X- * note for cd_txt[] -- this is supplied by a little daemon
X- * which creates /lib/cdate.o containing today's date. the
X- * daemon to do this is available from "ki4pv!tanner" upon
X- * application. you could also eliminate the reference.
X- *
X- * This prog and documentation (C) 1987, CompuData, Inc.
X- * Permission is granted to use it, so long as this
X- * copyright notice remains intact, and so long as you
X- * don't try to sell it or claim that you wrote it.
X- * By making this program available, CompuData neither gives
X- * up any rights in it, nor assumes any responsibility for
X- * any damages caused by it.
X- */
X-
X- /* important vars */
X-
X-
X-static char
X- tf_blt[] = "FDDT vers 1.2a built %s\n\n",
X-
X- tf_usg[] = "? usage: %s [-rw] [-p old=new ...]\n",
X-
X- tf_sup[] = "%% %s suppressed\n",
X- tx_rd[] = "reading",
X- tx_wr[] = "writing",
X-
X- tf_bad[] = "? %s: bad %s: %s\n",
X- tf_bdr[] = "? bad range: %08lX > %08lX\n",
X- tf_nos[] = "? no search values\n",
X- tf_sek[] = "? can't seek: %08lX\n",
X- tf_wre[] = "? write error: file %s, off 0x%08X, n 0x%X\n",
X-
X- tf_fnd[] = "found @ 0x%08lX\n",
X- tf_nfd[] = "not found, end @ 0x%08lX\n",
X- tf_8x[] = "%08lX: ",
X- tf_2x[] = "%02X ",
X-
X- tf_pat[] = "patching 0x%08lX: ",
X- tf_pr1[] = "0x%02X",
X- tx_prx[] = " xx ",
X- tf_per[] = "read mismatch: exp 0x%02X, got 0x%02X\n",
X- tx_pex[] = "patch expr",
X-
X- tx_int[] = "** intr **\n";
X-
X-
X-unsigned int _fmode = 0x8000; /* for ms-dos */
X-
X-
X- /* - - - - */
X-
X-short int
X- stoppt, /* "action stopped" flag */
X- rw_sup, /* -r or -w flag */
X- patch, /* set true if patching */
X- ed_fd; /* fd of file to be patched */
X-
X-char
X- *prog_name,
X- *inbuf, /* user input buffer */
X- *ed_fn, /* name of file being patched */
X- *ed_buf, /* edit buffer */
X- *match; /* file match buffer */
X-
X- /* - - - - - */
X-
X-extern char
X- cd_txt[]; /* /lib/cdate.o, kept by daemon */
X-
X- /* = = = = = */
X-
X-short int
X- do_hdr(), /* things to do before any work */
X- do_lev(), /* evaluate a long addr */
X- get_ln(), /* get series of numbers */
X- get_st(), /* get "stopped" flag */
X- pat_ev(), /* eval expression for patch */
X- sig_st(); /* signal handler */
X-
X-void
X- do_opn(), /* open the file */
X- do_pat(), /* patch the file */
X- do_edt(), /* edit the file */
X- do_dmp(), /* dump part of file */
X- do_inp(), /* input new values to file */
X- do_src(), /* find values in file */
X- usage();
X-
X- /* - - - - - */
X-
X-extern long int
X- lseek();
X-
X-extern int
X- chupper(), /* $LOCLIB */
X- dehex(); /* $LOCLIB */
X- isprint(), iswhite(), isxdigit(),
X- rdchk(); /* $SYSDEP */ /* pending input check */
X-
X-extern char
X- *malloc(),
X- *strbrk(), /* $LOCLIB */
X- *strchr();
X-
X- /* main block of prog */
X-
X-main(ac, av)
X-short int ac;
X-char **av;
X- {
X- register char
X- *p;
X-
X-
X- fprintf(stderr, tf_blt, cd_txt);
X-
X- prog_name = **av ? *av : "FDDT";
X-
X- if (ac < 2)
X- usage();
X-
X- if (*(p = *++av) == '-') { /* have flag */
X- if (((rw_sup = chupper(*++p)) != 'R') &&
X- (rw_sup != 'W'))
X- usage();
X- ++av;
X- }
X- else
X- rw_sup = 0;
X-
X- ed_fn = *av; /* get working filename */
X-
X- setbuf(stdout, (char *)0);
X-
X- if ((!(ed_buf = malloc(SZ))) ||
X- (!(match = malloc(2*SZ))) ||
X- (!(inbuf = malloc(SZ)))) {
X- fprintf(stderr, "? %s: can't allocate\n", prog_name);
X- exit(1);
X- }
X-
X- signal(SIGINT, sig_st); /* catch ^C to abort command */
X-
X- do_opn(); /* open the file */
X-
X- if (*++av)
X- do_pat(av); /* patch the file */
X- else
X- do_edt(); /* edit the file */
X-
X- if (close(ed_fd)) /* close the file */
X- no_clos(ed_fn);
X-
X- exit(0);
X-
X- }
X-
X-
X-static void usage()
X- {
X-
X- fprintf(stderr, tf_usg, prog_name);
X- exit(1);
X-
X- }
X-
X-
X- /* open file to be edited */
X-
X-
X-void do_opn()
X- {
X- register short int
X- mode;
X-
X-
X- switch (rw_sup) { /* select file open mode */
X- case 'R':
X- mode = 0;
X- break;
X- case 'W':
X- mode = 1;
X- break;
X- default:
X- mode = 2;
X- }
X-
X- if ((ed_fd = open(ed_fn, mode)) < 0)
X- no_open(ed_fn);
X-
X- }
X-
X- /* patch the file */
X-
X-void do_pat(ap)
X-char **ap;
X- {
X- register char
X- *p;
X- short int
X- old, new;
X- long int
X- p_addr, /* patch addr */
X- tmp; /* tmp value from eval */
X- unsigned char
X- c; /* in/out data item */
X-
X-
X- if ((*(p = *ap) != '-') ||
X- (chupper(*++p) != 'P'))
X- usage();
X-
X- if (do_lev(*++ap, &p_addr)) { /* eval addr */
X- fprintf(stderr, tf_bad, prog_name, "addr", *ap);
X- exit(1);
X- }
X-
X- if (lseek(ed_fd, p_addr, 0) != p_addr) { /* just test */
X- fprintf(stderr, tf_sek, p_addr);
X- exit(2);
X- }
X-
X- for ( ; p = *++ap ; ++p_addr ) {
X- p += pat_ev(p, &old, "old");
X- if (*p++ != '=') {
X- fprintf(stderr, tf_bad, prog_name, tx_pex, *ap);
X- exit(3);
X- }
X- p += pat_ev(p, &new, "new");
X- if (*p) {
X- fprintf(stderr, tf_bad, prog_name, tx_pex, *ap);
X- exit(4);
X- }
X- printf(tf_pat, p_addr);
X- if (old >= 0) { /* match old */
X- if (rw_sup == 'R') {
X- fprintf(stderr, tf_sup, tx_rd);
X- exit(5);
X- }
X- if ((lseek(ed_fd, p_addr, 0) != p_addr) ||
X- (read(ed_fd, &c, 1) != 1) ||
X- (c != old)) {
X- fprintf(stderr, tf_per, old, c);
X- exit(6);
X- }
X- printf(tf_pr1, old);
X- }
X- else
X- printf(tx_prx);
X- printf(" -> ");
X- if (new >= 0) {
X- if (rw_sup == 'W') {
X- fprintf(stderr, tf_sup, tx_wr);
X- exit(7);
X- }
X- c = new;
X- if ((lseek(ed_fd, p_addr, 0) != p_addr) ||
X- (write(ed_fd, &c, 1) != 1)) {
X- fprintf(stderr, tf_wre, ed_fn, p_addr, 1);
X- exit(8);
X- }
X- printf(tf_pr1, new);
X- }
X- else
X- printf(tx_prx);
X- printf(" ok\n");
X- }
X-
X- }
X-
X-
X- /* patch support: evaluate old/new value */
X-
X-
X-static short int pat_ev(sp, dp, err)
X-char *sp, *err;
X-short int *dp; /* result goes here */
X- {
X- register char
X- *q;
X- long int
X- tmp;
X-
X-
X- if (chupper(*sp) == 'X') {
X- *dp = -1;
X- return(1);
X- }
X- if (do_lev(sp, &tmp) || (tmp < 0) || (tmp > 0xFF)) {
X- fprintf(stderr, tf_bad, prog_name, err, sp);
X- exit(3);
X- }
X- *dp = tmp;
X-
X- for ( q=sp ; isxdigit(*q) ; ++q );
X- return((short int)(q - sp));
X-
X- }
X-
X- /* edit the file (top-level interaction) */
X-
X-
X-void do_edt()
X- {
X- register char
X- *p;
X- register short int
X- nrd;
X-
X-
X- while (((nrd=read(0, inbuf, 100)) > 0) || get_st()) {
X- if (nrd < 0) /* ^C caused I/O err */
X- nrd = 0;
X- *(inbuf+nrd) = 0; /* null at end-of-input */
X- if (p = strchr(inbuf, '\n'))
X- *p = 0;
X- p = inbuf;
X- while (iswhite(*p))
X- ++p;
X- switch (chupper(*p)) {
X- case 'F':
X- do_src(p+1);
X- break;
X- case 'E':
X- do_inp(p+1);
X- break;
X- case 'D':
X- do_dmp(p+1);
X- break;
X- case 'Q':
X- case 'X':
X- return;
X- case '?':
X- printf("D-display E-enter F-find Q-exit\n");
X- break;
X- default:
X- printf("unknown: %c\n", *p);
X- case 0:
X- break;
X- }
X- }
X-
X- }
X-
X- /* dump values */
X-
X-
X-void do_dmp(p)
X-char *p;
X- {
X- register short int
X- sz, nd;
X- long int
X- ed_adr,
X- ed_cur,
X- ed_end,
X- lnend;
X-
X-
X- if (do_hdr('R', p, &ed_adr, &ed_end)) /* input bad */
X- return;
X-
X- ed_cur = ed_adr; /* back to start */
X-
X- do {
X- lnend = ed_cur - (ed_cur % 16) + 15;
X- if (lnend > ed_end)
X- lnend = ed_end;
X- sz = lnend - ed_cur + 1;
X- if ((nd = read(ed_fd, ed_buf, sz)) < sz)
X- sz = nd;
X- if (sz < 1) {
X- printf("e-o-f\n");
X- break;
X- }
X- printf(tf_8x, ed_cur);
X- for ( nd=0 ; nd= 0 ; ) {
X- if ((n > 0) && (write(ed_fd, ed_buf, n) < n)) {
X- fprintf(stderr, tf_wre, ed_fn, ed_cur, n);
X- break;
X- }
X- if ((ed_cur += n) > ed_end) /* gave exit point */
X- break;
X- }
X-
X- }
X-
X-
X- /* find values in file */
X-
X-#define MATCH (*(ed_buf+bufm) == *(match+bufo+bufm))
X-
X-void do_src(p)
X-char *p;
X- {
X- register short int
X- nsrc, /* # to search for */
X- nbuf, /* # chars in buff */
X- bufo, /* buffer offset */
X- bufm, /* buffer # matched */
X- nrd;
X- long int
X- ed_adr,
X- ed_cur,
X- ed_end,
X- val;
X-
X-
X- if (do_hdr('R', p, &ed_adr, &ed_end)) /* input bad */
X- return;
X-
X- ed_cur = ed_adr; /* back to start */
X-
X- if ((nsrc = get_ln(0L)) <= 0) {
X- printf(tf_nos);
X- return;
X- }
X-
X- printf("searching...");
X- nrd = nbuf = read(ed_fd, match, 2*SZ);
X- for ( bufo=0 ;; ) {
X- for ( bufm=0 ; (bufm < nsrc) && MATCH ; ++bufm );
X- if (bufm == nsrc) {
X- printf(tf_fnd, ed_cur);
X- return;
X- }
X- ++ed_cur; /* start at next char */
X- if (++bufo > SZ) { /* must read more */
X- move(match, match+SZ, SZ);
X- bufo -= SZ;
X- nbuf -= SZ;
X- if (get_st()) /* input, stop search */
X- nrd = 0;
X- if (nrd && ((nrd=read(ed_fd, match+SZ, SZ)) > 0))
X- nbuf += nrd;
X- }
X- if ((bufo >= nbuf) || (ed_cur > ed_end)) {
X- printf(tf_nfd, ed_cur);
X- return;
X- }
X- }
X-
X- }
X-
X- /* common support routines */
X-
X-
X- /* handle the command understanding for both display and edit
X- * expects
X- * sup 'R', 'W' if reading, writing required
X- * p user's input
X- * sad, ead ptrs to display/edit start/end addr
X- * returns
X- * 0 good input
X- * -1 didn't
X- */
X-static short int do_hdr(sup, p, sad, ead)
X-char sup, *p;
X-long int *sad, *ead;
X- {
X-
X- if (rw_sup && (rw_sup != sup)) { /* make sure it's OK */
X- printf(tf_sup, (sup=='R') ? tx_rd : tx_wr);
X- return;
X- }
X-
X- if (do_lev(p, sad)) /* get starting addr */
X- return(-1);
X-
X- *ead = 0x40000000; /* dflt end addr */
X-
X- while (iswhite(*p)) /* skip white space */
X- ++p;
X-
X- if ((p = strbrk(p, "-, ")) && do_lev(++p, ead)) {
X- printf(tf_bad, prog_name, "end", p);
X- return(-1);
X- }
X-
X- if (*ead < *sad) {
X- printf(tf_bdr, *sad, *ead);
X- return(-1);
X- }
X-
X- if (lseek(ed_fd, *sad, 0) != *sad) { /* do the seek */
X- printf(tf_sek, *sad);
X- return(-1);
X- }
X-
X- return(0);
X-
X- }
X-
X-
X- /* evaluate an address
X- * expects
X- * p ptr to addr to scan
X- * adr addr to receive value if we found number
X- * returns
X- * 0 worked
X- * -1 no addr found
X- * note
X- * if it works, *adr will be filled in.
X- */
X-
X-static short int do_lev(p, adr)
X-char *p;
X-long int *adr;
X- {
X- register long int
X- val;
X-
X-
X- while (iswhite(*p)) /* skip */
X- ++p;
X-
X- if (! isxdigit(*p))
X- return(-1);
X-
X- for ( val=0 ; isxdigit(*p) ; ++p )
X- val = (val << 4) + dehex(*p);
X-
X- if (*p && (! iswhite(*p)) && (*p != '=') && (*p != '-'))
X- return(-1);
X-
X- *adr = val;
X- return(0);
X-
X- }
X-
X-
X- /* get a list of numbers into the edit buffer
X- * expects
X- * ed_cur address to be printed in prompt
X- * returns
X- * -1 trouble
X- * n # bytes specified on line by user
X- * fills in ed_buf with the values given
X- */
X-
X-static short int get_ln(ed_cur)
X-long int ed_cur;
X- {
X- register char
X- *p;
X- register short int
X- n;
X- long int
X- val;
X-
X-
X- printf(tf_8x, ed_cur); /* prompt */
X- zero(inbuf, SZ);
X- if (read(0, p=inbuf, 200) < 1) { /* hit EOF */
X- fputs(" ** OK\n", stdout);
X- return(-1);
X- }
X- for ( n=0 ; *p ; ) { /* scan & convert */
X- if (do_lev(p, &val) ||
X- (val > 0x00FF) || (val < 0)) {
X- printf("bad value: %s\n", p);
X- n = 0;
X- break;
X- }
X- *(ed_buf+(n++)) = val;
X- while (isxdigit(*p))
X- ++p;
X- while (isxdigit(*p))
X- ++p;
X- if (*p == ',')
X- ++p;
X- while (iswhite(*p))
X- ++p;
X- }
X-
X- return(n);
X-
X- }
X-
X- /* user-attention handlers */
X-
X- /* user hits ^C, set flag to indicate same
X- * note: under ms-dos, signal() only works for ^C
X- * but that's OK. use MS-C; lattice doesn't have
X- * signal(2).
X- */
X-static short int sig_st()
X- {
X-
X- signal(SIGINT, sig_st); /* continued protection */
X- printf(tx_int); /* ack for abuser */
X- stoppt = 1; /* set flag */
X-
X- }
X-
X-
X- /* routine to see if user wants to stop command
X- * checks/resets "stoppt" flag set by ^C
X- * if machine has rdchk() uses that to see if pending input
X- */
X- /* $SYSDEP */
X-static short int get_st()
X- {
X-
X- if (stoppt) { /* hit ^C */
X- stoppt = 0; /* clear it */
X- return(1);
X- }
X-
X- return(rdchk(0) > 0); /* pending input */
X-
X- }
X-
X- /* local library routines */
X-
X- /* these routines normally live in a local library. the names
X- * are actually left-overs from CP/M days.
X- */
X-#ifndef DONT_NEED
X- /* convert a hex digit */
X-int dehex(c)
X-int c;
X- {
X- if ((c >= '0') && (c <= '9'))
X- return(c - '0');
X- if ((c >= 'A') && (c <= 'F'))
X- return(c + 10 - 'A');
X- if ((c >= 'a') && (c <= 'f'))
X- return(c + 10 - 'a');
X- return(-1);
X- }
X-
X- /* find character in "breakset" */
X-char *strbrk(s1, s2)
X-register char *s1, *s2;
X- {
X-
X- if (s1 && s2) /* have strings */
X- for ( ; *s1 ; ++s1 ) /* scan string */
X- if (strchr(s2, *s1)) /* match any? */
X- return(s1); /* yup, winner */
X-
X- return((char *)0);
X-
X- }
X-
X- /* case conversion -- don't trust "toupper" or "tolower */
X-int chupper(c)
X-int c;
X- {
X- return(((c >= 'a') && (c <= 'z')) ? (c - ('a'-'A')) : c);
X- }
X-
X-#endif
X-
END_OF_FILE