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