1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-01-12     Shell        separate argv, envp, aux processing to lwp_args.c
9  *                             Bugs fix for script arguments processing.
10  *                             support args larger than 4k
11  */
12 #include "lwp_args.h"
13 #include "lwp_internal.h"
14 #include "mm_page.h"
15 
_strvec_init(struct lwp_string_vector * sv)16 static void _strvec_init(struct lwp_string_vector *sv)
17 {
18     #define DEFAUTL_ARGV_BUFLEN 4
19     sv->strvec = rt_malloc(DEFAUTL_ARGV_BUFLEN * sizeof(char *));
20     sv->strvec_buflen = DEFAUTL_ARGV_BUFLEN;
21     sv->string_count = 0;
22 }
23 
_strvec_detach(struct lwp_string_vector * sv)24 static void _strvec_detach(struct lwp_string_vector *sv)
25 {
26     if (sv->strvec)
27     {
28         rt_free(sv->strvec);
29     }
30 }
31 
_strvec_append(struct lwp_string_vector * sv,const char * string)32 static rt_err_t _strvec_append(struct lwp_string_vector *sv, const char *string)
33 {
34     if (sv->string_count == sv->strvec_buflen)
35     {
36         void *newptr;
37         newptr = rt_realloc(sv->strvec, sv->strvec_buflen * 2 * sizeof(char *));
38         if (!newptr)
39             return -RT_ENOMEM;
40         sv->strvec = newptr;
41         sv->strvec_buflen *= 2;
42     }
43 
44     sv->strvec[sv->string_count++] = string;
45     return RT_EOK;
46 }
47 
args_append(struct lwp_args_info * ai,const char * str_addr,size_t str_len,enum lwp_args_type atype)48 static rt_err_t args_append(struct lwp_args_info *ai, const char *str_addr,
49                             size_t str_len, enum lwp_args_type atype)
50 {
51     rt_err_t error;
52     char *str_bufaddr;
53 
54     if (ai->strings_length + str_len + 1 > ai->str_buf_size)
55     {
56         /* reallocate buffer for this */
57         void *newptr;
58         newptr = rt_realloc(ai->str_buf, ai->str_buf_size * 2);
59         if (!newptr)
60             return -RT_ENOMEM;
61         ai->str_buf = newptr;
62         ai->str_buf_size *= 2;
63     }
64 
65     /* append new string to string buffer and update strings_length */
66     str_bufaddr = &ai->str_buf[ai->strings_length];
67     if (atype == LWP_ARGS_TYPE_KARG || atype == LWP_ARGS_TYPE_KENVP)
68     {
69         strcpy(str_bufaddr, str_addr);
70         ai->strings_length += str_len + 1;
71     }
72     else
73     {
74         lwp_get_from_user(str_bufaddr, (void *)str_addr, str_len);
75         ai->strings_length += str_len;
76         ai->str_buf[ai->strings_length++] = '\0';
77     }
78 
79     /* append new argument or environment */
80     switch (atype)
81     {
82         case LWP_ARGS_TYPE_ARG:
83         case LWP_ARGS_TYPE_KARG:
84             error = _strvec_append(&ai->argv, str_bufaddr);
85             if (!error && ai->argv.string_count == 1)
86             {
87                 ai->argv0_strlen = str_len;
88             }
89             break;
90         case LWP_ARGS_TYPE_ENVP:
91         case LWP_ARGS_TYPE_KENVP:
92             error = _strvec_append(&ai->envp, str_bufaddr);
93             break;
94         default:
95             break;
96     }
97     return error;
98 }
99 
100 
101 /**
102  * @brief Override arguments 0 for script interpreter.
103  *
104  * Manual: interpreter will be invoked with the following arguments:
105  *      {interpreter [optional-arg] pathname arg...}
106  * where pathname is the pathname of the file specified as the first
107  * argument of execve(), and arg...  is the series of words pointed
108  * to by the argv argument of execve(), starting at argv[1].  Note
109  * that there is no way to get the argv[0] that was passed to the
110  * execve() call.
111  */
_args_override_argv0(struct lwp_args_info * ai,struct lwp_args_info * ow_ai)112 static rt_err_t _args_override_argv0(struct lwp_args_info *ai, struct lwp_args_info *ow_ai)
113 {
114     rt_err_t error = 0;
115     int i, new_argc, new_strbuf_size, ai_bytes_tobe_copied;
116     char **new_argv, *new_strbuf, *base;
117     rt_base_t off;
118 
119     if (ow_ai == 0 || ow_ai->argv.string_count == 0)
120     {
121         return -RT_EINVAL;
122     }
123 
124     /* for new argument vector */
125     new_argc = ai->argv.string_count - 1 + ow_ai->argv.string_count;
126     new_argv = rt_malloc(new_argc * sizeof(char *));
127     if (!new_argv)
128     {
129         return -RT_ENOMEM;
130     }
131 
132     /* for new string buffer */
133     ai_bytes_tobe_copied = ai->strings_length - (ai->argv0_strlen + 1);
134     new_strbuf_size = ai_bytes_tobe_copied + ow_ai->strings_length;
135     new_strbuf = rt_malloc(new_strbuf_size);
136     if (!new_argv)
137     {
138         rt_free(new_argv);
139         return -RT_ENOMEM;
140     }
141 
142     base = new_strbuf;
143     off = base - ow_ai->str_buf;
144     /* copy overriding argument strings and argv */
145     memcpy(base, ow_ai->str_buf, ow_ai->strings_length);
146     for (i = 0; i < ow_ai->argv.string_count; i++)
147     {
148         /* base + ow_ai->argv.strvec[i] - ow_ai->str_buf */
149         new_argv[i] = (char *)ow_ai->argv.strvec[i] + off;
150     }
151 
152     base += ow_ai->strings_length;
153     off = base - (ai->str_buf + ai->argv0_strlen + 1);
154     /* copy old argument strings starting from argv[1] and setup new_argv */
155     memcpy(base, ai->str_buf + ai->argv0_strlen + 1, ai_bytes_tobe_copied);
156     for (size_t j = 1; j < ai->argv.string_count; i++, j++)
157     {
158         /* base + ai->argv->strvec[j] - ai->str_buf */
159         new_argv[i] = (char *)ai->argv.strvec[j] + off;
160     }
161 
162     /* setup envp for ai */
163     for (i = 0; i < ai->envp.string_count; i++)
164     {
165         /* base + ai->envp->strvec[i] - ai->str_buf */
166         ai->envp.strvec[i] += off;
167     }
168 
169     /* replace strings buffer and argv buffer */
170     ai->str_buf = new_strbuf;
171     ai->strings_length = new_strbuf_size;
172     ai->str_buf_size = new_strbuf_size;
173     ai->argv.string_count = new_argc;
174     ai->argv.strvec = (void *)new_argv;
175     ai->argv.strvec_buflen = new_argc;
176 
177     ai->argv0_strlen = ow_ai->argv0_strlen;
178     return error;
179 }
180 
lwp_args_get_argv_0(struct lwp_args_info * ai)181 const char *lwp_args_get_argv_0(struct lwp_args_info *ai)
182 {
183     return ai->str_buf;
184 }
185 
args_init(struct lwp_args_info * ai,size_t str_buf_size)186 static rt_err_t args_init(struct lwp_args_info *ai, size_t str_buf_size)
187 {
188     void *str_buf;
189     str_buf = rt_malloc(str_buf_size);
190     if (!str_buf)
191         return -RT_ENOMEM;
192 
193     memset(ai, 0, sizeof(*ai));
194 
195     _strvec_init(&ai->argv);
196     if (!ai->argv.strvec)
197     {
198         rt_free(str_buf);
199         return -RT_ENOMEM;
200     }
201     _strvec_init(&ai->envp);
202     if (!ai->envp.strvec)
203     {
204         rt_free(str_buf);
205         _strvec_detach(&ai->argv);
206         return -RT_ENOMEM;
207     }
208 
209     ai->str_buf_size = str_buf_size;
210     ai->str_buf = str_buf;
211     return RT_EOK;
212 }
213 
214 #define STR_BUF_DEFAULT_SIZE 2048
lwp_args_init(struct lwp_args_info * ai)215 rt_err_t lwp_args_init(struct lwp_args_info *ai)
216 {
217     return args_init(ai, STR_BUF_DEFAULT_SIZE);
218 }
219 
lwp_args_detach(struct lwp_args_info * ai)220 void lwp_args_detach(struct lwp_args_info *ai)
221 {
222     _strvec_detach(&ai->argv);
223     _strvec_detach(&ai->envp);
224     rt_free(ai->str_buf);
225 }
226 
227 #ifdef ARCH_MM_MMU
lwp_argscopy(struct rt_lwp * lwp,struct lwp_args_info * ai)228 struct process_aux *lwp_argscopy(struct rt_lwp *lwp, struct lwp_args_info *ai)
229 {
230     int size = sizeof(rt_base_t) * 4; /* store argc, argv_NULL, envp_NULL, aux_NULL */
231     char *str_ua;
232     const char **args_ua;
233     const char **iter;
234     rt_base_t off;
235     struct process_aux_item pa_item;
236     struct process_aux *aux_ua;
237     size_t prot = PROT_READ | PROT_WRITE;
238     size_t flags = MAP_FIXED | MAP_PRIVATE;
239     rt_base_t argc = ai->argv.string_count;
240     rt_base_t envc = ai->envp.string_count;
241 
242     /**
243      * counts the bytes to storage the args
244      */
245     size += argc * sizeof(char *) + envc * sizeof(char *)
246         + ai->strings_length + sizeof(struct process_aux);
247 
248     args_ua = lwp_mmap2(lwp, (void *)(USER_STACK_VEND), size, prot, flags, -1, 0);
249     if (args_ua == RT_NULL)
250     {
251         return RT_NULL;
252     }
253 
254     /**
255      * @brief Put data from args info to user space
256      * argc, argv[], NULL, envp[], NULL, aux[], NULL, strings
257      */
258     iter = args_ua;
259 
260     /* argc */
261     lwp_data_put(lwp, iter++, &argc, sizeof(char *));
262 
263     /* strings */
264     str_ua = (char *)((rt_ubase_t)args_ua +
265         (1 + argc + 1 + envc + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(rt_base_t));
266     lwp_data_put(lwp, str_ua, ai->str_buf, ai->strings_length);
267 
268     /* argv */
269     off = str_ua - ai->str_buf;
270     for (size_t i = 0; i < argc; i++)
271     {
272         /* str_ua + ai->argv.strvec[i] - ai->str_buf */
273         ai->argv.strvec[i] += off;
274     }
275     lwp_data_put(lwp, iter, ai->argv.strvec, sizeof(char *) * ai->argv.string_count);
276     iter += ai->argv.string_count;
277 
278     /* NULL */
279     lwp_data_set(lwp, iter++, 0, sizeof(char *));
280 
281     /* envp */
282     for (size_t i = 0; i < envc; i++)
283     {
284         /* str_ua + ai->envp.strvec[i] - ai->str_buf */
285         ai->envp.strvec[i] += off;
286     }
287     lwp_data_put(lwp, iter, ai->envp.strvec, sizeof(char *) * ai->envp.string_count);
288     iter += ai->envp.string_count;
289 
290     /* NULL */
291     lwp_data_set(lwp, iter++, 0, sizeof(char *));
292 
293     /* aux */
294     aux_ua = (struct process_aux *)iter;
295     pa_item.key = AT_EXECFN;
296     pa_item.value = (size_t)str_ua;
297     lwp_data_put(lwp, iter, &pa_item, sizeof(pa_item));
298     iter += AUX_ARRAY_ITEMS_NR * 2;
299 
300     /* NULL */
301     lwp_data_set(lwp, iter++, 0, sizeof(char *));
302 
303     lwp->args = args_ua;
304 
305     return aux_ua;
306 }
307 #else
lwp_argscopy(struct rt_lwp * lwp,int argc,char ** argv,char ** envp)308 static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
309 {
310 #ifdef ARCH_MM_MMU
311     int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */
312     struct process_aux *aux;
313 #else
314     int size = sizeof(int) * 4; /* store argc, argv, envp, NULL */
315 #endif /* ARCH_MM_MMU */
316     int *args;
317     char *str;
318     char **new_argve;
319     int i;
320     int len;
321 
322     for (i = 0; i < argc; i++)
323     {
324         size += (rt_strlen(argv[i]) + 1);
325     }
326     size += (sizeof(int) * argc);
327 
328     i = 0;
329     if (envp)
330     {
331         while (envp[i] != 0)
332         {
333             size += (rt_strlen(envp[i]) + 1);
334             size += sizeof(int);
335             i++;
336         }
337     }
338 
339 #ifdef ARCH_MM_MMU
340     /* for aux */
341     size += sizeof(struct process_aux);
342 
343     args = (int *)rt_malloc(size);
344     if (args == RT_NULL)
345     {
346         return RT_NULL;
347     }
348 
349     /* argc, argv[], 0, envp[], 0 */
350     str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int));
351 #else
352     args = (int *)rt_malloc(size);
353     if (args == RT_NULL)
354     {
355         return RT_NULL;
356     }
357     str = (char*)((int)args + (argc + 2 + i + 1) * sizeof(int));
358 #endif /* ARCH_MM_MMU */
359 
360     new_argve = (char **)&args[1];
361     args[0] = argc;
362 
363     for (i = 0; i < argc; i++)
364     {
365         len = rt_strlen(argv[i]) + 1;
366         new_argve[i] = str;
367         lwp_memcpy(str, argv[i], len);
368         str += len;
369     }
370     new_argve[i] = 0;
371     i++;
372 
373     new_argve[i] = 0;
374     if (envp)
375     {
376         int j;
377         for (j = 0; envp[j] != 0; j++)
378         {
379             len = rt_strlen(envp[j]) + 1;
380             new_argve[i] = str;
381             lwp_memcpy(str, envp[j], len);
382             str += len;
383             i++;
384         }
385         new_argve[i] = 0;
386     }
387 #ifdef ARCH_MM_MMU
388     /* aux */
389     aux = (struct process_aux *)(new_argve + i);
390     aux->item[0].key = AT_EXECFN;
391     aux->item[0].value = (uint32_t)(size_t)new_argve[0];
392     i += AUX_ARRAY_ITEMS_NR * 2;
393     new_argve[i] = 0;
394 
395     lwp->args = args;
396 
397     return aux;
398 #else
399     lwp->args = args;
400     lwp->args_length = size;
401 
402     return (struct process_aux *)(new_argve + i);
403 #endif /* ARCH_MM_MMU */
404 }
405 #endif
406 
lwp_args_put(struct lwp_args_info * args,const char ** strv_addr,enum lwp_args_type atype)407 rt_err_t lwp_args_put(struct lwp_args_info *args, const char **strv_addr, enum lwp_args_type atype)
408 {
409     rt_err_t error;
410     int iter = 0;
411     int len;
412     const char *arg_ptr;
413 
414     while (1)
415     {
416         if (atype == LWP_ARGS_TYPE_ARG || atype == LWP_ARGS_TYPE_ENVP)
417         {
418             len = lwp_get_from_user(&arg_ptr, strv_addr + iter++, sizeof(char *));
419             if (len != sizeof(char *))
420             {
421                 return -EFAULT;
422             }
423             if (arg_ptr == NULL)
424             {
425                 break;
426             }
427             len = lwp_user_strlen(arg_ptr);
428             if (len < 0)
429             {
430                 return -EFAULT;
431             }
432         }
433         else
434         {
435             arg_ptr = strv_addr[iter++];
436             if (arg_ptr == NULL)
437             {
438                 break;
439             }
440             len = strlen(arg_ptr);
441         }
442 
443         error = args_append(args, arg_ptr, len, atype);
444         if (error)
445         {
446             return error;
447         }
448     }
449     return 0;
450 }
451 
452 /**
453  * @brief Put argument vector to args object
454  */
lwp_args_put_argv(struct lwp_args_info * args,const char ** argv_uaddr)455 rt_err_t lwp_args_put_argv(struct lwp_args_info *args, const char **argv_uaddr)
456 {
457     return lwp_args_put(args, argv_uaddr, LWP_ARGS_TYPE_ARG);
458 }
459 
460 /**
461  * @brief Put argument vector to args object
462  */
lwp_args_put_envp(struct lwp_args_info * args,const char ** envp_uaddr)463 rt_err_t lwp_args_put_envp(struct lwp_args_info *args, const char **envp_uaddr)
464 {
465     return lwp_args_put(args, envp_uaddr, LWP_ARGS_TYPE_ENVP);
466 }
467 
468 /**
469  * read words until reach nextline or EOF.
470  * words copied into buffer is never truncated.
471  */
472 #define READFILE_STAT_EOF_REACHED           0
473 #define READFILE_STAT_NEXTLINE_REACHED      0
474 #define READFILE_STAT_TRUNCATED             1
475 #define READFILE_STAT_CAN_READMORE(stat)    (stat)
_readfile(int fd,size_t maxbytes,char * buffer,int * p_readlen)476 static int _readfile(int fd, size_t maxbytes, char *buffer, int *p_readlen)
477 {
478     int readlen;
479     int stat;
480     char *nlp;
481 
482     readlen = read(fd, buffer, maxbytes - 1);
483     if (readlen <= 0)
484     {
485         /* eof, failed */
486         stat = READFILE_STAT_EOF_REACHED;
487         buffer[0] = '\0';
488     }
489     else
490     {
491         if ((nlp = strchr(buffer, '\n')) == NULL)
492         {
493             if (readlen == maxbytes - 1)
494             {
495                 int tailing_wordlen = 0;
496                 char *cp = buffer + readlen - 1;
497                 for (; *cp && *cp != ' ' && *cp != '\t'; cp--, tailing_wordlen++)
498                     ;
499                 if (tailing_wordlen)
500                 {
501                     lseek(fd, -tailing_wordlen, SEEK_CUR);
502                     readlen -= tailing_wordlen;
503                     stat = READFILE_STAT_TRUNCATED;
504                 }
505                 else
506                 {
507                     stat = READFILE_STAT_EOF_REACHED;
508                 }
509             }
510             else
511             {
512                 stat = READFILE_STAT_EOF_REACHED;
513             }
514         }
515         else
516         {
517             stat = READFILE_STAT_NEXTLINE_REACHED;
518             readlen = nlp - buffer;
519         }
520         buffer[readlen] = '\0';
521     }
522 
523     if (p_readlen)
524         *p_readlen = readlen;
525     return stat;
526 }
527 
_find_word(char * cp)528 static char *_find_word(char *cp)
529 {
530     for (; (*cp == ' ') || (*cp == '\t'); cp++)
531         ;
532     return cp;
533 }
534 
_seperate_and_get_nextword(char * cp)535 static char *_seperate_and_get_nextword(char *cp)
536 {
537     /* find next whitespace */
538     for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
539         ;
540     /* seperate words */
541     while ((*cp == ' ') || (*cp == '\t'))
542     {
543         *cp++ = '\0';
544     }
545     return cp;
546 }
547 
548 #define INTERP_BUF_SIZE 128
lwp_args_load_script(struct lwp_args_info * ai,const char * filename)549 rt_err_t lwp_args_load_script(struct lwp_args_info *ai, const char *filename)
550 {
551     rt_err_t error = -1;
552     int fd = -RT_ERROR;
553     int len;
554     int rf_stat;
555     char interp[INTERP_BUF_SIZE];
556     char *cp, *nextword;
557     char script_magic[2];
558     struct lwp_args_info ow_ai = {0};
559 
560     fd = open(filename, O_BINARY | O_RDONLY, 0);
561     if (fd < 0)
562     {
563         goto quit;
564     }
565 
566     /**
567      * verify an interpreter script by matching script file magic
568      * eg: #!/bin/sh
569      */
570     len = read(fd, script_magic, sizeof(script_magic));
571     if (len != 2 || memcmp(script_magic, "#!", sizeof(script_magic)))
572     {
573         goto quit;
574     }
575 
576     /* setup a new args struct to save script arguments */
577     if (args_init(&ow_ai, INTERP_BUF_SIZE))
578     {
579         goto quit;
580     }
581 
582     while (1)
583     {
584         /* read file to buffer (avoid any truncated words in buffer) */
585         rf_stat = _readfile(fd, INTERP_BUF_SIZE, interp, &len);
586         if (len <= 0)
587         {
588             goto quit;
589         }
590 
591         /* find first word until reaching nil */
592         cp = _find_word(interp);
593         if (*cp == '\0')
594         {
595             if (READFILE_STAT_CAN_READMORE(rf_stat))
596                 continue;
597             else
598                 break;
599         }
600 
601         do
602         {
603             nextword = _seperate_and_get_nextword(cp);
604             args_append(&ow_ai, cp, strlen(cp), LWP_ARGS_TYPE_KARG);
605             cp = nextword;
606         }
607         while (*cp);
608 
609         if (READFILE_STAT_CAN_READMORE(rf_stat))
610             continue;
611         else
612             break;
613     }
614 
615     if (ow_ai.argv.string_count == 0)
616     {
617         goto quit; /* No interpreter name found */
618     }
619 
620     args_append(&ow_ai, filename, strlen(filename), LWP_ARGS_TYPE_KARG);
621     error = _args_override_argv0(ai, &ow_ai);
622     if (error)
623     {
624         goto quit;
625     }
626 
627 quit:
628     lwp_args_detach(&ow_ai);
629     if (fd >= 0)
630     {
631         close(fd);
632     }
633     return error;
634 }
635 
lwp_get_command_line_args(struct rt_lwp * lwp)636 char **lwp_get_command_line_args(struct rt_lwp *lwp)
637 {
638     size_t argc = 0;
639     char **argv = NULL;
640     int ret;
641     size_t i;
642     size_t len;
643 
644     if (lwp)
645     {
646         ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
647         if (ret == 0)
648         {
649             return RT_NULL;
650         }
651         argv = (char**)rt_calloc((argc + 1), sizeof(char*));
652 
653         if (argv)
654         {
655             for (i = 0; i < argc; i++)
656             {
657                 char *argvp = NULL;
658                 ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp));
659                 if (ret == 0)
660                 {
661                     goto error_exit;
662                 }
663 
664                 len = lwp_user_strlen_ext(lwp, argvp);
665                 if (len >= 0)
666                 {
667                     argv[i] = (char*)rt_malloc(len + 1);
668                     ret = lwp_data_get(lwp, argv[i], argvp, len);
669                     if (ret != len)
670                     {
671                         goto error_exit;
672                     }
673                     argv[i][len] = '\0';
674                 }
675                 else
676                 {
677                     goto error_exit;
678                 }
679             }
680             argv[argc] = NULL;
681         }
682     }
683 
684     return argv;
685 error_exit:
686     lwp_free_command_line_args(argv);
687     return RT_NULL;
688 }
689 
lwp_print_envp(struct rt_lwp * lwp)690 void lwp_print_envp(struct rt_lwp *lwp)
691 {
692     rt_size_t envp_counts;
693     char **kenvp_array = lwp_get_envp(lwp, &envp_counts);
694     if (kenvp_array)
695     {
696         rt_kprintf("envp_counts: %d\n", envp_counts);
697         for (size_t i = 0; i < envp_counts; i++)
698         {
699             rt_kprintf("envp[%d]: %s\n", i, kenvp_array[i]);
700         }
701     }
702     lwp_free_command_line_args(kenvp_array);
703     return ;
704 }
705 
lwp_get_envp(struct rt_lwp * lwp,rt_size_t * penvp_counts)706 char** lwp_get_envp(struct rt_lwp *lwp, rt_size_t *penvp_counts)
707 {
708     int ret, len;
709     rt_base_t argc;
710     char **p_kenvp = RT_NULL;
711     char *envp, **p_envp;
712     size_t envp_counts = 0;
713 
714     if (lwp)
715     {
716         ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
717         if (ret == 0)
718         {
719             return RT_NULL;
720         }
721         p_envp = (char **)lwp->args + 1 + argc + 1;
722 
723         /* counts envp */
724         while (lwp_data_get(lwp, &envp, p_envp, sizeof(void *)) == sizeof(void *)
725                && envp != NULL)
726         {
727             p_envp++;
728             envp_counts++;
729         }
730 
731         p_kenvp = (char **)rt_malloc((envp_counts + 1) * sizeof(char *));
732         if (p_kenvp)
733         {
734             /* copy env from envp array */
735             p_envp =  (char **)lwp->args + 1 + argc + 1;
736             for (size_t i = 0; i < envp_counts; i++)
737             {
738                 ret = lwp_data_get(lwp, &envp, &p_envp[i], sizeof(char *));
739                 if (ret != sizeof(char **))
740                 {
741                     lwp_free_command_line_args(p_kenvp);
742                     return RT_NULL;
743                 }
744 
745                 len = lwp_user_strlen_ext(lwp, envp);
746                 if (len > 0)
747                 {
748                     p_kenvp[i] = (char*)rt_malloc(len + 1);
749                     ret = lwp_data_get(lwp, p_kenvp[i], envp, len + 1);
750                     if (ret != len + 1)
751                     {
752                         lwp_free_command_line_args(p_kenvp);
753                         return RT_NULL;
754                     }
755                 }
756                 else
757                 {
758                     p_kenvp[i] = NULL;
759                 }
760             }
761             if (penvp_counts)
762                 *penvp_counts = envp_counts;
763             p_kenvp[envp_counts] = NULL;
764         }
765     }
766 
767     return p_kenvp;
768 }
769 
lwp_free_command_line_args(char ** argv)770 void lwp_free_command_line_args(char** argv)
771 {
772     size_t i;
773 
774     if (argv)
775     {
776         for (i = 0; argv[i]; i++)
777         {
778             rt_free(argv[i]);
779         }
780         rt_free(argv);
781     }
782 }
783