static int map_header(char **exec_hdr, const struct vnode *vp) { int r; u64_t new_pos; unsigned int cum_io; off_t pos; static char hdr[PAGE_SIZE]; /* Assume that header is not larger than a page */ pos = 0; /* Read from the start of the file */ r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING, VFS_PROC_NR, hdr, MIN(vp->v_size, PAGE_SIZE), &new_pos, &cum_io); if (r != OK) { printf("VFS: exec: map_header: req_readwrite failed\n"); return(r); } *exec_hdr = hdr; return(OK); }
/** * @brief Check whether it is aout format * @param vp[in] pointer inode for reading exec file * @return 0 on success */ static int aout_check_binfmt(struct nucleos_binprm *param, struct vnode *vp) { /* Read the header and check the magic number. The standard MINIX header * is defined in <nucleos/a.out.h>. It consists of 8 chars followed by 6 longs. * Then come 4 more longs that are not used here. * Byte 0: magic number 0x01 * Byte 1: magic number 0x03 * Byte 2: normal = 0x10 (not checked, 0 is OK), separate I/D = 0x20 * Byte 3: CPU type, Intel 16 bit = 0x04, Intel 32 bit = 0x10, * Motorola = 0x0B, Sun SPARC = 0x17 * Byte 4: Header length = 0x20 * Bytes 5-7 are not used. * * Now come the 6 longs * Bytes 8-11: size of text segments in bytes * Bytes 12-15: size of initialized data segment in bytes * Bytes 16-19: size of bss in bytes * Bytes 20-23: program entry point * Bytes 24-27: total memory allocated to program (text, data + stack) * Bytes 28-31: size of symbol table in bytes * The longs are represented in a machine dependent order, * little-endian on the 8088, big-endian on the 68000. * The header is followed directly by the text and data segments, and the * symbol table (if any). The sizes are given in the header. Only the * text and data segments are copied into memory by exec. The header is * used here only. The symbol table is for the benefit of a debugger and * is ignored here. */ off_t pos; int err; u64_t new_pos; unsigned int cum_io_incr; struct exec hdr; /* Read from the start of the file */ pos = 0; /* Issue request */ err = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING, VFS_PROC_NR, (char*)&hdr, sizeof(struct exec), &new_pos, &cum_io_incr); if (err) { app_err("Can't read the file header\n"); return -1; } /* Interpreted script? */ if (((char*)&hdr)[0] == '#' && ((char*)&hdr)[1] == '!' && vp->v_size >= 2) { return ESCRIPT; } if (vp->v_size < A_MINHDR) return -1; if (BADMAG(hdr)) return -1; #ifdef CONFIG_X86_32 if (hdr.a_cpu != A_I8086 && hdr.a_cpu != A_I80386) return -1; #endif if ((hdr.a_flags & ~(A_NSYM | A_EXEC)) != 0) return -1; memcpy(param->buf, &hdr, hdr.a_hdrlen); param->vp = vp; return BINFMT_AOUT; }
/** * @brief Read segment * @param vp inode descriptor to read from * @param off offset in file * @param proc_e process number (endpoint) * @param seg T, D, or S * @param seg_bytes how much is to be transferred? * @return 0 on success */ static int aout_read_seg(struct vnode *vp, off_t off, int proc_e, int seg, phys_bytes seg_bytes) { /* The byte count on read is usually smaller than the segment count, because * a segment is padded out to a click multiple, and the data segment is only * partially initialized. */ int err = 0; unsigned n, k; u64_t new_pos; unsigned int cum_io; /* Make sure that the file is big enough */ if (vp->v_size < off+seg_bytes) return -EIO; if (seg != D) { char *buf = 0; /* We have to use a copy loop until safecopies support segments */ k = 0; buf = malloc(1024); if (!buf) { printk("Not enough memory!\n"); return -ENOMEM; } while (k < seg_bytes) { n = seg_bytes - k; if (n > sizeof(buf)) n = sizeof(buf); #if CONFIG_DEBUG_VFS_AOUT printk("read_seg for user %d, seg %d: buf 0x%x, size %d, pos %d\n", proc_e, seg, buf, n, off+k); #endif /* Issue request */ err = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off+k), READING, VFS_PROC_NR, buf, n, &new_pos, &cum_io); if (err) { printk("VFS: read_seg: req_readwrite failed (text)\n"); goto aout_free_buf; } if (cum_io != n) { printk("read_seg segment has not been read properly by exec()\n"); err = -EIO; goto aout_free_buf; } err = sys_vircopy(VFS_PROC_NR, D, (vir_bytes)buf, proc_e, seg, k, n); if (err) { printk("VFS: read_seg: copy failed (text)\n"); goto aout_free_buf; } k += n; } aout_free_buf: free(buf); return err; } /* Issue request */ err = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING, proc_e, 0, seg_bytes, &new_pos, &cum_io); if (err) { printk("VFS: read_seg: req_readwrite failed (data)\n"); return err; } if (!err && cum_io != seg_bytes) printk("VFSread_seg segment has not been read properly by exec() \n"); return err; }
/*===========================================================================* * read_write * *===========================================================================*/ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, vir_bytes buf, size_t size, endpoint_t for_e) { register struct vnode *vp; off_t position, res_pos; unsigned int cum_io, cum_io_incr, res_cum_io; int op, r; dev_t dev; position = f->filp_pos; vp = f->filp_vno; r = OK; cum_io = 0; assert(rw_flag == READING || rw_flag == WRITING || rw_flag == PEEKING); if (size > SSIZE_MAX) return(EINVAL); op = (rw_flag == READING ? CDEV_READ : CDEV_WRITE); if (S_ISFIFO(vp->v_mode)) { /* Pipes */ if (rfp->fp_cum_io_partial != 0) { panic("VFS: read_write: fp_cum_io_partial not clear"); } if(rw_flag == PEEKING) { printf("read_write: peek on pipe makes no sense\n"); return EINVAL; } r = rw_pipe(rw_flag, for_e, f, buf, size); } else if (S_ISCHR(vp->v_mode)) { /* Character special files. */ if(rw_flag == PEEKING) { printf("read_write: peek on char device makes no sense\n"); return EINVAL; } if (vp->v_sdev == NO_DEV) panic("VFS: read_write tries to access char dev NO_DEV"); dev = vp->v_sdev; r = cdev_io(op, dev, for_e, buf, position, size, f->filp_flags); if (r >= 0) { /* This should no longer happen: all calls are asynchronous. */ printf("VFS: I/O to device %llx succeeded immediately!?\n", dev); cum_io = r; position += r; r = OK; } else if (r == SUSPEND) { /* FIXME: multiple read/write operations on a single filp * should be serialized. They currently aren't; in order to * achieve a similar effect, we optimistically advance the file * position here. This works under the following assumptions: * - character drivers that use the seek position at all, * expose a view of a statically-sized range of bytes, i.e., * they are basically byte-granular block devices; * - if short I/O or an error is returned, all subsequent calls * will return (respectively) EOF and an error; * - the application never checks its own file seek position, * or does not care that it may end up having seeked beyond * the number of bytes it has actually read; * - communication to the character driver is FIFO (this one * is actually true! whew). * Many improvements are possible here, but in the end, * anything short of queuing concurrent operations will be * suboptimal - so we settle for this hack for now. */ position += size; } } else if (S_ISBLK(vp->v_mode)) { /* Block special files. */ if (vp->v_sdev == NO_DEV) panic("VFS: read_write tries to access block dev NO_DEV"); lock_bsf(); if(rw_flag == PEEKING) { r = req_bpeek(vp->v_bfs_e, vp->v_sdev, position, size); } else { r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position, size, buf, rw_flag, &res_pos, &res_cum_io); if (r == OK) { position = res_pos; cum_io += res_cum_io; } } unlock_bsf(); } else { /* Regular files */ if (rw_flag == WRITING) { /* Check for O_APPEND flag. */ if (f->filp_flags & O_APPEND) position = vp->v_size; } /* Issue request */ if(rw_flag == PEEKING) { r = req_peek(vp->v_fs_e, vp->v_inode_nr, position, size); } else { off_t new_pos; r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position, rw_flag, for_e, buf, size, &new_pos, &cum_io_incr); if (r >= 0) { position = new_pos; cum_io += cum_io_incr; } } } /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (S_ISREG(vp->v_mode) || S_ISDIR(vp->v_mode)) { if (position > vp->v_size) { vp->v_size = position; } } } f->filp_pos = position; if (r == EPIPE && rw_flag == WRITING) { /* Process is writing, but there is no reader. Tell the kernel to * generate s SIGPIPE signal. */ if (!(f->filp_flags & O_NOSIGPIPE)) { sys_kill(rfp->fp_endpoint, SIGPIPE); } } if (r == OK) { return(cum_io); } return(r); }
/*===========================================================================* * read_seg * *===========================================================================*/ static int read_seg( struct vnode *vp, /* inode descriptor to read from */ off_t off, /* offset in file */ int proc_e, /* process number (endpoint) */ int seg, /* T, D, or S */ vir_bytes seg_addr, /* address to load segment */ phys_bytes seg_bytes /* how much is to be transferred? */ ) { /* * The byte count on read is usually smaller than the segment count, because * a segment is padded out to a click multiple, and the data segment is only * partially initialized. */ int r; unsigned n, o; u64_t new_pos; unsigned int cum_io; static char buf[128 * 1024]; assert((seg == T)||(seg == D)); /* Make sure that the file is big enough */ if (vp->v_size < off+seg_bytes) return(EIO); if (seg == T) { /* We have to use a copy loop until safecopies support segments */ o = 0; while (o < seg_bytes) { n = seg_bytes - o; if (n > sizeof(buf)) n = sizeof(buf); if ((r = req_readwrite(vp->v_fs_e,vp->v_inode_nr,cvul64(off+o), READING, VFS_PROC_NR, buf, n, &new_pos, &cum_io)) != OK) { printf("VFS: read_seg: req_readwrite failed (text)\n"); return(r); } if (cum_io != n) { printf( "VFSread_seg segment has not been read properly by exec() \n"); return(EIO); } if ((r = sys_vircopy(VFS_PROC_NR, D, (vir_bytes)buf, proc_e, seg, seg_addr + o, n)) != OK) { printf("VFS: read_seg: copy failed (text)\n"); return(r); } o += n; } return(OK); } else if (seg == D) { if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING, proc_e, (char*)seg_addr, seg_bytes, &new_pos, &cum_io)) != OK) { printf("VFS: read_seg: req_readwrite failed (data)\n"); return(r); } if (r == OK && cum_io != seg_bytes) printf("VFS: read_seg segment has not been read properly by exec()\n"); return(r); } return(OK); }
/*===========================================================================* * patch_stack * *===========================================================================*/ static int patch_stack( struct vnode *vp, /* pointer for open script file */ char stack[ARG_MAX], /* pointer to stack image within VFS */ vir_bytes *stk_bytes /* size of initial stack */ ) { /* Patch the argument vector to include the path name of the script to be * interpreted, and all strings on the #! line. Returns the path name of * the interpreter. */ enum { INSERT=FALSE, REPLACE=TRUE }; int n, r; off_t pos; char *sp, *interp = NULL; u64_t new_pos; unsigned int cum_io; char buf[_MAX_BLOCK_SIZE]; /* Make user_fullpath the new argv[0]. */ if (!insert_arg(stack, stk_bytes, user_fullpath, REPLACE)) { printf("VFS: patch_stack: insert_arg for argv[0] failed\n"); return(ENOMEM); } pos = 0; /* Read from the start of the file */ /* Issue request */ r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING, VFS_PROC_NR, buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io); if (r != OK) return(r); n = vp->v_size; if (n > _MAX_BLOCK_SIZE) n = _MAX_BLOCK_SIZE; if (n < 2) return ENOEXEC; sp = &(buf[2]); /* just behind the #! */ n -= 2; if (n > PATH_MAX) n = PATH_MAX; /* Use the user_fullpath variable for temporary storage */ memcpy(user_fullpath, sp, n); if ((sp = memchr(user_fullpath, '\n', n)) == NULL) /* must be a proper line */ return(ENOEXEC); /* Move sp backwards through script[], prepending each string to stack. */ for (;;) { /* skip spaces behind argument. */ while (sp > user_fullpath && (*--sp == ' ' || *sp == '\t')) {} if (sp == user_fullpath) break; sp[1] = 0; /* Move to the start of the argument. */ while (sp > user_fullpath && sp[-1] != ' ' && sp[-1] != '\t') --sp; interp = sp; if (!insert_arg(stack, stk_bytes, sp, INSERT)) { printf("VFS: patch_stack: insert_arg failed\n"); return(ENOMEM); } } if(!interp) return ENOEXEC; /* Round *stk_bytes up to the size of a pointer for alignment contraints. */ *stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE; if (interp != user_fullpath) memmove(user_fullpath, interp, strlen(interp)+1); return(OK); }