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