proc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. */
  9. #include "proc.h"
  10. #include "procfs.h"
  11. #include <rthw.h>
  12. #include <rtdbg.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. /*
  16. * This is the root in the proc tree..
  17. */
  18. static struct proc_dentry _proc_root = {
  19. .mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH),
  20. .ref_count = 1,
  21. .parent = &_proc_root,
  22. .node.sibling = RT_LIST_OBJECT_INIT(_proc_root.node.sibling),
  23. .node.subnode = RT_LIST_OBJECT_INIT(_proc_root.node.subnode),
  24. .fops = RT_NULL,
  25. .name = "/",
  26. .data = RT_NULL,
  27. };
  28. static int _proc_find(struct proc_dentry **parent, const char *name)
  29. {
  30. struct proc_dentry *dentry = RT_NULL, *tmp;
  31. dfs_vfs_for_each_subnode(dentry, tmp, (*parent), node)
  32. {
  33. if (dentry == RT_NULL)
  34. {
  35. break;
  36. }
  37. if (rt_strcmp(dentry->name, name) == 0)
  38. {
  39. *parent = dentry;
  40. return 0;
  41. }
  42. }
  43. return -1;
  44. }
  45. static int proc_find(struct proc_dentry **parent, const char **name, rt_bool_t force_lookup)
  46. {
  47. int ret = 0;
  48. char *tmp = RT_NULL;
  49. if (!(*parent))
  50. {
  51. *parent = &_proc_root;
  52. }
  53. tmp = rt_strdup(*name);
  54. if (tmp)
  55. {
  56. char *begin = tmp, *end = RT_NULL;
  57. if (*begin == '/')
  58. {
  59. begin++;
  60. if (*begin == '\0')
  61. {
  62. rt_free(tmp);
  63. *parent = proc_acquire(*parent);
  64. return ret;
  65. }
  66. }
  67. while (1)
  68. {
  69. end = rt_strstr(begin, "/");
  70. if (end)
  71. {
  72. *end = '\0';
  73. ret = _proc_find(parent, begin);
  74. if (ret < 0 || !S_ISDIR((*parent)->mode))
  75. {
  76. *parent = RT_NULL;
  77. ret = -1;
  78. break;
  79. }
  80. begin = end + 1;
  81. }
  82. else if (force_lookup)
  83. {
  84. ret = _proc_find(parent, begin);
  85. if (ret < 0)
  86. {
  87. if ((*parent)->ops && (*parent)->ops->lookup)
  88. {
  89. *parent = (*parent)->ops->lookup(*parent, begin);
  90. if (*parent == RT_NULL)
  91. {
  92. ret = -1;
  93. }
  94. }
  95. else
  96. {
  97. *parent = RT_NULL;
  98. }
  99. }
  100. else
  101. {
  102. *parent = proc_acquire(*parent);
  103. }
  104. break;
  105. }
  106. else
  107. {
  108. *parent = proc_acquire(*parent);
  109. break;
  110. }
  111. }
  112. *name = *name + (begin - tmp);
  113. rt_free(tmp);
  114. }
  115. return ret;
  116. }
  117. static void *single_start(struct dfs_seq_file *seq, off_t *index)
  118. {
  119. return NULL + (*index == 0);
  120. }
  121. static void *single_next(struct dfs_seq_file *seq, void *data, off_t *index)
  122. {
  123. ++*index;
  124. return NULL;
  125. }
  126. static void single_stop(struct dfs_seq_file *seq, void *data)
  127. {
  128. }
  129. static int proc_open(struct dfs_file *file)
  130. {
  131. struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
  132. if (entry->single_show)
  133. {
  134. struct dfs_seq_ops *seq_ops = (struct dfs_seq_ops *)rt_calloc(1, sizeof(struct dfs_seq_ops));
  135. if (seq_ops)
  136. {
  137. int ret = 0;
  138. seq_ops->start = single_start;
  139. seq_ops->next = single_next;
  140. seq_ops->stop = single_stop;
  141. seq_ops->show = entry->single_show;
  142. ret = dfs_seq_open(file, seq_ops);
  143. if (ret != 0)
  144. {
  145. rt_free(seq_ops);
  146. }
  147. return ret;
  148. }
  149. }
  150. return dfs_seq_open(file, entry->seq_ops);
  151. }
  152. static int proc_close(struct dfs_file *file)
  153. {
  154. struct dfs_seq_file *seq = file->data;
  155. struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
  156. if (seq && entry->single_show && seq->ops)
  157. {
  158. rt_free((void *)seq->ops);
  159. seq->ops = RT_NULL;
  160. }
  161. return dfs_seq_release(file);
  162. }
  163. static const struct dfs_file_ops proc_file_ops = {
  164. .open = proc_open,
  165. .read = dfs_seq_read,
  166. .lseek = dfs_seq_lseek,
  167. .close = proc_close,
  168. };
  169. static struct proc_dentry *proc_create(struct proc_dentry **parent, const char *name, mode_t mode)
  170. {
  171. int ret = 0;
  172. struct proc_dentry *dentry = RT_NULL;
  173. ret = proc_find(parent, &name, 0);
  174. if (ret >= 0)
  175. {
  176. dentry = *parent;
  177. ret = proc_find(&dentry, &name, 1);
  178. if (ret < 0)
  179. {
  180. dentry = rt_calloc(1, sizeof(struct proc_dentry));
  181. if (dentry)
  182. {
  183. dentry->mode = mode;
  184. dentry->ref_count = 1;
  185. dentry->name = rt_strdup(name);
  186. dfs_vfs_init_node(&dentry->node);
  187. }
  188. }
  189. else
  190. {
  191. proc_release(dentry);
  192. dentry = RT_NULL;
  193. }
  194. }
  195. return dentry;
  196. }
  197. /**
  198. * @brief The dentry reference count is incremented by one
  199. *
  200. * @param dentry
  201. *
  202. * @return dentry
  203. */
  204. struct proc_dentry *proc_acquire(struct proc_dentry *dentry)
  205. {
  206. if (dentry)
  207. {
  208. dentry->ref_count += 1;
  209. }
  210. return dentry;
  211. }
  212. /**
  213. * @brief The dentry reference count is minus one, or release
  214. *
  215. * @param dentry
  216. *
  217. * @return none
  218. */
  219. void proc_release(struct proc_dentry *dentry)
  220. {
  221. if (dentry)
  222. {
  223. if (dentry->ref_count == 1)
  224. {
  225. if (dentry->name)
  226. {
  227. rt_free(dentry->name);
  228. }
  229. if (S_ISLNK(dentry->mode) && dentry->data)
  230. {
  231. rt_free(dentry->data);
  232. }
  233. rt_free(dentry);
  234. }
  235. else
  236. {
  237. dentry->ref_count -= 1;
  238. }
  239. }
  240. }
  241. static struct proc_dentry *proc_register(struct proc_dentry *parent, struct proc_dentry *child)
  242. {
  243. child->parent = parent;
  244. dfs_vfs_append_node(&parent->node, &child->node);
  245. child->ref_count += 1;
  246. child->pid = parent->pid;
  247. return child;
  248. }
  249. /**
  250. * @brief Make a dir
  251. *
  252. * @param name fullpath based on _proc_root or parent
  253. * @param mode permission configuration
  254. * @param parent can be empty
  255. * @param fops
  256. * @param data
  257. *
  258. * @return dentry
  259. */
  260. struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
  261. const struct dfs_file_ops *fops, void *data)
  262. {
  263. struct proc_dentry *dentry, *_parent = parent;
  264. if (mode == 0)
  265. mode = (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
  266. dentry = proc_create(&_parent, name, S_IFDIR | mode);
  267. if (dentry)
  268. {
  269. dentry->fops = fops;
  270. dentry->data = data;
  271. dentry = proc_register(_parent, dentry);
  272. }
  273. proc_release(_parent);
  274. return dentry;
  275. }
  276. /**
  277. * @brief Make a dir
  278. *
  279. * @param name fullpath based on _proc_root or parent
  280. * @param mode permission configuration
  281. * @param parent can be empty
  282. *
  283. * @return dentry
  284. */
  285. struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent)
  286. {
  287. return proc_mkdir_data(name, mode, parent, NULL, NULL);
  288. }
  289. /**
  290. * @brief Make a dir
  291. *
  292. * @param name fullpath based on _proc_root or parent
  293. * @param parent can be empty
  294. *
  295. * @return dentry
  296. */
  297. struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent)
  298. {
  299. return proc_mkdir_data(name, 0, parent, NULL, NULL);
  300. }
  301. static struct proc_dentry *proc_create_reg(const char *name, mode_t mode, struct proc_dentry **parent)
  302. {
  303. struct proc_dentry *dentry = RT_NULL;
  304. if ((mode & S_IFMT) == 0)
  305. mode |= S_IFREG;
  306. if ((mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)) == 0)
  307. mode |= S_IRUSR | S_IRGRP | S_IROTH;
  308. if (!S_ISREG(mode))
  309. {
  310. *parent = RT_NULL;
  311. return dentry;
  312. }
  313. return proc_create(parent, name, mode);
  314. }
  315. /**
  316. * @brief Make a file
  317. *
  318. * @param name fullpath based on _proc_root or parent
  319. * @param mode permission configuration
  320. * @param parent can be empty
  321. * @param fops
  322. * @param data
  323. *
  324. * @return dentry
  325. */
  326. struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
  327. const struct dfs_file_ops *fops, void *data)
  328. {
  329. struct proc_dentry *dentry, *_parent = parent;
  330. dentry = proc_create_reg(name, mode, &_parent);
  331. if (dentry)
  332. {
  333. dentry->fops = fops ? fops : &proc_file_ops;
  334. dentry->data = data;
  335. dentry = proc_register(_parent, dentry);
  336. }
  337. proc_release(_parent);
  338. return dentry;
  339. }
  340. /**
  341. * @brief Make a file
  342. *
  343. * @param name fullpath based on _proc_root or parent
  344. * @param mode permission configuration
  345. * @param parent can be empty
  346. * @param show
  347. * @param data
  348. *
  349. * @return dentry
  350. */
  351. struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent,
  352. int (*show)(struct dfs_seq_file *, void *), void *data)
  353. {
  354. struct proc_dentry *dentry, *_parent = parent;
  355. dentry = proc_create_reg(name, mode, &_parent);
  356. if (dentry)
  357. {
  358. dentry->fops = &proc_file_ops;
  359. dentry->single_show = show;
  360. dentry->data = data;
  361. dentry = proc_register(_parent, dentry);
  362. }
  363. proc_release(_parent);
  364. return dentry;
  365. }
  366. /**
  367. * @brief Make a symlink
  368. *
  369. * @param name fullpath based on _proc_root or parent
  370. * @param parent can be empty
  371. * @param dest link file fullpath
  372. *
  373. * @return dentry
  374. */
  375. struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest)
  376. {
  377. struct proc_dentry *dentry, *_parent = parent;
  378. dentry = proc_create(&_parent, name, (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH)
  379. | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH)));
  380. if (dentry)
  381. {
  382. dentry->data = (void *)rt_strdup(dest);
  383. if (dentry->data)
  384. {
  385. dentry = proc_register(_parent, dentry);
  386. }
  387. else
  388. {
  389. proc_release(dentry);
  390. dentry = NULL;
  391. }
  392. }
  393. proc_release(_parent);
  394. return dentry;
  395. }
  396. static void remove_proc_subtree(struct proc_dentry *dentry)
  397. {
  398. struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
  399. dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
  400. {
  401. if (iter == RT_NULL)
  402. {
  403. break;
  404. }
  405. if (tmp)
  406. {
  407. proc_release(tmp);
  408. tmp = RT_NULL;
  409. }
  410. tmp = iter;
  411. if (S_ISDIR(dentry->mode))
  412. {
  413. remove_proc_subtree(iter);
  414. }
  415. }
  416. if (tmp)
  417. {
  418. proc_release(tmp);
  419. tmp = RT_NULL;
  420. }
  421. }
  422. /**
  423. * @brief remove a dentry
  424. *
  425. * @param dentry
  426. *
  427. * @return none
  428. */
  429. void proc_remove(struct proc_dentry *dentry)
  430. {
  431. if (dentry && dentry != &_proc_root)
  432. {
  433. if (S_ISDIR(dentry->mode))
  434. {
  435. remove_proc_subtree(dentry);
  436. }
  437. dfs_vfs_remove_node(&dentry->node);
  438. proc_release(dentry);
  439. }
  440. }
  441. /**
  442. * @brief find dentry exist
  443. *
  444. * @param name fullpath based on _proc_root
  445. *
  446. * @return dentry
  447. */
  448. struct proc_dentry *dfs_proc_find(const char *name)
  449. {
  450. struct proc_dentry *dentry = RT_NULL;
  451. proc_find(&dentry, &name, 1);
  452. return dentry;
  453. }
  454. /**
  455. * @brief remove a dentry on parent
  456. *
  457. * @param name fullpath based on parent
  458. * @param parent
  459. *
  460. * @return none
  461. */
  462. void proc_remove_dentry(const char *name, struct proc_dentry *parent)
  463. {
  464. struct proc_dentry *dentry = parent;
  465. if (proc_find(&dentry, &name, 1) >= 0)
  466. {
  467. proc_remove(dentry);
  468. proc_release(dentry);
  469. }
  470. }
  471. #define _COLOR_RED "\033[31m"
  472. #define _COLOR_GREEN "\033[32m"
  473. #define _COLOR_BLUE "\033[34m"
  474. #define _COLOR_CYAN "\033[36m"
  475. #define _COLOR_WHITE "\033[37m"
  476. #define _COLOR_NORMAL "\033[0m"
  477. static void dump_proc_subtree(struct proc_dentry *dentry, int tab)
  478. {
  479. struct proc_dentry *iter = RT_NULL, *tmp;
  480. dfs_vfs_for_each_subnode(iter, tmp, dentry, node)
  481. {
  482. if (iter == RT_NULL)
  483. {
  484. break;
  485. }
  486. for(int i = 0; i < tab; i ++)
  487. {
  488. rt_kprintf("%-4s", i + 1 >= tab ? "|-" : " ");
  489. }
  490. if (S_ISDIR(iter->mode))
  491. {
  492. rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
  493. dump_proc_subtree(iter, tab + 1);
  494. }
  495. else if (S_ISLNK(iter->mode))
  496. {
  497. rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
  498. }
  499. else
  500. {
  501. rt_kprintf("%-20s %d\n", iter->name, iter->ref_count);
  502. }
  503. }
  504. }
  505. static void proc_dump(struct proc_dentry *dentry)
  506. {
  507. if (dentry)
  508. {
  509. if (S_ISDIR(dentry->mode))
  510. {
  511. rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
  512. dump_proc_subtree(dentry, 1);
  513. }
  514. else if (S_ISLNK(dentry->mode))
  515. {
  516. rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
  517. }
  518. else
  519. {
  520. rt_kprintf("%-20s %d\n", dentry->name, dentry->ref_count);
  521. }
  522. }
  523. }
  524. static int msh_proc_dump(int argc, char** argv)
  525. {
  526. const char *name = argc > 1 ? argv[1] : "/";
  527. struct proc_dentry *dentry = RT_NULL;
  528. int ret = proc_find(&dentry, &name, 1);
  529. if (ret >= 0)
  530. {
  531. proc_dump(dentry);
  532. }
  533. proc_release(dentry);
  534. return 0;
  535. }
  536. MSH_CMD_EXPORT_ALIAS(msh_proc_dump, proc_dump, proc dump);
  537. static int msh_proc_remove(int argc, char** argv)
  538. {
  539. if (argc > 1)
  540. {
  541. const char *name = argv[1];
  542. struct proc_dentry *dentry = RT_NULL;
  543. int ret = proc_find(&dentry, &name, 1);
  544. if (ret >= 0)
  545. {
  546. if (dentry != &_proc_root)
  547. {
  548. proc_remove(dentry);
  549. }
  550. else
  551. {
  552. struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
  553. dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
  554. {
  555. if (iter == RT_NULL)
  556. {
  557. break;
  558. }
  559. if (tmp)
  560. {
  561. proc_remove(tmp);
  562. }
  563. tmp = iter;
  564. }
  565. if (tmp)
  566. {
  567. proc_remove(tmp);
  568. }
  569. }
  570. }
  571. proc_release(dentry);
  572. }
  573. else
  574. {
  575. rt_kprintf("proc_remove path\n");
  576. }
  577. return 0;
  578. }
  579. MSH_CMD_EXPORT_ALIAS(msh_proc_remove, proc_remove, proc remove);
  580. static int msh_proc_symlink(int argc, char** argv)
  581. {
  582. if (argc > 2)
  583. {
  584. struct proc_dentry *entry = proc_symlink(argv[1], 0, argv[2]);
  585. if (entry)
  586. {
  587. proc_release(entry);
  588. }
  589. }
  590. else
  591. {
  592. rt_kprintf("proc_symlink path dest\n");
  593. }
  594. return 0;
  595. }
  596. MSH_CMD_EXPORT_ALIAS(msh_proc_symlink, proc_symlink, proc symlink);
  597. static int msh_proc_echo(int argc, char** argv)
  598. {
  599. if (argc > 1)
  600. {
  601. for(int i = 1; i <= argc - 1; i ++)
  602. {
  603. struct proc_dentry *entry = proc_create_data(argv[i], 0, 0, 0, 0);
  604. if (entry)
  605. {
  606. proc_release(entry);
  607. }
  608. }
  609. }
  610. else
  611. {
  612. rt_kprintf("proc_echo path\n");
  613. }
  614. return 0;
  615. }
  616. MSH_CMD_EXPORT_ALIAS(msh_proc_echo, proc_echo, proc echo);
  617. static int msh_proc_mkdir(int argc, char** argv)
  618. {
  619. if (argc > 1)
  620. {
  621. for(int i = 1; i <= argc - 1; i ++)
  622. {
  623. struct proc_dentry *entry = proc_mkdir(argv[i], 0);
  624. if (entry)
  625. {
  626. proc_release(entry);
  627. }
  628. }
  629. }
  630. else
  631. {
  632. rt_kprintf("proc_mkdir path\n");
  633. }
  634. return 0;
  635. }
  636. MSH_CMD_EXPORT_ALIAS(msh_proc_mkdir, proc_mkdir, proc mkdir);