Minimal changes to get m6502 to compile (won't work)
[Apout.git] / v7trap.c
1 /* v7trap.c - Deal with V7 trap instructions. V5 and V6 syscalls are also
2  * done here, because the syscall interface is nearly the same as V7.
3  *
4  * $Revision: 1.50 $
5  * $Date: 2008/05/19 13:45:58 $
6  */
7 #include <assert.h>
8 #include <stdbool.h>
9 #include "defines.h"
10 #include <sys/stat.h>
11 #include <sys/time.h>
12 #include <time.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <dirent.h>
17 #include <sys/wait.h>
18 #include <signal.h>
19 #include <termios.h>
20 #include <utime.h>
21 #include "v7trap.h"
22
23 #ifdef __linux__
24 #undef STREAM_BUFFERING         /* It seems to work */
25 #else
26 #define STREAM_BUFFERING        /* but not for Linux */
27 #endif
28
29 /* Forward prototypes */
30 #ifdef __STDC__
31 #define P(s) s
32 #else
33 #define P(s) ()
34 #endif
35 static int trap_exec P((int want_env));
36 static int open_dir P((char *name));
37 static int trap_gtty P((u_int16_t fd, u_int16_t ucnt));
38 static int trap_stty P((u_int16_t fd, u_int16_t ucnt));
39 static int v7signal P((int sig, int val));
40 static void fixv6time P((time_t * t));
41 #undef P
42
43
44 /* V7 keeps some of the arguments to syscalls in registers, and some
45  * after the `sys' instruction itself. The list below gives the number
46  * of words, and the number in registers.
47  */
48 struct v7sysent {
49     int nwords;
50     int nregs;
51 };
52 static struct v7sysent v7arg[] = {
53     {0, 0}, {1, 1}, {0, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 1}, {0, 0},
54     {2, 0}, {2, 0}, {1, 0}, {2, 0}, {1, 0}, {0, 0}, {3, 0}, {2, 0},
55     {3, 0}, {1, 0}, {2, 0}, {4, 1}, {0, 0}, {3, 0}, {1, 0}, {1, 1},
56     {0, 0}, {2, 2}, {4, 1}, {1, 1}, {2, 1}, {0, 0}, {2, 0}, {2, 1},
57     {2, 1}, {2, 0}, {1, 1}, {1, 0}, {0, 0}, {2, 1}, {0, 0}, {0, 0},
58     {1, 1}, {2, 2}, {0, 0}, {1, 0}, {4, 0}, {0, 0}, {1, 1}, {0, 0},
59     {2, 0}, {0, 0}, {0, 0}, {1, 0}, {3, 0}, {1, 0}, {3, 0}, {0, 0},
60     {4, 0}, {0, 0}, {0, 0}, {3, 0}, {1, 0}, {1, 0}, {0, 0}, {0, 0}
61 };
62
63 static arglist V7A;
64
65
66 void v7trap()
67 {
68     int i, pid, pfd[2];
69     int whence;
70     u_int16_t argbase;
71     int trapnum;
72     long larg;
73     char *buf, *buf2;
74     char *fmode;                /* used with fdopen only */
75     time_t tim;
76
77     struct stat stbuf;          /* used in STAT */
78     struct tr_v7stat *t;        /* used in STAT */
79     struct tr_v6stat *t6;       /* used in STAT */
80     struct tr_timeb *tb;        /* used in FTIME */
81     struct timezone tz;         /* used in FTIME */
82     struct timeval tv;          /* used in FTIME */
83     struct timeval utv[2];      /* used in UTIME */
84
85
86
87 #ifdef CPU_PDP11
88     /* Work out the actual trap number, and */
89     /* shift the PC up past any arguments */
90     /* to the syscall. Calculate base of args */
91     trapnum = ir & 077;
92     if (trapnum == S_INDIR) {
93         lli_word(regs[PC], argbase);
94         ll_word(argbase, ir);
95         trapnum = ir & 077;
96         argbase += 2;
97         regs[PC] += 2;
98     } else {
99         argbase = regs[PC];
100         regs[PC] += 2 * (v7arg[trapnum].nwords - v7arg[trapnum].nregs);
101
102         /* However, V6 seek() has 1 less arg */
103         if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
104             if (trapnum == S_LSEEK)
105                 regs[PC] -= 2;
106         }
107     }
108
109     /* Move arguments into V7A so we can use them */
110     for (i = 0; i < v7arg[trapnum].nregs; i++)
111         V7A.uarg[i] = regs[i];
112     for (; i < v7arg[trapnum].nwords; i++, argbase += 2)
113         ll_word(argbase, V7A.uarg[i]);
114 #else
115  assert(false);
116 #endif
117
118     TrapDebug((dbg_file, "pid %d %s: ", (int) getpid(),
119                v7trap_name[trapnum]));
120
121     switch (trapnum) {
122     /* These syscalls are not implemented, and */
123     /* always return EPERM to the caller */
124     case S_PHYS:
125     case S_PROF:
126     case S_PTRACE:
127     case S_ACCT:
128     case S_MOUNT:
129     case S_UMOUNT:
130     case S_TIMES:
131         i = -1;
132         errno = EPERM;
133         break;
134
135     /* These syscalls are ignored, and */
136     /* always return C=0 to the caller */
137     case S_LOCK:
138     case S_STIME:
139     case S_BREAK:
140         i = sarg1;
141         break;
142     case S_SYNC:
143         sync();
144         i = 0;
145         break;
146
147     case S_SIGNAL:
148         i = v7signal(uarg1, uarg2);
149         break;
150     case S_EXIT:
151 #ifdef CPU_PDP11
152         exit(regs[0]);
153 #else
154  assert(false);
155 #endif
156         i = -1;
157         errno = EPERM;
158         break;
159     case S_NICE:
160 #ifdef CPU_PDP11
161         i = nice(regs[0]);
162 #else
163  assert(false);
164 #endif
165         break;
166     case S_PAUSE:
167         i = pause();
168         break;
169     case S_DUP:
170         if (sarg1 > 0100) {
171             sarg1 -= 0100;
172             i = dup2(sarg1, sarg2);     /* Check that sarg2, not r1, holds */
173 #ifdef STREAM_BUFFERING
174             if ((i != -1) && ValidFD(sarg2) && ValidFD(sarg1)
175                     && stream[sarg1]) {
176                 fmode = streammode[sarg1];
177                 stream[sarg2] = fdopen(sarg2, fmode);
178                 streammode[sarg2] = fmode;
179             }
180 #endif
181         } else
182             i = dup(sarg1);
183 #ifdef STREAM_BUFFERING
184         if ((i != -1) && ValidFD(i) && ValidFD(sarg1) && stream[sarg1]) {
185             fmode = streammode[sarg1];
186             stream[i] = fdopen(i, fmode);
187             streammode[i] = fmode;
188         }
189 #endif
190         break;
191     case S_TIME:
192         tim = larg;
193         i = time(&tim);
194
195         if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
196             fixv6time(&tim);    /* Fix annoying bug in V5/V6 ctime() */
197         }
198 #ifdef CPU_PDP11
199         regs[1] = tim & 0xffff;
200 #else
201  assert(false);
202 #endif
203         i = tim >> 16;
204         break;
205     case S_ALARM:
206         i = alarm(uarg1);
207         break;
208     case S_UMASK:
209         i = umask(uarg1);
210         break;
211     case S_LSEEK:
212         /* Work out the args before we do the lseek */
213         if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
214             whence = uarg3;
215             switch (uarg3) {
216             case 0:
217                 larg = uarg2;
218                 break;
219             case 1:
220             case 2:
221                 larg = sarg2;
222                 break;
223             case 3:
224                 whence = 0;
225                 larg = 512 * uarg2;
226                 break;
227             case 4:
228                 whence = 1;
229                 larg = 512 * sarg2;
230                 break;
231             case 5:
232                 whence = 2;
233                 larg = 512 * sarg2;
234                 break;
235             }
236         } else {
237             larg = (uarg2 << 16) | uarg3;
238             whence = uarg4;
239         }
240 #ifdef STREAM_BUFFERING
241         if (ValidFD(sarg1) && stream[sarg1]) {
242             i = fseek(stream[sarg1], larg, whence);
243             if (i == 0)
244                 i = ftell(stream[sarg1]);
245         } else
246 #endif
247             i = lseek(sarg1, larg, whence);
248
249         TrapDebug((dbg_file, " on fd %d amt %ld whence %d return %d ",
250                    sarg1, larg, whence, i));
251         if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
252             if (i != -1)
253                 i = 0;
254             break;
255         }
256 #ifdef CPU_PDP11
257         regs[1] = i & 0xffff;
258 #else
259  assert(false);
260 #endif
261         i = i >> 16;
262         break;
263     case S_READ:
264         buf = (char *) &dspace[uarg2];
265 #ifdef STREAM_BUFFERING
266         if (ValidFD(sarg1) && stream[sarg1])
267             i = fread(buf, 1, uarg3, stream[sarg1]);
268         else
269 #endif
270             i = read(sarg1, buf, uarg3);
271         TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
272         break;
273     case S_LINK:
274         buf = xlate_filename((char *) &dspace[uarg1]);
275         buf2 = xlate_filename((char *) &dspace[uarg2]);
276         if (!strcmp(buf, buf2))
277             i = 0;              /* Happens on mkdir(1) */
278         else
279             i = link(buf, buf2);
280         break;
281     case S_ACCESS:
282         buf = xlate_filename((char *) &dspace[uarg1]);
283         i = access(buf, sarg2);
284         break;
285     case S_WRITE:
286         buf = (char *) &dspace[uarg2];
287 #ifdef STREAM_BUFFERING
288         if (ValidFD(sarg1) && stream[sarg1])
289             i = fwrite(buf, 1, uarg3, stream[sarg1]);
290         else
291 #endif
292             i = write(sarg1, buf, uarg3);
293         TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
294         break;
295     case S_CLOSE:
296 #ifdef STREAM_BUFFERING
297         if (ValidFD(sarg1) && stream[sarg1]) {
298             i = fclose(stream[sarg1]);
299             stream[sarg1] = NULL;
300         } else
301 #endif
302             i = close(sarg1);
303         TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
304         break;
305     case S_GTTY:
306         i = trap_gtty(uarg1, uarg2);
307         break;
308     case S_STTY:
309         i = trap_stty(uarg1, uarg2);
310         break;
311     case S_IOCTL:
312         switch (uarg2) {
313         case (('t' << 8) + 8):  /* GTTY */
314             i = trap_gtty(uarg1, uarg3);
315             break;
316         case (('t' << 8) + 9):  /* STTY */
317             i = trap_stty(uarg1, uarg3);
318             break;
319         default:
320             i = 0;
321         }
322         break;
323     case S_FTIME:
324         buf = (char *) &dspace[uarg1];
325         tb = (struct tr_timeb *) buf;
326         i = gettimeofday(&tv, &tz);
327         if (i == -1)
328             break;
329         copylong(tb->time, tv.tv_sec);
330 #if 0
331         buf = (char *) &(tb->time);
332         buf2 = (char *) &(tv.tv_sec);
333         buf[0] = buf2[2];
334         buf[1] = buf2[3];
335         buf[2] = buf2[0];
336         buf[3] = buf2[1];
337 #endif
338         tb->millitm = tv.tv_usec / 1000;
339         tb->timezone = tz.tz_minuteswest;
340         tb->dstflag = tz.tz_dsttime;
341         break;
342     case S_STAT:
343         buf = xlate_filename((char *) &dspace[uarg1]);
344         if (buf[0] == '\0')
345             buf = ".";  /* Not documented anywhere */
346         if (uarg1 == 0)
347             buf = ".";
348         buf2 = (char *) &dspace[uarg2];
349         i = stat(buf, &stbuf);
350         TrapDebug((dbg_file, " on %s return %d ", buf, i));
351         goto dostat;
352     case S_FSTAT:
353         buf2 = (char *) &dspace[uarg2];
354         i = fstat(sarg1, &stbuf);
355         TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
356
357 dostat:
358         if (i == -1)
359             break;
360         /* V6 and V7 have different stats */
361         if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
362             t6 = (struct tr_v6stat *) buf2;
363             t6->idev = stbuf.st_dev;
364             t6->inum = stbuf.st_ino;
365             t6->iflags = stbuf.st_mode;
366             t6->inl = stbuf.st_nlink;
367             t6->iuid = stbuf.st_uid;
368             t6->igid = stbuf.st_gid;
369             t6->isize = (u_int16_t) (stbuf.st_size & 0xffff);
370             t6->isize0 = (u_int8_t) ((stbuf.st_size >> 16) & 0xff);
371             /* Fix annoying bug in V5/V6 ctime() */
372             fixv6time(&(stbuf.st_atime));
373             fixv6time(&(stbuf.st_mtime));
374             copylong(t6->atime, stbuf.st_atime);
375             copylong(t6->mtime, stbuf.st_mtime);
376 #if 0
377             buf = (char *) &(t6->atime);
378             buf2 = (char *) &(stbuf.st_atime);
379             buf[0] = buf2[2];
380             buf[1] = buf2[3];
381             buf[2] = buf2[0];
382             buf[3] = buf2[1];
383             buf = (char *) &(t6->mtime);
384             buf2 = (char *) &(stbuf.st_mtime);
385             buf[0] = buf2[2];
386             buf[1] = buf2[3];
387             buf[2] = buf2[0];
388             buf[3] = buf2[1];
389 #endif
390         } else {
391             t = (struct tr_v7stat *) buf2;
392             t->st_dev = stbuf.st_dev;
393             t->st_ino = stbuf.st_ino;
394             t->st_mode = stbuf.st_mode;
395             t->st_nlink = stbuf.st_nlink;
396             t->st_uid = stbuf.st_uid;
397             t->st_gid = stbuf.st_gid;
398             t->st_rdev = stbuf.st_rdev;
399             copylong(t->st_size, stbuf.st_size);
400             copylong(t->st_atim, stbuf.st_atime);
401             copylong(t->st_mtim, stbuf.st_mtime);
402             copylong(t->st_ctim, stbuf.st_ctime);
403 #if 0
404             buf = (char *) &(t->st_size);
405             buf2 = (char *) &(stbuf.st_size);
406             buf[0] = buf2[2];
407             buf[1] = buf2[3];
408             buf[2] = buf2[0];
409             buf[3] = buf2[1];
410             buf = (char *) &(t->st_atim);
411             buf2 = (char *) &(stbuf.st_atime);
412             buf[0] = buf2[2];
413             buf[1] = buf2[3];
414             buf[2] = buf2[0];
415             buf[3] = buf2[1];
416             buf = (char *) &(t->st_mtim);
417             buf2 = (char *) &(stbuf.st_mtime);
418             buf[0] = buf2[2];
419             buf[1] = buf2[3];
420             buf[2] = buf2[0];
421             buf[3] = buf2[1];
422             buf = (char *) &(t->st_ctim);
423             buf2 = (char *) &(stbuf.st_ctime);
424             buf[0] = buf2[2];
425             buf[1] = buf2[3];
426             buf[2] = buf2[0];
427             buf[3] = buf2[1];
428 #endif
429         }
430         break;
431     case S_UTIME:
432         utv[0].tv_usec = utv[1].tv_usec = 0;
433         copylong(dspace[uarg2], utv[0].tv_sec);
434         copylong(dspace[uarg2 + 4], utv[1].tv_sec);
435         buf = xlate_filename((char *) &dspace[uarg1]);
436 #if 0
437         buf2 = &dspace[uarg2];
438         buf3 = (char *) &(utv[0].tv_sec);
439         buf3[0] = buf2[2];
440         buf3[1] = buf2[3];
441         buf3[2] = buf2[0];
442         buf3[3] = buf2[1];
443
444         buf2 += 4;
445         buf3 = (char *) &(utv[1].tv_sec);
446         buf3[0] = buf2[2];
447         buf3[1] = buf2[3];
448         buf3[2] = buf2[0];
449         buf3[3] = buf2[1];
450 #endif
451
452         i = utimes(buf, utv);
453         break;
454     case S_UNLINK:
455         buf = xlate_filename((char *) &dspace[uarg1]);
456         i = unlink(buf);
457         break;
458     case S_OPEN:
459         buf = xlate_filename((char *) &dspace[uarg1]);
460
461         i = stat(buf, &stbuf);  /* If file is a directory */
462         if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
463             i = open_dir(buf);
464             fmode = "w+";
465             TrapDebug((dbg_file, "(dir) on %s return %d ", buf, i));
466         } else {
467             switch (sarg2) {
468             case 0:
469                 sarg2 = O_RDONLY;
470                 fmode = "r";
471                 break;
472             case 1:
473                 sarg2 = O_WRONLY;
474                 fmode = "w";
475                 break;
476             default:
477                 sarg2 = O_RDWR;
478                 fmode = "w+";
479                 break;
480             }
481             i = open(buf, sarg2);
482             TrapDebug((dbg_file, " on %s return %d ", buf, i));
483         }
484
485 #ifdef STREAM_BUFFERING
486         if (i == -1)
487             break;
488 #if 0
489         /* Now get its stream pointer if possible */
490         /* Can someone explain why fdopen doesn't work for O_RDWR? */
491         if (ValidFD(i) && !isatty(i) && (sarg2 != O_RDWR)) {
492             stream[i] = fdopen(i, fmode);
493             streammode[i] = fmode;
494         }
495 #endif
496         stream[i] = fdopen(i, fmode);
497         streammode[i] = fmode;
498 #endif
499         break;
500     case S_MKNOD:
501         buf = xlate_filename((char *) &dspace[uarg1]);
502
503         if ((uarg2 & 077000) == 040000) {
504             /* It's a directory creation */
505             i = mkdir(buf, uarg2 & 0777);
506         } else
507             i = mknod(buf, uarg2, sarg3);
508         break;
509     case S_CHMOD:
510         buf = xlate_filename((char *) &dspace[uarg1]);
511         i = chmod(buf, uarg2);
512         break;
513     case S_KILL:
514         i = kill(sarg1, sarg2);
515         break;
516     case S_CHOWN:
517         buf = xlate_filename((char *) &dspace[uarg1]);
518         i = chown(buf, sarg2, sarg3);
519         break;
520     case S_PIPE:
521         i = pipe(pfd);
522         if (i == -1)
523             break;
524 #ifdef STREAM_BUFFERING
525         if (ValidFD(pfd[0])) {
526             stream[pfd[0]] = fdopen(pfd[0], "r");
527             streammode[pfd[0]] = "r";
528         }
529         if (ValidFD(pfd[1])) {
530             stream[pfd[1]] = fdopen(pfd[1], "w");
531             streammode[pfd[1]] = "w";
532         }
533 #endif
534         i = pfd[0];
535 #ifdef CPU_PDP11
536         regs[1] = pfd[1];
537 #else
538  assert(false);
539 #endif
540         break;
541     case S_CHROOT:
542         buf = xlate_filename((char *) &dspace[uarg1]);
543         if (buf == NULL) {
544             i = -1;
545             errno = ENOENT;
546             break;
547         }
548         set_apout_root(buf);
549         i = 0;
550         break;
551     case S_CHDIR:
552         buf = xlate_filename((char *) &dspace[uarg1]);
553         i = chdir(buf);
554         break;
555     case S_CREAT:
556         buf = xlate_filename((char *) &dspace[uarg1]);
557         i = creat(buf, sarg2);
558 #ifdef STREAM_BUFFERING
559         if (i == -1)
560             break;
561         if (ValidFD(i)) {
562             stream[i] = fdopen(i, "w");
563             streammode[i] = "w";
564         }
565 #endif
566         break;
567     case S_EXECE:
568         i = trap_exec(1);
569         break;
570
571     case S_EXEC:
572         i = trap_exec(0);
573         break;
574     case S_WAIT:
575         i = wait(&pid);
576         if (i == -1)
577             break;
578 #ifdef CPU_PDP11
579         regs[1] = pid;
580 #else
581  assert(false);
582 #endif
583         break;
584     case S_FORK:
585         pid = getpid();
586         i = fork();
587         switch (i) {
588         /* Error, inform the parent */
589         case -1:
590             break;
591         /* Child gets ppid in r0 */
592         case 0:
593             i = pid;
594             break;
595         /* Parent: Skip child `bf', pid into r0 */
596         default:
597 #ifdef CPU_PDP11
598             regs[PC] += 2;
599 #else
600  assert(false);
601 #endif
602         }
603         break;
604     case S_GETUID:
605         i = geteuid();
606 #ifdef CPU_PDP11
607         regs[1] = i;
608 #else
609  assert(false);
610 #endif
611         i = getuid();
612         break;
613     case S_GETPID:
614         i = getpid();
615         break;
616     case S_GETGID:
617         i = getegid();
618 #ifdef CPU_PDP11
619         regs[1] = i;
620 #else
621  assert(false);
622 #endif
623         i = getgid();
624         break;
625     case S_SETUID:
626         i = setuid(sarg1);
627         break;
628     case S_SETGID:
629         i = setgid(sarg1);
630         break;
631     default:
632         if (trapnum > S_CHROOT) {
633 #ifdef CPU_PDP11
634             fprintf(stderr, "Apout - unknown syscall %d at PC 0%o\n",
635                     trapnum, regs[PC]);
636 #else
637  assert(false);
638 #endif
639         } else {
640             fprintf(stderr,
641                     "Apout - the %s syscall is not yet implemented\n",
642                     v7trap_name[trapnum]);
643         }
644         exit(1);
645     }
646
647     /* Set r0 to either errno or i, */
648     /* and clear/set C bit */
649
650     if (i == -1) {
651 #ifdef CPU_PDP11
652         SET_CC_C();
653 #else
654  assert(false);
655 #endif
656         TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
657     } else {
658 #ifdef CPU_PDP11
659         CLR_CC_C();
660         regs[0] = i;
661 #else
662  assert(false);
663 #endif
664 #ifdef DEBUG
665         if (trap_debug) {
666             fprintf(dbg_file, "return %d\n", i);
667             fflush(dbg_file);
668         }
669 #endif
670     }
671     return;
672 }
673
674
675 /* Translate V7 signal value to our value. */
676 static int v7sig[] = {
677     0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGIOT, SIGEMT,
678     SIGFPE, SIGKILL, SIGBUS, SIGSEGV, SIGSYS, SIGPIPE, SIGALRM, SIGTERM
679 };
680
681 static int trap_exec(int want_env)
682 {
683     int i;
684     u_int16_t cptr, cptr2;
685     char *buf, *name, *origpath;
686
687     origpath = strdup((char *) &dspace[uarg1]);
688     name = xlate_filename(origpath);
689     TrapDebug((dbg_file, "%s Execing %s ", progname, name));
690
691     for (i = 0; i < V7_NSIG; i++)
692         signal(v7sig[i], SIG_DFL);
693
694     cptr = uarg2;
695
696     Argc = 0;
697     Envc = 0;
698     while (Argc < MAX_ARGS) {
699         ll_word(cptr, cptr2);
700         if (cptr2 == 0)
701             break;
702         buf = (char *) &dspace[cptr2];
703         Argv[Argc++] = strdup(buf);
704         cptr += 2;
705         TrapDebug((dbg_file, "%s ", buf));
706     }
707     Argv[Argc] = NULL;
708     TrapDebug((dbg_file, "\n"));
709
710     if (want_env) {
711         cptr = uarg3;
712         while (Envc < MAX_ARGS) {
713             ll_word(cptr, cptr2);
714             if (cptr2 == 0)
715                 break;
716             buf = (char *) &dspace[cptr2];
717             Envp[Envc++] = strdup(buf);
718             cptr += 2;
719         }
720     }
721     Envp[Envc] = NULL;
722
723     if (load_a_out(name, origpath, want_env) == -1) {
724 #if 1 // Nick
725         struct stat statbuf;
726         if (stat(name, &statbuf) == 0) {
727             free(origpath); // note: clobbers name
728             if (Argc >= MAX_ARGS)
729                 Argv[--Argc] = NULL;
730             for (i = Argc++; i >= 1; --i)
731                 Argv[i + 1] = Argv[i];
732             Argv[1] = strdup((char *) &dspace[uarg1]);
733             origpath = "/bin/sh";
734             name = xlate_filename(origpath);
735             if (load_a_out(name, origpath, want_env) != -1)
736                 goto ok;
737         }
738 #endif
739         for (Argc--; Argc >= 0; Argc--)
740             free(Argv[Argc]);
741         for (Envc--; Envc >= 0; Envc--)
742             free(Envp[Envc]);
743         errno = ENOENT;
744         return (-1);
745     }
746     free(origpath); // Nick... fix memory leak
747 #if 1 // Nick
748 ok:
749 #endif
750     run();                      /* Ok, so it's recursive, I dislike setjmp */
751     return (0);
752 }
753
754 /* 7th Edition reads directories as if they were ordinary files.
755  * The solution is to read the directory entries, and build a
756  * real file, which is passed back to the open call.
757  * Limitation: 32-bit inode numbers are truncated to 16-bit ones.
758  */
759 static int open_dir(char *name)
760 {
761     DIR *d;
762     char *tmpname;
763     int i;
764     struct dirent *dent;
765
766     struct old_direct {
767         int16_t d_ino;
768         int8_t d_name[14];
769     } odent;
770
771     d = opendir(name);
772     if (d == NULL)
773         return (-1);
774     tmpname = strdup(TMP_PLATE);
775     i = mkstemp(tmpname);
776     if (i == -1) {
777         fprintf(stderr, "Apout - open_dir couldn't open %s\n", tmpname);
778         exit(1);
779     }
780     unlink(tmpname);
781     free(tmpname);
782
783     while ((dent = readdir(d)) != NULL) {
784         odent.d_ino = dent->d_fileno;
785         strncpy((char *) odent.d_name, dent->d_name, 14);
786         write(i, &odent, 16);
787     }
788     closedir(d);
789     lseek(i, 0, SEEK_SET);
790     return (i);
791 }
792
793 static int trap_gtty(u_int16_t fd, u_int16_t ucnt)
794 {
795     struct tr_sgttyb *sgtb;     /* used in GTTY/STTY */
796     struct termios tios;        /* used in GTTY/STTY */
797     int i;
798
799     i = tcgetattr(fd, &tios);
800     if (i == -1)
801         return i;
802 #ifdef CPU_PDP11
803     CLR_CC_C();
804 #else
805  assert(false);
806 #endif
807     sgtb = (struct tr_sgttyb *) &dspace[ucnt];
808     sgtb->sg_ispeed = cfgetispeed(&tios);       /* tios.c_ispeed; --gray */
809     sgtb->sg_ospeed = cfgetospeed(&tios);       /* tios.c_ospeed; --gray */
810     sgtb->sg_erase = tios.c_cc[VERASE];
811     sgtb->sg_kill = tios.c_cc[VKILL];
812     sgtb->sg_flags = 0;
813     if (tios.c_oflag & OXTABS)
814         sgtb->sg_flags |= TR_XTABS;
815     if (tios.c_cflag & PARENB) {
816         if (tios.c_cflag & PARODD)
817             sgtb->sg_flags |= TR_ODDP;
818         else
819             sgtb->sg_flags |= TR_EVENP;
820     } else
821         sgtb->sg_flags |= TR_ANYP;
822     if (tios.c_oflag & ONLCR)
823         sgtb->sg_flags |= TR_CRMOD;
824     if (tios.c_lflag & ECHO)
825         sgtb->sg_flags |= TR_ECHO;
826     if (!(tios.c_lflag & ICANON)) {
827         if (!(tios.c_lflag & ECHO))
828             sgtb->sg_flags |= TR_CBREAK;
829         else
830             sgtb->sg_flags |= TR_RAW;
831     }
832     return 0;
833 }
834
835 static int trap_stty(u_int16_t fd, u_int16_t ucnt)
836 {
837     struct tr_sgttyb *sgtb;     /* used in GTTY/STTY */
838     struct termios tios;        /* used in GTTY/STTY */
839     int i;
840
841     if (ucnt != 0) {
842         sgtb = (struct tr_sgttyb *) &dspace[ucnt];
843         cfsetispeed(&tios, sgtb->sg_ispeed);
844         cfsetospeed(&tios, sgtb->sg_ospeed);
845         tios.c_cc[VERASE] = sgtb->sg_erase;
846         tios.c_cc[VKILL] = sgtb->sg_kill;
847         if (sgtb->sg_flags & TR_XTABS)
848             tios.c_oflag |= OXTABS;
849         if (sgtb->sg_flags & TR_ODDP) {
850             tios.c_cflag |= PARENB;
851             tios.c_cflag &= ~PARODD;
852         }
853         if (sgtb->sg_flags & TR_EVENP)
854             tios.c_cflag |= PARENB | PARODD;
855         if (sgtb->sg_flags & TR_ANYP)
856             tios.c_cflag &= ~PARENB;
857         if (sgtb->sg_flags & TR_CRMOD)
858             tios.c_oflag |= ONLCR;
859         if (sgtb->sg_flags & TR_ECHO)
860             tios.c_lflag |= ECHO;
861         if (sgtb->sg_flags & TR_RAW) {
862             tios.c_lflag &= (~ICANON) & (~ECHO);
863             for (i = 0; i < NCCS; i++)
864                 tios.c_cc[i] = 0;
865             tios.c_cc[VMIN] = 1;
866         }
867         if (sgtb->sg_flags & TR_CBREAK) {
868             tios.c_lflag &= (~ICANON);
869             tios.c_lflag |= ECHO;
870             for (i = 0; i < NCCS; i++)
871                 tios.c_cc[i] = 0;
872             tios.c_cc[VMIN] = 1;
873         }
874         i = tcsetattr(fd, TCSANOW, &tios);
875         return (i);
876     } else
877         return (-1);
878 }
879
880
881 /* Where possible, deal with signals */
882 static int v7signal(int sig, int val)
883 {
884     if (sig > V7_NSIG) {
885         errno = EINVAL;
886         return (-1);
887     }
888     if (v7sig[sig] == 0)
889         return (0);
890
891     switch (val) {
892     case V7_SIG_IGN:
893         return ((int) signal(v7sig[sig], SIG_IGN));
894     case V7_SIG_DFL:
895         return ((int) signal(v7sig[sig], SIG_DFL));
896     default:
897         return (0);             /* No handling of this as yet */
898     }
899 }
900
901 /* Workaround for bug in V5/V6 ctime() */
902 static void fixv6time(time_t * t)
903 {
904     struct tm *T;
905
906     T = gmtime(t);
907     if (T->tm_year > 98)
908         T->tm_year = 98;
909     *t = timegm(T);
910 }