Просмотр исходного кода

!160 execve增加对script调用支持
Merge pull request !160 from jesven/execve_script

bernard 4 лет назад
Родитель
Сommit
1078fddb23
2 измененных файлов с 221 добавлено и 27 удалено
  1. 9 0
      components/lwp/lwp.h
  2. 212 27
      components/lwp/lwp_syscall.c

+ 9 - 0
components/lwp/lwp.h

@@ -230,4 +230,13 @@ struct process_aux
     struct process_aux_item item[AUX_ARRAY_ITEMS_NR];
 };
 
+struct lwp_args_info
+{
+    char **argv;
+    char **envp;
+    int argc;
+    int envc;
+    int size;
+};
+
 #endif

+ 212 - 27
components/lwp/lwp_syscall.c

@@ -1613,12 +1613,186 @@ void lwp_user_obj_free(struct rt_lwp *lwp);
         lwp_new->member = tmp;\
     } while (0)
 
+static char *_insert_args(int new_argc, char *new_argv[], struct lwp_args_info *args)
+{
+    void *page = NULL;
+    int err = 0;
+    char **nargv;
+    char **nenvp;
+    char *p;
+    int i, len;
+    int nsize;
+
+    if (new_argc == 0)
+    {
+        goto quit;
+    }
+    page = rt_pages_alloc(0); /* 1 page */
+    if (!page)
+    {
+        goto quit;
+    }
+
+    nsize = new_argc * sizeof(char *);
+    for (i = 0; i < new_argc; i++)
+    {
+        nsize += rt_strlen(new_argv[i]) + 1;
+    }
+    if (nsize + args->size > ARCH_PAGE_SIZE)
+    {
+        err = 1;
+        goto quit;
+    }
+    nargv = (char **)page;
+    nenvp = nargv + args->argc + new_argc + 1;
+    p = (char *)(nenvp + args->envc + 1);
+    /* insert argv */
+    for (i = 0; i < new_argc; i++)
+    {
+        nargv[i] = p;
+        len = rt_strlen(new_argv[i]) + 1;
+        rt_memcpy(p, new_argv[i], len);
+        p += len;
+    }
+    /* copy argv */
+    nargv += new_argc;
+    for (i = 0; i < args->argc; i++)
+    {
+        nargv[i] = p;
+        len = rt_strlen(args->argv[i]) + 1;
+        rt_memcpy(p, args->argv[i], len);
+        p += len;
+    }
+    nargv[i] = NULL;
+    /* copy envp */
+    for (i = 0; i < args->envc; i++)
+    {
+        nenvp[i] = p;
+        len = rt_strlen(args->envp[i]) + 1;
+        rt_memcpy(p, args->envp[i], len);
+        p += len;
+    }
+    nenvp[i] = NULL;
+
+    /* update args */
+    args->argv = (char **)page;
+    args->argc = args->argc + new_argc;
+    args->envp = args->argv + args->argc + 1;
+    /* args->envc no change */
+    args->size = args->size + nsize;
+
+quit:
+    if (err && page)
+    {
+        rt_pages_free(page, 0);
+        page = NULL;
+    }
+    return page;
+}
+
+#define INTERP_BUF_SIZE 128
+static char *_load_script(const char *filename, struct lwp_args_info *args)
+{
+    void *page = NULL;
+    char *new_page;
+    int fd = -1;
+    int len;
+    char interp[INTERP_BUF_SIZE];
+    char *cp;
+    char *i_name;
+    char *i_arg;
+
+    fd = open(filename, O_BINARY | O_RDONLY, 0);
+    if (fd < 0)
+    {
+        goto quit;
+    }
+    len = read(fd, interp, INTERP_BUF_SIZE);
+    if (len < 2)
+    {
+        goto quit;
+    }
+
+    if ((interp[0] != '#') || (interp[1] != '!'))
+    {
+        goto quit;
+    }
+
+    if (len == INTERP_BUF_SIZE)
+    {
+        len--;
+    }
+    interp[len] = '\0';
+
+    if ((cp = strchr(interp, '\n')) == NULL)
+    {
+        cp = interp + INTERP_BUF_SIZE - 1;
+    }
+    *cp = '\0';
+    while (cp > interp)
+    {
+        cp--;
+        if ((*cp == ' ') || (*cp == '\t'))
+        {
+            *cp = '\0';
+        }
+        else
+        {
+            break;
+        }
+    }
+    for (cp = interp + 2; (*cp == ' ') || (*cp == '\t'); cp++)
+    {
+        /* nothing */
+    }
+    if (*cp == '\0')
+    {
+        goto quit; /* No interpreter name found */
+    }
+    i_name = cp;
+    i_arg = NULL;
+    for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
+    {
+        /* nothing */
+    }
+    while ((*cp == ' ') || (*cp == '\t'))
+    {
+        *cp++ = '\0';
+    }
+    if (*cp)
+    {
+        i_arg = cp;
+    }
+
+    if (i_arg)
+    {
+        new_page = _insert_args(1, &i_arg, args);
+        rt_pages_free(page, 0);
+        page = new_page;
+        if (!page)
+        {
+            goto quit;
+        }
+    }
+    new_page = _insert_args(1, &i_name, args);
+    rt_pages_free(page, 0);
+    page = new_page;
+
+quit:
+    if (fd >= 0)
+    {
+        close(fd);
+    }
+    return page;
+}
+
 int sys_execve(const char *path, char *const argv[], char *const envp[])
 {
     int ret = -1;
     int argc = 0;
     int envc = 0;
     void *page = NULL;
+    void *new_page;
     int size = 0;
     size_t len;
     int access_err;
@@ -1632,6 +1806,7 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
     rt_thread_t thread;
     struct process_aux *aux;
     int i;
+    struct lwp_args_info args_info;
 
     lwp = lwp_self();
     thread = rt_thread_self();
@@ -1658,6 +1833,8 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
         rt_set_errno(EFAULT);
         goto quit;
     }
+
+    size += sizeof(char *);
     if (argv)
     {
         while (1)
@@ -1667,7 +1844,6 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
                 rt_set_errno(EFAULT);
                 goto quit;
             }
-            size += sizeof(char *);
             if (!argv[argc])
             {
                 break;
@@ -1678,11 +1854,11 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
                 rt_set_errno(EFAULT);
                 goto quit;
             }
-            size += len + 1;
+            size += sizeof(char *) + len + 1;
             argc++;
         }
-        size += sizeof(char *);
     }
+    size += sizeof(char *);
     if (envp)
     {
         while (1)
@@ -1692,7 +1868,6 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
                 rt_set_errno(EFAULT);
                 goto quit;
             }
-            size += sizeof(char *);
             if (!envp[envc])
             {
                 break;
@@ -1703,10 +1878,9 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
                 rt_set_errno(EFAULT);
                 goto quit;
             }
-            size += len + 1;
+            size += sizeof(char *) + len + 1;
             envc++;
         }
-        size += sizeof(char *);
     }
     if (size > ARCH_PAGE_SIZE)
     {
@@ -1728,13 +1902,10 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
     {
         for (i = 0; i < argc; i++)
         {
-            if (argv[i])
-            {
-                kargv[i] = p;
-                len = rt_strlen(argv[i]) + 1;
-                rt_memcpy(p, argv[i], len);
-                p += len;
-            }
+            kargv[i] = p;
+            len = rt_strlen(argv[i]) + 1;
+            rt_memcpy(p, argv[i], len);
+            p += len;
         }
         kargv[i] = NULL;
     }
@@ -1743,13 +1914,10 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
     {
         for (i = 0; i < envc; i++)
         {
-            if (envp[i])
-            {
-                kenvp[i] = p;
-                len = rt_strlen(envp[i]) + 1;
-                rt_memcpy(p, envp[i], len);
-                p += len;
-            }
+            kenvp[i] = p;
+            len = rt_strlen(envp[i]) + 1;
+            rt_memcpy(p, envp[i], len);
+            p += len;
         }
         kenvp[i] = NULL;
     }
@@ -1769,24 +1937,39 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
         rt_set_errno(ENOMEM);
         goto quit;
     }
-    if ((aux = lwp_argscopy(new_lwp, argc, kargv, kenvp)) == NULL)
+    /* file is a script ? */
+    args_info.argc = argc;
+    args_info.argv = kargv;
+    args_info.envc = envc;
+    args_info.envp = kenvp;
+    args_info.size = size;
+    do
+    {
+        new_page = _load_script(args_info.argv[0], &args_info);
+        if (new_page)
+        {
+            rt_pages_free(page, 0);
+            page = new_page;
+        }
+    } while (new_page);
+
+    /* now load elf */
+    if ((aux = lwp_argscopy(new_lwp, args_info.argc, args_info.argv, args_info.envp)) == NULL)
     {
         rt_set_errno(ENOMEM);
         goto quit;
     }
-    rt_pages_free(page, 0);
-    page = NULL;
-
-    ret = lwp_load(path, new_lwp, RT_NULL, 0, aux);
+    ret = lwp_load(args_info.argv[0], new_lwp, RT_NULL, 0, aux);
     if (ret == RT_EOK)
     {
         int off = 0;
         int last_backslash = 0;
+        char *run_name = args_info.argv[0];
 
         /* find last \ or / */
         while (1)
         {
-            char c = path[off++];
+            char c = run_name[off++];
 
             if (c == '\0')
             {
@@ -1801,7 +1984,9 @@ int sys_execve(const char *path, char *const argv[], char *const envp[])
         /* load ok, now set thread name and swap the data of lwp and new_lwp */
         level = rt_hw_interrupt_disable();
 
-        rt_strncpy(thread->name, path + last_backslash, RT_NAME_MAX);
+        rt_strncpy(thread->name, run_name + last_backslash, RT_NAME_MAX);
+
+        rt_pages_free(page, 0);
 
 #ifdef RT_USING_USERSPACE
         _swap_lwp_data(lwp, new_lwp, rt_mmu_info, mmu_info);