1
0

ptyfs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-12-02 Shell init ver.
  9. */
  10. #define DBG_TAG "filesystem.ptyfs"
  11. #define DBG_LVL DBG_INFO
  12. #include <rtdbg.h>
  13. #include "ptyfs.h"
  14. #include <dfs.h>
  15. #include <dfs_fs.h>
  16. #include <dfs_dentry.h>
  17. #include <dfs_file.h>
  18. #include <dfs_mnt.h>
  19. #include <devfs.h>
  20. #include <rid_bitmap.h>
  21. #include <rthw.h>
  22. #include <rtthread.h>
  23. #include <terminal/terminal.h>
  24. #include <dirent.h>
  25. #include <unistd.h>
  26. #ifndef S_IRWXUGO
  27. #define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
  28. #endif /* S_IRWXUGO */
  29. #ifndef S_IALLUGO
  30. #define S_IALLUGO (S_ISUID | S_ISGID | S_ISVTX | S_IRWXUGO)
  31. #endif /* S_IALLUGO */
  32. #ifndef S_IRUGO
  33. #define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
  34. #endif /* S_IRUGO */
  35. #ifndef S_IWUGO
  36. #define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
  37. #endif /* S_IWUGO */
  38. #ifndef S_IXUGO
  39. #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
  40. #endif /* S_IXUGO */
  41. #define PTYFS_MAGIC 0x9D94A07D
  42. #define PTYFS_TYPE_DIR 0x00
  43. #define PTYFS_TYPE_FILE_PTMX 0x01
  44. #define PTYFS_TYPE_FILE_SLAVE 0x02
  45. /* TODO: using Symbolic permission, but not ours */
  46. #define PTMX_DEFAULT_FILE_MODE (S_IFCHR | 0666)
  47. #define PTS_DEFAULT_FILE_MODE (S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP)
  48. #define ROOT_DEFUALT_FILE_MODE (S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR)
  49. struct ptyfs_sb;
  50. struct ptyfs_file
  51. {
  52. char basename[DIRENT_NAME_MAX]; /* file name */
  53. rt_uint32_t mode; /* file modes allowed */
  54. rt_uint32_t type; /* file type */
  55. rt_list_t subdirs; /* file subdir list */
  56. rt_list_t ent_node; /* entry node in subdir list */
  57. struct ptyfs_sb *sb; /* superblock ptr */
  58. rt_device_t device; /* device binding on this file */
  59. };
  60. struct ptyfs_sb
  61. {
  62. struct rt_device ptmx_device; /* ptmx device */
  63. struct rt_mutex lock; /* tmpfs lock */
  64. struct ptyfs_file root_file; /* root dir */
  65. struct ptyfs_file ptmx_file; /* `/ptmx` file */
  66. struct rid_bitmap ptsno_pool; /* pts number pool */
  67. rt_uint32_t magic; /* PTYFS_MAGIC */
  68. rt_size_t df_size; /* df size */
  69. rt_list_t sibling; /* sb sibling list */
  70. struct dfs_mnt *mount; /* mount data */
  71. /**
  72. * Note: This upper limit is set to protect kernel memory from draining
  73. * out by the application if it keeps allocating pty devices.
  74. *
  75. * Still, current implementation of bitmap can not efficiently use the
  76. * memory
  77. */
  78. rt_bitmap_t
  79. ptsno_pool_bitset[LWP_PTY_MAX_PARIS_LIMIT / (sizeof(rt_bitmap_t) * 8)];
  80. };
  81. static struct dfs_file_ops _default_fops;
  82. static int _split_out_subdir(const char *path, char *name)
  83. {
  84. const char *subpath = path;
  85. while (*subpath == '/' && *subpath)
  86. {
  87. subpath++;
  88. }
  89. while (*subpath != '/' && *subpath)
  90. {
  91. *name++ = *subpath++;
  92. }
  93. *name = '\0';
  94. return 0;
  95. }
  96. static rt_err_t ptyfile_init(struct ptyfs_file *file, struct ptyfs_sb *sb,
  97. const char *name, rt_uint32_t type,
  98. rt_uint32_t mode, rt_device_t device)
  99. {
  100. if (name)
  101. strncpy(file->basename, name, sizeof(file->basename));
  102. file->type = type;
  103. file->mode = mode;
  104. rt_list_init(&file->subdirs);
  105. rt_list_init(&file->ent_node);
  106. file->sb = sb;
  107. file->device = device;
  108. return 0;
  109. }
  110. static rt_err_t ptyfile_add_to_root(struct ptyfs_sb *sb,
  111. struct ptyfs_file *new_file)
  112. {
  113. struct ptyfs_file *root_file = &sb->root_file;
  114. /* update super block */
  115. sb->df_size += sizeof(struct ptyfs_file);
  116. rt_mutex_take(&sb->lock, RT_WAITING_FOREVER);
  117. rt_list_insert_after(&(root_file->subdirs), &(new_file->ent_node));
  118. rt_mutex_release(&sb->lock);
  119. return 0;
  120. }
  121. static rt_err_t ptyfile_remove_from_root(struct ptyfs_sb *sb,
  122. struct ptyfs_file *rm_file)
  123. {
  124. /* update super block */
  125. sb->df_size -= sizeof(struct ptyfs_file);
  126. rt_mutex_take(&sb->lock, RT_WAITING_FOREVER);
  127. rt_list_remove(&(rm_file->ent_node));
  128. rt_mutex_release(&sb->lock);
  129. return 0;
  130. }
  131. static struct ptyfs_file *ptyfile_lookup(struct ptyfs_sb *superblock,
  132. const char *path)
  133. {
  134. const char *subpath_iter, *curpath_iter, *basename = RT_NULL;
  135. char subdir_name[DIRENT_NAME_MAX];
  136. struct ptyfs_file *curfile, *found_file = RT_NULL;
  137. rt_list_t *list;
  138. int do_path_resolve = 1;
  139. subpath_iter = path;
  140. /* skip starting "/" */
  141. while (*subpath_iter == '/') subpath_iter++;
  142. if (!*subpath_iter)
  143. {
  144. return &(superblock->root_file);
  145. }
  146. curpath_iter = subpath_iter;
  147. curfile = &superblock->root_file;
  148. /* resolve chain of files splited from path one by one */
  149. while (do_path_resolve)
  150. {
  151. do_path_resolve = 0;
  152. /* splitout sub-directory or basename */
  153. while (*subpath_iter != '/' && *subpath_iter) subpath_iter++;
  154. if (!*subpath_iter)
  155. {
  156. basename = curpath_iter;
  157. }
  158. else
  159. {
  160. _split_out_subdir(curpath_iter, subdir_name);
  161. /* skip "/" for next search */
  162. subpath_iter++;
  163. }
  164. rt_mutex_take(&superblock->lock, RT_WAITING_FOREVER);
  165. rt_list_for_each(list, &curfile->subdirs)
  166. {
  167. struct ptyfs_file *file_iter;
  168. file_iter = rt_list_entry(list, struct ptyfs_file, ent_node);
  169. if (basename)
  170. {
  171. if (strcmp(file_iter->basename, basename) == 0)
  172. {
  173. found_file = file_iter;
  174. break;
  175. }
  176. }
  177. else if (strcmp(file_iter->basename, subdir_name) == 0)
  178. {
  179. curpath_iter = subpath_iter;
  180. curfile = file_iter;
  181. do_path_resolve = 1;
  182. break;
  183. }
  184. }
  185. rt_mutex_release(&superblock->lock);
  186. }
  187. return found_file;
  188. }
  189. const char *ptyfs_get_rootpath(rt_device_t ptmx)
  190. {
  191. const char *rc;
  192. struct ptyfs_sb *sb;
  193. /* allocate id for it and register file */
  194. sb = rt_container_of(ptmx, struct ptyfs_sb, ptmx_device);
  195. if (sb->magic != PTYFS_MAGIC)
  196. {
  197. rc = 0;
  198. }
  199. else
  200. {
  201. /* fullpath is always started with /dev/ */
  202. return sb->mount->fullpath + 5;
  203. }
  204. return rc;
  205. }
  206. ptsno_t ptyfs_register_pts(rt_device_t ptmx, rt_device_t pts)
  207. {
  208. ptsno_t rc;
  209. struct ptyfs_sb *sb;
  210. struct ptyfs_file *pts_file;
  211. struct rid_bitmap *ptsno_pool;
  212. /* allocate id for it and register file */
  213. sb = rt_container_of(ptmx, struct ptyfs_sb, ptmx_device);
  214. if (sb->magic != PTYFS_MAGIC)
  215. {
  216. rc = -1;
  217. }
  218. else
  219. {
  220. ptsno_pool = &sb->ptsno_pool;
  221. rc = rid_bitmap_get(ptsno_pool);
  222. if (rc >= 0)
  223. {
  224. pts_file = rt_calloc(1, sizeof(struct ptyfs_file));
  225. if (pts_file)
  226. {
  227. snprintf(pts_file->basename, DIRENT_NAME_MAX, "%lu", (unsigned long)rc);
  228. ptyfile_init(pts_file, sb, 0, PTYFS_TYPE_FILE_SLAVE,
  229. PTS_DEFAULT_FILE_MODE, pts);
  230. ptyfile_add_to_root(sb, pts_file);
  231. }
  232. else
  233. {
  234. rid_bitmap_put(ptsno_pool, rc);
  235. rc = -1;
  236. }
  237. }
  238. /* else rc == -1 */
  239. }
  240. return rc;
  241. }
  242. rt_err_t ptyfs_unregister_pts(rt_device_t ptmx, ptsno_t ptsno)
  243. {
  244. ptsno_t rc;
  245. struct ptyfs_sb *sb;
  246. struct ptyfs_file *pts_file;
  247. struct rid_bitmap *ptsno_pool;
  248. char path_buf[DIRENT_NAME_MAX];
  249. /* allocate id for it and register file */
  250. sb = rt_container_of(ptmx, struct ptyfs_sb, ptmx_device);
  251. if (sb->magic != PTYFS_MAGIC || ptsno < 0)
  252. {
  253. rc = -EINVAL;
  254. }
  255. else
  256. {
  257. /* get path and findout device */
  258. snprintf(path_buf, sizeof(path_buf), "%lu", (unsigned long)ptsno);
  259. pts_file = ptyfile_lookup(sb, path_buf);
  260. if (pts_file)
  261. {
  262. ptyfile_remove_from_root(sb, pts_file);
  263. ptsno_pool = &sb->ptsno_pool;
  264. rid_bitmap_put(ptsno_pool, ptsno);
  265. rc = 0;
  266. }
  267. else
  268. {
  269. rc = -ENOENT;
  270. }
  271. }
  272. return rc;
  273. }
  274. #define DEVFS_PREFIX "/dev/"
  275. #define DEVFS_PREFIX_LEN (sizeof(DEVFS_PREFIX) - 1)
  276. /**
  277. * Create an new instance of ptyfs, and mount on target point
  278. * 2 basic files are created: root, ptmx.
  279. *
  280. * todo: support of mount options?
  281. */
  282. static int ptyfs_ops_mount(struct dfs_mnt *mnt, unsigned long rwflag,
  283. const void *data)
  284. {
  285. struct ptyfs_sb *sb;
  286. rt_device_t ptmx_device;
  287. rt_err_t rc;
  288. if (strncmp(mnt->fullpath, DEVFS_PREFIX, DEVFS_PREFIX_LEN) != 0)
  289. {
  290. LOG_I("%s() Not mounted on `/dev/'", __func__);
  291. return -EINVAL;
  292. }
  293. sb = rt_calloc(1, sizeof(struct ptyfs_sb));
  294. if (sb)
  295. {
  296. rt_mutex_init(&sb->lock, "ptyfs", RT_IPC_FLAG_PRIO);
  297. /* setup the ptmx device */
  298. ptmx_device = &sb->ptmx_device;
  299. rc = lwp_ptmx_init(ptmx_device, mnt->fullpath + DEVFS_PREFIX_LEN);
  300. if (rc == RT_EOK)
  301. {
  302. /* setup 2 basic files */
  303. ptyfile_init(&sb->root_file, sb, "/", PTYFS_TYPE_DIR,
  304. ROOT_DEFUALT_FILE_MODE, 0);
  305. ptyfile_init(&sb->ptmx_file, sb, "ptmx", PTYFS_TYPE_FILE_PTMX,
  306. PTMX_DEFAULT_FILE_MODE, ptmx_device);
  307. ptyfile_add_to_root(sb, &sb->ptmx_file);
  308. /* setup rid */
  309. rid_bitmap_init(&sb->ptsno_pool, 0, LWP_PTY_MAX_PARIS_LIMIT,
  310. sb->ptsno_pool_bitset, &sb->lock);
  311. /* setup properties and members */
  312. sb->magic = PTYFS_MAGIC;
  313. sb->df_size = sizeof(struct ptyfs_sb);
  314. rt_list_init(&sb->sibling);
  315. /* binding superblocks and mount point */
  316. mnt->data = sb;
  317. sb->mount = mnt;
  318. rc = 0;
  319. }
  320. /* else just return rc */
  321. }
  322. else
  323. {
  324. rc = -ENOMEM;
  325. }
  326. return rc;
  327. }
  328. static int ptyfs_ops_umount(struct dfs_mnt *mnt)
  329. {
  330. /* Not supported yet */
  331. return -1;
  332. }
  333. static int ptyfs_ops_setattr(struct dfs_dentry *dentry, struct dfs_attr *attr)
  334. {
  335. struct ptyfs_file *pty_file;
  336. struct ptyfs_sb *superblock;
  337. RT_ASSERT(dentry);
  338. RT_ASSERT(dentry->mnt);
  339. superblock = (struct ptyfs_sb *)dentry->mnt->data;
  340. RT_ASSERT(superblock);
  341. /* find the device related to current pts slave device */
  342. pty_file = ptyfile_lookup(superblock, dentry->pathname);
  343. if (pty_file && pty_file->type == PTYFS_TYPE_FILE_SLAVE)
  344. {
  345. pty_file->mode &= ~0xFFF;
  346. pty_file->mode |= attr->st_mode & 0xFFF;
  347. return 0;
  348. }
  349. return -1;
  350. }
  351. #define OPTIMAL_BSIZE 1024
  352. static int ptyfs_ops_statfs(struct dfs_mnt *mnt, struct statfs *buf)
  353. {
  354. struct ptyfs_sb *superblock;
  355. RT_ASSERT(mnt != NULL);
  356. RT_ASSERT(buf != NULL);
  357. superblock = (struct ptyfs_sb *)mnt->data;
  358. RT_ASSERT(superblock != NULL);
  359. buf->f_bsize = OPTIMAL_BSIZE;
  360. buf->f_blocks = (superblock->df_size + OPTIMAL_BSIZE - 1) / OPTIMAL_BSIZE;
  361. buf->f_bfree = 1;
  362. buf->f_bavail = buf->f_bfree;
  363. return RT_EOK;
  364. }
  365. static int ptyfs_ops_stat(struct dfs_dentry *dentry, struct stat *st)
  366. {
  367. struct dfs_vnode *vnode;
  368. if (dentry && dentry->vnode)
  369. {
  370. vnode = dentry->vnode;
  371. /* device id ? */
  372. st->st_dev = (dev_t)(long)(dentry->mnt->dev_id);
  373. st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
  374. st->st_gid = vnode->gid;
  375. st->st_uid = vnode->uid;
  376. st->st_mode = vnode->mode;
  377. st->st_nlink = vnode->nlink;
  378. st->st_size = vnode->size;
  379. st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
  380. st->st_mtim.tv_sec = vnode->mtime.tv_sec;
  381. st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
  382. st->st_ctim.tv_sec = vnode->ctime.tv_sec;
  383. st->st_atim.tv_nsec = vnode->atime.tv_nsec;
  384. st->st_atim.tv_sec = vnode->atime.tv_sec;
  385. }
  386. return 0;
  387. }
  388. static struct dfs_vnode *ptyfs_ops_lookup(struct dfs_dentry *dentry)
  389. {
  390. struct dfs_vnode *vnode = RT_NULL;
  391. struct ptyfs_sb *superblock;
  392. struct ptyfs_file *pty_file;
  393. if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
  394. {
  395. return NULL;
  396. }
  397. superblock = (struct ptyfs_sb *)dentry->mnt->data;
  398. pty_file = ptyfile_lookup(superblock, dentry->pathname);
  399. if (pty_file)
  400. {
  401. vnode = dfs_vnode_create();
  402. if (vnode)
  403. {
  404. vnode->data = pty_file->device;
  405. vnode->nlink = 1;
  406. vnode->size = 0;
  407. vnode->mnt = dentry->mnt;
  408. /* if it's root directory */
  409. vnode->fops = &_default_fops;
  410. vnode->mode = pty_file->mode;
  411. vnode->type = pty_file->type == PTYFS_TYPE_DIR ? FT_DIRECTORY : FT_DEVICE;
  412. }
  413. }
  414. return vnode;
  415. }
  416. static struct dfs_vnode *ptyfs_ops_create_vnode(struct dfs_dentry *dentry,
  417. int type, mode_t mode)
  418. {
  419. struct dfs_vnode *vnode = RT_NULL;
  420. struct ptyfs_sb *sb;
  421. struct ptyfs_file *pty_file;
  422. char *vnode_path;
  423. if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
  424. {
  425. return NULL;
  426. }
  427. sb = (struct ptyfs_sb *)dentry->mnt->data;
  428. RT_ASSERT(sb != NULL);
  429. vnode = dfs_vnode_create();
  430. if (vnode)
  431. {
  432. vnode_path = dentry->pathname;
  433. /* Query if file existed. Filter out illegal open modes */
  434. pty_file = ptyfile_lookup(sb, vnode_path);
  435. if (!pty_file || (~pty_file->mode & mode))
  436. {
  437. dfs_vnode_destroy(vnode);
  438. return NULL;
  439. }
  440. vnode->data = pty_file->device;
  441. vnode->nlink = 1;
  442. vnode->size = 0;
  443. vnode->mnt = dentry->mnt;
  444. vnode->fops = pty_file->device ? pty_file->device->fops : RT_NULL;
  445. vnode->mode &= pty_file->mode;
  446. if (type == FT_DIRECTORY)
  447. {
  448. vnode->mode |= S_IFDIR;
  449. vnode->type = FT_DIRECTORY;
  450. LOG_I("%s: S_IFDIR created", __func__);
  451. }
  452. else if (type == FT_REGULAR)
  453. {
  454. vnode->mode |= S_IFCHR;
  455. vnode->type = FT_DEVICE;
  456. LOG_I("%s: S_IFDIR created", __func__);
  457. }
  458. else
  459. {
  460. /* unsupported types */
  461. dfs_vnode_destroy(vnode);
  462. return NULL;
  463. }
  464. }
  465. return vnode;
  466. }
  467. static int ptyfs_ops_free_vnode(struct dfs_vnode *vnode)
  468. {
  469. return RT_EOK;
  470. }
  471. static int devpty_deffops_getdents(struct dfs_file *file, struct dirent *dirp,
  472. uint32_t count)
  473. {
  474. struct ptyfs_file *d_file;
  475. struct ptyfs_sb *superblock;
  476. RT_ASSERT(file);
  477. RT_ASSERT(file->dentry);
  478. RT_ASSERT(file->dentry->mnt);
  479. superblock = (struct ptyfs_sb *)file->dentry->mnt->data;
  480. RT_ASSERT(superblock);
  481. d_file = ptyfile_lookup(superblock, file->dentry->pathname);
  482. if (d_file)
  483. {
  484. rt_size_t index, end;
  485. struct dirent *d;
  486. struct ptyfs_file *n_file;
  487. rt_list_t *list;
  488. /* make integer count */
  489. count = (count / sizeof(struct dirent));
  490. if (count == 0)
  491. {
  492. return -EINVAL;
  493. }
  494. end = file->fpos + count;
  495. index = 0;
  496. count = 0;
  497. rt_list_for_each(list, &d_file->subdirs)
  498. {
  499. if (index >= (rt_size_t)file->fpos)
  500. {
  501. n_file = rt_list_entry(list, struct ptyfs_file, ent_node);
  502. d = dirp + count;
  503. if (n_file->type == PTYFS_TYPE_DIR)
  504. {
  505. d->d_type = DT_DIR;
  506. }
  507. else
  508. {
  509. /* ptmx(5,2) or slave(136,[0,1048575]) device, on Linux */
  510. d->d_type = DT_CHR;
  511. }
  512. d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
  513. rt_strncpy(d->d_name, n_file->basename, DIRENT_NAME_MAX);
  514. d->d_namlen = rt_strlen(d->d_name);
  515. count += 1;
  516. file->fpos += 1;
  517. }
  518. index += 1;
  519. if (index >= end)
  520. {
  521. break;
  522. }
  523. }
  524. }
  525. return count * sizeof(struct dirent);
  526. }
  527. static const struct dfs_filesystem_ops _ptyfs_ops = {
  528. .name = "ptyfs",
  529. .flags = DFS_FS_FLAG_DEFAULT,
  530. .default_fops = &_default_fops,
  531. .mount = ptyfs_ops_mount,
  532. .umount = ptyfs_ops_umount,
  533. /* don't allow to create symbolic link */
  534. .symlink = RT_NULL,
  535. .readlink = RT_NULL,
  536. .unlink = RT_NULL,
  537. .setattr = ptyfs_ops_setattr,
  538. .statfs = ptyfs_ops_statfs,
  539. .stat = ptyfs_ops_stat,
  540. .lookup = ptyfs_ops_lookup,
  541. .create_vnode = ptyfs_ops_create_vnode,
  542. .free_vnode = ptyfs_ops_free_vnode,
  543. };
  544. static struct dfs_filesystem_type _devptyfs = {
  545. .fs_ops = &_ptyfs_ops,
  546. };
  547. static int _ptyfs_init(void)
  548. {
  549. _default_fops = *dfs_devfs_fops();
  550. _default_fops.getdents = devpty_deffops_getdents;
  551. /* register file system */
  552. dfs_register(&_devptyfs);
  553. return 0;
  554. }
  555. INIT_COMPONENT_EXPORT(_ptyfs_init);