Esempio n. 1
0
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);
}
Esempio n. 2
0
/**
 * @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;
}
Esempio n. 3
0
/**
 * @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;
}
Esempio n. 4
0
/*===========================================================================*
 *				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);
}
Esempio n. 5
0
/*===========================================================================*
 *				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);
}
Esempio n. 6
0
/*===========================================================================*
 *				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);
}