Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info.

Binpatch.shar

From Higher Intellect Vintage Wiki
Jump to navigation Jump to search
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	binpatch.c
#	Makefile
# This archive created: Tue Mar  2 11:57:39 1999
export PATH; PATH=/bin:$PATH
if test -f 'binpatch.c'
then
	echo shar: will not over-write existing file "'binpatch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'binpatch.c'
X
X/*
X
X$Revision: 1.5 $
X$Date: 1999/03/02 19:57:08 $
X
X
X	binpatch is for binary patching of an a.out or any other
X	file.
X
X	Written by David B. Anderson.  October, 1996.
X	Silicon Graphics.
X	No restrictions of any kind on use or distribution of the
X	source or binary.
X
X	example:
X		binpatch 1356 0xff32  0xef31 filetopatch
X	which patches the two bytes which contain xff32 to contain
X	the two bytes 0xef31 instead.
X
X	All messages come out on standard output.
X	Exit code is 0 in case of success. 
X	Exits with a small positive number in case of failure.
X
X	Usage:
X	binpatch offset oldvalue newvalue filename
X
X	where
X	  offset is a file offset. 
X		The offset can be plain decimal or it can
X		be octal with a leading 0 or it can be
X		hex with a leading 0x.
X		examples:
X				16
X				0x10
X
X	  oldvalue is a hex representation of as many bytes as are to
X		be updated.  The representation must match exactly the
X		bytes in the file being patched. In otherwords, this
X		is a representation of the existing values in the file
X		starting at offset 'offset'.
X		A leading 0x (to emphasize the hex representation)
X		is reqired.
X
X	  newvalue is a hex representation of those same bytes, but
X		here the value is the new value to be plugged into
X		the file.
X
X	  Both oldvalue and newvalue must have an even number of hex
X	  	digits.  Both must have exactly the same number of
X		digits and each digit must be 
X		one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
X		(after the required leading 0x)
X
X	  filename is the name of the file to be changed.
X		The file will be modified in place if and only if
X		the oldvalue matches the appropriate bytes in
X		the file and all the digits are valid and
X		the oldvalue and newvalue are equal length.
X
X	  The file must exist and be writable.
X
X
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <errno.h>
X#include <ctype.h>
X#include <alloca.h>
X#include <malloc.h>
X#ifdef __linux__
X#include <string.h> /* for strerror */
X#endif
X
Xchar *explanation[] = {
X"        binpatch offset oldvalue newvalue filename",
X"",
X"        where",
X"          offset is a file offset.",
X"                The offset can be plain decimal or it can",
X"                be octal with a leading 0 or it can be",
X"                hex with a leading 0x.",
X"                examples:",
X"                                16",
X"                                0x10",
X"",
X"          oldvalue is a hex representation of as many bytes as are to",
X"                be updated.  The representation must match exactly the",
X"                bytes in the file being patched. In otherwords, this",
X"                is a representation of the existing values in the file",
X"                starting at offset 'offset'.",
X"                A leading 0x (to emphasize the hex representation)",
X"                is reqired.",
X"",
X"          newvalue is a hex representation of those same bytes, but",
X"                here the value is the new value to be plugged into",
X"                the file.",
X"",
X"          Both oldvalue and newvalue must have an even number of hex",
X"                digits.  Both must have exactly the same number of",
X"                digits and each digit must be",
X"                one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F",
X"                (after the required leading 0x)",
X"",
X"          filename is the name of the file to be changed.",
X"                The file will be modified in place if and only if",
X"                the oldvalue matches the appropriate bytes in",
X"                the file and all the digits are valid and",
X"                the oldvalue and newvalue are equal length.",
X"",
X"          The file must exist and be writable.",
X0
X};
X
X
Xstatic void usage(void)
X{
X  int i;
X  printf("Usage:  \n");
X  for (i = 0; explanation[i]; ++i) {
X	printf("%s\n",explanation[i]);
X  }
X
X}
Xstatic void updatethefile(void);
X
Xstatic char *offstring;
Xoff_t fileoff;
Xstatic char *oldvalstring;
Xstatic char *old_val_bytes;
Xstatic char *newvalstring;
Xstatic int  bytes_to_update;
Xstatic char *new_val_bytes;
Xstatic char *filenamestring;
X
X
Xstatic void do_the_update(int filefd);
Xstatic void verify_the_args(void);
Xstatic void validatehexstr(char *instring, char *msg,char *target);
X
X
Xint main(int argc, char **argv) 
X
X{
X	if(argc != 5) {
X		usage();
X		exit(1);
X	}
X	offstring = argv[1];
X	oldvalstring = argv[2];
X	newvalstring = argv[3];
X	filenamestring = argv[4];
X	verify_the_args();
X	updatethefile();
X	return 0;
X}
X
X/*
Xverify the arguments and create the internal form of each
X*/
Xstatic void verify_the_args(void)
X{
X	char * endptr = 0;
X	int slen1;
X	int slen2;
X
X	errno = 0;
X	fileoff = strtoul(offstring, &endptr,0);
X	if(fileoff == 0 && errno != 0) {
X		printf("offset is not a valid number\n");
X		printf("Nothing done\n");
X		exit(2);
X	}
X	if(endptr != offstring + strlen(offstring)) {
X		printf("offset had some unrecognizable non-digit characters\n");
X		printf("Nothing done\n");
X		exit(2);
X	}
X
X	slen1 = strlen(oldvalstring);
X	slen2 = strlen(newvalstring);
X
X
X	if (slen1 != slen2) {
X	  printf(" oldvalue had %d characters, newvalue had %d characters.\n",
X			slen1,slen2);
X		printf("Nothing done\n");
X		exit(2);
X	}
X	if(slen1 < 3) {
X	  printf(
X	   "oldvalue is not a valid hex value starting with 0x (is %s )\n",
X		oldvalstring);
X		printf("Nothing done\n");
X		exit(2);
X	}
X
X
X	bytes_to_update = (slen1-2)/2;
X
X	old_val_bytes = malloc(bytes_to_update);
X	if(old_val_bytes == 0) {
X	  printf("%d bytes could not be malloc'd.\n",bytes_to_update);
X	  printf("Nothing done\n");
X          exit(2);
X	}
X	new_val_bytes = malloc(bytes_to_update);
X	if(new_val_bytes == 0) {
X	  printf("%d bytes could not be malloc'd..\n",bytes_to_update);
X	  printf("Nothing done\n");
X          exit(2);
X	}
X
X
X	validatehexstr(oldvalstring,"oldvalue",old_val_bytes);
X	validatehexstr(newvalstring,"newvalue",new_val_bytes);
X
X
X	
X
X	
X	
X}
Xstatic void updatethefile(void)
X{
X	int filefd;
X	int res;
X
X	filefd = open(filenamestring,O_RDWR,0);
X	if(filefd < 0) {
X		int myerr = errno;
X		printf("Cannot open %s read/write. %s (errno %d)\n",
X				filenamestring,
X				strerror(myerr),myerr);
X                printf("Nothing done\n");
X		exit(1);
X	}
X
X	
X	do_the_update(filefd);
X
X	
X	res = close(filefd);
X	if(res != 0) {
X		int myerr = errno;
X		printf("Cannot close %s -- %s (errno %d)\n",
X				filenamestring,
X				strerror(myerr),myerr);
X		exit(1);
X	}
X
X}
X
X/* verify that there is a match with oldvalue and, if present,
X   write in the newvalue stuff.
X
X*/
Xstatic void do_the_update(int filefd)
X{
X
X	char *filebuffer;	
X	size_t readres;
X	size_t bytes_to_write;
X	size_t total_written = 0;
X	char *outbuff;
X	off_t res_off;
X	int i;
X
X	bytes_to_write = bytes_to_update;
X
X	filebuffer = alloca(bytes_to_write);
X        res_off = lseek(filefd,fileoff,SEEK_SET);
X        if(res_off == (off_t)-1) {
X                int myerr = errno;
X                printf("Cannot lseek to %lu in  %s -- %s (errno %d)\n",
X                                (unsigned long)fileoff,
X                                filenamestring,
X                                strerror(myerr),myerr);
X                printf("Nothing done\n");
X
X                exit(1);
X        }
X
X
X
X	readres = read(filefd,filebuffer,bytes_to_write);
X
X	if(readres == (size_t)-1) {
X	  int myerr = errno;
X	  printf("Read  %lu bytes failed %s (errno %d)\n",
X			(unsigned long)bytes_to_write,
X			strerror(myerr),myerr);
X			
X	  printf("Nothing done\n");
X	  exit(3);
X        }
X	if(readres != bytes_to_write) {
X	  printf("Read %lu bytes, not the %lu requested to update\n",
X			(unsigned long)readres,(unsigned long)bytes_to_write);
X	  printf("Nothing done\n");
X	  exit(3);
X	}
X	
X	for(i = 0; i < bytes_to_write; ++i) {
X		if(filebuffer[i] != old_val_bytes[i]) {
X			printf("old value does not match file value "
X			 "in byte %lu of the bytes you are attempting "
X			 "to change (file byte %ld)\n",
X				(unsigned long)i,
X				(unsigned long)(fileoff + i));
X			printf("file has 0x%x, old_val_bytes has 0x%x\n",
X				(int)filebuffer[i]&0xff,
X				(int)old_val_bytes[i]&0xff);
X			printf("Nothing done\n");
X			exit(3);
X		}
X	}
X	
X	
X	/* we passed the tests. */
X        res_off = lseek(filefd,fileoff,SEEK_SET);
X        if(res_off == (off_t)-1) {
X                int myerr = errno;
X                printf("Cannot re-lseek to %lu in  %s -- %s (errno %d)\n",
X                                (unsigned long)fileoff,
X                                filenamestring,
X                                strerror(myerr),myerr);
X                printf("Nothing done\n");
X
X                exit(1);
X        }
X
X	/* write out the new bytes */
X	outbuff = new_val_bytes;
X	while(bytes_to_write > 0 ) {
X	    errno = 0;
X	    readres = write(filefd,outbuff,bytes_to_write);
X	    if(readres  == (size_t)-1) {
X		int myerr = errno;
X		printf("Write failed on %lu bytes: %s (%d)\n",
X			(unsigned long)bytes_to_write,
X			strerror(myerr), myerr);
X	 	if(total_written > 0) {
X			printf("Wrote %lu bytes\n",
X			(unsigned long) total_written);
X		} else {
X			printf("Nothing done.\n");
X		}
X		
X			
X	    }
X	    if(readres == 0) {
X		printf("Zero length write: giving up\n");
X	 	if(total_written > 0) {
X			printf("Wrote %lu bytes\n",
X			(unsigned long) total_written);
X		} else {
X			printf("Nothing done.\n");
X		}
X	    }
X	    bytes_to_write -= readres;
X	    outbuff += readres;
X	    total_written += readres;
X	}
X	
X}
X
X/*
X	precondition: input chars must be valid hex.
X	Returns int with low 4 bits being the nibble for the char.
X*/
Xstatic int 
Xmakehex(int in)
X{
X
X	if(isdigit(in)) {
X		return in - '0';
X	}
X	if(isupper(in)) {
X	  return in = 'A' + 10;
X	}
X	return  in - 'a' + 10;
X}
X/*
X	Ensure string is
X	0x followed by hex digits (an even number of them)
X*/
Xstatic void 
Xvalidatehexstr(char *instring, char *msg, char *bytebuff)
X{
X	int len;
X	char *curloc;
X
X	if(instring[0] != '0') {
X		printf("%s %s does not begin with 0x\n",msg,instring);
X		printf("Nothing done\n");
X		exit(3);
X	}
X
X	if(instring[1] != 'x' && instring[1] != 'X') {
X		printf("%s %s does not begin with 0x\n",msg,instring);
X		printf("Nothing done\n");
X		exit(3);
X	}
X
X	len = strlen(instring);
X
X	if((len&1) != 0) {
X		printf(" %s%s does not have an even number of hex digits\n",
X		msg,instring);
X		printf("Nothing done\n");
X		exit(3);
X	}
X
X
X	curloc = instring+2;
X	
X	for( ; *curloc ; curloc+= 2,++bytebuff) {
X		if(!isxdigit(curloc[0])) {
X			printf(" Non-hex digit %c found in %s\n",
X				curloc[0],msg);
X			printf("Nothing done\n");
X			exit(3);
X		}
X		if(!isxdigit(curloc[1])) {
X			printf(" Non-hex digit %c found in %s\n",
X				curloc[0],msg);
X			printf("Nothing done\n");
X			exit(3);
X		}
X		bytebuff[0] = (makehex(curloc[0])<<4) | makehex(curloc[1]);
X	}
X		
X
X	return;
X	
X	
X}
X
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X
XSHELL=/bin/sh
XCFLAGS = -g
X
Xall: binpatch
Xshar:
X	shar -p X binpatch.c Makefile  \
X		>/d2/public/binpatch.shar
X
X
Xbinpatch: binpatch.c
X	$(CC) $(CFLAGS) binpatch.c -o binpatch
X
Xclean clobber:
X	-rm -f *.o
X	-rm -f binpatch
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0