* fix an issue that execve attempts to parse directory as elf file.
[lunaix-os.git] / lunaix-os / kernel / exe / exec.c
index 8a14c4ad0f8059694430f3cc65b98956f586e6ba..813d5c32b99ff5dd4b5ba8c5c3c56fb221fb5741 100644 (file)
@@ -1,4 +1,3 @@
-#include <arch/abi.h>
 #include <lunaix/exec.h>
 #include <lunaix/fs.h>
 #include <lunaix/load.h>
@@ -6,26 +5,33 @@
 #include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/process.h>
+#include <lunaix/sched.h>
 #include <lunaix/spike.h>
 #include <lunaix/status.h>
 #include <lunaix/syscall.h>
 #include <lunaix/syscall_utils.h>
 
+#include <sys/abi.h>
+#include <sys/mm/mm_defs.h>
+
 #include <klibc/string.h>
 
 void
-exec_container(struct exec_container* param,
-               struct proc_info* proc,
+exec_init_container(struct exec_container* param,
+               struct thread* thread,
                ptr_t vms,
                const char** argv,
                const char** envp)
 {
-    *param = (struct exec_container){ .proc = proc,
+    assert(thread->ustack);
+    ptr_t ustack_top = align_stack(thread->ustack->end - 1);
+    *param = (struct exec_container){ .proc = thread->process,
                                       .vms_mnt = vms,
                                       .exe = { .container = param },
                                       .argv_pp = { 0, 0 },
                                       .argv = argv,
-                                      .envp = envp };
+                                      .envp = envp,
+                                      .stack_top = ustack_top };
 }
 
 size_t
@@ -40,7 +46,7 @@ args_ptr_size(const char** paramv)
     return (sz + 1) * sizeof(ptr_t);
 }
 
-ptr_t
+static ptr_t
 copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
 {
     ptr_t ptr;
@@ -59,6 +65,32 @@ copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
     return stack_top;
 }
 
+static void
+save_process_cmd(struct proc_info* proc, ptr_t* argv)
+{
+    ptr_t ptr, *_argv = argv;
+    size_t total_sz = 0;
+    while ((ptr = *_argv)) {
+        total_sz += strlen((const char*)ptr) + 1;
+        _argv++;
+    }
+
+    if (proc->cmd) {
+        vfree(proc->cmd);
+    }
+
+    char* cmd_ = (char*)valloc(total_sz);
+    proc->cmd = cmd_;
+    proc->cmd_len = total_sz;
+
+    while ((ptr = *argv)) {
+        cmd_ = strcpy(cmd_, (const char*)ptr);
+        cmd_[-1] = ' ';
+        argv++;
+    }
+    cmd_[-1] = '\0';
+}
+
 // externed from mm/dmm.c
 extern int
 create_heap(struct proc_mm* pvms, ptr_t addr);
@@ -77,7 +109,8 @@ exec_load(struct exec_container* container, struct v_file* executable)
         goto done;
     }
 
-    struct proc_mm* pvms = &container->proc->mm;
+    struct proc_info* proc = container->proc;
+    struct proc_mm* pvms = vmspace(proc);
 
     if (pvms->heap) {
         mem_unmap_region(container->vms_mnt, pvms->heap);
@@ -87,13 +120,13 @@ exec_load(struct exec_container* container, struct v_file* executable)
     if (!argv_extra[1]) {
         // If loading a statically linked file, then heap remapping we can do,
         // otherwise delayed.
-        create_heap(&container->proc->mm, PG_ALIGN(container->exe.end));
+        create_heap(vmspace(proc), page_aligned(container->exe.end));
     }
 
     if (container->vms_mnt == VMS_SELF) {
         // we are loading executable into current addr space
 
-        ptr_t ustack = USTACK_TOP;
+        ptr_t ustack = container->stack_top;
         size_t argv_len = 0, envp_len = 0;
         ptr_t argv_ptr = 0, envp_ptr = 0;
 
@@ -104,23 +137,32 @@ exec_load(struct exec_container* container, struct v_file* executable)
 
             memcpy((void*)ustack, (const void*)envp, envp_len);
             ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
+        } else {
+            ustack -= sizeof(ptr_t);
+            *((ptr_t*)ustack) = 0;
         }
 
-        if (argv) {
+        if (argv) {            
             argv_len = args_ptr_size(argv);
             ustack -= argv_len;
 
             memcpy((void*)ustack, (const void**)argv, argv_len);
-            for (size_t i = 0; i < 2 && argv_extra[i]; i++) {
-                ustack -= sizeof(ptr_t);
-                *((ptr_t*)ustack) = (ptr_t)argv_extra[i];
-                argv_len += sizeof(ptr_t);
-            }
+        } else {
+            ustack -= sizeof(ptr_t);
+            *((ptr_t*)ustack) = 0;
+        }
 
-            argv_ptr = ustack;
-            ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
+        for (size_t i = 0; i < 2 && argv_extra[i]; i++) {
+            ustack -= sizeof(ptr_t);
+            *((ptr_t*)ustack) = (ptr_t)argv_extra[i];
+            argv_len += sizeof(ptr_t);
         }
 
+        argv_ptr = ustack;
+        ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
+
+        save_process_cmd(proc, (ptr_t*)argv_ptr);
+
         // four args (arg{c|v}, env{c|p}) for main
         struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1];
 
@@ -133,20 +175,11 @@ exec_load(struct exec_container* container, struct v_file* executable)
                                 .envp = (char**)envp_ptr };
     } else {
         /*
-            TODO need to find a way to inject argv and envp remotely
-                 this is for the support of kernel level implementation of
-                 posix_spawn
-
-            IDEA
-                1. Allocate a orphaned physical page (i.e., do not belong to any
-                VMA)
-                2. Mounted to a temporary mount point in current VMA, (i.e.,
-                PG_MOUNT_*)
-                3. Do setup there.
-                4. Unmount then mounted to the foreign VMA as the first stack
-                page.
+            TODO Inject to remote user stack with our procvm_remote toolsets
+                 Need a better way to factorise the argv/envp length calculating
         */
         fail("not implemented");
+
     }
 
 done:
@@ -168,8 +201,19 @@ exec_load_byname(struct exec_container* container, const char* filename)
         goto done;
     }
 
+    if (!check_itype_any(dnode->inode, F_FILE)) {
+        errno = EISDIR;
+        goto done;
+    }
+
     errno = exec_load(container, file);
 
+    // It shouldn't matter which pid we passed. As the only reader is 
+    //  in current context and we must finish read at this point,
+    //  therefore the dead-lock condition will not exist and the pid
+    //  for arbitration has no use.
+    vfs_pclose(file, container->proc->pid);
+
 done:
     return errno;
 }
@@ -180,8 +224,7 @@ exec_kexecve(const char* filename, const char* argv[], const char* envp[])
     int errno = 0;
     struct exec_container container;
 
-    exec_container(
-      &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
+    exec_init_container(&container, current_thread, VMS_SELF, argv, envp);
 
     errno = exec_load_byname(&container, filename);
 
@@ -211,8 +254,8 @@ __DEFINE_LXSYSCALL3(int,
     int errno = 0;
     struct exec_container container;
 
-    exec_container(
-      &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
+    exec_init_container(
+      &container, current_thread, VMS_SELF, argv, envp);
 
     if ((errno = exec_load_byname(&container, filename))) {
         goto done;
@@ -220,12 +263,13 @@ __DEFINE_LXSYSCALL3(int,
 
     // we will jump to new entry point (_u_start) upon syscall's
     // return so execve 'will not return' from the perspective of it's invoker
-    eret_target(__current) = container.exe.entry;
-    eret_stack(__current) = container.stack_top;
+    eret_target(current_thread) = container.exe.entry;
+    eret_stack(current_thread) = container.stack_top;
 
     // these become meaningless once execved!
-    __current->ustack_top = 0;
-    proc_clear_signal(__current);
+    current_thread->ustack_top = 0;
+    signal_reset_context(&current_thread->sigctx);
+    signal_reset_register(__current->sigreg);
 
 done:
     // set return value