fs_procfs.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  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 module_operations;
  74. extern const struct procfs_operations uptime_operations;
  75. extern const struct procfs_operations version_operations;
  76. /* This is not good. These are implemented in other sub-systems. Having to
  77. * deal with them here is not a good coupling. What is really needed is a
  78. * run-time procfs registration system vs. a build time, fixed procfs
  79. * configuration.
  80. */
  81. extern const struct procfs_operations net_procfsoperations;
  82. extern const struct procfs_operations net_procfs_routeoperations;
  83. extern const struct procfs_operations part_procfsoperations;
  84. extern const struct procfs_operations mount_procfsoperations;
  85. extern const struct procfs_operations smartfs_procfsoperations;
  86. /* And even worse, this one is specific to the STM32. The solution to
  87. * this nasty couple would be to replace this hard-coded, ROM-able
  88. * operations table with a RAM-base registration table.
  89. */
  90. #if defined(CONFIG_STM32_CCM_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_CCM)
  91. extern const struct procfs_operations ccm_procfsoperations;
  92. #endif
  93. /****************************************************************************
  94. * Private Types
  95. ****************************************************************************/
  96. /* Table of all known / pre-registered procfs handlers / participants. */
  97. #ifdef CONFIG_FS_PROCFS_REGISTER
  98. static const struct procfs_entry_s g_base_entries[] =
  99. #else
  100. static const struct procfs_entry_s g_procfs_entries[] =
  101. #endif
  102. {
  103. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  104. { "[0-9]*/**", &proc_operations, PROCFS_UNKOWN_TYPE },
  105. { "[0-9]*", &proc_operations, PROCFS_DIR_TYPE },
  106. #endif
  107. #if defined(CONFIG_SCHED_CPULOAD) && !defined(CONFIG_FS_PROCFS_EXCLUDE_CPULOAD)
  108. { "cpuload", &cpuload_operations, PROCFS_FILE_TYPE },
  109. #endif
  110. #if defined(CONFIG_SCHED_CRITMONITOR)
  111. { "critmon", &critmon_operations, PROCFS_FILE_TYPE },
  112. #endif
  113. #ifdef CONFIG_SCHED_IRQMONITOR
  114. { "irqs", &irq_operations, PROCFS_FILE_TYPE },
  115. #endif
  116. #ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMINFO
  117. { "meminfo", &meminfo_operations, PROCFS_FILE_TYPE },
  118. #endif
  119. #if defined(CONFIG_MODULE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
  120. { "modules", &module_operations, PROCFS_FILE_TYPE },
  121. #endif
  122. #ifndef CONFIG_FS_PROCFS_EXCLUDE_BLOCKS
  123. { "fs/blocks", &mount_procfsoperations, PROCFS_FILE_TYPE },
  124. #endif
  125. #ifndef CONFIG_FS_PROCFS_EXCLUDE_MOUNT
  126. { "fs/mount", &mount_procfsoperations, PROCFS_FILE_TYPE },
  127. #endif
  128. #ifndef CONFIG_FS_PROCFS_EXCLUDE_USAGE
  129. { "fs/usage", &mount_procfsoperations, PROCFS_FILE_TYPE },
  130. #endif
  131. #if defined(CONFIG_FS_SMARTFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)
  132. { "fs/smartfs**", &smartfs_procfsoperations, PROCFS_UNKOWN_TYPE },
  133. #endif
  134. #if defined(CONFIG_NET) && !defined(CONFIG_FS_PROCFS_EXCLUDE_NET)
  135. { "net", &net_procfsoperations, PROCFS_DIR_TYPE },
  136. #if defined(CONFIG_NET_ROUTE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_ROUTE)
  137. { "net/route", &net_procfs_routeoperations, PROCFS_DIR_TYPE },
  138. { "net/route/**", &net_procfs_routeoperations, PROCFS_UNKOWN_TYPE },
  139. #endif
  140. { "net/**", &net_procfsoperations, PROCFS_UNKOWN_TYPE },
  141. #endif
  142. #if defined(CONFIG_MTD_PARTITION) && !defined(CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS)
  143. { "partitions", &part_procfsoperations, PROCFS_FILE_TYPE },
  144. #endif
  145. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  146. { "self", &proc_operations, PROCFS_DIR_TYPE },
  147. { "self/**", &proc_operations, PROCFS_UNKOWN_TYPE },
  148. #endif
  149. #if !defined(CONFIG_FS_PROCFS_EXCLUDE_UPTIME)
  150. { "uptime", &uptime_operations, PROCFS_FILE_TYPE },
  151. #endif
  152. #if !defined(CONFIG_FS_PROCFS_EXCLUDE_VERSION)
  153. { "version", &version_operations, PROCFS_FILE_TYPE },
  154. #endif
  155. };
  156. #ifdef CONFIG_FS_PROCFS_REGISTER
  157. static const uint8_t g_base_entrycount = sizeof(g_base_entries) /
  158. sizeof(struct procfs_entry_s);
  159. static FAR struct procfs_entry_s *g_procfs_entries;
  160. static uint8_t g_procfs_entrycount;
  161. #else
  162. static const uint8_t g_procfs_entrycount = sizeof(g_procfs_entries) /
  163. sizeof(struct procfs_entry_s);
  164. #endif
  165. /****************************************************************************
  166. * Private Function Prototypes
  167. ****************************************************************************/
  168. /* Helpers */
  169. static void procfs_enum(FAR struct tcb_s *tcb, FAR void *arg);
  170. /* File system methods */
  171. static int procfs_open(FAR struct file *filep, FAR const char *relpath,
  172. int oflags, mode_t mode);
  173. static int procfs_close(FAR struct file *filep);
  174. static ssize_t procfs_read(FAR struct file *filep, FAR char *buffer,
  175. size_t buflen);
  176. static ssize_t procfs_write(FAR struct file *filep, FAR const char *buffer,
  177. size_t buflen);
  178. static int procfs_ioctl(FAR struct file *filep, int cmd,
  179. unsigned long arg);
  180. static int procfs_dup(FAR const struct file *oldp,
  181. FAR struct file *newp);
  182. static int procfs_fstat(FAR const struct file *filep,
  183. FAR struct stat *buf);
  184. static int procfs_opendir(FAR struct inode *mountpt, const char *relpath,
  185. FAR struct fs_dirent_s *dir);
  186. static int procfs_closedir(FAR struct inode *mountpt,
  187. FAR struct fs_dirent_s *dir);
  188. static int procfs_readdir(FAR struct inode *mountpt,
  189. FAR struct fs_dirent_s *dir);
  190. static int procfs_rewinddir(FAR struct inode *mountpt,
  191. FAR struct fs_dirent_s *dir);
  192. static int procfs_bind(FAR struct inode *blkdriver,
  193. FAR const void *data, FAR void **handle);
  194. static int procfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
  195. unsigned int flags);
  196. static int procfs_statfs(FAR struct inode *mountpt,
  197. FAR struct statfs *buf);
  198. static int procfs_stat(FAR struct inode *mountpt,
  199. FAR const char *relpath, FAR struct stat *buf);
  200. /* Initialization */
  201. #ifdef CONFIG_FS_PROCFS_REGISTER
  202. int procfs_initialize(void);
  203. #else
  204. # define procfs_initialize()
  205. #endif
  206. /****************************************************************************
  207. * Private Data
  208. ****************************************************************************/
  209. /****************************************************************************
  210. * Public Data
  211. ****************************************************************************/
  212. /* See fs_mount.c -- this structure is explicitly externed there.
  213. * We use the old-fashioned kind of initializers so that this will compile
  214. * with any compiler.
  215. */
  216. const struct mountpt_operations procfs_operations =
  217. {
  218. procfs_open, /* open */
  219. procfs_close, /* close */
  220. procfs_read, /* read */
  221. procfs_write, /* write */
  222. NULL, /* seek */
  223. procfs_ioctl, /* ioctl */
  224. NULL, /* sync */
  225. procfs_dup, /* dup */
  226. procfs_fstat, /* fstat */
  227. NULL, /* truncate */
  228. procfs_opendir, /* opendir */
  229. procfs_closedir, /* closedir */
  230. procfs_readdir, /* readdir */
  231. procfs_rewinddir, /* rewinddir */
  232. procfs_bind, /* bind */
  233. procfs_unbind, /* unbind */
  234. procfs_statfs, /* statfs */
  235. NULL, /* unlink */
  236. NULL, /* mkdir */
  237. NULL, /* rmdir */
  238. NULL, /* rename */
  239. procfs_stat /* stat */
  240. };
  241. /* Level 0 contains the directory of active tasks in addition to other
  242. * statically registered entries with custom handlers. This strcture
  243. * contains a snapshot of the active tasks when the directory is first
  244. * opened.
  245. */
  246. struct procfs_level0_s
  247. {
  248. struct procfs_dir_priv_s base; /* Base struct for ProcFS dir */
  249. /* Our private data */
  250. uint8_t lastlen; /* length of last reported static dir */
  251. pid_t pid[CONFIG_MAX_TASKS]; /* Snapshot of all active task IDs */
  252. FAR const char *lastread; /* Pointer to last static dir read */
  253. };
  254. /* Level 1 is an internal virtual directory (such as /proc/fs) which
  255. * will contain one or more additional static entries based on the
  256. * configuration.
  257. */
  258. struct procfs_level1_s
  259. {
  260. struct procfs_dir_priv_s base; /* Base struct for ProcFS dir */
  261. /* Our private data */
  262. uint8_t lastlen; /* length of last reported static dir */
  263. uint8_t subdirlen; /* Length of the subdir search */
  264. uint16_t firstindex; /* Index of 1st entry matching this subdir */
  265. FAR const char *lastread; /* Pointer to last static dir read */
  266. };
  267. /****************************************************************************
  268. * Private Functions
  269. ****************************************************************************/
  270. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  271. /****************************************************************************
  272. * Name: procfs_enum
  273. ****************************************************************************/
  274. static void procfs_enum(FAR struct tcb_s *tcb, FAR void *arg)
  275. {
  276. FAR struct procfs_level0_s *dir = (FAR struct procfs_level0_s *)arg;
  277. int index;
  278. DEBUGASSERT(dir);
  279. /* Add the PID to the list */
  280. index = dir->base.nentries;
  281. DEBUGASSERT(index < CONFIG_MAX_TASKS);
  282. dir->pid[index] = tcb->pid;
  283. dir->base.nentries = index + 1;
  284. }
  285. #endif
  286. /****************************************************************************
  287. * Name: procfs_open
  288. ****************************************************************************/
  289. static int procfs_open(FAR struct file *filep, FAR const char *relpath,
  290. int oflags, mode_t mode)
  291. {
  292. int x, 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 successful,
  481. * this opendir routine will create an entry derived from struct
  482. * procfs_dir_priv_s as dir->u.procfs.
  483. */
  484. DEBUGASSERT(g_procfs_entries[x].ops && g_procfs_entries[x].ops->opendir);
  485. ret = g_procfs_entries[x].ops->opendir(relpath, dir);
  486. if (ret == OK)
  487. {
  488. DEBUGASSERT(dir->u.procfs);
  489. /* Set the procfs_entry handler */
  490. dirpriv = (FAR struct procfs_dir_priv_s *)dir->u.procfs;
  491. dirpriv->procfsentry = &g_procfs_entries[x];
  492. }
  493. return ret;
  494. }
  495. /* Test for a sub-string match (e.g. "ls /proc/fs") */
  496. else if (strncmp(g_procfs_entries[x].pathpattern, relpath, len) == 0)
  497. {
  498. FAR struct procfs_level1_s *level1;
  499. /* Doing an intermediate directory search */
  500. /* The path refers to the top level directory. Allocate the level1
  501. * dirent structure.
  502. */
  503. level1 = (FAR struct procfs_level1_s *)
  504. kmm_zalloc(sizeof(struct procfs_level1_s));
  505. if (!level1)
  506. {
  507. ferr("ERROR: Failed to allocate the level0 directory structure\n");
  508. return -ENOMEM;
  509. }
  510. level1->base.level = 1;
  511. level1->base.index = x;
  512. level1->firstindex = x;
  513. level1->subdirlen = len;
  514. level1->lastread = "";
  515. level1->lastlen = 0;
  516. level1->base.procfsentry = NULL;
  517. priv = (FAR void *)level1;
  518. break;
  519. }
  520. }
  521. }
  522. dir->u.procfs = priv;
  523. return OK;
  524. }
  525. /****************************************************************************
  526. * Name: procfs_closedir
  527. *
  528. * Description: Close the directory listing
  529. *
  530. ****************************************************************************/
  531. static int procfs_closedir(FAR struct inode *mountpt,
  532. FAR struct fs_dirent_s *dir)
  533. {
  534. FAR struct procfs_dir_priv_s *priv;
  535. DEBUGASSERT(mountpt && dir && dir->u.procfs);
  536. priv = dir->u.procfs;
  537. if (priv)
  538. {
  539. kmm_free(priv);
  540. }
  541. dir->u.procfs = NULL;
  542. return OK;
  543. }
  544. /****************************************************************************
  545. * Name: procfs_readdir
  546. *
  547. * Description: Read the next directory entry
  548. *
  549. ****************************************************************************/
  550. static int procfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
  551. {
  552. FAR const struct procfs_entry_s *entry = NULL;
  553. FAR struct procfs_dir_priv_s *priv;
  554. FAR struct procfs_level0_s *level0;
  555. FAR struct tcb_s *tcb;
  556. FAR const char *name = NULL;
  557. unsigned int index;
  558. pid_t pid;
  559. int ret = -ENOENT;
  560. DEBUGASSERT(mountpt && dir && dir->u.procfs);
  561. priv = dir->u.procfs;
  562. /* Are we reading the 1st directory level with dynamic PID and static
  563. * entries?
  564. */
  565. if (priv->level == 0)
  566. {
  567. level0 = (FAR struct procfs_level0_s *)priv;
  568. /* Have we reached the end of the PID information */
  569. index = priv->index;
  570. if (index >= priv->nentries)
  571. {
  572. /* We must report the next static entry ... no more PID entries.
  573. * skip any entries with wildcards in the first segment of the
  574. * directory name.
  575. */
  576. while (index < priv->nentries + g_procfs_entrycount)
  577. {
  578. entry = &g_procfs_entries[index - priv->nentries];
  579. name = entry->pathpattern;
  580. while (*name != '/' && *name != '\0')
  581. {
  582. if (*name == '*' || *name == '[' || *name == '?')
  583. {
  584. /* Wildcard found. Skip this entry */
  585. index++;
  586. name = NULL;
  587. break;
  588. }
  589. name++;
  590. }
  591. /* Test if we skipped this entry */
  592. if (name != NULL)
  593. {
  594. /* This entry is okay to report. Test if it has a duplicate
  595. * first level name as the one we just reported. This could
  596. * happen in the event of procfs_entry_s such as:
  597. *
  598. * fs/smartfs
  599. * fs/nfs
  600. * fs/nxffs
  601. */
  602. name = g_procfs_entries[index - priv->nentries].pathpattern;
  603. if (!level0->lastlen || (strncmp(name, level0->lastread,
  604. level0->lastlen) != 0))
  605. {
  606. /* Not a duplicate, return the first segment of this
  607. * entry
  608. */
  609. break;
  610. }
  611. else
  612. {
  613. /* Skip this entry ... duplicate 1st level name found */
  614. index++;
  615. }
  616. }
  617. }
  618. /* Test if we are at the end of the directory */
  619. if (index >= priv->nentries + g_procfs_entrycount)
  620. {
  621. /* We signal the end of the directory by returning the special
  622. * error -ENOENT
  623. */
  624. finfo("Entry %d: End of directory\n", index);
  625. ret = -ENOENT;
  626. }
  627. else
  628. {
  629. /* Report the next static entry */
  630. level0->lastlen = strcspn(name, "/");
  631. level0->lastread = name;
  632. strncpy(dir->fd_dir.d_name, name, level0->lastlen);
  633. dir->fd_dir.d_name[level0->lastlen] = '\0';
  634. /* If the entry is a directory type OR if the reported name is
  635. * only a sub-string of the entry (meaning that it contains
  636. * '/'), then report this entry as a directory.
  637. */
  638. if (entry->type == PROCFS_DIR_TYPE ||
  639. level0->lastlen != strlen(name))
  640. {
  641. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  642. }
  643. else
  644. {
  645. dir->fd_dir.d_type = DTYPE_FILE;
  646. }
  647. /* Advance to next entry for the next read */
  648. priv->index = index;
  649. ret = OK;
  650. }
  651. }
  652. #ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
  653. else
  654. {
  655. /* Verify that the pid still refers to an active task/thread */
  656. pid = level0->pid[index];
  657. tcb = sched_gettcb(pid);
  658. if (!tcb)
  659. {
  660. ferr("ERROR: PID %d is no longer valid\n", (int)pid);
  661. return -ENOENT;
  662. }
  663. /* Save the filename=pid and file type=directory */
  664. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  665. snprintf(dir->fd_dir.d_name, NAME_MAX+1, "%d", (int)pid);
  666. /* Set up the next directory entry offset. NOTE that we could use the
  667. * standard f_pos instead of our own private index.
  668. */
  669. level0->base.index = index + 1;
  670. ret = OK;
  671. }
  672. #endif /* CONFIG_FS_PROCFS_EXCLUDE_PROCESS */
  673. }
  674. /* Are we reading an intermediate subdirectory? */
  675. else if (priv->level > 0 && priv->procfsentry == NULL)
  676. {
  677. FAR struct procfs_level1_s *level1;
  678. level1 = (FAR struct procfs_level1_s *) priv;
  679. /* Test if this entry matches. We assume all entries of the same
  680. * subdirectory are listed in order in the procfs_entry array.
  681. */
  682. if (strncmp(g_procfs_entries[level1->base.index].pathpattern,
  683. g_procfs_entries[level1->firstindex].pathpattern,
  684. level1->subdirlen) == 0)
  685. {
  686. /* This entry matches. Report the subdir entry */
  687. name = &g_procfs_entries[level1->base.index].pathpattern[
  688. level1->subdirlen + 1];
  689. level1->lastlen = strcspn(name, "/");
  690. level1->lastread = name;
  691. strncpy(dir->fd_dir.d_name, name, level1->lastlen);
  692. /* Some of the search entries contain '**' wildcards. When we
  693. * report the entry name, we must remove this wildcard search
  694. * specifier.
  695. */
  696. while (dir->fd_dir.d_name[level1->lastlen - 1] == '*')
  697. {
  698. level1->lastlen--;
  699. }
  700. dir->fd_dir.d_name[level1->lastlen] = '\0';
  701. if (name[level1->lastlen] == '/')
  702. {
  703. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  704. }
  705. else
  706. {
  707. dir->fd_dir.d_type = DTYPE_FILE;
  708. }
  709. level1->base.index++;
  710. ret = OK;
  711. }
  712. else
  713. {
  714. /* No more entries in the subdirectory */
  715. ret = -ENOENT;
  716. }
  717. }
  718. else
  719. {
  720. /* We are performing a directory search of one of the subdirectories
  721. * and we must let the handler perform the read.
  722. */
  723. DEBUGASSERT(priv->procfsentry && priv->procfsentry->ops->readdir);
  724. ret = priv->procfsentry->ops->readdir(dir);
  725. }
  726. return ret;
  727. }
  728. /****************************************************************************
  729. * Name: procfs_rewindir
  730. *
  731. * Description: Reset directory read to the first entry
  732. *
  733. ****************************************************************************/
  734. static int procfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir)
  735. {
  736. FAR struct procfs_dir_priv_s *priv;
  737. DEBUGASSERT(mountpt && dir && dir->u.procfs);
  738. priv = dir->u.procfs;
  739. if (priv->level > 0 && priv->procfsentry == NULL)
  740. {
  741. priv->index = ((struct procfs_level1_s *) priv)->firstindex;
  742. }
  743. else
  744. {
  745. priv->index = 0;
  746. }
  747. return OK;
  748. }
  749. /****************************************************************************
  750. * Name: procfs_bind
  751. *
  752. * Description: This implements a portion of the mount operation. This
  753. * function allocates and initializes the mountpoint private data and
  754. * binds the blockdriver inode to the filesystem private data. The final
  755. * binding of the private data (containing the blockdriver) to the
  756. * mountpoint is performed by mount().
  757. *
  758. ****************************************************************************/
  759. static int procfs_bind(FAR struct inode *blkdriver, const void *data,
  760. void **handle)
  761. {
  762. /* Make sure that we are properly initialized */
  763. procfs_initialize();
  764. return OK;
  765. }
  766. /****************************************************************************
  767. * Name: procfs_unbind
  768. *
  769. * Description: This implements the filesystem portion of the umount
  770. * operation.
  771. *
  772. ****************************************************************************/
  773. static int procfs_unbind(void *handle, FAR struct inode **blkdriver,
  774. unsigned int flags)
  775. {
  776. return OK;
  777. }
  778. /****************************************************************************
  779. * Name: procfs_statfs
  780. *
  781. * Description: Return filesystem statistics
  782. *
  783. ****************************************************************************/
  784. static int procfs_statfs(struct inode *mountpt, struct statfs *buf)
  785. {
  786. /* Fill in the statfs info */
  787. memset(buf, 0, sizeof(struct statfs));
  788. buf->f_type = PROCFS_MAGIC;
  789. buf->f_bsize = 0;
  790. buf->f_blocks = 0;
  791. buf->f_bfree = 0;
  792. buf->f_bavail = 0;
  793. buf->f_namelen = NAME_MAX;
  794. return OK;
  795. }
  796. /****************************************************************************
  797. * Name: procfs_stat
  798. *
  799. * Description: Return information about a file or directory
  800. *
  801. ****************************************************************************/
  802. static int procfs_stat(struct inode *mountpt, const char *relpath,
  803. struct stat *buf)
  804. {
  805. int ret = -ENOSYS;
  806. /* Three path forms are accepted:
  807. *
  808. * "" - The relative path refers to the top level directory
  809. * "<pid>" - If <pid> refers to a currently active task/thread, then it
  810. * is a directory
  811. * "<pid>/<attr>" - If <attr> is a recognized attribute then, then it
  812. * is a file.
  813. */
  814. memset(buf, 0, sizeof(struct stat));
  815. if (!relpath || relpath[0] == '\0')
  816. {
  817. /* The path refers to the top level directory */
  818. /* It's a read-only directory */
  819. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  820. ret = OK;
  821. }
  822. else
  823. {
  824. int x;
  825. int len = strlen(relpath);
  826. /* Perform the stat based on the procfs_entry operations */
  827. for (x = 0; x < g_procfs_entrycount; x++)
  828. {
  829. /* Test if the path matches this entry's specification */
  830. if (match(g_procfs_entries[x].pathpattern, relpath))
  831. {
  832. /* Match found! Stat using this procfs entry */
  833. DEBUGASSERT(g_procfs_entries[x].ops &&
  834. g_procfs_entries[x].ops->stat);
  835. return g_procfs_entries[x].ops->stat(relpath, buf);
  836. }
  837. /* Test for an internal subdirectory stat */
  838. else if (strncmp(g_procfs_entries[x].pathpattern, relpath, len) == 0)
  839. {
  840. /* It's an internal subdirectory */
  841. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  842. ret = OK;
  843. break;
  844. }
  845. }
  846. }
  847. return ret;
  848. }
  849. /****************************************************************************
  850. * Name: procfs_initialize
  851. *
  852. * Description:
  853. * Configure the initial set of entries in the procfs file system.
  854. *
  855. * Input Parameters:
  856. * None
  857. *
  858. * Returned Value:
  859. * Zero (OK) on success; a negated errno value on failure
  860. *
  861. ****************************************************************************/
  862. #ifdef CONFIG_FS_PROCFS_REGISTER
  863. int procfs_initialize(void)
  864. {
  865. /* Are we already initialized? */
  866. if (g_procfs_entries == NULL)
  867. {
  868. /* No.. allocate a modifyable list of entries */
  869. g_procfs_entries = (FAR struct procfs_entry_s *)
  870. kmm_malloc(sizeof(g_base_entries));
  871. if (g_procfs_entries == NULL)
  872. {
  873. return -ENOMEM;
  874. }
  875. /* And copy the fixed entries into the allocated array */
  876. memcpy(g_procfs_entries, g_base_entries, sizeof(g_base_entries));
  877. g_procfs_entrycount = g_base_entrycount;
  878. }
  879. return OK;
  880. }
  881. #endif
  882. /****************************************************************************
  883. * Public Functions
  884. ****************************************************************************/
  885. /****************************************************************************
  886. * Name: procfs_register
  887. *
  888. * Description:
  889. * Add a new entry to the procfs file system.
  890. *
  891. * NOTE: This function should be called *prior* to mounting the procfs
  892. * file system to prevent concurrency problems with the modification of
  893. * the procfs data set while it is in use.
  894. *
  895. * Input Parameters:
  896. * entry - Describes the entry to be registered.
  897. *
  898. * Returned Value:
  899. * Zero (OK) on success; a negated errno value on failure
  900. *
  901. ****************************************************************************/
  902. #ifdef CONFIG_FS_PROCFS_REGISTER
  903. int procfs_register(FAR const struct procfs_entry_s *entry)
  904. {
  905. FAR struct procfs_entry_s *newtable;
  906. unsigned int newcount;
  907. size_t newsize;
  908. int ret;
  909. /* Make sure that we are properly initialized */
  910. procfs_initialize();
  911. /* realloc the table of procfs entries.
  912. *
  913. * REVISIT: This reallocation may free memory previously used for the
  914. * procfs entry table. If that table were actively in use, then that
  915. * could cause procfs logic to use a stale memory pointer! We avoid that
  916. * problem by requiring that the procfs file be unmounted when the new
  917. * entry is added. That requirement, however, is not enforced explicitly.
  918. *
  919. * Locking the scheduler as done below is insufficient. As would be just
  920. * marking the entries as volatile.
  921. */
  922. newcount = g_procfs_entrycount + 1;
  923. newsize = newcount * sizeof(struct procfs_entry_s);
  924. sched_lock();
  925. newtable = (FAR struct procfs_entry_s *)kmm_realloc(g_procfs_entries, newsize);
  926. if (newtable == NULL)
  927. {
  928. /* Reallocation failed! */
  929. ret = -ENOMEM;
  930. }
  931. else
  932. {
  933. /* Copy the new entry at the end of the reallocated table */
  934. memcpy(&newtable[g_procfs_entrycount], entry, sizeof(struct procfs_entry_s));
  935. /* Instantiate the reallocated table */
  936. g_procfs_entries = newtable;
  937. g_procfs_entrycount = newcount;
  938. ret = OK;
  939. }
  940. sched_unlock();
  941. return ret;
  942. }
  943. #endif
  944. #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */