1*6809Srrh #
2*6809Srrh static char sccsid[] = "	unixtraps.c	1.1	82/05/12	";
3*6809Srrh /*	Function to execute version 6 and version 7 UNIX system calls from
4*6809Srrh  *	compatability mode on UNIX-32V.
5*6809Srrh  *	Art Wetzel	August 1979
6*6809Srrh  */
7*6809Srrh #include <stdio.h>
8*6809Srrh #include <signal.h>
9*6809Srrh #include <sys/types.h>
10*6809Srrh #include <sys/stat.h>
11*6809Srrh #ifdef V6UNIX
12*6809Srrh #ifdef TRACE
13*6809Srrh #define	RTSNAME	"/../../../../usr/local/v6trc"
14*6809Srrh #else
15*6809Srrh #define	RTSNAME	"/../../../../usr/local/v6run"
16*6809Srrh #endif
17*6809Srrh #include "unix6sys.h"
18*6809Srrh #ifdef TRACE
19*6809Srrh #include "unix6sysn.h"
20*6809Srrh #endif
21*6809Srrh #endif
22*6809Srrh #ifdef V7UNIX
23*6809Srrh #ifdef TRACE
24*6809Srrh #define	RTSNAME	"/../../../../usr/local/v7trc"
25*6809Srrh #else
26*6809Srrh #define	RTSNAME	"/../../../../usr/local/v7run"
27*6809Srrh #endif
28*6809Srrh #include "unix7sys.h"
29*6809Srrh #ifdef TRACE
30*6809Srrh #include "unix7sysn.h"
31*6809Srrh #endif
32*6809Srrh #endif
33*6809Srrh #include "defs.h"
34*6809Srrh #define	CARRY	1
35*6809Srrh #define	MAXSARGS	25
36*6809Srrh #ifdef V6UNIX
37*6809Srrh #define	ARGVLEN	512
38*6809Srrh #define	ENVLEN	0
39*6809Srrh #endif
40*6809Srrh #ifdef V7UNIX
41*6809Srrh #define	ARGVLEN	5120
42*6809Srrh #define	ENVLEN	1000
43*6809Srrh #endif
44*6809Srrh char	argvs[ARGVLEN+ENVLEN];
45*6809Srrh int	args[MAXSARGS];
46*6809Srrh /* 32v type stat structure */
47*6809Srrh extern struct	stat	stat32v;
48*6809Srrh /* place for times data so we can reverse the longs */
49*6809Srrh struct timebuf {
50*6809Srrh 	long	t1;
51*6809Srrh 	long	t2;
52*6809Srrh 	long	t3;
53*6809Srrh 	long	t4;
54*6809Srrh } timebuf;
55*6809Srrh /* place for pipe file descriptors */
56*6809Srrh int	pipes[2];
57*6809Srrh /* wait status */
58*6809Srrh int	wstatus;
59*6809Srrh #ifdef	V6UNIX
60*6809Srrh /* version 6 style stat structure */
61*6809Srrh struct v6nod {
62*6809Srrh 	dev_t	majmin;
63*6809Srrh 	ino_t	inumber;
64*6809Srrh 	unsigned short	flags;
65*6809Srrh 	unsigned char	nlinks;
66*6809Srrh 	unsigned char	uid;
67*6809Srrh 	unsigned char	gid;
68*6809Srrh 	unsigned char	size0;
69*6809Srrh 	unsigned short	size1;
70*6809Srrh 	unsigned short	addr[8];
71*6809Srrh 	long	actime;
72*6809Srrh 	long	modtime;
73*6809Srrh } *v6stat;
74*6809Srrh #endif
75*6809Srrh /* do the trap stuff for the trap with code */
76*6809Srrh dotrap(code) int code; {
77*6809Srrh 	register unsigned short *argp, *savp, *savep;
78*6809Srrh 	register int i, j, indirflg;
79*6809Srrh 	register char *avp, *oavp;
80*6809Srrh 	extern sigcatch();
81*6809Srrh 	extern errno;
82*6809Srrh 	/* clear out condition codes of psl */
83*6809Srrh 	psl &= ~017;
84*6809Srrh 	/* special case of indirect sys call */
85*6809Srrh 	if(code == 0) {
86*6809Srrh 		/* remember this was indirect */
87*6809Srrh 		indirflg = 1;
88*6809Srrh 		/* point to args */
89*6809Srrh 		argp = (unsigned short *)*(pc++);
90*6809Srrh 		/* code for indirect sys call */
91*6809Srrh 		code = *argp++;
92*6809Srrh 		/* is it legit */
93*6809Srrh 		if(code>>8 != TRAPS) {
94*6809Srrh 			fprintf(stderr,"Bad indirect sys call at 0x%x\n",pc-2);
95*6809Srrh 			pc++;
96*6809Srrh 			/* set carry flag */
97*6809Srrh 			psl |= CARRY;
98*6809Srrh 			regs[0] = -1;
99*6809Srrh 			return(-1);
100*6809Srrh 		}
101*6809Srrh 		code &= 0377;
102*6809Srrh 	}
103*6809Srrh 	else {
104*6809Srrh 		/* remember this was not indirect */
105*6809Srrh 		indirflg = 0;
106*6809Srrh 		/* point to args */
107*6809Srrh 		argp = pc;
108*6809Srrh 	}
109*6809Srrh 	/* check if code too high or bad sys code */
110*6809Srrh 	if(code >= NSYSTRAPS || sysargs[code][0] == ILLSYS) {
111*6809Srrh 		fprintf(stderr,"Unimplimented trap %d at 0x%x\n",code,argp);
112*6809Srrh 		/* set carry bit */
113*6809Srrh 		psl |= CARRY;
114*6809Srrh 		regs[0] = -1;
115*6809Srrh 		return(-1);
116*6809Srrh 	}
117*6809Srrh 	/* copy args to known locations */
118*6809Srrh 	i=0;
119*6809Srrh 	for(j=0; j<sysargs[code][0]; j++) args[i++] = regs[j];
120*6809Srrh 	for(j=0; j<(sysargs[code][1]); j++) args[i++] = *argp++;
121*6809Srrh #ifdef TRACE
122*6809Srrh 	fprintf(stderr,"pid %d ",getpid());
123*6809Srrh 	if(indirflg) fprintf(stderr,"indirect ");
124*6809Srrh 	fprintf(stderr,"%s (%d) from 0%o with %d args",sysnames[code],code,pc-1,i);
125*6809Srrh 	for(j=0; j<i; j++)
126*6809Srrh 		fprintf(stderr," 0%o",args[j]);
127*6809Srrh 	if(code==OPEN||code==STAT||code==CREAT||code==EXEC||code==UNLNK||code==LINK||code==CHDIR||code==MKNOD)
128*6809Srrh 		fprintf(stderr," (%s)",args[0]);
129*6809Srrh #ifdef V7UNIX
130*6809Srrh 	if(code==EXECE)
131*6809Srrh 		fprintf(stderr," (%s)",args[0]);
132*6809Srrh #endif
133*6809Srrh 	if(code==LINK)
134*6809Srrh 		fprintf(stderr," (%s)",args[1]);
135*6809Srrh #endif
136*6809Srrh 	/* go do whatever sys call it is */
137*6809Srrh 	switch(code) {
138*6809Srrh 	case	FORK:
139*6809Srrh 		/* indirect forks return pids on both sides - must do here */
140*6809Srrh 		/* this is possibly a bug in 32V */
141*6809Srrh 		i = fork();
142*6809Srrh 		break;
143*6809Srrh 	case	WAIT:
144*6809Srrh 		i = wait(&wstatus);
145*6809Srrh 		args[0] = i;
146*6809Srrh 		args[1] = wstatus;
147*6809Srrh 		break;
148*6809Srrh 	case	EXEC:
149*6809Srrh #ifdef V7UNIX
150*6809Srrh 	case	EXECE:
151*6809Srrh #endif
152*6809Srrh 		/*
153*6809Srrh 		 *  have to do a lot of junk here to fix up an argv
154*6809Srrh 		 *  for execute since (1) the pdp-11 argv consists of 16
155*6809Srrh 		 *  bit pointers and (2) the argv itself is in the
156*6809Srrh 		 *  pdp-11 program space where it would get clobbered
157*6809Srrh 		 *  when a new program is read in and before its
158*6809Srrh 		 *  argv is set up.
159*6809Srrh 		 */
160*6809Srrh 		avp = &argvs[0];
161*6809Srrh 		savp = (unsigned short *)args[1];
162*6809Srrh #ifdef	V6UNIX
163*6809Srrh 		for(i=1; args[i] = *savp++; i++)
164*6809Srrh 			if(args[i] == 0177777) break;
165*6809Srrh #ifdef	TRACE
166*6809Srrh 			else fprintf(stderr,"argv[%d]%s ",i-1,args[i]);
167*6809Srrh #endif
168*6809Srrh #endif
169*6809Srrh #ifdef	V7UNIX
170*6809Srrh 		savep = (unsigned short *)args[2];
171*6809Srrh 		for(i=1; args[i] = *savp++; i++)
172*6809Srrh #ifdef	TRACE
173*6809Srrh 			fprintf(stderr,"argv[%d]%s ",i-1,args[i]);
174*6809Srrh #else
175*6809Srrh 			;
176*6809Srrh #endif
177*6809Srrh #endif
178*6809Srrh 		if(stat(args[0], &stat32v)) {
179*6809Srrh 			/* return error here if file does not exist */
180*6809Srrh #ifdef	TRACE
181*6809Srrh 			fprintf(stderr," does not exist\n");
182*6809Srrh #endif
183*6809Srrh 			i = -1;
184*6809Srrh 			break;
185*6809Srrh 		}
186*6809Srrh 		/* must have execute permission */
187*6809Srrh 		if(stat32v.st_mode & (S_IEXEC>>6)) goto experm;
188*6809Srrh 		if(stat32v.st_mode & (S_IEXEC>>3)) {
189*6809Srrh 			if(stat32v.st_gid == getegid()) goto experm;
190*6809Srrh 			if(geteuid() == 0) goto experm;
191*6809Srrh 		}
192*6809Srrh 		if(stat32v.st_mode & S_IEXEC) {
193*6809Srrh 			if(stat32v.st_uid == geteuid()) goto experm;
194*6809Srrh 			if(geteuid() == 0) goto experm;
195*6809Srrh 		}
196*6809Srrh 		/* return failure if no exec permision allowed */
197*6809Srrh 		i = -1;
198*6809Srrh experm:
199*6809Srrh 		/* can't exec a directory */
200*6809Srrh 		if(stat32v.st_mode & S_IFDIR)
201*6809Srrh 			i = -1;
202*6809Srrh 		if(i == -1) break;
203*6809Srrh 		args[i] = 0;
204*6809Srrh 		for(j=0; j<i; j++) {
205*6809Srrh 			oavp = (char *)args[j];
206*6809Srrh 			args[j] = (int)avp;
207*6809Srrh 			while(*avp++ = *oavp++) ;
208*6809Srrh 		}
209*6809Srrh #ifdef V7UNIX
210*6809Srrh 		if(code == EXECE) {
211*6809Srrh 			for(j = ++i; args[j] = *savep++; j++) ;
212*6809Srrh 			for( ; j>i; j--) {
213*6809Srrh 				oavp = (char *)args[j];
214*6809Srrh 				args[j] = (int)avp;
215*6809Srrh 				while(*avp++ = *oavp++) ;
216*6809Srrh 			}
217*6809Srrh 		}
218*6809Srrh #endif
219*6809Srrh 		/* SETUID and SETGID files must be started with a fresh RTS */
220*6809Srrh 		if(stat32v.st_mode & S_ISGID || stat32v.st_mode & S_ISUID) {
221*6809Srrh 			/* should add a check here for good magic # in header */
222*6809Srrh 			args[1] = args[0];
223*6809Srrh 			args[0] = (int)RTSNAME;
224*6809Srrh #ifdef TRACE
225*6809Srrh 			fprintf(stderr," SETUID-GID");
226*6809Srrh #endif
227*6809Srrh 			if(args[i])
228*6809Srrh 				i = execve(args[0], &args[0], &args[i]);
229*6809Srrh 			else
230*6809Srrh 				i = execv(args[0], &args[0]);
231*6809Srrh 			fprintf(stderr,"can't exec %s\n",RTSNAME);
232*6809Srrh 			break;
233*6809Srrh 		}
234*6809Srrh 		i = execute(args[0], &args[1], &args[i]);
235*6809Srrh 		/* shouldn't get here if exec works */
236*6809Srrh 		break;
237*6809Srrh 	case	SEEK:
238*6809Srrh #ifdef	V6UNIX
239*6809Srrh 		/* fix up negative offsets */
240*6809Srrh 		if(args[2] != 0 && args[2] != 3)
241*6809Srrh 			if(args[1] >= 32768) args[1] -= 65536;
242*6809Srrh 		if(args[2] <= 2)
243*6809Srrh 			i = lseek(args[0], args[1], args[2]);
244*6809Srrh 		else
245*6809Srrh 			i = lseek(args[0], args[1]*512, args[2]-3);
246*6809Srrh 		if(i != -1) i = 0;
247*6809Srrh #endif
248*6809Srrh #ifdef	V7UNIX
249*6809Srrh 		i = lseek(args[0], (args[1]<<16)|(args[2]&0177777), args[3]);
250*6809Srrh #endif
251*6809Srrh 		break;
252*6809Srrh #ifdef	V6UNIX
253*6809Srrh 	case	MKNOD:
254*6809Srrh 		/* version 6 uses allocated bit which means regular file here */
255*6809Srrh 		if(args[1] & S_IFBLK)
256*6809Srrh 			args[1] &= ~S_IFREG;
257*6809Srrh 		i = mknod(args[0], args[1], args[2]);
258*6809Srrh 		break;
259*6809Srrh #endif
260*6809Srrh 	case	PIPE:
261*6809Srrh 		i = pipe(pipes);
262*6809Srrh 		args[0] = pipes[0];
263*6809Srrh 		args[1] = pipes[1];
264*6809Srrh 		break;
265*6809Srrh #ifdef	V6UNIX
266*6809Srrh 	case	TELL:
267*6809Srrh 		i = lseek(args[0], 0L, 1);
268*6809Srrh 		break;
269*6809Srrh #endif
270*6809Srrh 	case	STAT:
271*6809Srrh 	case	FSTAT:
272*6809Srrh 		/* do the syscall to a local stat buffer */
273*6809Srrh 		i = syscall(code, args[0], &stat32v);
274*6809Srrh 		/* reverse the longs */
275*6809Srrh 		stat32v.st_size = longrev(stat32v.st_size);
276*6809Srrh 		stat32v.st_atime = longrev(stat32v.st_atime);
277*6809Srrh 		stat32v.st_mtime = longrev(stat32v.st_mtime);
278*6809Srrh 		stat32v.st_ctime = longrev(stat32v.st_ctime);
279*6809Srrh #ifdef V7UNIX
280*6809Srrh 		/* copy out otherwise unchanged stat buffer */
281*6809Srrh 		/* in two pieces with st_size as the breaking point */
282*6809Srrh 		/* note that st_rdev is a short but due to alingnmemt */
283*6809Srrh 		/* problems the rest of the structure is out of sync */
284*6809Srrh 		j = (int)((char *)(&stat32v.st_size)-(char *)(&stat32v.st_dev));
285*6809Srrh 		bcopy(&stat32v, args[1], j);
286*6809Srrh 		bcopy(&stat32v.st_size, args[1]+j-2, sizeof(struct stat)-j);
287*6809Srrh #endif
288*6809Srrh #ifdef	V6UNIX
289*6809Srrh 		/* point to user area as v6stat structure */
290*6809Srrh 		v6stat = (struct v6nod *)args[1];
291*6809Srrh 		/* copy out piece by piece */
292*6809Srrh 		v6stat->majmin = stat32v.st_dev;
293*6809Srrh 		v6stat->inumber = stat32v.st_ino;
294*6809Srrh 		v6stat->flags = stat32v.st_mode;
295*6809Srrh 		v6stat->nlinks = (unsigned char)stat32v.st_nlink;
296*6809Srrh 		v6stat->uid = (unsigned char)stat32v.st_uid;
297*6809Srrh 		v6stat->gid = (unsigned char)stat32v.st_gid;
298*6809Srrh 		/* note size already reversed */
299*6809Srrh 		v6stat->size0 = (unsigned char)(stat32v.st_size & 0377);
300*6809Srrh 		v6stat->size1 = (unsigned short)(stat32v.st_size>>16);
301*6809Srrh 		v6stat->actime = stat32v.st_atime;
302*6809Srrh 		v6stat->modtime = stat32v.st_mtime;
303*6809Srrh 		/* patch up flags */
304*6809Srrh 		/* for now just set 100000 bit if not a plain file */
305*6809Srrh 		if(v6stat->flags & 060000)
306*6809Srrh 			v6stat->flags |= 0100000;
307*6809Srrh #endif
308*6809Srrh 		break;
309*6809Srrh 	case	TIMES:
310*6809Srrh 		i = times(&timebuf);
311*6809Srrh 		timebuf.t2 = longrev(timebuf.t2) + timebuf.t1;
312*6809Srrh 		timebuf.t3 = longrev(timebuf.t3);
313*6809Srrh 		timebuf.t4 = longrev(timebuf.t4);
314*6809Srrh 		bcopy(&timebuf.t2,args[0],sizeof(struct timebuf)-sizeof(long));
315*6809Srrh 		break;
316*6809Srrh #ifdef	V6UNIX
317*6809Srrh 	case	SLEEP:
318*6809Srrh 		/* do a sleep function - what about pwb which has alarm? */
319*6809Srrh 		sleep(args[0]);
320*6809Srrh 		break;
321*6809Srrh #endif
322*6809Srrh 	case	GETUID:
323*6809Srrh 		args[0] = getuid();
324*6809Srrh 		args[1] = geteuid();
325*6809Srrh #ifdef V6UNIX
326*6809Srrh 		i = args[1]<<8 | args[0];
327*6809Srrh #endif
328*6809Srrh 		break;
329*6809Srrh 	case	GETGID:
330*6809Srrh 		args[0] = getgid();
331*6809Srrh 		args[1] = getegid();
332*6809Srrh #ifdef V6UNIX
333*6809Srrh 		i = args[1]<<8 | args[0];
334*6809Srrh #endif
335*6809Srrh 		break;
336*6809Srrh #ifdef V6UNIX
337*6809Srrh 	case	SETUID:
338*6809Srrh 	case	SETGID:
339*6809Srrh 		/* uids and gids are 8 bits in version 6 */
340*6809Srrh 		i = syscall(code,args[0]&0377);
341*6809Srrh 		break;
342*6809Srrh #endif
343*6809Srrh 	case	SIG:
344*6809Srrh 		/* if it is a good signal code */
345*6809Srrh 		if(args[0] <= NSIG) {
346*6809Srrh 			/* get the current signal value */
347*6809Srrh 			i = sigvals[args[0]];
348*6809Srrh 			/* reset the signal to the new value */
349*6809Srrh 			sigvals[args[0]] = args[1];
350*6809Srrh 			/* actually do signal except don't reset SIGILL */
351*6809Srrh 			if(args[0] != SIGILL) {
352*6809Srrh 				if(args[1] == (int)SIG_DFL || args[1] & (int)SIG_IGN) {
353*6809Srrh 					if((int)signal(args[0],args[1]) == -1)
354*6809Srrh 						i = -1;
355*6809Srrh 				} else {
356*6809Srrh 					if((int)signal(args[0], sigcatch) == -1)
357*6809Srrh 						i = -1;
358*6809Srrh 				}
359*6809Srrh 			}
360*6809Srrh 		}
361*6809Srrh 		else i = -1;
362*6809Srrh 		break;
363*6809Srrh 	case	BRK:
364*6809Srrh 		/* brk is successful unless we run over the stack */
365*6809Srrh 		i = 0;
366*6809Srrh 		if(args[0] >= regs[6]) i = -1;
367*6809Srrh 		break;
368*6809Srrh #ifdef	V6UNIX
369*6809Srrh 	case	PWBSYS:
370*6809Srrh 		/* ignore pwbsys for now */
371*6809Srrh 		switch(args[2]) {
372*6809Srrh 		case	UNAME:
373*6809Srrh #ifdef	TRACE
374*6809Srrh 			fprintf(stderr,"UNAME with %d %d\n",args[0],args[1]);
375*6809Srrh #endif
376*6809Srrh 			strcpy(args[0],"pwbname");
377*6809Srrh 			i = 0;
378*6809Srrh 			break;
379*6809Srrh 		case	UDATA:
380*6809Srrh #ifdef	TRACE
381*6809Srrh 			fprintf(stderr,"UDATA with %d %d\n",args[0],args[1]);
382*6809Srrh #endif
383*6809Srrh 			i = 0;
384*6809Srrh 			break;
385*6809Srrh 		case	USTAT:
386*6809Srrh fprintf(stderr,"USTAT with %d %d\n",args[0],args[1]);
387*6809Srrh 			i = 0;
388*6809Srrh 			break;
389*6809Srrh 		case	UTIME:
390*6809Srrh fprintf(stderr,"UTIME with %d %d\n",args[0],args[1]);
391*6809Srrh 			i = 0;
392*6809Srrh 			break;
393*6809Srrh 		default:
394*6809Srrh fprintf(stderr,"bad PWBSYS %d\n",args[3]);
395*6809Srrh 			i = -1;
396*6809Srrh 			break;
397*6809Srrh 		}
398*6809Srrh 		break;
399*6809Srrh #endif
400*6809Srrh 	default:
401*6809Srrh 		/*
402*6809Srrh 		 *	Many sys calls are easily done here since most
403*6809Srrh 		 *	system call codes are the same on version 6 and 7 UNIX
404*6809Srrh 		 *	as they are here.
405*6809Srrh 		 */
406*6809Srrh 		i = syscall(code,args[0],args[1],args[2],args[3],args[4]);
407*6809Srrh #ifdef V6UNIX
408*6809Srrh 		/* allow read write access to created files for(IDIS v6 mod) */
409*6809Srrh 		if(code==CREAT) {
410*6809Srrh 			/* get actual file mode after create */
411*6809Srrh 			fstat(i, &stat32v);
412*6809Srrh 			close(i);
413*6809Srrh 			/* ensure read/write access to owner */
414*6809Srrh 			chmod(args[0], 0644);
415*6809Srrh 			i = open(args[0], 2);
416*6809Srrh 			/* change mode back the way it was */
417*6809Srrh 			chmod(args[0], stat32v.st_mode);
418*6809Srrh 		}
419*6809Srrh #endif
420*6809Srrh 		break;
421*6809Srrh 	}
422*6809Srrh #ifdef TRACE
423*6809Srrh 	fprintf(stderr," sys val -> 0%o\n",i);
424*6809Srrh #endif
425*6809Srrh 	/* set carry bit if sys error */
426*6809Srrh 	if(i == -1)
427*6809Srrh 		psl |= CARRY;
428*6809Srrh 	/* if not an indirect sys call, adjust the pc */
429*6809Srrh 	if(indirflg == 0)
430*6809Srrh 		pc = argp;
431*6809Srrh 	/* do alternate return on one side of fork */
432*6809Srrh 	if(code == FORK && i != 0)
433*6809Srrh 		pc++;
434*6809Srrh 	/* do the various return value formats */
435*6809Srrh 	switch(sysargs[code][2]) {
436*6809Srrh 	case	NORMRET:
437*6809Srrh 		/* normal case only one return value in r0 */
438*6809Srrh 		regs[0] = i;
439*6809Srrh 		break;
440*6809Srrh 	case	LONGRET:
441*6809Srrh 		/* return a long in r0 - r1 as in time */
442*6809Srrh 		regs[1] = i;
443*6809Srrh 		regs[0] = i >> 16;
444*6809Srrh 		break;
445*6809Srrh 	case	TWORET:
446*6809Srrh 		/* return two ints in r0 - r1 as in pipe */
447*6809Srrh 		if(i == -1)
448*6809Srrh 			regs[0] = i;
449*6809Srrh 		else {
450*6809Srrh 			regs[1] = args[1];
451*6809Srrh 			regs[0] = args[0];
452*6809Srrh 		}
453*6809Srrh 		break;
454*6809Srrh 	}
455*6809Srrh 	if(i== -1)
456*6809Srrh 		regs[0] = errno;
457*6809Srrh }
458*6809Srrh long longrev(l) long l; {
459*6809Srrh 	/* function to reverse the halves of a long */
460*6809Srrh 	union {
461*6809Srrh 		long	lng;
462*6809Srrh 		short	s[2];
463*6809Srrh 	} u;
464*6809Srrh 	register short t;
465*6809Srrh 	u.lng = l;
466*6809Srrh 	t = u.s[0];
467*6809Srrh 	u.s[0] = u.s[1];
468*6809Srrh 	u.s[1] = t;
469*6809Srrh 	return(u.lng);
470*6809Srrh }
471