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.
5 * $Date: 2008/05/19 13:45:58 $
24 #undef STREAM_BUFFERING /* It seems to work */
26 #define STREAM_BUFFERING /* but not for Linux */
29 /* Forward prototypes */
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));
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.
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}
74 char *fmode; /* used with fdopen only */
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 */
88 /* Work out the actual trap number, and */
89 /* shift the PC up past any arguments */
90 /* to the syscall. Calculate base of args */
92 if (trapnum == S_INDIR) {
93 lli_word(regs[PC], argbase);
100 regs[PC] += 2 * (v7arg[trapnum].nwords - v7arg[trapnum].nregs);
102 /* However, V6 seek() has 1 less arg */
103 if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
104 if (trapnum == S_LSEEK)
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]);
118 TrapDebug((dbg_file, "pid %d %s: ", (int) getpid(),
119 v7trap_name[trapnum]));
122 /* These syscalls are not implemented, and */
123 /* always return EPERM to the caller */
135 /* These syscalls are ignored, and */
136 /* always return C=0 to the caller */
148 i = v7signal(uarg1, uarg2);
172 i = dup2(sarg1, sarg2); /* Check that sarg2, not r1, holds */
173 #ifdef STREAM_BUFFERING
174 if ((i != -1) && ValidFD(sarg2) && ValidFD(sarg1)
176 fmode = streammode[sarg1];
177 stream[sarg2] = fdopen(sarg2, fmode);
178 streammode[sarg2] = fmode;
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;
195 if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
196 fixv6time(&tim); /* Fix annoying bug in V5/V6 ctime() */
199 regs[1] = tim & 0xffff;
212 /* Work out the args before we do the lseek */
213 if ((Binary == IS_A68 || Binary == IS_V6) || (Binary == IS_V5)) {
237 larg = (uarg2 << 16) | uarg3;
240 #ifdef STREAM_BUFFERING
241 if (ValidFD(sarg1) && stream[sarg1]) {
242 i = fseek(stream[sarg1], larg, whence);
244 i = ftell(stream[sarg1]);
247 i = lseek(sarg1, larg, whence);
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)) {
257 regs[1] = i & 0xffff;
264 buf = (char *) &dspace[uarg2];
265 #ifdef STREAM_BUFFERING
266 if (ValidFD(sarg1) && stream[sarg1])
267 i = fread(buf, 1, uarg3, stream[sarg1]);
270 i = read(sarg1, buf, uarg3);
271 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
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) */
282 buf = xlate_filename((char *) &dspace[uarg1]);
283 i = access(buf, sarg2);
286 buf = (char *) &dspace[uarg2];
287 #ifdef STREAM_BUFFERING
288 if (ValidFD(sarg1) && stream[sarg1])
289 i = fwrite(buf, 1, uarg3, stream[sarg1]);
292 i = write(sarg1, buf, uarg3);
293 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
296 #ifdef STREAM_BUFFERING
297 if (ValidFD(sarg1) && stream[sarg1]) {
298 i = fclose(stream[sarg1]);
299 stream[sarg1] = NULL;
303 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
306 i = trap_gtty(uarg1, uarg2);
309 i = trap_stty(uarg1, uarg2);
313 case (('t' << 8) + 8): /* GTTY */
314 i = trap_gtty(uarg1, uarg3);
316 case (('t' << 8) + 9): /* STTY */
317 i = trap_stty(uarg1, uarg3);
324 buf = (char *) &dspace[uarg1];
325 tb = (struct tr_timeb *) buf;
326 i = gettimeofday(&tv, &tz);
329 copylong(tb->time, tv.tv_sec);
331 buf = (char *) &(tb->time);
332 buf2 = (char *) &(tv.tv_sec);
338 tb->millitm = tv.tv_usec / 1000;
339 tb->timezone = tz.tz_minuteswest;
340 tb->dstflag = tz.tz_dsttime;
343 buf = xlate_filename((char *) &dspace[uarg1]);
345 buf = "."; /* Not documented anywhere */
348 buf2 = (char *) &dspace[uarg2];
349 i = stat(buf, &stbuf);
350 TrapDebug((dbg_file, " on %s return %d ", buf, i));
353 buf2 = (char *) &dspace[uarg2];
354 i = fstat(sarg1, &stbuf);
355 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
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);
377 buf = (char *) &(t6->atime);
378 buf2 = (char *) &(stbuf.st_atime);
383 buf = (char *) &(t6->mtime);
384 buf2 = (char *) &(stbuf.st_mtime);
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);
404 buf = (char *) &(t->st_size);
405 buf2 = (char *) &(stbuf.st_size);
410 buf = (char *) &(t->st_atim);
411 buf2 = (char *) &(stbuf.st_atime);
416 buf = (char *) &(t->st_mtim);
417 buf2 = (char *) &(stbuf.st_mtime);
422 buf = (char *) &(t->st_ctim);
423 buf2 = (char *) &(stbuf.st_ctime);
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]);
437 buf2 = &dspace[uarg2];
438 buf3 = (char *) &(utv[0].tv_sec);
445 buf3 = (char *) &(utv[1].tv_sec);
452 i = utimes(buf, utv);
455 buf = xlate_filename((char *) &dspace[uarg1]);
459 buf = xlate_filename((char *) &dspace[uarg1]);
461 i = stat(buf, &stbuf); /* If file is a directory */
462 if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
465 TrapDebug((dbg_file, "(dir) on %s return %d ", buf, i));
481 i = open(buf, sarg2);
482 TrapDebug((dbg_file, " on %s return %d ", buf, i));
485 #ifdef STREAM_BUFFERING
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;
496 stream[i] = fdopen(i, fmode);
497 streammode[i] = fmode;
501 buf = xlate_filename((char *) &dspace[uarg1]);
503 if ((uarg2 & 077000) == 040000) {
504 /* It's a directory creation */
505 i = mkdir(buf, uarg2 & 0777);
507 i = mknod(buf, uarg2, sarg3);
510 buf = xlate_filename((char *) &dspace[uarg1]);
511 i = chmod(buf, uarg2);
514 i = kill(sarg1, sarg2);
517 buf = xlate_filename((char *) &dspace[uarg1]);
518 i = chown(buf, sarg2, sarg3);
524 #ifdef STREAM_BUFFERING
525 if (ValidFD(pfd[0])) {
526 stream[pfd[0]] = fdopen(pfd[0], "r");
527 streammode[pfd[0]] = "r";
529 if (ValidFD(pfd[1])) {
530 stream[pfd[1]] = fdopen(pfd[1], "w");
531 streammode[pfd[1]] = "w";
542 buf = xlate_filename((char *) &dspace[uarg1]);
552 buf = xlate_filename((char *) &dspace[uarg1]);
556 buf = xlate_filename((char *) &dspace[uarg1]);
557 i = creat(buf, sarg2);
558 #ifdef STREAM_BUFFERING
562 stream[i] = fdopen(i, "w");
588 /* Error, inform the parent */
591 /* Child gets ppid in r0 */
595 /* Parent: Skip child `bf', pid into r0 */
632 if (trapnum > S_CHROOT) {
634 fprintf(stderr, "Apout - unknown syscall %d at PC 0%o\n",
641 "Apout - the %s syscall is not yet implemented\n",
642 v7trap_name[trapnum]);
647 /* Set r0 to either errno or i, */
648 /* and clear/set C bit */
656 TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
666 fprintf(dbg_file, "return %d\n", i);
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
681 static int trap_exec(int want_env)
684 u_int16_t cptr, cptr2;
685 char *buf, *name, *origpath;
687 origpath = strdup((char *) &dspace[uarg1]);
688 name = xlate_filename(origpath);
689 TrapDebug((dbg_file, "%s Execing %s ", progname, name));
691 for (i = 0; i < V7_NSIG; i++)
692 signal(v7sig[i], SIG_DFL);
698 while (Argc < MAX_ARGS) {
699 ll_word(cptr, cptr2);
702 buf = (char *) &dspace[cptr2];
703 Argv[Argc++] = strdup(buf);
705 TrapDebug((dbg_file, "%s ", buf));
708 TrapDebug((dbg_file, "\n"));
712 while (Envc < MAX_ARGS) {
713 ll_word(cptr, cptr2);
716 buf = (char *) &dspace[cptr2];
717 Envp[Envc++] = strdup(buf);
723 if (load_a_out(name, origpath, want_env) == -1) {
726 if (stat(name, &statbuf) == 0) {
727 free(origpath); // note: clobbers name
728 if (Argc >= MAX_ARGS)
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)
739 for (Argc--; Argc >= 0; Argc--)
741 for (Envc--; Envc >= 0; Envc--)
746 free(origpath); // Nick... fix memory leak
750 run(); /* Ok, so it's recursive, I dislike setjmp */
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.
759 static int open_dir(char *name)
774 tmpname = strdup(TMP_PLATE);
775 i = mkstemp(tmpname);
777 fprintf(stderr, "Apout - open_dir couldn't open %s\n", tmpname);
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);
789 lseek(i, 0, SEEK_SET);
793 static int trap_gtty(u_int16_t fd, u_int16_t ucnt)
795 struct tr_sgttyb *sgtb; /* used in GTTY/STTY */
796 struct termios tios; /* used in GTTY/STTY */
799 i = tcgetattr(fd, &tios);
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];
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;
819 sgtb->sg_flags |= TR_EVENP;
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;
830 sgtb->sg_flags |= TR_RAW;
835 static int trap_stty(u_int16_t fd, u_int16_t ucnt)
837 struct tr_sgttyb *sgtb; /* used in GTTY/STTY */
838 struct termios tios; /* used in GTTY/STTY */
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;
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++)
867 if (sgtb->sg_flags & TR_CBREAK) {
868 tios.c_lflag &= (~ICANON);
869 tios.c_lflag |= ECHO;
870 for (i = 0; i < NCCS; i++)
874 i = tcsetattr(fd, TCSANOW, &tios);
881 /* Where possible, deal with signals */
882 static int v7signal(int sig, int val)
893 return ((int) signal(v7sig[sig], SIG_IGN));
895 return ((int) signal(v7sig[sig], SIG_DFL));
897 return (0); /* No handling of this as yet */
901 /* Workaround for bug in V5/V6 ctime() */
902 static void fixv6time(time_t * t)