sys_exec() uses the FS, sys_proc_create takes args
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 26 Jul 2010 17:43:15 +0000 (10:43 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:49 +0000 (17:35 -0700)
Rebuild your cross compiler!

The syscalls take a path, instead of a file descriptor, similarly to
linux, and mostly due to it being unclear whether a process should have
its program open().  Also, sys_open() doesn't use the FS yet...

Both syscalls still use the ghetto-procinfo-style arg packing, since
it's a pain to change.  I like not having the kernel worry about argv
packing, but struct procinfo is about 3 pages huge.

kern/include/syscall.h
kern/src/syscall.c
tests/fork.c
tests/proctests.c
tests/spawn.c
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/execve.c
user/include/parlib.h
user/parlib/syscall.c

index 03ae2f5..ef6396d 100644 (file)
@@ -61,5 +61,4 @@ intreg_t sys_getcwd(struct proc* p, char* pwd, int size);
 intreg_t sys_gettimeofday(struct proc* p, int* buf);
 intreg_t sys_tcsetattr(struct proc* p, int fd, int optional_actions, const void* termios_p);
 intreg_t sys_tcgetattr(struct proc* p, int fd, void* termios_p);
-intreg_t sys_exec(struct proc* p, int fd, procinfo_t* pi);
 #endif /* !ROS_KERN_SYSCALL_H */
index b25b8d8..4822619 100644 (file)
@@ -196,19 +196,44 @@ static pid_t sys_getpid(struct proc *p)
 /* Creates a process from the file 'path'.  The process is not runnable by
  * default, so it needs it's status to be changed so that the next call to
  * schedule() will try to run it.  TODO: take args/envs from userspace. */
-static int sys_proc_create(struct proc *p, const char *DANGEROUS path)
+static int sys_proc_create(struct proc *p, char *path, size_t path_l,
+                           struct procinfo *pi)
 {
        int pid = 0;
-       char t_path[MAX_PATH_LEN];
+       char *t_path;
        struct file *program;
        struct proc *new_p;
 
-       /* Copy in.  TODO: make syscalls come with a length */
-       user_mem_strlcpy(p, t_path, path, MAX_PATH_LEN, PTE_USER_RO);
+       /* Copy in the path.  Consider putting an upper bound. */
+       t_path = kmalloc(path_l, 0);
+       if (!t_path) {
+               set_errno(current_tf, ENOMEM);
+               return -1;
+       }
+       if (memcpy_from_user(p, t_path, path, path_l)) {
+               kfree(t_path);
+               set_errno(current_tf, EINVAL);
+               return -1;
+       }
        program = path_to_file(t_path);
+       kfree(t_path);
        if (!program)
                return -1;                      /* presumably, errno is already set */
        new_p = proc_create(program, 0, 0);
+       /* Set the argument stuff needed by glibc */
+       if (memcpy_from_user(p, new_p->procinfo->argp, pi->argp, sizeof(pi->argp))){
+               atomic_dec(&program->f_refcnt); /* TODO: REF */
+               proc_destroy(new_p);
+               set_errno(current_tf, EINVAL);
+               return -1;
+       }
+       if (memcpy_from_user(p, new_p->procinfo->argbuf, pi->argbuf,
+                            sizeof(pi->argbuf))) {
+               atomic_dec(&program->f_refcnt); /* TODO: REF */
+               proc_destroy(new_p);
+               set_errno(current_tf, EINVAL);
+               return -1;
+       }
        pid = new_p->pid;
        proc_decref(new_p, 1);  /* give up the reference created in proc_create() */
        atomic_dec(&program->f_refcnt);         /* TODO: REF / KREF */
@@ -360,46 +385,61 @@ static ssize_t sys_fork(env_t* e)
        return env->pid;
 }
 
-intreg_t sys_exec(struct proc* p, int fd, procinfo_t* pi)
+/* Load the binary "path" into the current process, and start executing it.
+ * argv and envp are magically bundled in procinfo for now.  Keep in sync with
+ * glibc's sysdeps/ros/execve.c */
+static int sys_exec(struct proc *p, char *path, size_t path_l,
+                    struct procinfo *pi)
 {
+       int ret = -1;
+       char *t_path;
+       struct file *program;
+
+       /* We probably want it to never be allowed to exec if it ever was _M */
        if(p->state != PROC_RUNNING_S)
                return -1;
-
-       int ret = -1;
-       struct file* f = file_open_from_fd(p,fd);
-       if(f == NULL) {
-               set_errno(current_tf, EBADF);
-               goto out;
+       /* Copy in the path.  Consider putting an upper bound. */
+       t_path = kmalloc(path_l, 0);
+       if (!t_path) {
+               set_errno(current_tf, ENOMEM);
+               return -1;
        }
-
-       // Set the argument stuff needed by glibc
-       if(memcpy_from_user(p,p->procinfo->argp,pi->argp,sizeof(pi->argp))) {
-               proc_destroy(p);
-               goto out;
+       if (memcpy_from_user(p, t_path, path, path_l)) {
+               kfree(t_path);
+               set_errno(current_tf, EINVAL);
+               return -1;
        }
-       if(memcpy_from_user(p,p->procinfo->argbuf,pi->argbuf,sizeof(pi->argbuf))) {
-               proc_destroy(p);
-               goto out;
+       program = path_to_file(t_path);
+       kfree(t_path);
+       if (!program)
+               return -1;                      /* presumably, errno is already set */
+       /* Set the argument stuff needed by glibc */
+       if (memcpy_from_user(p, p->procinfo->argp, pi->argp, sizeof(pi->argp))) {
+               atomic_dec(&program->f_refcnt); /* TODO: REF */
+               set_errno(current_tf, EINVAL);
+               return -1;
        }
-
-       // TODO: don't do this either (PC)
+       if (memcpy_from_user(p, p->procinfo->argbuf, pi->argbuf,
+                            sizeof(pi->argbuf))) {
+               atomic_dec(&program->f_refcnt); /* TODO: REF */
+               set_errno(current_tf, EINVAL);
+               return -1;
+       }
+       /* This is the point of no return for the process. */
+       /* TODO: issues with this: Need to also assert there are no outstanding
+        * users of the sysrings.  the ldt page will get freed shortly, so that's
+        * okay.  Potentially issues with the nm and vcpd if we were in _M before
+        * and someone is trying to notify. */
        memset(p->procdata, 0, sizeof(procdata_t));
-
-       env_user_mem_free(p,0,USTACKTOP);
-
-       if(load_elf(p,f))
-       {
+       env_user_mem_free(p, 0, UMAPTOP);
+       if (load_elf(p, program)) {
                proc_destroy(p);
-               goto out;
+               smp_idle();             /* syscall can't return on failure now */
        }
-       file_decref(f);
+       printk("[PID %d] exec %s\n", p->pid, file_name(program));
+       atomic_dec(&program->f_refcnt);         /* TODO: (REF) / KREF */
        *current_tf = p->env_tf;
-       ret = 0;
-
-       printd("[PID %d] exec fd %d\n",p->pid,fd);
-
-out:
-       return ret;
+       return 0;
 }
 
 static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)
index 11ea1c7..c6084f2 100644 (file)
@@ -14,6 +14,8 @@ int main(int argc, char** argv)
                waitpid(pid, &status, 0);
        } else {
                printf("Hello world from child!!\n");
+               printf("Child trying to exec Hello...\n");
+               execv("/bin/hello", argv);
        }
        return 0;
 }
index 1507df7..d5a287a 100644 (file)
@@ -11,10 +11,11 @@ int main(int argc, char** argv)
        /* first instance.  this is ghetto, since it relies on being the first proc
         * ever.  fix this when we can pass arguments.  (TODO) */
        #define NUM_KIDS 5
+       #define FILENAME "/bin/proctests"
        int child_pid[NUM_KIDS];
        if (pid == 0x1000) {
                for (int i = 0; i < NUM_KIDS; i++)
-                       child_pid[i] = sys_proc_create("roslib_proctests");
+                       child_pid[i] = sys_proc_create(FILENAME, strlen(FILENAME), 0, 0);
                for (int i = 0; i < NUM_KIDS; i++) {
                        printf("U: attempting to spawn yielders (pid: %d)\n", child_pid[i]);
                        sys_proc_run(child_pid[i]);
index 413a577..67311c7 100644 (file)
@@ -4,6 +4,7 @@
 
 int main(int argc, char** argv)
 {
+       #define FILENAME "/bin/hello"
        #if 0
        /* try some bad combos */
        int pid = sys_proc_create("garbagexxx");
@@ -29,10 +30,10 @@ int main(int argc, char** argv)
        }
        #endif
        printf("U: attempting to create and run hello\n");
-       child_pid[0] = sys_proc_create("/bin/hello");
+       child_pid[0] = sys_proc_create(FILENAME, strlen(FILENAME), 0, 0);
        sys_proc_run(child_pid[0]);
        printf("U: attempting to create and run another hello\n");
-       child_pid[1] = sys_proc_create("/bin/hello");
+       child_pid[1] = sys_proc_create(FILENAME, strlen(FILENAME), 0, 0);
        sys_proc_run(child_pid[1]);
        return 0;
 }
index c39f713..5bf4c32 100644 (file)
@@ -41,20 +41,11 @@ __execve (path, argv, envp)
     return -1;
   }
 
-  int fd = __libc_open(path,O_RDONLY);
-  if(fd == -1)
-               return -1; // errno already set by open
-
-  int ret = ros_syscall(SYS_exec,fd,(uintptr_t)&pi,0,0,0);
+  int ret = ros_syscall(SYS_exec, path, strlen(path), (uintptr_t)&pi, 0, 0);
 
   // if we got here, then exec better have failed...
   assert(ret == -1);
 
-  // close the file, but keep exec's errno
-  int exec_errno = errno;
-  close(fd);
-  errno = exec_errno;
-
   return ret;
 }
 weak_alias (__execve, execve)
index 8e9719c..a180f2a 100644 (file)
@@ -35,7 +35,7 @@ void *      sys_brk(void* addr);
 int         sys_getpid(void);
 int         sys_proc_destroy(int pid, int exitcode);
 void        sys_yield(bool being_nice);
-int         sys_proc_create(char* path);
+int         sys_proc_create(char *path, size_t path_l, char *argv[], char *envp[]);
 int         sys_proc_run(int pid);
 ssize_t     sys_shared_page_alloc(void *COUNT(PGSIZE) *addr, pid_t p2, 
                                   int p1_flags, int p2_flags);
index f9d4a4c..ce166b9 100644 (file)
@@ -96,9 +96,14 @@ void sys_yield(bool being_nice)
        ros_syscall(SYS_yield, being_nice, 0, 0, 0, 0);
 }
 
-int sys_proc_create(char* path)
-{
-       return ros_syscall(SYS_proc_create, (uintreg_t)path, 0, 0, 0, 0);
+int sys_proc_create(char *path, size_t path_l, char *argv[], char *envp[])
+{
+       struct procinfo pi;
+       if (procinfo_pack_args(&pi, argv, envp)) {
+               errno = ENOMEM;
+               return -1;
+       }
+       return ros_syscall(SYS_proc_create, path, path_l, &pi, 0, 0);
 }
 
 int sys_proc_run(int pid)