lwp_args.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. /*
  2. * Copyright (c) 2006-2025 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. /**
  16. * @brief Initializes a string vector structure with default buffer size
  17. *
  18. * @param[out] sv Pointer to the string vector structure to initialize
  19. */
  20. static void _strvec_init(struct lwp_string_vector *sv)
  21. {
  22. #define DEFAUTL_ARGV_BUFLEN 4
  23. sv->strvec = rt_malloc(DEFAUTL_ARGV_BUFLEN * sizeof(char *));
  24. sv->strvec_buflen = DEFAUTL_ARGV_BUFLEN;
  25. sv->string_count = 0;
  26. }
  27. /**
  28. * @brief Detaches and frees memory from a string vector structure
  29. *
  30. * @param[in,out] sv Pointer to the string vector structure to detach
  31. */
  32. static void _strvec_detach(struct lwp_string_vector *sv)
  33. {
  34. if (sv->strvec)
  35. {
  36. rt_free(sv->strvec);
  37. }
  38. }
  39. /**
  40. * @brief Appends a string to a string vector structure
  41. *
  42. * @param[in,out] sv Pointer to the string vector structure
  43. * @param[in] string String to append to the vector
  44. *
  45. * @return rt_err_t RT_EOK on success, -RT_ENOMEM on memory allocation failure
  46. *
  47. * @note This function dynamically grows the string vector's buffer into 2 times its current size
  48. * if buffer is full.
  49. */
  50. static rt_err_t _strvec_append(struct lwp_string_vector *sv, const char *string)
  51. {
  52. if (sv->string_count == sv->strvec_buflen)
  53. {
  54. void *newptr;
  55. newptr = rt_realloc(sv->strvec, sv->strvec_buflen * 2 * sizeof(char *));
  56. if (!newptr)
  57. return -RT_ENOMEM;
  58. sv->strvec = newptr;
  59. sv->strvec_buflen *= 2;
  60. }
  61. sv->strvec[sv->string_count++] = string;
  62. return RT_EOK;
  63. }
  64. /**
  65. * @brief Appends an argument or environment variable to the LWP arguments info structure
  66. *
  67. * @param[in,out] ai Pointer to the arguments info structure
  68. * @param[in] str_addr Address of the string to append (user or kernel space)
  69. * @param[in] str_len Length of the string to append
  70. * @param[in] atype Type of argument being appended (LWP_ARGS_TYPE_*)
  71. *
  72. * @return rt_err_t RT_EOK on success, -RT_ENOMEM on memory allocation failure
  73. *
  74. * @note This function handles both kernel-space and user-space strings, dynamically
  75. * growing the string buffer into 2 times its current size if buffer is full.
  76. */
  77. static rt_err_t args_append(struct lwp_args_info *ai, const char *str_addr,
  78. size_t str_len, enum lwp_args_type atype)
  79. {
  80. rt_err_t error;
  81. char *str_bufaddr;
  82. if (ai->strings_length + str_len + 1 > ai->str_buf_size)
  83. {
  84. /* reallocate buffer for this */
  85. void *newptr;
  86. newptr = rt_realloc(ai->str_buf, ai->str_buf_size * 2);
  87. if (!newptr)
  88. return -RT_ENOMEM;
  89. ai->str_buf = newptr;
  90. ai->str_buf_size *= 2;
  91. }
  92. /* append new string to string buffer and update strings_length */
  93. str_bufaddr = &ai->str_buf[ai->strings_length];
  94. if (atype == LWP_ARGS_TYPE_KARG || atype == LWP_ARGS_TYPE_KENVP)
  95. {
  96. strcpy(str_bufaddr, str_addr);
  97. ai->strings_length += str_len + 1;
  98. }
  99. else
  100. {
  101. lwp_get_from_user(str_bufaddr, (void *)str_addr, str_len);
  102. ai->strings_length += str_len;
  103. ai->str_buf[ai->strings_length++] = '\0';
  104. }
  105. /* append new argument or environment */
  106. switch (atype)
  107. {
  108. case LWP_ARGS_TYPE_ARG:
  109. case LWP_ARGS_TYPE_KARG:
  110. error = _strvec_append(&ai->argv, str_bufaddr);
  111. if (!error && ai->argv.string_count == 1)
  112. {
  113. ai->argv0_strlen = str_len;
  114. }
  115. break;
  116. case LWP_ARGS_TYPE_ENVP:
  117. case LWP_ARGS_TYPE_KENVP:
  118. error = _strvec_append(&ai->envp, str_bufaddr);
  119. break;
  120. default:
  121. break;
  122. }
  123. return error;
  124. }
  125. /**
  126. * @brief Override arguments 0 for script interpreter.
  127. *
  128. * @param[in,out] ai Pointer to the target argument info structure to be modified.
  129. * @param[in] ow_ai Pointer to the source argument info structure containing arguments to override
  130. * argv[0] with.
  131. *
  132. * @return rt_err_t RT_EOK on success, -RT_EINVAL for invalid input, -RT_ENOMEM on memory allocation failure
  133. *
  134. * @note Manual: interpreter will be invoked with the following arguments:
  135. * {interpreter [optional-arg] pathname arg...}
  136. * where pathname is the pathname of the file specified as the first
  137. * argument of execve(), and arg... is the series of words pointed
  138. * to by the argv argument of execve(), starting at argv[1]. Note
  139. * that there is no way to get the argv[0] that was passed to the
  140. * execve() call.
  141. */
  142. static rt_err_t _args_override_argv0(struct lwp_args_info *ai, struct lwp_args_info *ow_ai)
  143. {
  144. rt_err_t error = 0;
  145. int i, new_argc, new_strbuf_size, ai_bytes_tobe_copied;
  146. char **new_argv, *new_strbuf, *base;
  147. rt_base_t off;
  148. if (ow_ai == 0 || ow_ai->argv.string_count == 0)
  149. {
  150. return -RT_EINVAL;
  151. }
  152. /* for new argument vector */
  153. new_argc = ai->argv.string_count - 1 + ow_ai->argv.string_count;
  154. new_argv = rt_malloc(new_argc * sizeof(char *));
  155. if (!new_argv)
  156. {
  157. return -RT_ENOMEM;
  158. }
  159. /* for new string buffer */
  160. ai_bytes_tobe_copied = ai->strings_length - (ai->argv0_strlen + 1);
  161. new_strbuf_size = ai_bytes_tobe_copied + ow_ai->strings_length;
  162. new_strbuf = rt_malloc(new_strbuf_size);
  163. if (!new_argv)
  164. {
  165. rt_free(new_argv);
  166. return -RT_ENOMEM;
  167. }
  168. base = new_strbuf;
  169. off = base - ow_ai->str_buf;
  170. /* copy overriding argument strings and argv */
  171. memcpy(base, ow_ai->str_buf, ow_ai->strings_length);
  172. for (i = 0; i < ow_ai->argv.string_count; i++)
  173. {
  174. /* base + ow_ai->argv.strvec[i] - ow_ai->str_buf */
  175. new_argv[i] = (char *)ow_ai->argv.strvec[i] + off;
  176. }
  177. base += ow_ai->strings_length;
  178. off = base - (ai->str_buf + ai->argv0_strlen + 1);
  179. /* copy old argument strings starting from argv[1] and setup new_argv */
  180. memcpy(base, ai->str_buf + ai->argv0_strlen + 1, ai_bytes_tobe_copied);
  181. for (size_t j = 1; j < ai->argv.string_count; i++, j++)
  182. {
  183. /* base + ai->argv->strvec[j] - ai->str_buf */
  184. new_argv[i] = (char *)ai->argv.strvec[j] + off;
  185. }
  186. /* setup envp for ai */
  187. for (i = 0; i < ai->envp.string_count; i++)
  188. {
  189. /* base + ai->envp->strvec[i] - ai->str_buf */
  190. ai->envp.strvec[i] += off;
  191. }
  192. /* replace strings buffer and argv buffer */
  193. ai->str_buf = new_strbuf;
  194. ai->strings_length = new_strbuf_size;
  195. ai->str_buf_size = new_strbuf_size;
  196. ai->argv.string_count = new_argc;
  197. ai->argv.strvec = (void *)new_argv;
  198. ai->argv.strvec_buflen = new_argc;
  199. ai->argv0_strlen = ow_ai->argv0_strlen;
  200. return error;
  201. }
  202. /**
  203. * @brief Get argument 0.
  204. *
  205. * @param[in] ai Pointer to the argument info structure.
  206. *
  207. * @return const char* Pointer to the arguments 0.
  208. */
  209. const char *lwp_args_get_argv_0(struct lwp_args_info *ai)
  210. {
  211. return ai->str_buf;
  212. }
  213. /**
  214. * @brief implementation for initializing a light-weight process arguments info structure
  215. *
  216. * @param[in,out] ai Pointer to the arguments info structure to initialize
  217. * @param[in] str_buf_size Size of the string buffer to allocate
  218. *
  219. * @return rt_err_t
  220. * - RT_EOK on successful initialization
  221. * - -RT_ENOMEM if memory allocation fails
  222. */
  223. static rt_err_t args_init(struct lwp_args_info *ai, size_t str_buf_size)
  224. {
  225. void *str_buf;
  226. str_buf = rt_malloc(str_buf_size);
  227. if (!str_buf)
  228. return -RT_ENOMEM;
  229. memset(ai, 0, sizeof(*ai));
  230. _strvec_init(&ai->argv);
  231. if (!ai->argv.strvec)
  232. {
  233. rt_free(str_buf);
  234. return -RT_ENOMEM;
  235. }
  236. _strvec_init(&ai->envp);
  237. if (!ai->envp.strvec)
  238. {
  239. rt_free(str_buf);
  240. _strvec_detach(&ai->argv);
  241. return -RT_ENOMEM;
  242. }
  243. ai->str_buf_size = str_buf_size;
  244. ai->str_buf = str_buf;
  245. return RT_EOK;
  246. }
  247. #define STR_BUF_DEFAULT_SIZE 2048
  248. /**
  249. * @brief Initialize a light-weight process arguments info structure
  250. *
  251. * @param[in,out] ai Pointer to the arguments info structure to initialize
  252. *
  253. * @return rt_err_t
  254. * - RT_EOK on successful initialization
  255. * - -RT_ENOMEM if memory allocation fails
  256. *
  257. * @see args_init
  258. */
  259. rt_err_t lwp_args_init(struct lwp_args_info *ai)
  260. {
  261. return args_init(ai, STR_BUF_DEFAULT_SIZE);
  262. }
  263. /**
  264. * @brief Detach a light-weight process arguments info structure
  265. *
  266. * @param[in,out] ai Pointer to the arguments info structure to detach
  267. */
  268. void lwp_args_detach(struct lwp_args_info *ai)
  269. {
  270. _strvec_detach(&ai->argv);
  271. _strvec_detach(&ai->envp);
  272. rt_free(ai->str_buf);
  273. }
  274. #ifdef ARCH_MM_MMU
  275. /**
  276. * @brief Copy a light-weight process arguments info structure to user space
  277. *
  278. * @param[in] lwp Pointer to the light-weight process structure
  279. * @param[in] ai Pointer to the arguments info structure to copy
  280. *
  281. * @return struct process_aux* Pointer to the process auxiliary structure in user space
  282. */
  283. struct process_aux *lwp_argscopy(struct rt_lwp *lwp, struct lwp_args_info *ai)
  284. {
  285. int size = sizeof(rt_base_t) * 4; /* store argc, argv_NULL, envp_NULL, aux_NULL */
  286. char *str_ua;
  287. const char **args_ua;
  288. const char **iter;
  289. rt_base_t off;
  290. struct process_aux_item pa_item;
  291. struct process_aux *aux_ua;
  292. size_t prot = PROT_READ | PROT_WRITE;
  293. size_t flags = MAP_FIXED | MAP_PRIVATE;
  294. rt_base_t argc = ai->argv.string_count;
  295. rt_base_t envc = ai->envp.string_count;
  296. /**
  297. * counts the bytes to storage the args
  298. */
  299. size += argc * sizeof(char *) + envc * sizeof(char *)
  300. + ai->strings_length + sizeof(struct process_aux);
  301. args_ua = lwp_mmap2(lwp, (void *)(USER_STACK_VEND), size, prot, flags, -1, 0);
  302. if (args_ua == RT_NULL)
  303. {
  304. return RT_NULL;
  305. }
  306. /**
  307. * @brief Put data from args info to user space
  308. * argc, argv[], NULL, envp[], NULL, aux[], NULL, strings
  309. */
  310. iter = args_ua;
  311. /* argc */
  312. lwp_data_put(lwp, iter++, &argc, sizeof(char *));
  313. /* strings */
  314. str_ua = (char *)((rt_ubase_t)args_ua +
  315. (1 + argc + 1 + envc + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(rt_base_t));
  316. lwp_data_put(lwp, str_ua, ai->str_buf, ai->strings_length);
  317. /* argv */
  318. off = str_ua - ai->str_buf;
  319. for (size_t i = 0; i < argc; i++)
  320. {
  321. /* str_ua + ai->argv.strvec[i] - ai->str_buf */
  322. ai->argv.strvec[i] += off;
  323. }
  324. lwp_data_put(lwp, iter, ai->argv.strvec, sizeof(char *) * ai->argv.string_count);
  325. iter += ai->argv.string_count;
  326. /* NULL */
  327. lwp_data_set(lwp, iter++, 0, sizeof(char *));
  328. /* envp */
  329. for (size_t i = 0; i < envc; i++)
  330. {
  331. /* str_ua + ai->envp.strvec[i] - ai->str_buf */
  332. ai->envp.strvec[i] += off;
  333. }
  334. lwp_data_put(lwp, iter, ai->envp.strvec, sizeof(char *) * ai->envp.string_count);
  335. iter += ai->envp.string_count;
  336. /* NULL */
  337. lwp_data_set(lwp, iter++, 0, sizeof(char *));
  338. /* aux */
  339. aux_ua = (struct process_aux *)iter;
  340. pa_item.key = AT_EXECFN;
  341. pa_item.value = (size_t)str_ua;
  342. lwp_data_put(lwp, iter, &pa_item, sizeof(pa_item));
  343. iter += AUX_ARRAY_ITEMS_NR * 2;
  344. /* NULL */
  345. lwp_data_set(lwp, iter++, 0, sizeof(char *));
  346. lwp->args = args_ua;
  347. return aux_ua;
  348. }
  349. #else
  350. static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
  351. {
  352. #ifdef ARCH_MM_MMU
  353. int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */
  354. struct process_aux *aux;
  355. #else
  356. int size = sizeof(int) * 4; /* store argc, argv, envp, NULL */
  357. #endif /* ARCH_MM_MMU */
  358. int *args;
  359. char *str;
  360. char **new_argve;
  361. int i;
  362. int len;
  363. for (i = 0; i < argc; i++)
  364. {
  365. size += (rt_strlen(argv[i]) + 1);
  366. }
  367. size += (sizeof(int) * argc);
  368. i = 0;
  369. if (envp)
  370. {
  371. while (envp[i] != 0)
  372. {
  373. size += (rt_strlen(envp[i]) + 1);
  374. size += sizeof(int);
  375. i++;
  376. }
  377. }
  378. #ifdef ARCH_MM_MMU
  379. /* for aux */
  380. size += sizeof(struct process_aux);
  381. args = (int *)rt_malloc(size);
  382. if (args == RT_NULL)
  383. {
  384. return RT_NULL;
  385. }
  386. /* argc, argv[], 0, envp[], 0 */
  387. str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int));
  388. #else
  389. args = (int *)rt_malloc(size);
  390. if (args == RT_NULL)
  391. {
  392. return RT_NULL;
  393. }
  394. str = (char*)((int)args + (argc + 2 + i + 1) * sizeof(int));
  395. #endif /* ARCH_MM_MMU */
  396. new_argve = (char **)&args[1];
  397. args[0] = argc;
  398. for (i = 0; i < argc; i++)
  399. {
  400. len = rt_strlen(argv[i]) + 1;
  401. new_argve[i] = str;
  402. lwp_memcpy(str, argv[i], len);
  403. str += len;
  404. }
  405. new_argve[i] = 0;
  406. i++;
  407. new_argve[i] = 0;
  408. if (envp)
  409. {
  410. int j;
  411. for (j = 0; envp[j] != 0; j++)
  412. {
  413. len = rt_strlen(envp[j]) + 1;
  414. new_argve[i] = str;
  415. lwp_memcpy(str, envp[j], len);
  416. str += len;
  417. i++;
  418. }
  419. new_argve[i] = 0;
  420. }
  421. #ifdef ARCH_MM_MMU
  422. /* aux */
  423. aux = (struct process_aux *)(new_argve + i);
  424. aux->item[0].key = AT_EXECFN;
  425. aux->item[0].value = (uint32_t)(size_t)new_argve[0];
  426. i += AUX_ARRAY_ITEMS_NR * 2;
  427. new_argve[i] = 0;
  428. lwp->args = args;
  429. return aux;
  430. #else
  431. lwp->args = args;
  432. lwp->args_length = size;
  433. return (struct process_aux *)(new_argve + i);
  434. #endif /* ARCH_MM_MMU */
  435. }
  436. #endif
  437. /**
  438. * @brief Put arguments or environment variables into LWP arguments info structure
  439. *
  440. * @param[in,out] args Pointer to the lwp_args_info structure to store the arguments
  441. * @param[in] strv_addr Pointer to the string array (argv/envp) to be processed
  442. * @param[in] atype Type of arguments being processed (LWP_ARGS_TYPE_ARG/LWP_ARGS_TYPE_ENVP)
  443. *
  444. * @return rt_err_t
  445. * - RT_EOK on success
  446. * - -EFAULT if user-space string access fails
  447. * - Other errors from args_append() if memory allocation fails
  448. */
  449. rt_err_t lwp_args_put(struct lwp_args_info *args, const char **strv_addr, enum lwp_args_type atype)
  450. {
  451. rt_err_t error;
  452. int iter = 0;
  453. int len;
  454. const char *arg_ptr;
  455. while (1)
  456. {
  457. if (atype == LWP_ARGS_TYPE_ARG || atype == LWP_ARGS_TYPE_ENVP)
  458. {
  459. len = lwp_get_from_user(&arg_ptr, strv_addr + iter++, sizeof(char *));
  460. if (len != sizeof(char *))
  461. {
  462. return -EFAULT;
  463. }
  464. if (arg_ptr == NULL)
  465. {
  466. break;
  467. }
  468. len = lwp_user_strlen(arg_ptr);
  469. if (len < 0)
  470. {
  471. return -EFAULT;
  472. }
  473. }
  474. else
  475. {
  476. arg_ptr = strv_addr[iter++];
  477. if (arg_ptr == NULL)
  478. {
  479. break;
  480. }
  481. len = strlen(arg_ptr);
  482. }
  483. error = args_append(args, arg_ptr, len, atype);
  484. if (error)
  485. {
  486. return error;
  487. }
  488. }
  489. return 0;
  490. }
  491. /**
  492. * @brief Put command line arguments into LWP arguments info structure
  493. *
  494. * @param[in,out] args Pointer to the lwp_args_info structure to store the arguments
  495. * @param[in] argv_uaddr Pointer to the string array (argv) to be processed
  496. *
  497. * @return rt_err_t
  498. * - RT_EOK on success
  499. * - -EFAULT if user-space string access fails
  500. * - Other errors from args_append() if memory allocation fails
  501. */
  502. rt_err_t lwp_args_put_argv(struct lwp_args_info *args, const char **argv_uaddr)
  503. {
  504. return lwp_args_put(args, argv_uaddr, LWP_ARGS_TYPE_ARG);
  505. }
  506. /**
  507. * @brief Put environment variables into LWP arguments info structure
  508. *
  509. * @param[in,out] args Pointer to the lwp_args_info structure to store the arguments
  510. * @param[in] envp_uaddr Pointer to the string array (envp) to be processed
  511. *
  512. * @return rt_err_t
  513. * - RT_EOK on success
  514. * - -EFAULT if user-space string access fails
  515. * - Other errors from args_append() if memory allocation fails
  516. */
  517. rt_err_t lwp_args_put_envp(struct lwp_args_info *args, const char **envp_uaddr)
  518. {
  519. return lwp_args_put(args, envp_uaddr, LWP_ARGS_TYPE_ENVP);
  520. }
  521. /**
  522. * read words until reach nextline or EOF.
  523. * words copied into buffer is never truncated.
  524. */
  525. #define READFILE_STAT_EOF_REACHED 0
  526. #define READFILE_STAT_NEXTLINE_REACHED 0
  527. #define READFILE_STAT_TRUNCATED 1
  528. #define READFILE_STAT_CAN_READMORE(stat) (stat)
  529. /**
  530. * @brief Read data from a file descriptor with line handling
  531. *
  532. * @param[in] fd File descriptor to read from
  533. * @param[in] maxbytes Maximum bytes to read (buffer size - 1)
  534. * @param[out] buffer Output buffer for the read data (null-terminated)
  535. * @param[out] p_readlen Pointer to store actual bytes read (optional)
  536. *
  537. * @return int Status code:
  538. * - READFILE_STAT_NEXTLINE_REACHED when newline found
  539. * - READFILE_STAT_TRUNCATED when line truncated at word boundary
  540. * - READFILE_STAT_EOF_REACHED when EOF or error occurs
  541. *
  542. * @note Reads data from a file descriptor into a buffer, handling newlines and
  543. * truncating long lines while preserving word boundaries. Manages file
  544. * position for partial reads.
  545. */
  546. static int _readfile(int fd, size_t maxbytes, char *buffer, int *p_readlen)
  547. {
  548. int readlen;
  549. int stat;
  550. char *nlp;
  551. readlen = read(fd, buffer, maxbytes - 1);
  552. if (readlen <= 0)
  553. {
  554. /* eof, failed */
  555. stat = READFILE_STAT_EOF_REACHED;
  556. buffer[0] = '\0';
  557. }
  558. else
  559. {
  560. if ((nlp = strchr(buffer, '\n')) == NULL)
  561. {
  562. if (readlen == maxbytes - 1)
  563. {
  564. int tailing_wordlen = 0;
  565. char *cp = buffer + readlen - 1;
  566. for (; *cp && *cp != ' ' && *cp != '\t'; cp--, tailing_wordlen++)
  567. ;
  568. if (tailing_wordlen)
  569. {
  570. lseek(fd, -tailing_wordlen, SEEK_CUR);
  571. readlen -= tailing_wordlen;
  572. stat = READFILE_STAT_TRUNCATED;
  573. }
  574. else
  575. {
  576. stat = READFILE_STAT_EOF_REACHED;
  577. }
  578. }
  579. else
  580. {
  581. stat = READFILE_STAT_EOF_REACHED;
  582. }
  583. }
  584. else
  585. {
  586. stat = READFILE_STAT_NEXTLINE_REACHED;
  587. readlen = nlp - buffer;
  588. }
  589. buffer[readlen] = '\0';
  590. }
  591. if (p_readlen)
  592. *p_readlen = readlen;
  593. return stat;
  594. }
  595. /**
  596. * @brief Find the start of the next word in a string
  597. *
  598. * @param[in] cp Pointer to the string to search
  599. *
  600. * @return char* Pointer to the first non-space character in the string
  601. *
  602. * @note Skips leading whitespace characters and returns a pointer to the first
  603. * non-whitespace character.
  604. */
  605. static char *_find_word(char *cp)
  606. {
  607. for (; (*cp == ' ') || (*cp == '\t'); cp++)
  608. ;
  609. return cp;
  610. }
  611. /**
  612. * @brief Seperate words in a string and get the next word
  613. *
  614. * @param[in] cp Pointer to the string to process
  615. *
  616. * @return char* Pointer to the next word in the string
  617. *
  618. * @note Finds the next whitespace character, seperates words, and returns a
  619. * pointer to the next word.
  620. */
  621. static char *_seperate_and_get_nextword(char *cp)
  622. {
  623. /* find next whitespace */
  624. for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
  625. ;
  626. /* seperate words */
  627. while ((*cp == ' ') || (*cp == '\t'))
  628. {
  629. *cp++ = '\0';
  630. }
  631. return cp;
  632. }
  633. #define INTERP_BUF_SIZE 128
  634. /**
  635. * @brief Load and process interpreter script for light-weight process
  636. *
  637. * @param[in,out] ai Pointer to the lwp_args_info structure to store script arguments
  638. * @param[in] filename Path to the script file to load
  639. *
  640. * @return rt_err_t Returns RT_EOK (0) on success, negative error code on failure:
  641. * - -1: General error (file open/read failure)
  642. * - Other errors from args_init() or _args_override_argv0()
  643. *
  644. * @note This function reads an interpreter script (e.g., shell script starting with #!),
  645. * extracts the interpreter path and arguments, and prepares them for process execution.
  646. * It handles script verification, argument parsing, and proper cleanup on failure.
  647. */
  648. rt_err_t lwp_args_load_script(struct lwp_args_info *ai, const char *filename)
  649. {
  650. rt_err_t error = -1;
  651. int fd = -RT_ERROR;
  652. int len;
  653. int rf_stat;
  654. char interp[INTERP_BUF_SIZE];
  655. char *cp, *nextword;
  656. char script_magic[2];
  657. struct lwp_args_info ow_ai = {0};
  658. fd = open(filename, O_BINARY | O_RDONLY, 0);
  659. if (fd < 0)
  660. {
  661. goto quit;
  662. }
  663. /**
  664. * verify an interpreter script by matching script file magic
  665. * eg: #!/bin/sh
  666. */
  667. len = read(fd, script_magic, sizeof(script_magic));
  668. if (len != 2 || memcmp(script_magic, "#!", sizeof(script_magic)))
  669. {
  670. goto quit;
  671. }
  672. /* setup a new args struct to save script arguments */
  673. if (args_init(&ow_ai, INTERP_BUF_SIZE))
  674. {
  675. goto quit;
  676. }
  677. while (1)
  678. {
  679. /* read file to buffer (avoid any truncated words in buffer) */
  680. rf_stat = _readfile(fd, INTERP_BUF_SIZE, interp, &len);
  681. if (len <= 0)
  682. {
  683. goto quit;
  684. }
  685. /* find first word until reaching nil */
  686. cp = _find_word(interp);
  687. if (*cp == '\0')
  688. {
  689. if (READFILE_STAT_CAN_READMORE(rf_stat))
  690. continue;
  691. else
  692. break;
  693. }
  694. do
  695. {
  696. nextword = _seperate_and_get_nextword(cp);
  697. args_append(&ow_ai, cp, strlen(cp), LWP_ARGS_TYPE_KARG);
  698. cp = nextword;
  699. }
  700. while (*cp);
  701. if (READFILE_STAT_CAN_READMORE(rf_stat))
  702. continue;
  703. else
  704. break;
  705. }
  706. if (ow_ai.argv.string_count == 0)
  707. {
  708. goto quit; /* No interpreter name found */
  709. }
  710. args_append(&ow_ai, filename, strlen(filename), LWP_ARGS_TYPE_KARG);
  711. error = _args_override_argv0(ai, &ow_ai);
  712. if (error)
  713. {
  714. goto quit;
  715. }
  716. quit:
  717. lwp_args_detach(&ow_ai);
  718. if (fd >= 0)
  719. {
  720. close(fd);
  721. }
  722. return error;
  723. }
  724. /**
  725. * @brief Get command line arguments from light-weight process
  726. *
  727. * @param[in] lwp Pointer to the light-weight process structure
  728. *
  729. * @return char** Returns a NULL-terminated array of argument strings on success:
  730. * - The array and each string are allocated in kernel space
  731. * - The caller is responsible for freeing using lwp_free_command_line_args()
  732. * RT_NULL Returns NULL on failure (invalid LWP, memory allocation failure, or copy error)
  733. *
  734. * @note This function retrieves the command line arguments (argv) from a light-weight process (LWP)
  735. * and returns a NULL-terminated array of argument strings. It handles memory allocation and
  736. * proper NULL termination of the argument vector.
  737. */
  738. char **lwp_get_command_line_args(struct rt_lwp *lwp)
  739. {
  740. size_t argc = 0;
  741. char **argv = NULL;
  742. int ret;
  743. size_t i;
  744. size_t len;
  745. if (lwp)
  746. {
  747. ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
  748. if (ret == 0)
  749. {
  750. return RT_NULL;
  751. }
  752. argv = (char**)rt_calloc((argc + 1), sizeof(char*));
  753. if (argv)
  754. {
  755. for (i = 0; i < argc; i++)
  756. {
  757. char *argvp = NULL;
  758. ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp));
  759. if (ret == 0)
  760. {
  761. goto error_exit;
  762. }
  763. len = lwp_user_strlen_ext(lwp, argvp);
  764. if (len >= 0)
  765. {
  766. argv[i] = (char*)rt_malloc(len + 1);
  767. ret = lwp_data_get(lwp, argv[i], argvp, len);
  768. if (ret != len)
  769. {
  770. goto error_exit;
  771. }
  772. argv[i][len] = '\0';
  773. }
  774. else
  775. {
  776. goto error_exit;
  777. }
  778. }
  779. argv[argc] = NULL;
  780. }
  781. }
  782. return argv;
  783. error_exit:
  784. lwp_free_command_line_args(argv);
  785. return RT_NULL;
  786. }
  787. /**
  788. * @brief Print environment variables of light-weight process
  789. *
  790. * @param[in] lwp Pointer to the light-weight process structure
  791. *
  792. * @return void
  793. */
  794. void lwp_print_envp(struct rt_lwp *lwp)
  795. {
  796. rt_size_t envp_counts;
  797. char **kenvp_array = lwp_get_envp(lwp, &envp_counts);
  798. if (kenvp_array)
  799. {
  800. rt_kprintf("envp_counts: %d\n", envp_counts);
  801. for (size_t i = 0; i < envp_counts; i++)
  802. {
  803. rt_kprintf("envp[%d]: %s\n", i, kenvp_array[i]);
  804. }
  805. }
  806. lwp_free_command_line_args(kenvp_array);
  807. return ;
  808. }
  809. /**
  810. * @brief Get environment variables of light-weight process
  811. *
  812. * @param[in] lwp Pointer to the light-weight process structure
  813. * @param[out] penvp_counts Pointer to store the number of environment variables
  814. *
  815. * @return char** Returns a NULL-terminated array of environment variable strings on success:
  816. * - The array and each string are allocated in kernel space
  817. * - The caller is responsible for freeing using lwp_free_command_line_args()
  818. * RT_NULL Returns NULL on failure (invalid LWP, memory allocation failure, or copy error)
  819. */
  820. char** lwp_get_envp(struct rt_lwp *lwp, rt_size_t *penvp_counts)
  821. {
  822. int ret, len;
  823. rt_base_t argc;
  824. char **p_kenvp = RT_NULL;
  825. char *envp, **p_envp;
  826. size_t envp_counts = 0;
  827. if (lwp)
  828. {
  829. ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
  830. if (ret == 0)
  831. {
  832. return RT_NULL;
  833. }
  834. p_envp = (char **)lwp->args + 1 + argc + 1;
  835. /* counts envp */
  836. while (lwp_data_get(lwp, &envp, p_envp, sizeof(void *)) == sizeof(void *)
  837. && envp != NULL)
  838. {
  839. p_envp++;
  840. envp_counts++;
  841. }
  842. p_kenvp = (char **)rt_malloc((envp_counts + 1) * sizeof(char *));
  843. if (p_kenvp)
  844. {
  845. /* copy env from envp array */
  846. p_envp = (char **)lwp->args + 1 + argc + 1;
  847. for (size_t i = 0; i < envp_counts; i++)
  848. {
  849. ret = lwp_data_get(lwp, &envp, &p_envp[i], sizeof(char *));
  850. if (ret != sizeof(char **))
  851. {
  852. lwp_free_command_line_args(p_kenvp);
  853. return RT_NULL;
  854. }
  855. len = lwp_user_strlen_ext(lwp, envp);
  856. if (len > 0)
  857. {
  858. p_kenvp[i] = (char*)rt_malloc(len + 1);
  859. ret = lwp_data_get(lwp, p_kenvp[i], envp, len + 1);
  860. if (ret != len + 1)
  861. {
  862. lwp_free_command_line_args(p_kenvp);
  863. return RT_NULL;
  864. }
  865. }
  866. else
  867. {
  868. p_kenvp[i] = NULL;
  869. }
  870. }
  871. if (penvp_counts)
  872. *penvp_counts = envp_counts;
  873. p_kenvp[envp_counts] = NULL;
  874. }
  875. }
  876. return p_kenvp;
  877. }
  878. /**
  879. * @brief Free memory allocated for command line arguments
  880. *
  881. * @param argv Array of command line arguments to free
  882. *
  883. * @return void
  884. */
  885. void lwp_free_command_line_args(char** argv)
  886. {
  887. size_t i;
  888. if (argv)
  889. {
  890. for (i = 0; argv[i]; i++)
  891. {
  892. rt_free(argv[i]);
  893. }
  894. rt_free(argv);
  895. }
  896. }