fs_procfs.c 35 KB

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