Пример #1
0
/* if haven't started using the FPU the record that we're using it and init
   it.  If already using it, then restore its state */
static void fpu_device_handler(int trapno, u_int eip) {

  dlockputs(__UAREA_LD, "fpu_device_handler get lock ");
  EXOS_LOCK(UAREA_LOCK);
  dlockputs(__UAREA_LD, "... got lock\n");
  EnterCritical();

  /* clear the TS bit */
  sys_clts();
  if (UAREA.u_fpu == 0) {
    asm("fninit\n");
    UAREA.u_fpu = 1;
  } else
    asm("frstor __exos_fpus\n");
  _exos_fpu_used_ctxt = 1;
  
  EXOS_UNLOCK(UAREA_LOCK);
  dlockputs(__UAREA_LD, "fpu_device_handler release lock\n");
  ExitCritical();
}
Пример #2
0
/* everything is based on this exec, we have an extra flag
   (_EXEC_EXECONLY) to differentiate between the exec and fork_exec
   families.  the difference is that the latter forks and then execs
   the process thereby returning in the parent
   */
static int
fork_execve0(const char *path, char *const argv[], char * const envptr[],
	     int fd, u_int flags)
{
  u_int k = 0;
  int target_cpu = 0;
  struct Uenv cu;
  int NewPid = 0;
  int envid = 0; /* XXX -- init to supress warning */
  char **old_argv = (char **)argv;
  int r, exec_format;
  struct Env e;

  OSCALLENTER(OSCALL_execve);
  /* verify executable permission */
  if (!(flags & _EXEC_USE_FD) && access(path, X_OK) == -1) {
    /* access will set errno */
    r = -errno;
    goto err;
  }

  if (!(envid = sys_env_alloc (0, &r))) {
    fprintf(stderr,"could not sys_env_alloc\n");
    r = -ENOEXEC;
    goto err;
  }

  e = __envs[envidx(envid)];
  if ((exec_format = fork_execve0_part2(path, argv, envptr, &e, fd, flags)) < 0)
    goto err_env_free;

  /* write environment */
  if ((r = sys_wrenv (k, envid, &e)) < 0) {
    kprintf ("sys_wrenv failed\n");
    r = -ENOEXEC;
    goto err;
  }

  if (ExecuteOnExecHandlers(k, envid, flags & _EXEC_EXECONLY) == -1) {
    fprintf(stderr,"cleanup code not done yet\n");
    assert(-1);
  }

#ifdef PROCESS_TABLE
  if (flags & _EXEC_EXECONLY) {
    /* because true exec */
    NewPid = getpid();
  
    dlockputs(__PROCD_LD,"fork_execve0 get lock ");
    EXOS_LOCK(PROCINFO_LOCK);
    dlockputs(__PROCD_LD,"... got lock\n");
    EnterCritical (); 

    ProcChangeEnv(NewPid,envid);
    
    EXOS_UNLOCK(PROCINFO_LOCK);
    dlockputs(__PROCD_LD,"fork_execve0 release lock\n");
    ExitCritical (); 

  } else {
    /* because we are forking */
    NewPid = AllocateFreePid (envid);
  }

  cu = UAREA;
  if (!execonly) {
    AddProcEntry (&cu, (char *)path, (char **)argv, NewPid, UAREA.pid);
    if ((cu.parent_slot = GetChildSlot (NewPid)) < 0) {
      r = -ENOEXEC;
      goto err_env_free;
    }
  } else {
    /* TO TOM: what do we do this for?
    strncpy (UAREA.name, (char*)(((u_int)argv[0]) + ARGV_START_LOCAL - ARGV_START),
	     U_NAMEMAX-1);
    UAREA.name[U_NAMEMAX-1] = '\0'; */
  }
  /* XXX -- on an exec we'll forget to unref our children's pids */
  /* TO TOM: shouldnt this clearchildinfo be at the top */
  ClearChildInfo (&cu);
#else
#ifdef PROCD
  if (flags & _EXEC_EXECONLY) 
  {
    NewPid = getpid();
    /* only register us if we are of the right format */ 
    if (exec_format == EXEC_EXOS_AOUT)
      proc_exec(envid);
  } else {
    NewPid = proc_fork(envid);
  }
  cu = UAREA;
  //kprintf("NewPid %d envid: %d %s proc_%s: (%d) -> %d\n",
	    //NewPid,__envid,execonly ? "exec" : "fork",path,envid,NewPid);
#else
  NewPid = envid;
#endif /* PROCD */
#endif /* PROCESS_TABLE */

  strncpy (cu.name, path, U_NAMEMAX-1);
  cu.name[U_NAMEMAX-1] = '\0';
  cu.u_fpu = 0;
  cu.u_in_critical = 0;
  cu.u_status = U_RUN;
  cu.u_entprologue = e.env_tf.tf_eip;
  cu.u_entepilogue = e.env_tf.tf_eip;
  cu.u_entfault = 0;
  cu.u_entipc1 = 0;
  cu.u_entipc2 = 0;
  cu.u_ppc = 0;
#ifdef PROCESS_TABLE
  cu.u_chld_state_chng = 0;
#endif /* PROCESS_TABLE */
  cu.u_next_timeout = 0;
  cu.u_in_pfault = 0;
  cu.u_donate = -1;
  cu.u_yield_count = 0;
  cu.u_epilogue_count = 0;
  cu.u_epilogue_abort_count = 0;

  STOPP(misc,step7);
  ISTART(misc,step8);

  cu.u_start_kern_call_counting = 0;

  if ((r = sys_wru (0, envid, &cu)) < 0) {
    fprintf (stderr,"sys_wru failed\n");
    r = -ENOEXEC;
    goto err_env_free;
  }

  target_cpu = 0;

#ifdef __SMP__
  if (strncmp(path,"_cpu",4)==0 && strlen(path)>4) 
  {
    target_cpu = path[4]-'0';
    if (target_cpu<0 || target_cpu>sys_get_num_cpus()-1) 
      target_cpu = 0;
  }
#endif

  /* we can't do this until all the child state is setup */
  if ((r = sys_quantum_alloc (k, -1, target_cpu, envid)) < 0) {
    fprintf (stderr,"could not alloc quantum\n");
    r = -ENOEXEC;
    goto err_env_free;
  }

  /* if we're doing a true unix exec and not a combined fork/spawn
     we need to destroy ourselves since our child should have
     replaced us. */

  if (flags & _EXEC_EXECONLY) 
  {
    /* if not an exos format, should not expect normal child behaviors, so we
     * just quit from procd to avoid any hanging...
     */
    if (exec_format == EXEC_SIMPLE)
      proc_exit(0);

    /* we die anyways, so free quantum and env */
    ProcessFreeQuanta(__envid);
    sys_env_free (0, __envid);
  }

  if (old_argv != argv) __free((char**)argv);
  OSCALLEXIT(OSCALL_execve);
  return (NewPid);

err_env_free:
  ProcessFreeQuanta(__envid);
  sys_env_free (k, envid);

err:
  if (old_argv != argv) __free((char**)argv);
  errno = -r;
  OSCALLEXIT(OSCALL_execve);
  return -1;
}
Пример #3
0
/* everything is based on this exec, we have an extra argument
   (execonly) to differentiate between the exec and fork_exec
   families.  the difference is that the latter forks and then execs
   the process thereby returning in the parent
   */
static int
fork_execve0(const char *path, char *const argv_ori[], char * const envptr[], 
	     int execonly) {
  int envid;
  int fd;

  u_int k = 0;
  struct Uenv cu;
  int argc;
  char **argv_tmp,*argv_p,**argv;
  u32 lmagic;
  char *cmagic = (char*)&lmagic;
  u32 entry_point = 0;
  int running_emulator = 0;
  char *emu_path = NULL;
  char **argv_ori_tmp = (char**)argv_ori;
  char **argv_ori_tmp2;
#define FE_PATH (running_emulator ? emu_path : path)
#ifdef PROCESS_TABLE
  int NewPid = 0;
#endif
  char *extra_argv_space = NULL;
#if 0
  {
    extern void pr_fds();
    fprintf(stderr,"FDS BEFORE EXEC PID: %d execonly: %d\n",getpid(),execonly);
    pr_fds;
  }
#endif
//  printf("fork_execve0: path: %s\n",path);
#if 0
  for(argc = 0; argv_ori[argc] ; argc++) 
    kprintf("%d) %s\n",argc,argv_ori[argc]);
#endif

  proprintf("allocate env, and open file\n");
  ISTART(misc,execve);
  ISTART(misc,step1);
  /* fprintf(stderr,"fe_nfs2 %s\n",FE_PATH); */
  if (! (envid = sys_env_alloc (0))) {
    fprintf(stderr,"could not sys_env_alloc\n");
    goto err;
  }

open_binary:
  /* verify executable permission */
  if (access(FE_PATH, X_OK) == -1) {
    /* access will set errno */
    goto fork_execve0_end_error;
  }
  /* open the executable */
  fd = open (FE_PATH, O_RDONLY, 0644);
  if (fd < 0) {
    /* open will set errno */
    /*fprintf(stderr,"1could not open path %s, errno: %d\n",FE_PATH,errno);*/
    goto fork_execve0_end_error;
  }
  STOPP(misc,step1);
  proprintf("read file and open interpreter if necessary\n");
  ISTART(misc,step2);

  /* read in the magic number */
  if (read(fd, cmagic, 2) < 2) {
    errno = ENOEXEC;
    goto fork_execve0_end_error_closefd;
  }

  /* check for interpreter */
  if (cmagic[0] == '#' && cmagic[1] == '!') {
    int intersize;
    char inter[MAXINTERP+1], *interp;

    if ((intersize = read(fd,inter,MAXINTERP)) == -1) {
      errno = ENOEXEC;
      goto fork_execve0_end_error_closefd;
    }
    inter[intersize] = '\n';
    interp = inter;
    
    /* skip spaces */
    while ((*interp == ' ' || *interp == '\t') && 
	   *interp != '\n')
      interp++;
    
    {
      char **v = (char **)argv_ori_tmp;
      while(*v++);
      extra_argv_space = (char *)malloc((char *)v - (char *)argv_ori_tmp + 
					MAXINTERP*(sizeof(char*)));
      if (!extra_argv_space) {
	fprintf(stderr,"execve could not allocate extra argv space for "
		"interpreted file\n");
	goto fork_execve0_end_error_closefd;
      }
    }
    argv = (char **)extra_argv_space;
    *argv++ = interp;

    while (*interp != ' ' && *interp != '\t' && 
	   *interp != (char)0 && *interp != '\n')
      interp++;
    
    if (*interp != 0 && *interp != '\n') {
      /* more arguments, we only copy one more */
      *interp++ = 0;
      /* skip spaces */
      while ((*interp == ' ' || *interp == '\t') && 
	     *interp != '\n')
	interp++;

      *argv++ = interp;
      while (*interp != ' ' && *interp != '\t' && 
	     *interp != (char)0 && *interp != '\n')
	interp++;
      *interp = (char)0;
    } else {
      *interp = (char)0;
    }
    *argv++ = (char *)FE_PATH;
    argv_ori_tmp2 = argv_ori_tmp;
    argv_ori_tmp2++;
    while(*argv_ori_tmp2 != (char *) 0) {*argv++ = *argv_ori_tmp2++;}
    /* copy the 0 */
    *argv++ = *argv_ori_tmp2++;
    argv = (char **)extra_argv_space;
  
    close(fd);
    /* verify executable permission */
    if (access(argv[0], X_OK) == -1) {
      /* access will set errno */
      goto fork_execve0_end_error;
    }
    fd = open (argv[0], O_RDONLY, 0644);
    if (fd < 0) {
      /* open will set errno */
      /*fprintf(stderr,"2could not open path %s, errno: %d\n",argv[0],errno);*/
      goto fork_execve0_end_error;
    }
    /* read in the magic number (and nesting of interpreters not allowed) */
    if (read(fd, cmagic, 2) < 2 || (cmagic[0] == '#' && cmagic[1] == '!')) {
      errno = ENOEXEC;
      goto fork_execve0_end_error_closefd;
    }
  } else {
    argv = (char **)argv_ori_tmp;
  }

  STOPP(misc,step2);
  proprintf("read more magic and executable headers, check for emulation\n");
  ISTART(misc,step3);

  if (read(fd, &cmagic[2], 2) < 2) {
    errno = ENOEXEC;
    goto fork_execve0_end_error_closefd;
  }

  /* see whether we need to run an emulator */
  if (lmagic != 0700303000 && (lmagic & 0x0000ffff) != 0514) {
    if (running_emulator) {
      fprintf(stderr,"Emulator binary is in unrecognized executable "
	      "format.\n");
      goto fork_execve0_end_error_closefd;
    }
    else
      fprintf(stderr,"Unrecognized executable format; attempting to run " 
	      "emulator.\n");
    close(fd);
    {
      char **v = (char **)argv_ori_tmp;
      while(*v++);
      extra_argv_space = (char *)malloc((char *)v - (char *)argv_ori_tmp +
					2 * sizeof(char*));
      if (!extra_argv_space) {
	fprintf(stderr,"execve could not allocate extra argv space for "
		"copying args for emulator\n");
	goto fork_execve0_end_error_closefd;
      }
    }
    argv = (char **)extra_argv_space;
    running_emulator = 1;
    *argv++ = emu_path = getenv("EMULATOR");
    if (!FE_PATH) {
      fprintf(stderr,"EMULATOR environment variable not set to emulator path; "
	      "cannot run emulator.\n");
      goto fork_execve0_end_error;
    }
    *argv++ = (char *)path;
    argv_ori_tmp2 = argv_ori_tmp;
    argv_ori_tmp2++;
    while(*argv_ori_tmp2 != (char *) 0) {*argv++ = *argv_ori_tmp2++;}
    /* copy the 0 */
    *argv++ = *argv_ori_tmp2++;
    argv = (char **)extra_argv_space;
    argv_ori_tmp = argv;
    goto open_binary;
  }  

  /* check for original ExOS (OpenBSD) format - remove eventually */
  if (lmagic == 0700303000)
    {
      struct exec hdr;
      u_int byte_count, page_count;
      Pte *ptes;
      int i;

#if 0
      fprintf(stderr,"File uses old executable format.\n");
#endif
      /* allocate physical pages and read data into it. */

      /* read a.out headers */
      if (lseek(fd,0,SEEK_SET) == -1 ||
	  read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
	fprintf(stderr,"Invalid executable format.\n");
	errno = ENOEXEC;
	goto fork_execve0_end_error_closefd;
      }
      entry_point = hdr.a_entry;

      /* alloc this much memory */
      byte_count = hdr.a_text + hdr.a_data + hdr.a_bss;
      page_count = PGNO(PGROUNDUP(byte_count));

      /* allocate it in both child and parent areas */
      if ((ptes = malloc(sizeof(Pte) * page_count)) == 0) {
	errno = ENOEXEC;
	goto fork_execve0_end_error_closefd;
      }
      for (i=0; i < page_count; i++)
	ptes[i] = PG_U|PG_W|PG_P;
      STOPP(misc,step3);
      proprintf("allocate childs vm in both parent and child, read text+data "
		"(sz %ld)\n", hdr.a_text + hdr.a_data);
      ISTART(misc,read0);
      if (sys_self_insert_pte_range(k, ptes, page_count, TEMP_REGION) < 0 ||
	  sys_insert_pte_range(k, &vpt[PGNO(TEMP_REGION)], page_count, 
			       UTEXT, k, envid) < 0 ||
	  read(fd, (void*)TEMP_REGION, hdr.a_text + hdr.a_data) != 
	  hdr.a_text + hdr.a_data) {
	fprintf (stderr,"Binary file invalid or corrupt.\n");
	for (i=0; i < page_count; i++)
	  ptes[i] = 0;
	sys_self_insert_pte_range(k, ptes, page_count, TEMP_REGION);
	sys_insert_pte_range(k, ptes, page_count, UTEXT, k, envid);
	free(ptes);
	errno = ENOEXEC;
	goto fork_execve0_end_error_closefd;
      }

      STOPP(misc,read0);
      /* zero the bss */
      proprintf("bzero bss  (sz %ld)\n",hdr.a_bss);
      ISTART(misc,read1);
      bzero((void*)(TEMP_REGION + hdr.a_text + hdr.a_data), hdr.a_bss);

      STOP(misc,read1);
      PRNAME(misc,read1);
      proprintf("unmap TEMP_REGION (sz %d pages)\n", page_count);
      ISTART(misc,step4);
      /* unmap the used TEMP_REGION */
      for (i=0; i < page_count; i++)
	ptes[i] = 0;
      sys_self_insert_pte_range(k, ptes, page_count, TEMP_REGION);
      free(ptes);
    }
  else if ((lmagic & 0x0000ffff) == 0514) /* check for ExOS COFF format */
    {
      FILHDR hdr;
      AOUTHDR opthdr;
      SCNHDR shdr;
      int s;

      /* allocate physical pages and read data into it. */
      /* read file headers */
      if (lseek(fd,0,SEEK_SET) == -1 ||
	  read(fd, &hdr, FILHSZ) != FILHSZ ||
	  hdr.f_opthdr != sizeof(opthdr) ||
	  !(hdr.f_flags & F_EXEC) ||
	  read(fd, &opthdr, hdr.f_opthdr) != hdr.f_opthdr) {
	fprintf(stderr,"Invalid executable format.\n");
	errno = ENOEXEC;
	goto fork_execve0_end_error_closefd;
      }
      entry_point = opthdr.entry;

      /* ensure ZMAGIC */
      if (opthdr.magic != ZMAGIC) {
	fprintf(stderr,"Exec cannot read non-ZMAGIC COFF executables.\n");
	errno = ENOEXEC;
	goto fork_execve0_end_error_closefd;
      }

      STOPP(misc,step3);
      proprintf("read in and map/zero COFF sections then unmap\n");
      ISTART(misc,read0);
      for (s=0; s < hdr.f_nscns; s++)
	if (read(fd, &shdr, SCNHSZ) != SCNHSZ ||
	    map_section(k, fd, &shdr, envid) == -1) {
	  fprintf(stderr,"Invalid executable format.\n");
	  errno = ENOEXEC;
	  goto fork_execve0_end_error_closefd;
	}
      STOPP(misc,read0);
      proprintf("nothing\n");
      ISTART(misc,read1);
      STOP(misc,read1);
      PRNAME(misc,read1);
      proprintf("nothing\n");
      ISTART(misc,step4);
    } else {
      fprintf(stderr, "Unknown file format.\n");
      errno = ENOEXEC;
      goto fork_execve0_end_error_closefd;
    }

  STOPP(misc,step4);

  close (fd);

  proprintf("Allocate stack for child\n");
  ISTART(misc,step5);

  /* allocate stack space for child */
  if (sys_insert_pte (k, PG_U|PG_W|PG_P, USTACKTOP-NBPG, k, envid) < 0) {
    fprintf(stderr,"sys_insert_pte failed\n");
    errno = ENOEXEC;
    goto fork_execve0_end_error;
  }

  STOPP(misc,step5);
  proprintf("ExecuteOnExecHandlers\n");
  ISTART(misc,step6);
  if (ExecuteOnExecHandlers(k,envid,execonly) == -1) {
    fprintf(stderr,"cleanup code not done yet\n");
    assert(-1);
  }
  STOPP(misc,step6);
  proprintf("Process table stuff\n");
  ISTART(misc,step7);
#ifdef PROCESS_TABLE
  if (execonly) {
    /* because true exec */
    NewPid = getpid();
    /* XXX -- this locking is ... up. I should really come up with a better
       convention as to what expects to be called with things locked and
       what doesn't */
    dlockputs(__PROCD_LD,"fork_execve0 get lock ");
    EXOS_LOCK(PROCINFO_LOCK);
    dlockputs(__PROCD_LD,"... got lock\n");
    EnterCritical (); 

    ProcChangeEnv(NewPid,envid);

    EXOS_UNLOCK(PROCINFO_LOCK);
    dlockputs(__PROCD_LD,"fork_execve0 release lock\n");
    ExitCritical (); 
  } else {
    /* because we are forking */
    NewPid = AllocateFreePid (envid);
  }
#endif  

#ifdef PROCESS_TABLE
  cu = u;
  if (!execonly) {
    AddProcEntry (&cu, (char *)FE_PATH, (char **)argv, NewPid, UAREA.pid);
    if ((cu.parent_slot = GetChildSlot (NewPid)) < 0) {
      errno = ENOEXEC;
      goto fork_execve0_end_error;
    }
  } else {
    /* TO TOM: what do we do this for?  */
    strncpy (UAREA.name, argv[0], U_NAMEMAX-1);
    UAREA.name[U_NAMEMAX-1] = '\0';
  }
  /* XXX -- on an exec we'll forget to unref our children's pids */
  /* TO TOM: shouldnt this clearchildinfo be at the top */
  ClearChildInfo (&cu);
  strncpy (cu.name, FE_PATH, U_NAMEMAX-1);
  cu.name[U_NAMEMAX-1] = '\0';
  cu.u_chld_state_chng = 0;
#endif /* PROCESS_TABLE */
  cu.u_in_critical = 0;
  cu.u_status = U_RUN;
  cu.u_entprologue = entry_point;
  cu.u_next_timeout = 0;
  cu.u_in_pfault = 0;
  cu.u_revoked_pages = 0;
  cu.u_donate = -1;

  STOPP(misc,step7);
  proprintf("Argv and Environment copying\n");
  ISTART(misc,step8);


//  printf("ENTERING ARGV COPY\n");
  /* ----------------------------------------------------------------------------- */
  /* allocate argv space for child */
  {
    char *buf = (char *)ARGV_START_LOCAL;
    char **bufv = (char **)ARGV_START_LOCAL;
    int len,i;

    argc = 0;
    while (argv[argc] != 0) {
      //printf("argv[%d] = %p\n",argc,argv[argc]);
      argc++;}
    
//    printf("argv: %p, argc: %d\n",argv,argc);

    /* allocate pages */
    {
      Pte *ptes;

      if ((ptes = malloc(sizeof(Pte) * NRARGVPG)) == 0) {
	return -1;
      }
      for (i=0; i < NRARGVPG; i++)
	ptes[i] = PG_U|PG_W|PG_P;
      
      if (sys_self_insert_pte_range(k, ptes, NRARGVPG, ARGV_START_LOCAL) < 0 ||
	  sys_insert_pte_range(k, &vpt[PGNO(ARGV_START_LOCAL)], NRARGVPG, 
			       ARGV_START, k, envid) < 0) {
	fprintf(stderr,"sys_insert_pte failed\n");
	for (i=0; i < NRARGVPG; i++)
	  ptes[i] = 0;
	sys_self_insert_pte_range(k, ptes, NRARGVPG, ARGV_START_LOCAL);
	sys_insert_pte_range(k, ptes, NRARGVPG, ARGV_START, k, envid);
	free(ptes);
	errno = ENOEXEC;
	goto fork_execve0_end_error_closefd;
      }
      free(ptes);
    }

    /* copy the args */
    buf += (argc + 1) * sizeof(char *);
    for (i = 0; i < argc; i++) {
//      fprintf(stderr,"argv[%d] ",i);
      len = strlen(argv[i]) + 1;
//      fprintf(stderr,"length %d\n",len);
      
      if ((int)(buf + len) > ARGV_START_LOCAL + NRARGVPG*NBPG) {
	kprintf("Argv too large truncating\n");
	break;
      }

      bufv[i] = buf - (ARGV_START_LOCAL - ARGV_START);
//      fprintf(stderr,"copied argument %d: %p %s (len %d) to %p bufv: %p\n",i,argv[i],argv[i],len,buf,bufv);
      memcpy(buf, argv[i],len);
      buf += len;
    }
    bufv[argc] = (char *)0;

    
  }
//  printf("DONE ARGV COPY\n");

  /* ----------------------------------------------------------------------------- */

#if 0
  /* COPY ARGUMENTS */
  argc = 0;
  iptr = (int *)ARGV_START_LOCAL;
  argv_p = (char *)(ARGV_START_LOCAL + NBPG);
  while(*argv != (char *)0) {
    strcpy(argv_p,*argv);
    iptr[argc] = strlen(*argv) + 1;
    argv_p += strlen(*argv) + 1;
    /*     fprintf(stderr,"%d len %d \"%s\"  ",argc,cu.u_argv_lengths[argc],*argv); */
    argc++;
    argv++;
  }
  iptr[argc] = -1;
  /*   fprintf(stderr,"ARGC %d\n",argc); */
#endif
#if 0
  argc = 0;
  argv_p = (char *)&cu.u_argv_space;
  while(*argv != (char *)0) {
    strcpy(argv_p,*argv);
    cu.u_argv_lengths[argc] = strlen(*argv) + 1;
    argv_p += strlen(*argv) + 1;
    /*     fprintf(stderr,"%d len %d \"%s\"  ",argc,cu.u_argv_lengths[argc],*argv); */
    argc++;
    argv++;
    if (argc == (UNIX_NR_ARGV - 1)) {
      fprintf(stderr,"argc (%d) is greater than maximum allowed (%d), truncating.\n",
	     argc,UNIX_NR_ARGV - 1);
      break;
    }
    if ((int)argv_p > (int)&cu.u_argv_space[0] + UNIX_ARGV_SIZE) {
      fprintf(stderr,"too much data in argv (%d) max is %d\n",
	     (int)argv_p - (int)&cu.u_argv_space[0],UNIX_ARGV_SIZE);
      break;
    }
  }
  cu.u_argv_lengths[argc] = -1;
#endif

  /* COPY ENVIRONMENT */
  argc = 0;
  (char * const *)argv_tmp = envptr;
  argv_p = (char *)&cu.u_env_space;
  if (argv_tmp)
  while(*argv_tmp != (char *)0) {
    strcpy(argv_p,*argv_tmp);
    cu.u_env_lengths[argc] = strlen(*argv_tmp) + 1;
    argv_p += strlen(*argv_tmp) + 1;
    /* fprintf(stderr,"%d len %d \"%s\"  ",argc,cu.u_env_lengths[argc],*argv_tmp); */
    argc++;
    argv_tmp++;
    if (argc == (UNIX_NR_ENV - 1)) {
      fprintf(stderr,"envc (%d) is greater than maximum allowed (%d), truncating.\n",
	     argc,UNIX_NR_ENV - 1);
      break;
    }
    if ((int)argv_p > (int)&cu.u_env_space[0] + UNIX_ENV_SIZE) {
      fprintf(stderr,"too much data in envp (%d) max is %d (%s)\n",
	     (int)argv_p - (int)&cu.u_env_space[0],UNIX_ENV_SIZE, __FILE__);
      break;
    }
  }
  cu.u_env_lengths[argc] = -1;
  /* fprintf(stderr,"ENVC %d\n",argc); */

  if (sys_wru (0, envid, &cu) < 0) {
    fprintf (stderr,"sys_wru failed\n");
    errno = ENOEXEC;
    goto fork_execve0_end_error;
  }
  STOPP(misc,step8);

  STOP(misc,execve);
  PRNAME(misc,execve);
  {
    extern void pr_fd_stat(void);
    pr_fd_stat();
  }

  /*fprintf(stderr,"allocating quantum\n");*/
  if (sys_quantum_alloc (k, -1, 0, envid) < 0) {
    fprintf (stderr,"could not alloc quantum\n");
    errno = ENOEXEC;
    goto fork_execve0_end_error;
  }

  if (execonly) {
    ProcessFreeQuanta(__envid);
    sys_env_free (0, __envid);
  }

  return (NewPid);

fork_execve0_end_error_closefd:
  close(fd);
fork_execve0_end_error:
  ProcessFreeQuanta(__envid);
  sys_env_free (k, envid);
err:
  if (extra_argv_space != NULL) free(extra_argv_space);
  return -1;
}