1*14310Ssam static char sccsid[] = "@(#)runcompat.c	4.2 83/07/31";
26801Srrh 
36801Srrh /*
4*14310Ssam  *	Compatability mode support
56801Srrh  *	written by Art Wetzel during August 1979
66801Srrh  *	at the Interdisciplinary Dept of Information Science
76801Srrh  *	Room 711, LIS Bldg
86801Srrh  *	University of Pittsburgh
96801Srrh  *	Pittsburgh, Pa 15260
106801Srrh  *
116801Srrh  *	No claims are made on the completeness of the support of any
126801Srrh  *	of the systems simulated under this package
136801Srrh  */
14*14310Ssam 
156801Srrh #include <stdio.h>
166801Srrh #include <signal.h>
176801Srrh #include <sys/types.h>
186801Srrh #include <sys/stat.h>
196801Srrh #include <errno.h>
206801Srrh #include "defs.h"
216801Srrh #ifdef UNIX
226801Srrh #include "unixhdr.h"
236801Srrh #endif
246801Srrh #ifdef RT11
256801Srrh #include "rt11.h"
266801Srrh #endif
27*14310Ssam 
28*14310Ssam struct	stat stat32v;
29*14310Ssam u_short	regs[8];
30*14310Ssam u_long	psl;
31*14310Ssam u_short	*pc;
32*14310Ssam int	incompat;
336801Srrh char	*progname;
346801Srrh char	*nameend;
35*14310Ssam 
main(argc,argv,envp)36*14310Ssam main(argc, argv, envp)
37*14310Ssam 	int argc;
38*14310Ssam 	char **argv, **envp;
39*14310Ssam {
40*14310Ssam 
41*14310Ssam 	if (argc < 2) {
426801Srrh 		fprintf(stderr,"Usage: %s [-rootdir] file args...\n",argv[0]);
436801Srrh 		exit(1);
446801Srrh 	}
456801Srrh 	/* remember where the program name etc should go for using ps */
466801Srrh 	progname = argv[0];
476801Srrh 	nameend = envp[0]-1;
486801Srrh 	argv++;
496801Srrh 	/* set up alternate root directory if flagged for */
50*14310Ssam 	if (*argv[0] == '-') {
51*14310Ssam 		if (chroot(argv[0]+1)) {
526801Srrh 			fprintf(stderr,"Can't change root to %s\n",argv[0]+1);
536801Srrh 			exit(-1);
546801Srrh 		}
556801Srrh 		argv++;
566801Srrh 	}
576801Srrh 	/* check out file stats of file to run */
58*14310Ssam 	if (stat(argv[0], &stat32v)) {
596801Srrh 		fprintf(stderr,"%s does not exist\n",argv[0]);
606801Srrh 		exit(1);
616801Srrh 	}
626801Srrh 	/* a version of SETUID and SETGID file executions */
636801Srrh 	/* the binary of this program should be SETUID root for this to work */
646801Srrh 	/* requires nonstandard seteuid and setegid sys calls */
65*14310Ssam 	if (!(stat32v.st_mode & S_ISGID) || setegid(stat32v.st_gid))
666801Srrh 		/* if not SETGID file or error, drop back to real group */
676801Srrh 		setgid(getgid());
68*14310Ssam 	if (!(stat32v.st_mode & S_ISUID) || seteuid(stat32v.st_uid))
696801Srrh 		/* if not SETUID file or error, drop back to real uid */
706801Srrh 		setuid(getuid());
716801Srrh #ifdef V6UNIX
726801Srrh 	/* no umasks in version 6 */
736801Srrh 	umask(0);
746801Srrh #endif
756801Srrh 	/* go try to execute , passing along args and environment */
766801Srrh 	execute(argv[0], argv, envp);
776801Srrh 	/* only get here if execute fails */
786801Srrh 	fprintf(stderr,"Execution failure on %s\n",argv[0]);
796801Srrh 	exit(1);
806801Srrh }
81*14310Ssam 
execute(file,argv,envp)82*14310Ssam execute(file, argv, envp)
83*14310Ssam 	char *file, **argv, **envp;
84*14310Ssam {
856801Srrh 	int fd, n, tloadpt, dloadpt, tloadsize, dloadsize, stacksize;
866801Srrh 	register short *p;
876801Srrh 	extern illtrap();
886801Srrh 	extern char **environ;
89*14310Ssam 
906801Srrh 	/* file to run should be readable */
91*14310Ssam 	if ((fd = open(file, 0)) == -1) {
926801Srrh 		fprintf(stderr,"Can't open %s for read access\n",file);
936801Srrh 		return(-1);
946801Srrh 	}
956801Srrh #ifdef UNIX
96*14310Ssam 	if ((n = read(fd, &header, sizeof header)) != sizeof header)
976801Srrh 		return(ENOEXEC);
986801Srrh 	/* check to see if really unix file */
99*14310Ssam 	if (header.magic != MAGIC1 && header.magic != MAGIC2 &&
100*14310Ssam 	    header.magic != MAGIC3 && header.magic != MAGIC4) {
1016801Srrh 		return(ENOEXEC);
1026801Srrh 	}
103*14310Ssam 	/* if a UNIX file run it */
104*14310Ssam 	if (header.textsize == 0) {
1056801Srrh 		close(fd);
1066801Srrh 		/* if no explicit env, pass along environ */
107*14310Ssam 		if (!envp || *envp == 0)
1086801Srrh 			return(execve(file, argv, environ));
1096801Srrh 		return(execve(file, argv,  envp));
1106801Srrh 	}
1116801Srrh 	/* checks out OK as PDP-11 UNIX file */
112*14310Ssam 	if (header.magic == MAGIC3) {
1136801Srrh 		fprintf(stderr,"%s compiled for separate I/D space\n",argv[0]);
1146801Srrh 		return(-1);
1156801Srrh 	}
1166801Srrh 	/* unix text loads at 0 */
1176801Srrh 	tloadpt = 0;
1186801Srrh 	/* set starting pc value */
1196801Srrh 	pc = (unsigned short *)header.entry;
1206801Srrh 	/* figure out where to load initialized data */
1216801Srrh 	dloadpt = tloadsize = header.textsize;
1226801Srrh 	/* check if alignment of data segment to 8k byte boundary */
123*14310Ssam 	if (header.magic == MAGIC2)
1246801Srrh 		dloadpt = (dloadpt+8191) & (~8191);
1256801Srrh 	/* how much data */
1266801Srrh 	dloadsize = header.datasize;
1276801Srrh 	stacksize = header.bsssize;
1286801Srrh #endif
1296801Srrh #ifdef RT11
130*14310Ssam 	if ((n = read(fd, shortspace, RTHDRSIZ)) != RTHDRSIZ) {
1316801Srrh 		fprintf(stderr,"Error reading 1st block\n");
1326801Srrh 		return(-1);
1336801Srrh 	}
1346801Srrh 	/* rt11 files are 0 aligned including the header */
1356801Srrh 	tloadpt = RTHDRSIZ;
1366801Srrh 	/* set starting pc value */
1376801Srrh 	pc = (unsigned short *)shortspace[RTPC];
1386801Srrh 	/* initialize stack location */
1396801Srrh 	regs[6] = shortspace[RTSP];
1406801Srrh 	/* figure how much to load */
1416801Srrh 	dloadpt = tloadsize = shortspace[RTHGH]-RTHDRSIZ;
1426801Srrh 	/* no separate data as in unix */
1436801Srrh 	dloadsize = 0;
1446801Srrh 	stacksize = 0;
1456801Srrh #endif
1466801Srrh 	/* see if it all fits into available memory space */
147*14310Ssam 	if ((dloadpt+dloadsize+stacksize) > (int)memsiz) {
1486801Srrh 		fprintf(stderr,"File too big to run\n");
1496801Srrh 		return(-1);
1506801Srrh 	}
1516801Srrh 	/* read text segment */
152*14310Ssam 	if ((n = read(fd, tloadpt, tloadsize)) < tloadsize) {
1536801Srrh 		fprintf(stderr,"Text read failure\n");
1546801Srrh 		return(-1);
1556801Srrh 	}
1566801Srrh 	/* read data segment */
157*14310Ssam 	if ((n = read(fd, dloadpt, dloadsize)) < dloadsize) {
1586801Srrh 		fprintf(stderr,"Data read failure\n");
1596801Srrh 		return(-1);
1606801Srrh 	}
1616801Srrh 	/* clear out the rest of memory */
1626801Srrh 	p = (short *)(dloadpt + dloadsize);
163*14310Ssam 	while (p < (short *)memsiz)
164*14310Ssam 		*p++ = 0;
1656801Srrh 	/* close file before starting it */
1666801Srrh 	close(fd);
1676801Srrh 	/* set up illegal instruction trapping */
1686801Srrh 	signal(SIGILL, illtrap);
1696801Srrh 	/* lets give it a try */
1706801Srrh 	start(argv, envp);
1716801Srrh }
172*14310Ssam 
illtrap(signum,faultcode,scp)173*14310Ssam illtrap(signum, faultcode, scp)
174*14310Ssam 	int signum, faultcode;
175*14310Ssam 	struct sigcontext *scp;
176*14310Ssam {
1776801Srrh 	unsigned short *pcptr;
1786801Srrh 	int instr;
1796801Srrh 	register int i;
1806801Srrh 	extern getregs();
181*14310Ssam 
1826801Srrh 	/* record the fact that we are not in compatability mode now */
1836801Srrh 	incompat = 0;
1846801Srrh 	/* get the register values before they get clobbered */
1856801Srrh 	getregs();
1866801Srrh 	/* figure out what the pc was */
187*14310Ssam 	pcptr = (unsigned short *) &scp->sc_pc;
1886801Srrh 	pc = (unsigned short *) *pcptr;
1896801Srrh 	/* get the instruction */
1906801Srrh 	instr = *pc;
1916801Srrh 	/* incriment the pc over this instruction */
1926801Srrh 	pc++;
1936801Srrh 	/* set register 7 as pc synonym */
1946801Srrh 	regs[7] = (unsigned short)(int)pc;
1956801Srrh 	/* set up psl with condition codes */
1966801Srrh 	/* a UNIX-32V monitor patch is required to not clear condition codes */
197*14310Ssam 	psl = 0x83c00000 | (scp->sc_ps & 017);
198*14310Ssam 	sigsetmask(scp->sc_mask);
1996801Srrh 	/* pick out the appropriate action for this illegal instruction */
2006801Srrh 	switch(instr>>8){
201*14310Ssam 
202*14310Ssam 	case TRAPS:
2036801Srrh 		dotrap(instr & 0377);
2046801Srrh 		break;
205*14310Ssam 
206*14310Ssam 	case EMTS:
207*14310Ssam 		if (sigvals[SIGEMT] && ((sigvals[SIGEMT]%2) != 1)) {
2086801Srrh 			dosig(SIGEMT, pc);
2096801Srrh 			break;
2106801Srrh 		}
2116801Srrh 		doemt(instr & 0377);
2126801Srrh 		break;
213*14310Ssam 
2146801Srrh 	default:
215*14310Ssam 		if (instr >= 075000 && instr < 075040) {
2166801Srrh 			/* fis instructions */
217*14310Ssam 			if (dofloat(instr) == 0)
2186801Srrh 				break;
2196801Srrh 		}
220*14310Ssam 		if (instr >=  0170000) {
2216801Srrh 			/* floating point unit instructions */
222*14310Ssam 			if (dofloat(instr) == 0)
2236801Srrh 				break;
2246801Srrh 		}
2256801Srrh 		/* genuine illegal instruction */
2266801Srrh 		/* if signal trap set go to user's trap location */
227*14310Ssam 		if (sigvals[SIGILL] && ((sigvals[SIGILL]%2) != 1)) {
2286801Srrh 			dosig(SIGILL, pc);
2296801Srrh 			break;
2306801Srrh 		}
2316801Srrh 		/* ignore uncaught setd instructions */
232*14310Ssam 		if (instr == SETD)
2336801Srrh 			break;
2346801Srrh 		/* otherwise put out a message and quit */
235*14310Ssam 		printf("Illegal instruction, psl 0x%08x, pc 0%04o\n",psl,pc-1);
236*14310Ssam 		for (i = 0; i < 7; i++)
237*14310Ssam 			printf("0x%04x  ",regs[i]);
2386801Srrh 		printf("0x%04x -> 0%o\n",pc-1,instr);
2396801Srrh 		/* set up to dump on illegal instruction */
2406801Srrh 		signal(SIGILL,SIG_DFL);
2416801Srrh 		/* set pc back to bad instruction */
2426801Srrh 		pc--;
2436801Srrh 		/* go do it again for dump */
2446801Srrh 		compat();
2456801Srrh 	}
2466801Srrh 	/* go back to compatability mode */
2476801Srrh 	incompat++;
2486801Srrh 	compat();
2496801Srrh }
250