fs_procfs.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. /****************************************************************************
  2. * fs/procfs/fs_procfs.c
  3. *
  4. * Copyright (C) 2013-2018 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <sys/statfs.h>
  41. #include <sys/stat.h>
  42. #include <stdint.h>
  43. #include <stdbool.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <fcntl.h>
  48. #include <assert.h>
  49. #include <errno.h>
  50. #include <debug.h>
  51. #include <nuttx/irq.h>
  52. #include <nuttx/arch.h>
  53. #include <nuttx/sched.h>
  54. #include <nuttx/kmalloc.h>
  55. #include <nuttx/fs/fs.h>
  56. #include <nuttx/fs/procfs.h>
  57. #include <nuttx/fs/dirent.h>
  58. #include <nuttx/lib/regex.h>
  59. #include "mount/mount.h"
  60. #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS)
  61. /****************************************************************************
  62. * Pre-processor Definitions
  63. ****************************************************************************/
  64. #define PROCFS_NATTRS 2
  65. /****************************************************************************
  66. * External Definitions
  67. ****************************************************************************/
  68. extern const struct procfs_operations proc_operations;
  69. extern const struct procfs_operations irq_operations;
  70. extern const struct procfs_operations cpuload_operations;
  71. extern const struct procfs_operations critmon_operations;
  72. extern const struct procfs_operations meminfo_operations;
  73. extern const struct procfs_operations iobinfo_operations;
  74. extern const struct procfs_operations module_operations;
  75. extern const struct procfs_operations uptime_operations;
  76. extern const struct procfs_operations version_operations;
  77. /* This is not good. These are implemented in other sub-systems. Having to
  78. * deal with them here is not a good coupling. What is really needed is a
  79. * run-time procfs registration system vs. a build time, fixed procfs
  80. * configuration.
  81. */
  82. extern const struct procfs_operations net_procfsoperations;
  83. extern const struct procfs_operations net_procfs_routeoperations;
  84. extern const struct procfs_operations part_procfsoperations;
  85. extern const struct procfs_operations mount_procfsoperations;
  86. extern const struct procfs_operations smartfs_procfsoperations;
  87. /* And even worse, this one is specific to the STM32. The solution to
  88. * this nasty couple would be to replace this hard-coded, ROM-able
  89. * operations table with a RAM-base registration table.
  90. */
  91. #if defined(CONFIG_STM32_CCM_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_CCM)
  92. extern const struct procfs_operations ccm_procfsoperations;
  93. #endif
  94. /****************************************************************************
  95. * Private Types
  96. ****************************************************************************/
  97. /* Table of all known / pre-registered procfs handlers / participants. */
  98. #ifdef CONFIG_FS_PROCFS_REGISTER
  99. static const struct procfs_entry_s g_base_entries[] =
  100. #else
  101. static const struct procfs_entry_s g_procfs_entries[] =
  102. #endif
  103. {
  104. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  105. { "[0-9]*/**", &proc_operations, PROCFS_UNKOWN_TYPE },
  106. { "[0-9]*", &proc_operations, PROCFS_DIR_TYPE },
  107. #endif
  108. #if defined(CONFIG_SCHED_CPULOAD) && !defined(CONFIG_FS_PROCFS_EXCLUDE_CPULOAD)
  109. { "cpuload", &cpuload_operations, PROCFS_FILE_TYPE },
  110. #endif
  111. #if defined(CONFIG_SCHED_CRITMONITOR)
  112. { "critmon", &critmon_operations, PROCFS_FILE_TYPE },
  113. #endif
  114. #ifdef CONFIG_SCHED_IRQMONITOR
  115. { "irqs", &irq_operations, PROCFS_FILE_TYPE },
  116. #endif
  117. #ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMINFO
  118. { "meminfo", &meminfo_operations, PROCFS_FILE_TYPE },
  119. #endif
  120. #if defined(CONFIG_MM_IOB) && !defined(CONFIG_FS_PROCFS_EXCLUDE_IOBINFO)
  121. { "iobinfo", &iobinfo_operations, PROCFS_FILE_TYPE },
  122. #endif
  123. #if defined(CONFIG_MODULE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
  124. { "modules", &module_operations, PROCFS_FILE_TYPE },
  125. #endif
  126. #ifndef CONFIG_FS_PROCFS_EXCLUDE_BLOCKS
  127. { "fs/blocks", &mount_procfsoperations, PROCFS_FILE_TYPE },
  128. #endif
  129. #ifndef CONFIG_FS_PROCFS_EXCLUDE_MOUNT
  130. { "fs/mount", &mount_procfsoperations, PROCFS_FILE_TYPE },
  131. #endif
  132. #ifndef CONFIG_FS_PROCFS_EXCLUDE_USAGE
  133. { "fs/usage", &mount_procfsoperations, PROCFS_FILE_TYPE },
  134. #endif
  135. #if defined(CONFIG_FS_SMARTFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)
  136. { "fs/smartfs**", &smartfs_procfsoperations, PROCFS_UNKOWN_TYPE },
  137. #endif
  138. #if defined(CONFIG_NET) && !defined(CONFIG_FS_PROCFS_EXCLUDE_NET)
  139. { "net", &net_procfsoperations, PROCFS_DIR_TYPE },
  140. #if defined(CONFIG_NET_ROUTE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_ROUTE)
  141. { "net/route", &net_procfs_routeoperations, PROCFS_DIR_TYPE },
  142. { "net/route/**", &net_procfs_routeoperations, PROCFS_UNKOWN_TYPE },
  143. #endif
  144. { "net/**", &net_procfsoperations, PROCFS_UNKOWN_TYPE },
  145. #endif
  146. #if defined(CONFIG_MTD_PARTITION) && !defined(CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS)
  147. { "partitions", &part_procfsoperations, PROCFS_FILE_TYPE },
  148. #endif
  149. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  150. { "self", &proc_operations, PROCFS_DIR_TYPE },
  151. { "self/**", &proc_operations, PROCFS_UNKOWN_TYPE },
  152. #endif
  153. #if !defined(CONFIG_FS_PROCFS_EXCLUDE_UPTIME)
  154. { "uptime", &uptime_operations, PROCFS_FILE_TYPE },
  155. #endif
  156. #if !defined(CONFIG_FS_PROCFS_EXCLUDE_VERSION)
  157. { "version", &version_operations, PROCFS_FILE_TYPE },
  158. #endif
  159. };
  160. #ifdef CONFIG_FS_PROCFS_REGISTER
  161. static const uint8_t g_base_entrycount = sizeof(g_base_entries) /
  162. sizeof(struct procfs_entry_s);
  163. static FAR struct procfs_entry_s *g_procfs_entries;
  164. static uint8_t g_procfs_entrycount;
  165. #else
  166. static const uint8_t g_procfs_entrycount = sizeof(g_procfs_entries) /
  167. sizeof(struct procfs_entry_s);
  168. #endif
  169. /****************************************************************************
  170. * Private Function Prototypes
  171. ****************************************************************************/
  172. /* Helpers */
  173. static void procfs_enum(FAR struct tcb_s *tcb, FAR void *arg);
  174. /* File system methods */
  175. static int procfs_open(FAR struct file *filep, FAR const char *relpath,
  176. int oflags, mode_t mode);
  177. static int procfs_close(FAR struct file *filep);
  178. static ssize_t procfs_read(FAR struct file *filep, FAR char *buffer,
  179. size_t buflen);
  180. static ssize_t procfs_write(FAR struct file *filep, FAR const char *buffer,
  181. size_t buflen);
  182. static int procfs_ioctl(FAR struct file *filep, int cmd,
  183. unsigned long arg);
  184. static int procfs_dup(FAR const struct file *oldp,
  185. FAR struct file *newp);
  186. static int procfs_fstat(FAR const struct file *filep,
  187. FAR struct stat *buf);
  188. static int procfs_opendir(FAR struct inode *mountpt, const char *relpath,
  189. FAR struct fs_dirent_s *dir);
  190. static int procfs_closedir(FAR struct inode *mountpt,
  191. FAR struct fs_dirent_s *dir);
  192. static int procfs_readdir(FAR struct inode *mountpt,
  193. FAR struct fs_dirent_s *dir);
  194. static int procfs_rewinddir(FAR struct inode *mountpt,
  195. FAR struct fs_dirent_s *dir);
  196. static int procfs_bind(FAR struct inode *blkdriver,
  197. FAR const void *data, FAR void **handle);
  198. static int procfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
  199. unsigned int flags);
  200. static int procfs_statfs(FAR struct inode *mountpt,
  201. FAR struct statfs *buf);
  202. static int procfs_stat(FAR struct inode *mountpt,
  203. FAR const char *relpath, FAR struct stat *buf);
  204. /* Initialization */
  205. #ifdef CONFIG_FS_PROCFS_REGISTER
  206. static int procfs_initialize(void);
  207. #endif
  208. /****************************************************************************
  209. * Public Data
  210. ****************************************************************************/
  211. /* See fs_mount.c -- this structure is explicitly externed there.
  212. * We use the old-fashioned kind of initializers so that this will compile
  213. * with any compiler.
  214. */
  215. const struct mountpt_operations procfs_operations =
  216. {
  217. procfs_open, /* open */
  218. procfs_close, /* close */
  219. procfs_read, /* read */
  220. procfs_write, /* write */
  221. NULL, /* seek */
  222. procfs_ioctl, /* ioctl */
  223. NULL, /* sync */
  224. procfs_dup, /* dup */
  225. procfs_fstat, /* fstat */
  226. NULL, /* truncate */
  227. procfs_opendir, /* opendir */
  228. procfs_closedir, /* closedir */
  229. procfs_readdir, /* readdir */
  230. procfs_rewinddir, /* rewinddir */
  231. procfs_bind, /* bind */
  232. procfs_unbind, /* unbind */
  233. procfs_statfs, /* statfs */
  234. NULL, /* unlink */
  235. NULL, /* mkdir */
  236. NULL, /* rmdir */
  237. NULL, /* rename */
  238. procfs_stat /* stat */
  239. };
  240. /* Level 0 contains the directory of active tasks in addition to other
  241. * statically registered entries with custom handlers. This strcture
  242. * contains a snapshot of the active tasks when the directory is first
  243. * opened.
  244. */
  245. struct procfs_level0_s
  246. {
  247. struct procfs_dir_priv_s base; /* Base struct for ProcFS dir */
  248. /* Our private data */
  249. uint8_t lastlen; /* length of last reported static dir */
  250. pid_t pid[CONFIG_MAX_TASKS]; /* Snapshot of all active task IDs */
  251. FAR const char *lastread; /* Pointer to last static dir read */
  252. };
  253. /* Level 1 is an internal virtual directory (such as /proc/fs) which
  254. * will contain one or more additional static entries based on the
  255. * configuration.
  256. */
  257. struct procfs_level1_s
  258. {
  259. struct procfs_dir_priv_s base; /* Base struct for ProcFS dir */
  260. /* Our private data */
  261. uint8_t lastlen; /* length of last reported static dir */
  262. uint8_t subdirlen; /* Length of the subdir search */
  263. uint16_t firstindex; /* Index of 1st entry matching this subdir */
  264. FAR const char *lastread; /* Pointer to last static dir read */
  265. };
  266. /****************************************************************************
  267. * Private Functions
  268. ****************************************************************************/
  269. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  270. /****************************************************************************
  271. * Name: procfs_enum
  272. ****************************************************************************/
  273. static void procfs_enum(FAR struct tcb_s *tcb, FAR void *arg)
  274. {
  275. FAR struct procfs_level0_s *dir = (FAR struct procfs_level0_s *)arg;
  276. int index;
  277. DEBUGASSERT(dir);
  278. /* Add the PID to the list */
  279. index = dir->base.nentries;
  280. DEBUGASSERT(index < CONFIG_MAX_TASKS);
  281. dir->pid[index] = tcb->pid;
  282. dir->base.nentries = index + 1;
  283. }
  284. #endif
  285. /****************************************************************************
  286. * Name: procfs_open
  287. ****************************************************************************/
  288. static int procfs_open(FAR struct file *filep, FAR const char *relpath,
  289. int oflags, mode_t mode)
  290. {
  291. int x;
  292. int ret = -ENOENT;
  293. finfo("Open '%s'\n", relpath);
  294. /* Perform the stat based on the procfs_entry operations */
  295. for (x = 0; x < g_procfs_entrycount; x++)
  296. {
  297. /* Test if the path matches this entry's specification */
  298. if (match(g_procfs_entries[x].pathpattern, relpath))
  299. {
  300. /* Match found! Stat using this procfs entry */
  301. DEBUGASSERT(g_procfs_entries[x].ops &&
  302. g_procfs_entries[x].ops->open);
  303. ret = g_procfs_entries[x].ops->open(filep, relpath, oflags, mode);
  304. if (ret == OK)
  305. {
  306. DEBUGASSERT(filep->f_priv);
  307. ((struct procfs_file_s *) filep->f_priv)->procfsentry =
  308. &g_procfs_entries[x];
  309. break;
  310. }
  311. }
  312. }
  313. return ret;
  314. }
  315. /****************************************************************************
  316. * Name: procfs_close
  317. ****************************************************************************/
  318. static int procfs_close(FAR struct file *filep)
  319. {
  320. FAR struct procfs_file_s *attr;
  321. /* Recover our private data from the struct file instance */
  322. attr = (FAR struct procfs_file_s *)filep->f_priv;
  323. DEBUGASSERT(attr);
  324. /* Release the file attributes structure */
  325. kmm_free(attr);
  326. filep->f_priv = NULL;
  327. return OK;
  328. }
  329. /****************************************************************************
  330. * Name: procfs_read
  331. ****************************************************************************/
  332. static ssize_t procfs_read(FAR struct file *filep, FAR char *buffer,
  333. size_t buflen)
  334. {
  335. FAR struct procfs_file_s *handler;
  336. ssize_t ret = 0;
  337. finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
  338. /* Recover our private data from the struct file instance */
  339. handler = (FAR struct procfs_file_s *)filep->f_priv;
  340. DEBUGASSERT(handler);
  341. /* Call the handler's read routine */
  342. ret = handler->procfsentry->ops->read(filep, buffer, buflen);
  343. return ret;
  344. }
  345. /****************************************************************************
  346. * Name: procfs_write
  347. ****************************************************************************/
  348. static ssize_t procfs_write(FAR struct file *filep, FAR const char *buffer,
  349. size_t buflen)
  350. {
  351. FAR struct procfs_file_s *handler;
  352. ssize_t ret = 0;
  353. finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
  354. /* Recover our private data from the struct file instance */
  355. handler = (FAR struct procfs_file_s *)filep->f_priv;
  356. DEBUGASSERT(handler);
  357. /* Call the handler's read routine */
  358. if (handler->procfsentry->ops->write)
  359. {
  360. ret = handler->procfsentry->ops->write(filep, buffer, buflen);
  361. }
  362. return ret;
  363. }
  364. /****************************************************************************
  365. * Name: procfs_ioctl
  366. ****************************************************************************/
  367. static int procfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  368. {
  369. finfo("cmd: %d arg: %08lx\n", cmd, arg);
  370. /* No IOCTL commands supported */
  371. return -ENOTTY;
  372. }
  373. /****************************************************************************
  374. * Name: procfs_dup
  375. *
  376. * Description:
  377. * Duplicate open file data in the new file structure.
  378. *
  379. ****************************************************************************/
  380. static int procfs_dup(FAR const struct file *oldp, FAR struct file *newp)
  381. {
  382. FAR struct procfs_file_s *oldattr;
  383. finfo("Dup %p->%p\n", oldp, newp);
  384. /* Recover our private data from the old struct file instance */
  385. oldattr = (FAR struct procfs_file_s *)oldp->f_priv;
  386. DEBUGASSERT(oldattr);
  387. /* Allow lower-level handler do the dup to get it's extra data */
  388. return oldattr->procfsentry->ops->dup(oldp, newp);
  389. }
  390. /****************************************************************************
  391. * Name: procfs_fstat
  392. *
  393. * Description:
  394. * Obtain information about an open file associated with the file
  395. * descriptor 'fd', and will write it to the area pointed to by 'buf'.
  396. *
  397. ****************************************************************************/
  398. static int procfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
  399. {
  400. FAR struct procfs_file_s *handler;
  401. finfo("buf=%p\n", buf);
  402. /* Recover our private data from the struct file instance */
  403. handler = (FAR struct procfs_file_s *)filep->f_priv;
  404. DEBUGASSERT(handler);
  405. /* The procfs file system contains only directory and data file entries.
  406. * Since the file has been opened, we know that this is a data file and,
  407. * at a minimum, readable.
  408. */
  409. memset(buf, 0, sizeof(struct stat));
  410. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  411. /* If the write method is provided, then let's also claim that the file is
  412. * writable.
  413. */
  414. if (handler->procfsentry->ops->write != NULL)
  415. {
  416. buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR;
  417. }
  418. return OK;
  419. }
  420. /****************************************************************************
  421. * Name: procfs_opendir
  422. *
  423. * Description:
  424. * Open a directory for read access
  425. *
  426. ****************************************************************************/
  427. static int procfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
  428. FAR struct fs_dirent_s *dir)
  429. {
  430. FAR struct procfs_level0_s *level0;
  431. FAR struct procfs_dir_priv_s *dirpriv;
  432. FAR void *priv = NULL;
  433. finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL");
  434. DEBUGASSERT(mountpt && relpath && dir && !dir->u.procfs);
  435. /* The relative must be either:
  436. *
  437. * "" - The top level directory of task/thread IDs
  438. * "<pid>" - The sub-directory of task/thread attributes
  439. */
  440. if (!relpath || relpath[0] == '\0')
  441. {
  442. /* The path refers to the top level directory. Allocate the level0
  443. * dirent structure.
  444. */
  445. level0 = (FAR struct procfs_level0_s *)
  446. kmm_zalloc(sizeof(struct procfs_level0_s));
  447. if (!level0)
  448. {
  449. ferr("ERROR: Failed to allocate the level0 directory structure\n");
  450. return -ENOMEM;
  451. }
  452. /* Take a snapshot of all currently active tasks. Any new tasks
  453. * added between the opendir() and closedir() call will not be
  454. * visible.
  455. *
  456. * NOTE that interrupts must be disabled throughout the traversal.
  457. */
  458. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  459. sched_foreach(procfs_enum, level0);
  460. #else
  461. level0->base.index = 0;
  462. level0->base.nentries = 0;
  463. #endif
  464. /* Initialize lastread entries */
  465. level0->lastread = "";
  466. level0->lastlen = 0;
  467. level0->base.procfsentry = NULL;
  468. priv = (FAR void *)level0;
  469. }
  470. else
  471. {
  472. int x, ret;
  473. int len = strlen(relpath);
  474. /* Search the static array of procfs_entries */
  475. for (x = 0; x < g_procfs_entrycount; x++)
  476. {
  477. /* Test if the path matches this entry's specification */
  478. if (match(g_procfs_entries[x].pathpattern, relpath))
  479. {
  480. /* Match found! Call the handler's opendir routine. If
  481. * successful, this opendir routine will create an entry
  482. * derived from struct procfs_dir_priv_s as dir->u.procfs.
  483. */
  484. DEBUGASSERT(g_procfs_entries[x].ops != NULL &&
  485. g_procfs_entries[x].ops->opendir != NULL);
  486. ret = g_procfs_entries[x].ops->opendir(relpath, dir);
  487. if (ret == OK)
  488. {
  489. DEBUGASSERT(dir->u.procfs);
  490. /* Set the procfs_entry handler */
  491. dirpriv = (FAR struct procfs_dir_priv_s *)dir->u.procfs;
  492. dirpriv->procfsentry = &g_procfs_entries[x];
  493. }
  494. return ret;
  495. }
  496. /* Test for a sub-string match (e.g. "ls /proc/fs") */
  497. else if (strncmp(g_procfs_entries[x].pathpattern, relpath,
  498. len) == 0)
  499. {
  500. FAR struct procfs_level1_s *level1;
  501. /* Doing an intermediate directory search */
  502. /* The path refers to the top level directory. Allocate
  503. * the level1 dirent structure.
  504. */
  505. level1 = (FAR struct procfs_level1_s *)
  506. kmm_zalloc(sizeof(struct procfs_level1_s));
  507. if (!level1)
  508. {
  509. ferr("ERROR: Failed to allocate the level0 directory "
  510. "structure\n");
  511. return -ENOMEM;
  512. }
  513. level1->base.level = 1;
  514. level1->base.index = x;
  515. level1->firstindex = x;
  516. level1->subdirlen = len;
  517. level1->lastread = "";
  518. level1->lastlen = 0;
  519. level1->base.procfsentry = NULL;
  520. priv = (FAR void *)level1;
  521. break;
  522. }
  523. }
  524. }
  525. dir->u.procfs = priv;
  526. return OK;
  527. }
  528. /****************************************************************************
  529. * Name: procfs_closedir
  530. *
  531. * Description: Close the directory listing
  532. *
  533. ****************************************************************************/
  534. static int procfs_closedir(FAR struct inode *mountpt,
  535. FAR struct fs_dirent_s *dir)
  536. {
  537. FAR struct procfs_dir_priv_s *priv;
  538. DEBUGASSERT(mountpt && dir && dir->u.procfs);
  539. priv = dir->u.procfs;
  540. if (priv)
  541. {
  542. kmm_free(priv);
  543. }
  544. dir->u.procfs = NULL;
  545. return OK;
  546. }
  547. /****************************************************************************
  548. * Name: procfs_readdir
  549. *
  550. * Description: Read the next directory entry
  551. *
  552. ****************************************************************************/
  553. static int procfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
  554. {
  555. FAR const struct procfs_entry_s *entry = NULL;
  556. FAR struct procfs_dir_priv_s *priv;
  557. FAR struct procfs_level0_s *level0;
  558. FAR struct tcb_s *tcb;
  559. FAR const char *name = NULL;
  560. unsigned int index;
  561. pid_t pid;
  562. int ret = -ENOENT;
  563. DEBUGASSERT(mountpt && dir && dir->u.procfs);
  564. priv = dir->u.procfs;
  565. /* Are we reading the 1st directory level with dynamic PID and static
  566. * entries?
  567. */
  568. if (priv->level == 0)
  569. {
  570. level0 = (FAR struct procfs_level0_s *)priv;
  571. /* Have we reached the end of the PID information */
  572. index = priv->index;
  573. if (index >= priv->nentries)
  574. {
  575. /* We must report the next static entry ... no more PID entries.
  576. * skip any entries with wildcards in the first segment of the
  577. * directory name.
  578. */
  579. while (index < priv->nentries + g_procfs_entrycount)
  580. {
  581. entry = &g_procfs_entries[index - priv->nentries];
  582. name = entry->pathpattern;
  583. while (*name != '/' && *name != '\0')
  584. {
  585. if (*name == '*' || *name == '[' || *name == '?')
  586. {
  587. /* Wildcard found. Skip this entry */
  588. index++;
  589. name = NULL;
  590. break;
  591. }
  592. name++;
  593. }
  594. /* Test if we skipped this entry */
  595. if (name != NULL)
  596. {
  597. /* This entry is okay to report. Test if it has a duplicate
  598. * first level name as the one we just reported. This could
  599. * happen in the event of procfs_entry_s such as:
  600. *
  601. * fs/smartfs
  602. * fs/nfs
  603. * fs/nxffs
  604. */
  605. name = g_procfs_entries[index - priv->nentries].pathpattern;
  606. if (!level0->lastlen || (strncmp(name, level0->lastread,
  607. level0->lastlen) != 0))
  608. {
  609. /* Not a duplicate, return the first segment of this
  610. * entry
  611. */
  612. break;
  613. }
  614. else
  615. {
  616. /* Skip this entry ... duplicate 1st level name found */
  617. index++;
  618. }
  619. }
  620. }
  621. /* Test if we are at the end of the directory */
  622. if (index >= priv->nentries + g_procfs_entrycount)
  623. {
  624. /* We signal the end of the directory by returning the special
  625. * error -ENOENT
  626. */
  627. finfo("Entry %d: End of directory\n", index);
  628. ret = -ENOENT;
  629. }
  630. else
  631. {
  632. /* Report the next static entry */
  633. level0->lastlen = strcspn(name, "/");
  634. level0->lastread = name;
  635. strncpy(dir->fd_dir.d_name, name, level0->lastlen);
  636. dir->fd_dir.d_name[level0->lastlen] = '\0';
  637. /* If the entry is a directory type OR if the reported name is
  638. * only a sub-string of the entry (meaning that it contains
  639. * '/'), then report this entry as a directory.
  640. */
  641. if (entry->type == PROCFS_DIR_TYPE ||
  642. level0->lastlen != strlen(name))
  643. {
  644. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  645. }
  646. else
  647. {
  648. dir->fd_dir.d_type = DTYPE_FILE;
  649. }
  650. /* Advance to next entry for the next read */
  651. priv->index = index;
  652. ret = OK;
  653. }
  654. }
  655. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  656. else
  657. {
  658. /* Verify that the pid still refers to an active task/thread */
  659. pid = level0->pid[index];
  660. tcb = sched_gettcb(pid);
  661. if (!tcb)
  662. {
  663. ferr("ERROR: PID %d is no longer valid\n", (int)pid);
  664. return -ENOENT;
  665. }
  666. /* Save the filename=pid and file type=directory */
  667. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  668. snprintf(dir->fd_dir.d_name, NAME_MAX + 1, "%d", (int)pid);
  669. /* Set up the next directory entry offset. NOTE that we could use
  670. * the standard f_pos instead of our own private index.
  671. */
  672. level0->base.index = index + 1;
  673. ret = OK;
  674. }
  675. #endif /* CONFIG_FS_PROCFS_EXCLUDE_PROCESS */
  676. }
  677. /* Are we reading an intermediate subdirectory? */
  678. else if (priv->level > 0 && priv->procfsentry == NULL)
  679. {
  680. FAR struct procfs_level1_s *level1;
  681. level1 = (FAR struct procfs_level1_s *) priv;
  682. /* Test if this entry matches. We assume all entries of the same
  683. * subdirectory are listed in order in the procfs_entry array.
  684. */
  685. if (strncmp(g_procfs_entries[level1->base.index].pathpattern,
  686. g_procfs_entries[level1->firstindex].pathpattern,
  687. level1->subdirlen) == 0)
  688. {
  689. /* This entry matches. Report the subdir entry */
  690. name = &g_procfs_entries[level1->base.index].pathpattern[
  691. level1->subdirlen + 1];
  692. level1->lastlen = strcspn(name, "/");
  693. level1->lastread = name;
  694. strncpy(dir->fd_dir.d_name, name, level1->lastlen);
  695. /* Some of the search entries contain '**' wildcards. When we
  696. * report the entry name, we must remove this wildcard search
  697. * specifier.
  698. */
  699. while (dir->fd_dir.d_name[level1->lastlen - 1] == '*')
  700. {
  701. level1->lastlen--;
  702. }
  703. dir->fd_dir.d_name[level1->lastlen] = '\0';
  704. if (name[level1->lastlen] == '/')
  705. {
  706. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  707. }
  708. else
  709. {
  710. dir->fd_dir.d_type = DTYPE_FILE;
  711. }
  712. level1->base.index++;
  713. ret = OK;
  714. }
  715. else
  716. {
  717. /* No more entries in the subdirectory */
  718. ret = -ENOENT;
  719. }
  720. }
  721. else
  722. {
  723. /* We are performing a directory search of one of the subdirectories
  724. * and we must let the handler perform the read.
  725. */
  726. DEBUGASSERT(priv->procfsentry && priv->procfsentry->ops->readdir);
  727. ret = priv->procfsentry->ops->readdir(dir);
  728. }
  729. return ret;
  730. }
  731. /****************************************************************************
  732. * Name: procfs_rewindir
  733. *
  734. * Description: Reset directory read to the first entry
  735. *
  736. ****************************************************************************/
  737. static int procfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir)
  738. {
  739. FAR struct procfs_dir_priv_s *priv;
  740. DEBUGASSERT(mountpt && dir && dir->u.procfs);
  741. priv = dir->u.procfs;
  742. if (priv->level > 0 && priv->procfsentry == NULL)
  743. {
  744. priv->index = ((struct procfs_level1_s *) priv)->firstindex;
  745. }
  746. else
  747. {
  748. priv->index = 0;
  749. }
  750. return OK;
  751. }
  752. /****************************************************************************
  753. * Name: procfs_bind
  754. *
  755. * Description: This implements a portion of the mount operation. This
  756. * function allocates and initializes the mountpoint private data and
  757. * binds the block driver inode to the filesystem private data. The final
  758. * binding of the private data (containing the block driver) to the
  759. * mountpoint is performed by mount().
  760. *
  761. ****************************************************************************/
  762. static int procfs_bind(FAR struct inode *blkdriver, const void *data,
  763. void **handle)
  764. {
  765. #ifdef CONFIG_FS_PROCFS_REGISTER
  766. /* Make sure that we are properly initialized */
  767. procfs_initialize();
  768. #endif
  769. return OK;
  770. }
  771. /****************************************************************************
  772. * Name: procfs_unbind
  773. *
  774. * Description: This implements the filesystem portion of the umount
  775. * operation.
  776. *
  777. ****************************************************************************/
  778. static int procfs_unbind(void *handle, FAR struct inode **blkdriver,
  779. unsigned int flags)
  780. {
  781. return OK;
  782. }
  783. /****************************************************************************
  784. * Name: procfs_statfs
  785. *
  786. * Description: Return filesystem statistics
  787. *
  788. ****************************************************************************/
  789. static int procfs_statfs(struct inode *mountpt, struct statfs *buf)
  790. {
  791. /* Fill in the statfs info */
  792. memset(buf, 0, sizeof(struct statfs));
  793. buf->f_type = PROCFS_MAGIC;
  794. buf->f_bsize = 0;
  795. buf->f_blocks = 0;
  796. buf->f_bfree = 0;
  797. buf->f_bavail = 0;
  798. buf->f_namelen = NAME_MAX;
  799. return OK;
  800. }
  801. /****************************************************************************
  802. * Name: procfs_stat
  803. *
  804. * Description: Return information about a file or directory
  805. *
  806. ****************************************************************************/
  807. static int procfs_stat(struct inode *mountpt, const char *relpath,
  808. struct stat *buf)
  809. {
  810. int ret = -ENOSYS;
  811. /* Three path forms are accepted:
  812. *
  813. * "" - The relative path refers to the top level directory
  814. * "<pid>" - If <pid> refers to a currently active task/thread, then it
  815. * is a directory
  816. * "<pid>/<attr>" - If <attr> is a recognized attribute then, then it
  817. * is a file.
  818. */
  819. memset(buf, 0, sizeof(struct stat));
  820. if (!relpath || relpath[0] == '\0')
  821. {
  822. /* The path refers to the top level directory.
  823. * It's a read-only directory.
  824. */
  825. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  826. ret = OK;
  827. }
  828. else
  829. {
  830. int x;
  831. int len = strlen(relpath);
  832. /* Perform the stat based on the procfs_entry operations */
  833. for (x = 0; x < g_procfs_entrycount; x++)
  834. {
  835. /* Test if the path matches this entry's specification */
  836. if (match(g_procfs_entries[x].pathpattern, relpath))
  837. {
  838. /* Match found! Stat using this procfs entry */
  839. DEBUGASSERT(g_procfs_entries[x].ops &&
  840. g_procfs_entries[x].ops->stat);
  841. return g_procfs_entries[x].ops->stat(relpath, buf);
  842. }
  843. /* Test for an internal subdirectory stat */
  844. else if (strncmp(g_procfs_entries[x].pathpattern, relpath,
  845. len) == 0)
  846. {
  847. /* It's an internal subdirectory */
  848. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  849. ret = OK;
  850. break;
  851. }
  852. }
  853. }
  854. return ret;
  855. }
  856. /****************************************************************************
  857. * Name: procfs_initialize
  858. *
  859. * Description:
  860. * Configure the initial set of entries in the procfs file system.
  861. *
  862. * Input Parameters:
  863. * None
  864. *
  865. * Returned Value:
  866. * Zero (OK) on success; a negated errno value on failure
  867. *
  868. ****************************************************************************/
  869. #ifdef CONFIG_FS_PROCFS_REGISTER
  870. int procfs_initialize(void)
  871. {
  872. /* Are we already initialized? */
  873. if (g_procfs_entries == NULL)
  874. {
  875. /* No.. allocate a modifiable list of entries */
  876. g_procfs_entries = (FAR struct procfs_entry_s *)
  877. kmm_malloc(sizeof(g_base_entries));
  878. if (g_procfs_entries == NULL)
  879. {
  880. return -ENOMEM;
  881. }
  882. /* And copy the fixed entries into the allocated array */
  883. memcpy(g_procfs_entries, g_base_entries, sizeof(g_base_entries));
  884. g_procfs_entrycount = g_base_entrycount;
  885. }
  886. return OK;
  887. }
  888. #endif
  889. /****************************************************************************
  890. * Public Functions
  891. ****************************************************************************/
  892. /****************************************************************************
  893. * Name: procfs_register
  894. *
  895. * Description:
  896. * Add a new entry to the procfs file system.
  897. *
  898. * NOTE: This function should be called *prior* to mounting the procfs
  899. * file system to prevent concurrency problems with the modification of
  900. * the procfs data set while it is in use.
  901. *
  902. * Input Parameters:
  903. * entry - Describes the entry to be registered.
  904. *
  905. * Returned Value:
  906. * Zero (OK) on success; a negated errno value on failure
  907. *
  908. ****************************************************************************/
  909. #ifdef CONFIG_FS_PROCFS_REGISTER
  910. int procfs_register(FAR const struct procfs_entry_s *entry)
  911. {
  912. FAR struct procfs_entry_s *newtable;
  913. unsigned int newcount;
  914. size_t newsize;
  915. int ret;
  916. /* Make sure that we are properly initialized */
  917. procfs_initialize();
  918. /* realloc the table of procfs entries.
  919. *
  920. * REVISIT: This reallocation may free memory previously used for the
  921. * procfs entry table. If that table were actively in use, then that
  922. * could cause procfs logic to use a stale memory pointer! We avoid that
  923. * problem by requiring that the procfs file be unmounted when the new
  924. * entry is added. That requirement, however, is not enforced explicitly.
  925. *
  926. * Locking the scheduler as done below is insufficient. As would be just
  927. * marking the entries as volatile.
  928. */
  929. newcount = g_procfs_entrycount + 1;
  930. newsize = newcount * sizeof(struct procfs_entry_s);
  931. sched_lock();
  932. newtable = (FAR struct procfs_entry_s *)
  933. kmm_realloc(g_procfs_entries, newsize);
  934. if (newtable == NULL)
  935. {
  936. /* Reallocation failed! */
  937. ret = -ENOMEM;
  938. }
  939. else
  940. {
  941. /* Copy the new entry at the end of the reallocated table */
  942. memcpy(&newtable[g_procfs_entrycount], entry,
  943. sizeof(struct procfs_entry_s));
  944. /* Instantiate the reallocated table */
  945. g_procfs_entries = newtable;
  946. g_procfs_entrycount = newcount;
  947. ret = OK;
  948. }
  949. sched_unlock();
  950. return ret;
  951. }
  952. #endif
  953. #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */