1 /* v1trap.c - Deal with 1st Edition trap instructions.
4 * $Date: 2008/05/19 13:26:42 $
22 #undef STREAM_BUFFERING /* It seems to work */
24 #define STREAM_BUFFERING /* but not for Linux */
28 /* Forward prototypes */
34 static int v1trap_exec P((void));
35 static int v1open_dir P((char *name));
36 static u_int32_t sectosixty P((time_t tim));
41 /* V1 keeps some of the arguments to syscalls in registers, and some
42 * after the `sys' instruction itself. The list below gives the number
43 * of words, and the number in registers.
49 static struct v1sysent v1arg[] = {
50 {0, 0}, {0, 0}, {0, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 1}, {1, 1},
51 {2, 0}, {2, 0}, {1, 0}, {2, 0}, {1, 0}, {0, 0}, {2, 0}, {2, 0},
52 {2, 0}, {1, 0}, {2, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 0}, {1, 1},
53 {1, 1}, {0, 0}, {1, 0}, {1, 0}, {2, 1}, {1, 0}, {1, 0}, {2, 1},
57 /* Seeks on files in /dev are done in 512-byte blocks, not bytes.
58 * If a fd's entry in the following table is 1, then it's a device
61 int8_t isdev[NFILE] = {
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
70 extern int32_t AC, MQ; /* in ke11a.c */
72 int status, exitval, errval; /* used in V2 wait */
78 char *fmode; /* used with fdopen only */
80 struct stat stbuf; /* used in STAT */
81 struct tr_v1stat *t1; /* used in STAT */
82 struct timeval tval[2]; /* used in SMTIME */
86 /* Work out the actual trap number, and */
87 /* shift the PC up past any arguments */
88 /* to the syscall. Calculate base of args */
91 regs[PC] += 2 * (v1arg[trapnum].nwords - v1arg[trapnum].nregs);
93 /* Move arguments into V1A so we can use them */
94 for (i = 0; i < v1arg[trapnum].nregs; i++)
95 V1A.uarg[i] = regs[i];
96 for (; i < v1arg[trapnum].nwords; i++, argbase += 2)
97 ll_word(argbase, V1A.uarg[i]);
99 TrapDebug((dbg_file, "pid %d %s: ", (int) getpid(),
100 v1trap_name[trapnum]));
104 /* XXX STILL TO DO: V1_GTTY, V1_STTY, V1_TELL */
106 /* These syscalls are ignored, and return */
107 /* with no effect on the caller */
116 /* These syscalls are not implemented, and */
117 /* always return no error to the caller */
122 /* These syscalls are not implemented, and */
123 /* always return an error to the caller */
132 if (Binary == IS_V2) {
133 exitval = regs[0] & 0xff;
134 if (regs[PC] == 16790)
135 exitval = 0; /* s2-tape /bin/as doesn't set r0 */
136 TrapDebug((dbg_file, " with exitval %d\n", exitval));
142 #define EPOCH71 31536000 /* # seconds from 1970 to 1971 */
143 #define EPOCH72 63072000 /* # seconds from 1970 to 1972 */
145 buf = xlate_filename((char *) &dspace[uarg1]);
147 buf = "."; /* Not documented anywhere */
149 buf = "."; /* Who knows? for V1 */
150 i = stat(buf, &stbuf);
151 TrapDebug((dbg_file, " on %s (stat %d) ", buf, i));
155 /* Copy access time to preserve it */
156 tval[0].tv_sec = stbuf.st_atime;
158 larg = (AC << 16) | (MQ & 0xffff); /* Get mod time in 60ths of a second */
159 TrapDebug((dbg_file, " %ld -> ", larg));
160 larg = larg / 60 + EPOCH72; /* Convert to seconds since 1970 */
161 TrapDebug((dbg_file, " 0x%lx ", larg));
162 tval[1].tv_sec = larg;
164 i = utimes(buf, tval);
165 TrapDebug((dbg_file, " and %d for utimes ", i));
169 /* Kludge: treat start of this year as the epoch. */
170 /* Find #seconds from yearstart to now, multiply */
171 /* by 60 so as to be in V1 units */
172 larg = sectosixty(time(NULL));
173 MQ = (int) larg & 0xffff;
174 AC = ((int) larg >> 16) & 0xffff;
178 /* Work out the args before we do the lseek */
190 if (ValidFD(sarg1) && isdev[sarg1])
193 #ifdef STREAM_BUFFERING
194 if (ValidFD(sarg1) && stream[sarg1]) {
195 i = fseek(stream[sarg1], larg, whence);
197 i = ftell(stream[sarg1]);
200 i = lseek(sarg1, larg, whence);
202 TrapDebug((dbg_file, " on fd %d amt %ld whence %d return %d ",
203 sarg1, larg, whence, i));
209 buf = (char *) &dspace[uarg2];
210 #ifdef STREAM_BUFFERING
211 if (ValidFD(sarg1) && stream[sarg1])
212 i = fread(buf, 1, sarg3, stream[sarg1]);
215 i = read(sarg1, buf, sarg3);
216 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
220 buf = xlate_filename((char *) &dspace[uarg1]);
221 buf2 = xlate_filename((char *) &dspace[uarg2]);
226 buf = (char *) &dspace[uarg2];
227 #ifdef STREAM_BUFFERING
228 if (ValidFD(sarg1) && stream[sarg1])
229 i = fwrite(buf, 1, sarg3, stream[sarg1]);
232 i = write(sarg1, buf, sarg3);
233 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
237 #ifdef STREAM_BUFFERING
238 if (ValidFD(sarg1) && stream[sarg1]) {
239 i = fclose(stream[sarg1]);
240 stream[sarg1] = NULL;
244 if ((i == 0) && ValidFD(sarg1))
246 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
249 buf = xlate_filename((char *) &dspace[uarg1]);
251 buf = "."; /* Not documented anywhere */
253 buf = "."; /* Who knows? for V1 */
254 buf2 = (char *) &dspace[uarg2];
255 i = stat(buf, &stbuf);
256 TrapDebug((dbg_file, " on %s return %d ", buf, i));
259 buf2 = (char *) &dspace[uarg2];
260 i = fstat(sarg1, &stbuf);
261 TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
266 t1 = (struct tr_v1stat *) buf2;
267 /* Inode numbers <41 are reserved for */
268 /* device files. Ensure we don't use them */
269 t1->inum = stbuf.st_ino & 0x7fff;
272 t1->inl = stbuf.st_nlink;
273 t1->iuid = stbuf.st_uid;
274 t1->isize = (u_int16_t) (stbuf.st_size & 0xffff);
275 t1->iflags = (u_int16_t) (V1_ST_USED | V1_ST_MODIFIED);
276 if (stbuf.st_size > 4095)
277 t1->iflags |= V1_ST_LARGE;
278 if (stbuf.st_mode & S_IFDIR)
279 t1->iflags |= V1_ST_ISDIR;
280 if (stbuf.st_mode & S_ISUID)
281 t1->iflags |= V1_ST_SETUID;
282 if (stbuf.st_mode & S_IXUSR)
283 t1->iflags |= V1_ST_EXEC;
284 if (stbuf.st_mode & S_IRUSR)
285 t1->iflags |= V1_ST_OWNREAD;
286 if (stbuf.st_mode & S_IWUSR)
287 t1->iflags |= V1_ST_OWNWRITE;
288 if (stbuf.st_mode & S_IROTH)
289 t1->iflags |= V1_ST_WRLDREAD;
290 if (stbuf.st_mode & S_IWOTH)
291 t1->iflags |= V1_ST_WRLDWRITE;
293 larg = sectosixty(stbuf.st_ctime);
294 copylong(t1->ctime, larg);
295 larg = sectosixty(stbuf.st_mtime);
296 copylong(t1->mtime, larg);
299 buf = xlate_filename((char *) &dspace[uarg1]);
303 buf = xlate_filename((char *) &dspace[uarg1]);
305 i = stat(buf, &stbuf); /* If file is a directory */
306 if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
309 TrapDebug((dbg_file, "(dir) on %s return %d ", buf, i));
325 i = open(buf, sarg2);
326 TrapDebug((dbg_file, " on %s return %d ", buf, i));
331 && !strncmp((char *) &dspace[uarg1], "/dev/", 5)) {
332 TrapDebug((dbg_file, " (device file) "));
335 #ifdef STREAM_BUFFERING
339 /* Now get its stream pointer if possible */
340 /* Can someone explain why fdopen doesn't work for O_RDWR? */
341 if (ValidFD(i) && !isatty(i) && (sarg2 != O_RDWR)) {
342 stream[i] = fdopen(i, fmode);
343 streammode[i] = fmode;
346 stream[i] = fdopen(i, fmode);
347 streammode[i] = fmode;
351 buf = xlate_filename((char *) &dspace[uarg1]);
353 if (uarg2 & V1_ST_SETUID)
355 if (uarg2 & V1_ST_EXEC)
356 mode |= S_IXUSR | S_IXGRP | S_IXOTH;
357 if (uarg2 & V1_ST_OWNREAD)
359 if (uarg2 & V1_ST_OWNWRITE)
361 if (uarg2 & V1_ST_WRLDREAD)
362 mode |= S_IRGRP | S_IROTH;
363 if (uarg2 & V1_ST_WRLDWRITE)
364 mode |= S_IWGRP | S_IWOTH;
365 i = chmod(buf, mode);
368 buf = xlate_filename((char *) &dspace[uarg1]);
370 if (uarg2 & V1_ST_SETUID)
372 if (uarg2 & V1_ST_EXEC)
373 mode |= S_IXUSR | S_IXGRP | S_IXOTH;
374 if (uarg2 & V1_ST_OWNREAD)
376 if (uarg2 & V1_ST_OWNWRITE)
378 if (uarg2 & V1_ST_WRLDREAD)
379 mode |= S_IRGRP | S_IROTH;
380 if (uarg2 & V1_ST_WRLDWRITE)
381 mode |= S_IWGRP | S_IWOTH;
382 i = mkdir(buf, mode);
385 buf = xlate_filename((char *) &dspace[uarg1]);
386 uarg2 &= 0x3fff; /* Why are uids > 16384? */
387 i = chown(buf, uarg2, 0);
388 TrapDebug((dbg_file, " %d on %s return %d", uarg2, buf, i));
391 buf = xlate_filename((char *) &dspace[uarg1]);
395 buf = xlate_filename((char *) &dspace[uarg1]);
397 if (uarg2 & V1_ST_SETUID)
399 if (uarg2 & V1_ST_EXEC)
400 mode |= S_IXUSR | S_IXGRP | S_IXOTH;
401 if (uarg2 & V1_ST_OWNREAD)
403 if (uarg2 & V1_ST_OWNWRITE)
405 if (uarg2 & V1_ST_WRLDREAD)
406 mode |= S_IRGRP | S_IROTH;
407 if (uarg2 & V1_ST_WRLDWRITE)
408 mode |= S_IWGRP | S_IWOTH;
409 i = creat(buf, mode);
410 TrapDebug((dbg_file, " on %s return %d ", buf, i));
411 #ifdef STREAM_BUFFERING
413 stream[i] = fdopen(i, "w");
426 /* 2nd Edition wait is different */
427 regs[0] = i; /* Save pid found in r0 */
432 exitval = WEXITSTATUS(status);
433 TrapDebug((dbg_file, "exitval %d ", exitval));
435 if (WIFSIGNALED(status)) {
436 switch (WTERMSIG(status)) {
462 if (WCOREDUMP(status))
465 TrapDebug((dbg_file, "errval %d ", errval));
466 MQ = (exitval & 0xff) | (errval << 16);
467 TrapDebug((dbg_file, "v2 return pid is %d, MQ is 0x%x ", i,
474 /* Error, inform the parent */
477 /* Child gets ppid in r0 */
481 /* Parent: Skip child `bf', pid into r0 */
496 if (trapnum > V1_ILGINS) {
497 fprintf(stderr, "Apout - unknown syscall %d at PC 0%o\n",
501 "Apout - the %s syscall is not yet implemented\n",
502 v1trap_name[trapnum]);
507 /* Clear C bit if no error, or */
508 /* set C bit as there was an error */
512 TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
515 TrapDebug((dbg_file, "return %d\n", i));
524 static int v1trap_exec(void)
526 u_int16_t cptr, cptr2;
527 char *buf, *name, *origpath;
529 origpath = strdup((char *) &dspace[uarg1]);
530 name = xlate_filename(origpath);
531 TrapDebug((dbg_file, "%s Execing %s ", progname, name));
536 while (Argc < MAX_ARGS) {
537 ll_word(cptr, cptr2);
540 buf = (char *) &dspace[cptr2];
541 Argv[Argc++] = strdup(buf);
543 TrapDebug((dbg_file, "%s ", buf));
546 TrapDebug((dbg_file, "\n"));
548 if (load_a_out(name, origpath, 0) == -1) {
549 for (Argc--; Argc >= 0; Argc--)
553 run(); /* Ok, so it's recursive, I dislike setjmp */
557 /* 1st Edition reads directories as if they were ordinary files.
558 * The solution is to read the directory entries, and build a
559 * real file, which is passed back to the open call.
560 * Limitation: 32-bit inode numbers are truncated to 16-bit ones.
562 static int v1open_dir(char *name)
577 tmpname = strdup(TMP_PLATE);
578 i = mkstemp(tmpname);
580 fprintf(stderr, "Apout - open_dir couldn't open %s\n", tmpname);
586 while ((dent = readdir(d)) != NULL) {
587 v1dent.d_ino = dent->d_fileno & 0x7fff;
588 if (v1dent.d_ino < 41)
590 strncpy((char *) v1dent.d_name, dent->d_name, 8);
591 write(i, &v1dent, 10);
594 lseek(i, 0, SEEK_SET);
598 /* Given a time, work out the number of 1/60ths of seconds since
599 * the start of that time's year
601 u_int32_t sectosixty(time_t tim)
608 T->tm_sec = T->tm_min = T->tm_hour = T->tm_mon = 0;
611 epoch = timegm(T); /* Find time at start of year */
612 diff = 60 * (tim - epoch);
613 if (diff > 0x71172C00) {
614 fprintf(stderr, "Apout - V1 sectosixty too big by %d\n",