From 0061d8d74565beb644d9c38efc794c2a164942b3 Mon Sep 17 00:00:00 2001 From: zhao maosheng Date: Wed, 17 Jul 2024 17:46:54 +0800 Subject: [PATCH] add procfs --- .../dfs/dfs_v2/filesystems/procfs/README.md | 166 ++++ .../dfs/dfs_v2/filesystems/procfs/SConscript | 11 + .../dfs/dfs_v2/filesystems/procfs/proc.c | 732 ++++++++++++++++++ .../dfs/dfs_v2/filesystems/procfs/proc.h | 75 ++ .../dfs_v2/filesystems/procfs/proc_cmdline.c | 53 ++ .../dfs_v2/filesystems/procfs/proc_cpuinfo.c | 86 ++ .../dfs_v2/filesystems/procfs/proc_devices.c | 307 ++++++++ .../filesystems/procfs/proc_filesystems.c | 85 ++ .../dfs_v2/filesystems/procfs/proc_loadavg.c | 41 + .../dfs_v2/filesystems/procfs/proc_meminfo.c | 66 ++ .../dfs_v2/filesystems/procfs/proc_mounts.c | 101 +++ .../dfs/dfs_v2/filesystems/procfs/proc_net.c | 107 +++ .../filesystems/procfs/proc_partitions.c | 215 +++++ .../dfs/dfs_v2/filesystems/procfs/proc_pid.c | 449 +++++++++++ .../dfs/dfs_v2/filesystems/procfs/proc_self.c | 66 ++ .../dfs/dfs_v2/filesystems/procfs/proc_stat.c | 114 +++ .../dfs/dfs_v2/filesystems/procfs/proc_tty.c | 100 +++ .../dfs_v2/filesystems/procfs/proc_uptime.c | 38 + .../dfs_v2/filesystems/procfs/proc_version.c | 45 ++ .../dfs/dfs_v2/filesystems/procfs/procfs.c | 445 +++++++++++ .../dfs/dfs_v2/filesystems/procfs/procfs.h | 19 + 21 files changed, 3321 insertions(+) create mode 100644 components/dfs/dfs_v2/filesystems/procfs/README.md create mode 100644 components/dfs/dfs_v2/filesystems/procfs/SConscript create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc.h create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_cmdline.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_devices.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_filesystems.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_net.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_partitions.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_pid.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_self.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_stat.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_tty.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/proc_version.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/procfs.c create mode 100644 components/dfs/dfs_v2/filesystems/procfs/procfs.h diff --git a/components/dfs/dfs_v2/filesystems/procfs/README.md b/components/dfs/dfs_v2/filesystems/procfs/README.md new file mode 100644 index 000000000000..7ab01272910b --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/README.md @@ -0,0 +1,166 @@ +# 进程文件系统 (procfs) + +## 数据结构 + +```c +struct proc_dentry +{ + rt_uint32_t mode; + rt_atomic_t ref_count; + + struct proc_dentry *parent; + struct dfs_vfs_node node; + + const struct dfs_file_ops *fops; + const struct proc_ops *ops; + + char *name; + void *data; +}; +``` + +```log +root { mode: S_IFDIR, ref_count: 1, parent: root, name: /, child->next: file1->node } + | + |—— file1 { mode: S_IFREG, ref_count: 1, parent: root, name: file1, node->next: link1->node } + |—— link1 { mode: S_IFLNK, ref_count: 1, parent: root, name: link1, data: fullpath, node->next: dir1->node } + |—— dir1 { mode: S_IFDIR, ref_count: 1, parent: root, name: dir1, node->next: file3->node, child->next: file2->node } + | | + | |—— dir2 { mode: S_IFDIR, ref_count: 1, parent: dir1, name: dir2, node->next: link2->node } + | |—— link2 { mode: S_IFLNK, ref_count: 1, parent: dir1, name: link2, data: fullpath, node->next: file2->node } + | |—— file2 { mode: S_IFREG, ref_count: 1, parent: dir1, name: file2 } + | + |—— file3 { mode: S_IFREG, ref_count: 1, parent: root, name: file3 } +``` + +## API 介绍 + +```c +struct proc_dentry *dfs_proc_find(const char *name); + +struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent, + const struct dfs_file_ops *fops, void *data); +struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent); +struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent); + +struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent, + const struct dfs_file_ops *fops, void *data); + +struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest); + +struct proc_dentry *proc_acquire(struct proc_dentry *dentry); +void proc_release(struct proc_dentry *dentry); + +void proc_remove(struct proc_dentry *dentry); +``` + +- dfs_proc_find + + 查找指定节点,并返回节点数据指针 + + | 入参 | 说明 | + | ---- | ---------------------------------------------------- | + | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2” | + +- proc_mkdir_data + + 创建一个目录,并返回节点数据指针 + + | 入参 | 说明 | + | ------ | ------------------------------------------------------------ | + | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”
从 parent 起始的完整路径 | + | mode | 权限配置 | + | parent | 指定创建目录的起始节点 | + | fops | 文件操作接口配置 | + | data | 私有数据 | + +- proc_mkdir_mode + + 创建一个目录,并返回节点数据指针 + + | 入参 | 说明 | + | ------ | ------------------------------------------------------------ | + | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”
从 parent 起始的完整路径 | + | mode | 权限配置 | + | parent | 指定创建目录的起始节点 | + +- proc_mkdir + + 创建一个目录,并返回节点数据指针 + + | 入参 | 说明 | + | ---- | ------------------------------------------------------------ | + | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”
从 parent 起始的完整路径 | + | mode | 权限配置 | + +- proc_create_data + + 创建一个文件,并返回节点数据指针 + + | 入参 | 说明 | + | ------ | ------------------------------------------------------------ | + | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”
从 parent 起始的完整路径 | + | mode | 权限配置 | + | parent | 指定创建文件的起始节点 | + | fops | 文件操作接口配置 | + | data | 私有数据 | + +- proc_symlink + + 创建一个符号链接,并返回节点数据指针 + + | 入参 | 说明 | + | ------ | ------------------------------------------------------------ | + | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”
从 parent 起始的完整路径 | + | parent | 指定创建文件的起始节点 | + | dest | 链接的目标文件完整路径 | + +- proc_acquire + + 引用一个节点,并返回节点数据指针 + + | 入参 | 说明 | + | ------ | -------------- | + | dentry | 需要引用的节点 | + +- proc_release + + 释放一个节点 + + | 入参 | 说明 | + | ------ | -------------- | + | dentry | 需要释放的节点 | + +- proc_remove + + 删除一个节点包含子节点 + + | 入参 | 说明 | + | ------ | -------------- | + | dentry | 需要删除的节点 | + +## msh 调试命令 + +- proc_dump + + 遍历打印指定节点含子节点的信息(名称、引用计数),比如 `proc_dump /dir1` 或者 `proc_dump` + +- proc_remove + + 删除指定节点含子节点,比如 `proc_remove /dir1` 或者 `proc_remove /file3` + +- proc_symlink + + 创建一个符号链接,`proc_symlink /link3 /mnt` + +- proc_echo + + 创建一个空文件,`proc_echo /file4` + +- proc_mkdir + + 创建一个空目录,`proc_mkdir /dir3` + +- proc_pid + + 创建一个 pid 目录,`proc_pid /101` diff --git a/components/dfs/dfs_v2/filesystems/procfs/SConscript b/components/dfs/dfs_v2/filesystems/procfs/SConscript new file mode 100644 index 000000000000..4af49a1b7199 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_PROCFS'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc.c b/components/dfs/dfs_v2/filesystems/procfs/proc.c new file mode 100644 index 000000000000..93068009a192 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc.c @@ -0,0 +1,732 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +/* + * This is the root in the proc tree.. + */ +static struct proc_dentry _proc_root = { + .mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH), + .ref_count = 1, + + .parent = &_proc_root, + .node = {0}, + .child = {0}, + + .fops = RT_NULL, + + .name = "/", + .data = RT_NULL, +}; + +static int _proc_find(struct proc_dentry **parent, const char *name) +{ + struct proc_dentry *dentry = RT_NULL, *tmp; + + + { + if (dentry == RT_NULL) + { + break; + } + + if (rt_strcmp(dentry->name, name) == 0) + { + *parent = dentry; + return 0; + } + } + + return -1; +} + +static int proc_find(struct proc_dentry **parent, const char **name, rt_bool_t force_lookup) +{ + int ret = 0; + char *tmp = RT_NULL; + + if (!(*parent)) + { + *parent = &_proc_root; + } + + tmp = rt_strdup(*name); + if (tmp) + { + char *begin = tmp, *end = RT_NULL; + if (*begin == '/') + { + begin++; + if (*begin == '\0') + { + rt_free(tmp); + *parent = proc_acquire(*parent); + return ret; + } + } + + while (1) + { + end = rt_strstr(begin, "/"); + if (end) + { + *end = '\0'; + ret = _proc_find(parent, begin); + if (ret < 0 || !S_ISDIR((*parent)->mode)) + { + *parent = RT_NULL; + ret = -1; + break; + } + begin = end + 1; + } + else if (force_lookup) + { + ret = _proc_find(parent, begin); + if (ret < 0) + { + if ((*parent)->ops && (*parent)->ops->lookup) + { + *parent = (*parent)->ops->lookup(*parent, begin); + if (*parent == RT_NULL) + { + ret = -1; + } + } + else + { + *parent = RT_NULL; + } + } + else + { + *parent = proc_acquire(*parent); + } + break; + } + else + { + *parent = proc_acquire(*parent); + break; + } + } + + *name = *name + (begin - tmp); + + rt_free(tmp); + } + + return ret; +} + +static void *single_start(struct dfs_seq_file *seq, off_t *index) +{ + return NULL + (*index == 0); +} + +static void *single_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + ++*index; + return NULL; +} + +static void single_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static int proc_open(struct dfs_file *file) +{ + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (entry->single_show) + { + struct dfs_seq_ops *seq_ops = (struct dfs_seq_ops *)rt_calloc(1, sizeof(struct dfs_seq_ops)); + if (seq_ops) + { + int ret = 0; + + seq_ops->start = single_start; + seq_ops->next = single_next; + seq_ops->stop = single_stop; + seq_ops->show = entry->single_show; + + ret = dfs_seq_open(file, seq_ops); + if (ret != 0) + { + rt_free(seq_ops); + } + return ret; + } + } + + return dfs_seq_open(file, entry->seq_ops); +} + +static int proc_close(struct dfs_file *file) +{ + struct dfs_seq_file *seq = file->data; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (seq && entry->single_show && seq->ops) + { + rt_free((void *)seq->ops); + seq->ops = RT_NULL; + } + + return dfs_seq_release(file); +} + +static const struct dfs_file_ops proc_file_ops = { + .open = proc_open, + .read = dfs_seq_read, + .lseek = dfs_seq_lseek, + .close = proc_close, +}; + +static struct proc_dentry *proc_create(struct proc_dentry **parent, const char *name, mode_t mode) +{ + int ret = 0; + struct proc_dentry *dentry = RT_NULL; + + ret = proc_find(parent, &name, 0); + if (ret >= 0) + { + dentry = *parent; + ret = proc_find(&dentry, &name, 1); + if (ret < 0) + { + dentry = rt_calloc(1, sizeof(struct proc_dentry)); + if (dentry) + { + dentry->mode = mode; + dentry->ref_count = 1; + dentry->name = rt_strdup(name); + } + } + else + { + proc_release(dentry); + dentry = RT_NULL; + } + } + + return dentry; +} + +/** + * @brief The dentry reference count is incremented by one + * + * @param dentry + * + * @return dentry + */ +struct proc_dentry *proc_acquire(struct proc_dentry *dentry) +{ + if (dentry) + { + dentry->ref_count += 1; + } + + return dentry; +} + +/** + * @brief The dentry reference count is minus one, or release + * + * @param dentry + * + * @return none + */ +void proc_release(struct proc_dentry *dentry) +{ + if (dentry) + { + if (dentry->ref_count == 1) + { + if (dentry->name) + { + rt_free(dentry->name); + } + + if (S_ISLNK(dentry->mode) && dentry->data) + { + rt_free(dentry->data); + } + + rt_free(dentry); + } + else + { + dentry->ref_count -= 1; + } + } +} + +static struct proc_dentry *proc_register(struct proc_dentry *parent, struct proc_dentry *child) +{ + child->parent = parent; + dfs_vfs_append_node(&parent->node, &child->node); + child->ref_count += 1; + child->pid = parent->pid; + + return child; +} + +/** + * @brief Make a dir + * + * @param name fullpath based on _proc_root or parent + * @param mode permission configuration + * @param parent can be empty + * @param fops + * @param data + * + * @return dentry + */ +struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent, + const struct dfs_file_ops *fops, void *data) +{ + struct proc_dentry *dentry, *_parent = parent; + + if (mode == 0) + mode = (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH); + + dentry = proc_create(&_parent, name, S_IFDIR | mode); + if (dentry) + { + dentry->fops = fops; + dentry->data = data; + + dentry = proc_register(_parent, dentry); + } + proc_release(_parent); + + return dentry; +} + +/** + * @brief Make a dir + * + * @param name fullpath based on _proc_root or parent + * @param mode permission configuration + * @param parent can be empty + * + * @return dentry + */ +struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent) +{ + return proc_mkdir_data(name, mode, parent, NULL, NULL); +} + +/** + * @brief Make a dir + * + * @param name fullpath based on _proc_root or parent + * @param parent can be empty + * + * @return dentry + */ +struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent) +{ + return proc_mkdir_data(name, 0, parent, NULL, NULL); +} + +static struct proc_dentry *proc_create_reg(const char *name, mode_t mode, struct proc_dentry **parent) +{ + struct proc_dentry *dentry = RT_NULL; + + if ((mode & S_IFMT) == 0) + mode |= S_IFREG; + if ((mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)) == 0) + mode |= S_IRUSR | S_IRGRP | S_IROTH; + + if (!S_ISREG(mode)) + { + *parent = RT_NULL; + return dentry; + } + + return proc_create(parent, name, mode); +} + +/** + * @brief Make a file + * + * @param name fullpath based on _proc_root or parent + * @param mode permission configuration + * @param parent can be empty + * @param fops + * @param data + * + * @return dentry + */ +struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent, + const struct dfs_file_ops *fops, void *data) +{ + struct proc_dentry *dentry, *_parent = parent; + + dentry = proc_create_reg(name, mode, &_parent); + if (dentry) + { + dentry->fops = fops ? fops : &proc_file_ops; + dentry->data = data; + + dentry = proc_register(_parent, dentry); + } + proc_release(_parent); + + return dentry; +} + +/** + * @brief Make a file + * + * @param name fullpath based on _proc_root or parent + * @param mode permission configuration + * @param parent can be empty + * @param show + * @param data + * + * @return dentry + */ +struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent, + int (*show)(struct dfs_seq_file *, void *), void *data) +{ + struct proc_dentry *dentry, *_parent = parent; + + dentry = proc_create_reg(name, mode, &_parent); + if (dentry) + { + dentry->fops = &proc_file_ops; + dentry->single_show = show; + dentry->data = data; + + dentry = proc_register(_parent, dentry); + } + proc_release(_parent); + + return dentry; +} + +/** + * @brief Make a symlink + * + * @param name fullpath based on _proc_root or parent + * @param parent can be empty + * @param dest link file fullpath + * + * @return dentry + */ +struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest) +{ + struct proc_dentry *dentry, *_parent = parent; + + dentry = proc_create(&_parent, name, (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH) + | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH))); + if (dentry) + { + dentry->data = (void *)rt_strdup(dest); + if (dentry->data) + { + dentry = proc_register(_parent, dentry); + } + else + { + proc_release(dentry); + dentry = NULL; + } + } + proc_release(_parent); + + return dentry; +} + +static void remove_proc_subtree(struct proc_dentry *dentry) +{ + struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL; + + dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node) + { + if (iter == RT_NULL) + { + break; + } + + if (tmp) + { + proc_release(tmp); + tmp = RT_NULL; + } + + tmp = iter; + + if (S_ISDIR(dentry->mode)) + { + remove_proc_subtree(iter); + } + } + + if (tmp) + { + proc_release(tmp); + tmp = RT_NULL; + } +} + +/** + * @brief remove a dentry + * + * @param dentry + * + * @return none + */ +void proc_remove(struct proc_dentry *dentry) +{ + if (dentry && dentry != &_proc_root) + { + if (S_ISDIR(dentry->mode)) + { + remove_proc_subtree(dentry); + } + + dfs_vfs_remove_node(&dentry->parent->node, &dentry->node); + proc_release(dentry); + } +} + +/** + * @brief find dentry exist + * + * @param name fullpath based on _proc_root + * + * @return dentry + */ +struct proc_dentry *dfs_proc_find(const char *name) +{ + struct proc_dentry *dentry = RT_NULL; + + proc_find(&dentry, &name, 1); + + return dentry; +} + +/** + * @brief remove a dentry on parent + * + * @param name fullpath based on parent + * @param parent + * + * @return none + */ +void proc_remove_dentry(const char *name, struct proc_dentry *parent) +{ + struct proc_dentry *dentry = parent; + + if (proc_find(&dentry, &name, 1) >= 0) + { + proc_remove(dentry); + proc_release(dentry); + } +} + +#define _COLOR_RED "\033[31m" +#define _COLOR_GREEN "\033[32m" +#define _COLOR_BLUE "\033[34m" +#define _COLOR_CYAN "\033[36m" +#define _COLOR_WHITE "\033[37m" +#define _COLOR_NORMAL "\033[0m" + +static void dump_proc_subtree(struct proc_dentry *dentry, int tab) +{ + struct proc_dentry *iter = RT_NULL, *tmp; + + dfs_vfs_for_each_subnode(iter, tmp, dentry, node) + { + if (iter == RT_NULL) + { + break; + } + + for(int i = 0; i < tab; i ++) + { + rt_kprintf("%-4s", i + 1 >= tab ? "|-" : " "); + } + + if (S_ISDIR(iter->mode)) + { + rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count); + dump_proc_subtree(iter, tab + 1); + } + else if (S_ISLNK(iter->mode)) + { + rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count); + } + else + { + rt_kprintf("%-20s %d\n", iter->name, iter->ref_count); + } + } +} + +static void proc_dump(struct proc_dentry *dentry) +{ + if (dentry) + { + if (S_ISDIR(dentry->mode)) + { + rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count); + dump_proc_subtree(dentry, 1); + } + else if (S_ISLNK(dentry->mode)) + { + rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count); + } + else + { + rt_kprintf("%-20s %d\n", dentry->name, dentry->ref_count); + } + } +} + +static int msh_proc_dump(int argc, char** argv) +{ + const char *name = argc > 1 ? argv[1] : "/"; + struct proc_dentry *dentry = RT_NULL; + + int ret = proc_find(&dentry, &name, 1); + if (ret >= 0) + { + proc_dump(dentry); + } + proc_release(dentry); + + return 0; +} +MSH_CMD_EXPORT_ALIAS(msh_proc_dump, proc_dump, proc dump); + +static int msh_proc_remove(int argc, char** argv) +{ + if (argc > 1) + { + const char *name = argv[1]; + struct proc_dentry *dentry = RT_NULL; + + int ret = proc_find(&dentry, &name, 1); + if (ret >= 0) + { + if (dentry != &_proc_root) + { + proc_remove(dentry); + } + else + { + struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL; + + dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node) + { + if (iter == RT_NULL) + { + break; + } + + if (tmp) + { + proc_remove(tmp); + } + + tmp = iter; + } + + if (tmp) + { + proc_remove(tmp); + } + } + } + proc_release(dentry); + } + else + { + rt_kprintf("proc_remove path\n"); + } + + return 0; +} +MSH_CMD_EXPORT_ALIAS(msh_proc_remove, proc_remove, proc remove); + +static int msh_proc_symlink(int argc, char** argv) +{ + if (argc > 2) + { + struct proc_dentry *entry = proc_symlink(argv[1], 0, argv[2]); + if (entry) + { + proc_release(entry); + } + } + else + { + rt_kprintf("proc_symlink path dest\n"); + } + + return 0; +} +MSH_CMD_EXPORT_ALIAS(msh_proc_symlink, proc_symlink, proc symlink); + +static int msh_proc_echo(int argc, char** argv) +{ + if (argc > 1) + { + for(int i = 1; i <= argc - 1; i ++) + { + struct proc_dentry *entry = proc_create_data(argv[i], 0, 0, 0, 0); + if (entry) + { + proc_release(entry); + } + } + } + else + { + rt_kprintf("proc_echo path\n"); + } + + return 0; +} +MSH_CMD_EXPORT_ALIAS(msh_proc_echo, proc_echo, proc echo); + +static int msh_proc_mkdir(int argc, char** argv) +{ + if (argc > 1) + { + for(int i = 1; i <= argc - 1; i ++) + { + struct proc_dentry *entry = proc_mkdir(argv[i], 0); + if (entry) + { + proc_release(entry); + } + } + } + else + { + rt_kprintf("proc_mkdir path\n"); + } + + return 0; +} +MSH_CMD_EXPORT_ALIAS(msh_proc_mkdir, proc_mkdir, proc mkdir); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc.h b/components/dfs/dfs_v2/filesystems/procfs/proc.h new file mode 100644 index 000000000000..e697860e22e1 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __PROC_H__ +#define __PROC_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct proc_dentry; + +struct proc_ops +{ + struct proc_dentry *(*lookup)(struct proc_dentry *parent, const char *name); + int (*readlink)(struct proc_dentry *dentry, char *buf, int len); +}; + +struct proc_dentry +{ + rt_uint32_t mode; + rt_atomic_t ref_count; + + struct proc_dentry *parent; + struct dfs_vfs_node node; + + const struct dfs_file_ops *fops; + const struct proc_ops *ops; + const struct dfs_seq_ops *seq_ops; + int (*single_show)(struct dfs_seq_file *seq, void *data); + + int pid; + + char *name; + void *data; +}; + +struct proc_dentry *dfs_proc_find(const char *name); + +struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent, + const struct dfs_file_ops *fops, void *data); +struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent); +struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent); + +struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent, + const struct dfs_file_ops *fops, void *data); +struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent, + int (*show)(struct dfs_seq_file *, void *), void *data); + +struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest); + +struct proc_dentry *proc_acquire(struct proc_dentry *dentry); +void proc_release(struct proc_dentry *dentry); + +void proc_remove(struct proc_dentry *dentry); +void proc_remove_dentry(const char *name, struct proc_dentry *parent); + +int proc_pid(int pid); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_cmdline.c b/components/dfs/dfs_v2/filesystems/procfs/proc_cmdline.c new file mode 100644 index 000000000000..5845b5ff8839 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_cmdline.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + +static char *__proc_cmdline = NULL; + +int proc_cmdline_save(const char *cmdline) +{ + if (__proc_cmdline) + { + free(__proc_cmdline); + __proc_cmdline = NULL; + } + + __proc_cmdline = strdup(cmdline); + + return 0; +} + +static int single_show(struct dfs_seq_file *seq, void *data) +{ + if (__proc_cmdline) + { + dfs_seq_puts(seq, __proc_cmdline); + } + + return 0; +} + +int proc_cmdline_init(void) +{ + struct proc_dentry *dentry = proc_create_single_data("cmdline", 0, NULL, single_show, NULL); + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_cmdline_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c b/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c new file mode 100644 index 000000000000..6f4983299280 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + + return NULL + (i == 0); +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + + *index = i; + + return NULL; +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + /* data: The return value of the start or next*/ + dfs_seq_puts(seq, "rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)\n--need your own function--\n"); + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void) +{ + return &seq_ops; +} + +static int proc_open(struct dfs_file *file) +{ + return dfs_seq_open(file, cpuinfo_get_seq_ops()); +} + +static int proc_close(struct dfs_file *file) +{ + return dfs_seq_release(file); +} + +static const struct dfs_file_ops file_ops = { + .open = proc_open, + .read = dfs_seq_read, + .lseek = dfs_seq_lseek, + .close = proc_close, +}; + +int proc_cpuinfo_init(void) +{ + struct proc_dentry *dentry = proc_create_data("cpuinfo", 0, NULL, &file_ops, NULL); + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_cpuinfo_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_devices.c b/components/dfs/dfs_v2/filesystems/procfs/proc_devices.c new file mode 100644 index 000000000000..7bd07187d096 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_devices.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +#define LIST_FIND_OBJ_NR 8 + +struct device_show +{ + char *buf; + int size; + int len; + int index; +}; + +typedef struct +{ + rt_list_t *list; + rt_list_t **array; + rt_uint8_t type; + int nr; /* input: max nr, can't be 0 */ + int nr_out; /* out: got nr */ +} list_get_next_t; + +static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr) +{ + struct rt_object_information *info; + rt_list_t *list; + + info = rt_object_get_information((enum rt_object_class_type)type); + list = &info->object_list; + + p->list = list; + p->type = type; + p->array = array; + p->nr = nr; + p->nr_out = 0; +} + +static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg) +{ + int first_flag = 0; + rt_base_t level; + rt_list_t *node, *list; + rt_list_t **array; + struct rt_object_information *info; + int nr; + + arg->nr_out = 0; + + if (!arg->nr || !arg->type) + { + return (rt_list_t *)RT_NULL; + } + + list = arg->list; + info = rt_list_entry(list, struct rt_object_information, object_list); + + if (!current) /* find first */ + { + node = list; + first_flag = 1; + } + else + { + node = current; + } + + level = rt_spin_lock_irqsave(&info->spinlock); + + if (!first_flag) + { + struct rt_object *obj; + /* The node in the list? */ + obj = rt_list_entry(node, struct rt_object, list); + if ((obj->type & ~RT_Object_Class_Static) != arg->type) + { + rt_spin_unlock_irqrestore(&info->spinlock, level); + return (rt_list_t *)RT_NULL; + } + } + + nr = 0; + array = arg->array; + while (1) + { + node = node->next; + + if (node == list) + { + node = (rt_list_t *)RT_NULL; + break; + } + nr++; + *array++ = node; + if (nr == arg->nr) + { + break; + } + } + + rt_spin_unlock_irqrestore(&info->spinlock, level); + arg->nr_out = nr; + return node; +} + +static char *const device_type_str[RT_Device_Class_Unknown] = +{ + "Character Device", + "Block Device", + "Network Interface", + "MTD Device", + "CAN Device", + "RTC", + "Sound Device", + "Graphic Device", + "I2C Bus", + "USB Slave Device", + "USB Host Bus", + "USB OTG Bus", + "SPI Bus", + "SPI Device", + "SDIO Bus", + "PM Pseudo Device", + "Pipe", + "Portal Device", + "Timer Device", + "Miscellaneous Device", + "Sensor Device", + "Touch Device", + "Phy Device", + "Security Device", + "WLAN Device", + "Pin Device", + "ADC Device", + "DAC Device", + "WDT Device", + "PWM Device", + "Bus Device", +}; + +static void save_info(struct device_show *dev, char *dev_name) +{ + char tmp[256] = {0}; + int len; + + dev->index ++; + + rt_snprintf(tmp, 256, "%d %s\n", dev->index, dev_name); + tmp[255] = 0; + + len = rt_strlen(tmp); + if (dev->size > dev->len + len) + { + strcat(dev->buf, tmp); + dev->len += len; + } + else + { + if (dev->buf == RT_NULL) + { + dev->buf = rt_calloc(1, 4096); + } + else + { + dev->buf = rt_realloc(dev->buf, dev->size + 4096); + } + if (dev->buf) + { + dev->size += 4096; + strcat(dev->buf, tmp); + dev->len += len; + } + } +} + +static void list_device(struct device_show *dev) +{ + rt_base_t level; + list_get_next_t find_arg; + struct rt_object_information *info; + rt_list_t *obj_list[LIST_FIND_OBJ_NR]; + rt_list_t *next = (rt_list_t *)RT_NULL; + + list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0])); + info = rt_list_entry(find_arg.list, struct rt_object_information, object_list); + + do + { + next = list_get_next(next, &find_arg); + { + int i; + for (i = 0; i < find_arg.nr_out; i++) + { + struct rt_object *obj; + struct rt_device *device; + + obj = rt_list_entry(obj_list[i], struct rt_object, list); + level = rt_spin_lock_irqsave(&info->spinlock); + if ((obj->type & ~RT_Object_Class_Static) != find_arg.type) + { + rt_spin_unlock_irqrestore(&info->spinlock, level); + continue; + } + + rt_spin_unlock_irqrestore(&info->spinlock, level); + + device = (struct rt_device *)obj; + + if (device->type < RT_Device_Class_Unknown) + { + save_info(dev + device->type, device->parent.name); + } + } + } + } + while (next != (rt_list_t *)RT_NULL); +} + +static int show_info(struct dfs_seq_file *seq) +{ + struct device_show _show[RT_Device_Class_Unknown] = {0}; + + list_device(_show); + + for (int i = 0; i < RT_Device_Class_Unknown; i++) + { + if (_show[i].buf) + { + dfs_seq_printf(seq, "%s:\n", device_type_str[i]); + dfs_seq_write(seq, _show[i].buf, _show[i].len); + dfs_seq_putc(seq, '\n'); + + rt_free(_show[i].buf); + } + } + + return 0; +} + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + + return NULL + (i == 0); +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + + *index = i; + + return NULL; +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + /* data: The return value of the start or next*/ + show_info(seq); + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +int proc_devices_init(void) +{ + struct proc_dentry *dentry = proc_create_data("devices", 0, NULL, NULL, NULL); + if (dentry) + { + dentry->seq_ops = &seq_ops; + } + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_devices_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_filesystems.c b/components/dfs/dfs_v2/filesystems/procfs/proc_filesystems.c new file mode 100644 index 000000000000..94e7a858d5ac --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_filesystems.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include +#include + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + struct dfs_filesystem_type *fs = dfs_filesystems(); + + if (fs) + { + while (i--) + { + fs = fs->next; + if (!fs) + { + break; + } + } + } + + return fs; +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data; + + *index = i; + + return fs->next; +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + /* data: The return value of the start or next*/ + struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data; + + dfs_seq_printf(seq, "%-9s%s\n", (fs->fs_ops->flags == FS_NEED_DEVICE) ? "" : "nodev", fs->fs_ops->name); + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +int proc_filesystems_init(void) +{ + struct proc_dentry *dentry = proc_create_data("filesystems", 0, NULL, NULL, NULL); + if (dentry) + { + dentry->seq_ops = &seq_ops; + } + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_filesystems_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c b/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c new file mode 100644 index 000000000000..6ce1bc487a71 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include +#include + + +extern void rt_memory_info(rt_size_t *total, + rt_size_t *used, + rt_size_t *max_used); + +static int single_show(struct dfs_seq_file *seq, void *data) +{ + dfs_seq_printf(seq, "0.13 0.16 0.17 1/1035 380436\n"); + + return 0; +} + +int proc_loadavg_init(void) +{ + struct proc_dentry *dentry = proc_create_single_data("loadavg", 0, NULL, single_show, NULL); + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_loadavg_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c b/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c new file mode 100644 index 000000000000..b6ae56288f4a --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include +#include + + +extern void rt_memory_info(rt_size_t *total, + rt_size_t *used, + rt_size_t *max_used); + +static int single_show(struct dfs_seq_file *seq, void *data) +{ + rt_size_t total, used, max_used, freed; + rt_size_t total_sum = 0; + rt_size_t total_freed = 0; + + rt_memory_info(&total, &used, &max_used); + total_sum = total_sum + total; + total_freed = total_freed + total - used; + + dfs_seq_printf(seq, "%-16s%8d KB\n", "MemMaxUsed:", max_used / 1024); + dfs_seq_printf(seq, "%-16s%8d KB\n", "MemAvailable:", (total - used) / 1024); + dfs_seq_printf(seq, "%-16s%8d KB\n", "Cached:", 0); + dfs_seq_printf(seq, "%-16s%8d KB\n", "SReclaimable:", 0); + + rt_page_get_info(&total, &freed); + total_sum = total_sum + total * RT_MM_PAGE_SIZE; + total_freed = total_freed + freed * RT_MM_PAGE_SIZE; + + dfs_seq_printf(seq, "%-16s%8d KB\n", "MemTotal:", total_sum / 1024); + dfs_seq_printf(seq, "%-16s%8d KB\n", "MemFree:", total_freed / 1024); + dfs_seq_printf(seq, "%-16s%8d KB\n", "LowPageTotal:", total * RT_MM_PAGE_SIZE / 1024); + dfs_seq_printf(seq, "%-16s%8d KB\n", "lowPageFree:", freed * RT_MM_PAGE_SIZE/ 1024); + + rt_page_high_get_info(&total, &freed); + + dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageTotal:", total * RT_MM_PAGE_SIZE / 1024); + dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageFree:", freed * RT_MM_PAGE_SIZE / 1024); + + return 0; +} + +int proc_meminfo_init(void) +{ + struct proc_dentry *dentry = proc_create_single_data("meminfo", 0, NULL, single_show, NULL); + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_meminfo_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c b/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c new file mode 100644 index 000000000000..49a6ba99c6b0 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include +#include + + +const char *mnt_flag(int flag) +{ + /*if (flag & MNT_READONLY) + { + return "ro"; + }*/ + + return "rw"; +} + +static struct dfs_mnt* mnt_show(struct dfs_mnt *mnt, void *parameter) +{ + struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter; + + if (mnt) + { + if (mnt->dev_id) + { + dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->dev_id->parent.name, mnt->fullpath, + mnt->fs_ops->name, mnt_flag(mnt->flags)); + } + else + { + dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->fs_ops->name, mnt->fullpath, + mnt->fs_ops->name, mnt_flag(mnt->flags)); + } + } + + return RT_NULL; +} + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + + return NULL + (i == 0); +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + + *index = i; + + return NULL; +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + /* data: The return value of the start or next*/ + dfs_mnt_foreach(mnt_show, seq); + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +int proc_mounts_init(void) +{ + struct proc_dentry *dentry = proc_create_data("mounts", 0, NULL, NULL, NULL); + if (dentry) + { + dentry->seq_ops = &seq_ops; + } + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_mounts_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_net.c b/components/dfs/dfs_v2/filesystems/procfs/proc_net.c new file mode 100644 index 000000000000..778cec50f283 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_net.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + +#ifdef RT_USING_LWIP +#include "lwip/opt.h" +#endif + +#if LWIP_ROUTE +extern int inet_route_foreach(void (*func)(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter), void *parameter); +#endif + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + + return NULL + (i == 0); +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + + *index = i; + + return NULL; +} + +static void route_show(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter) +{ + struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter; + /* "Iface\tDestination\tGateway " + "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU" + "\tWindow\tIRTT"); */ + /* "%63s%lx%lx%X%d%d%d%lx%d%d%d\n" */ + dfs_seq_printf(seq, "%s ", name); + dfs_seq_printf(seq, "%lx ", ip_addr); + dfs_seq_printf(seq, "%lx ", 0); + dfs_seq_printf(seq, "%X ", 1); + dfs_seq_printf(seq, "%d ", 0); + dfs_seq_printf(seq, "%d ", 0); + dfs_seq_printf(seq, "%d ", 0); + dfs_seq_printf(seq, "%lx ", netmask); + dfs_seq_printf(seq, "%d ", 0); + dfs_seq_printf(seq, "%d ", 0); + dfs_seq_printf(seq, "%d\n", 0); +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + /* data: The return value of the start or next*/ + dfs_seq_printf(seq, "\n"); +#if LWIP_ROUTE + inet_route_foreach(route_show, seq); +#endif + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +int proc_net_init(void) +{ + struct proc_dentry *dentry; + + dentry = proc_mkdir("net", NULL); + if (!dentry) + return -1; + + proc_release(dentry); + + dentry = proc_create_data("net/route", 0, NULL, NULL, NULL); + if (dentry) + { + dentry->seq_ops = &seq_ops; + } + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_net_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_partitions.c b/components/dfs/dfs_v2/filesystems/procfs/proc_partitions.c new file mode 100644 index 000000000000..1c7a48a3651f --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_partitions.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +#define LIST_FIND_OBJ_NR 8 + +typedef struct +{ + rt_list_t *list; + rt_list_t **array; + rt_uint8_t type; + int nr; /* input: max nr, can't be 0 */ + int nr_out; /* out: got nr */ +} list_get_next_t; + +static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr) +{ + struct rt_object_information *info; + rt_list_t *list; + + info = rt_object_get_information((enum rt_object_class_type)type); + list = &info->object_list; + + p->list = list; + p->type = type; + p->array = array; + p->nr = nr; + p->nr_out = 0; +} + +static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg) +{ + int first_flag = 0; + rt_base_t level; + rt_list_t *node, *list; + rt_list_t **array; + struct rt_object_information *info; + int nr; + + arg->nr_out = 0; + + if (!arg->nr || !arg->type) + { + return (rt_list_t *)RT_NULL; + } + + list = arg->list; + info = rt_list_entry(list, struct rt_object_information, object_list); + + if (!current) /* find first */ + { + node = list; + first_flag = 1; + } + else + { + node = current; + } + + level = rt_spin_lock_irqsave(&info->spinlock); + + if (!first_flag) + { + struct rt_object *obj; + /* The node in the list? */ + obj = rt_list_entry(node, struct rt_object, list); + if ((obj->type & ~RT_Object_Class_Static) != arg->type) + { + rt_spin_unlock_irqrestore(&info->spinlock, level); + return (rt_list_t *)RT_NULL; + } + } + + nr = 0; + array = arg->array; + while (1) + { + node = node->next; + + if (node == list) + { + node = (rt_list_t *)RT_NULL; + break; + } + nr++; + *array++ = node; + if (nr == arg->nr) + { + break; + } + } + + rt_spin_unlock_irqrestore(&info->spinlock, level); + arg->nr_out = nr; + return node; +} + +static int show_info(struct dfs_seq_file *seq) +{ + rt_base_t level; + list_get_next_t find_arg; + struct rt_object_information *info; + rt_list_t *obj_list[LIST_FIND_OBJ_NR]; + rt_list_t *next = (rt_list_t *)RT_NULL; + + list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0])); + info = rt_list_entry(find_arg.list, struct rt_object_information, object_list); + + do + { + next = list_get_next(next, &find_arg); + { + int i; + for (i = 0; i < find_arg.nr_out; i++) + { + struct rt_object *obj; + struct rt_device *device; + + obj = rt_list_entry(obj_list[i], struct rt_object, list); + level = rt_spin_lock_irqsave(&info->spinlock); + if ((obj->type & ~RT_Object_Class_Static) != find_arg.type) + { + rt_spin_unlock_irqrestore(&info->spinlock, level); + continue; + } + + rt_spin_unlock_irqrestore(&info->spinlock, level); + + device = (struct rt_device *)obj; + + if (device->type == RT_Device_Class_Block) + { + struct rt_device_blk_geometry geometry = { 0 }; + + rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry); + + dfs_seq_printf(seq, "%4d %7d %14llu %s\n", 0, 0, + geometry.sector_count, device->parent.name); + } + } + } + } while (next != (rt_list_t *)RT_NULL); + + return 0; +} + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + + return NULL + (i == 0); +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + + *index = i; + + return NULL; +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + dfs_seq_puts(seq, "major minor #blocks name\n\n"); + /* data: The return value of the start or next*/ + show_info(seq); + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +int proc_partitions_init(void) +{ + struct proc_dentry *dentry = proc_create_data("partitions", 0, NULL, NULL, NULL); + if (dentry) + { + dentry->seq_ops = &seq_ops; + } + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_partitions_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c b/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c new file mode 100644 index 000000000000..a413f646c830 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ +#define __RT_IPC_SOURCE__ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include "lwp_internal.h" +#include +#include "lwp_internal.h" + +#if defined(RT_USING_SMART) + +#include "lwp.h" +#include "lwp_pid.h" +#include + +struct pid_dentry +{ + const char *name; + mode_t mode; + const struct dfs_file_ops *fops; + const struct proc_ops *ops; + const struct dfs_seq_ops *seq_ops; + int (*single_show)(struct dfs_seq_file *seq, void *data); + void *data; +}; + +static char stat_transform(int __stat) +{ + switch (__stat) + { + case RT_THREAD_RUNNING: + return 'R'; + default: + return 'T'; + } +} + +static int stat_single_show(struct dfs_seq_file *seq, void *data) +{ + struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data; + rt_list_t *list; + int mask = 0; + rt_thread_t thread; + rt_uint64_t user_time_lwp = 0; + rt_uint64_t system_time_lwp = 0; + int lwp_oncpu = RT_CPUS_NR; + int lwp_oncpu_ok = 0; + struct rt_lwp *lwp = RT_NULL; + char** argv = RT_NULL; + char *filename = RT_NULL; + char *dot = RT_NULL; + + lwp_pid_lock_take(); + + lwp = lwp_from_pid_locked(dentry->pid); + argv = lwp_get_command_line_args(lwp); + + if (lwp) + { + dfs_seq_printf(seq,"%d ",dentry->pid); + if (argv) + { + filename = strrchr(argv[0], '/'); + dot = strchr(argv[0], '.'); + + if (filename != NULL) + { + filename++; + } + else + { + filename = argv[0]; + } + + if (dot != NULL) + { + *dot = '\0'; + } + + if (filename != NULL) + { + dfs_seq_printf(seq,"(%s) ", filename); + } + else + { + dfs_seq_printf(seq,"(%s) ", argv[0]); + } + + lwp_free_command_line_args(argv); + } + else + { + dfs_seq_printf(seq,"(%s) ", ""); + } + + if (lwp->terminated) + { + dfs_seq_printf(seq,"%c ",'Z'); + } + else + { + list = lwp->t_grp.next; + while (list != &lwp->t_grp) + { + thread = rt_list_entry(list, struct rt_thread, sibling); + user_time_lwp = user_time_lwp + thread->user_time; + system_time_lwp = system_time_lwp + thread->system_time; + + #if RT_CPUS_NR > 1 + #define ONCPU(thread) RT_SCHED_CTX(thread).oncpu + #else + #define ONCPU(thread) 0 + #endif + if (lwp_oncpu_ok == 0) + { + lwp_oncpu = ONCPU(thread); + lwp_oncpu_ok = 1; + } + if (stat_transform(RT_SCHED_CTX(thread).stat) == 'R') + { + lwp_oncpu = ONCPU(thread); + mask = 1; + } + list = list->next; + } + + if (mask == 1) + { + dfs_seq_printf(seq,"%c ",'R'); + } + else + { + dfs_seq_printf(seq,"%c ",'S'); + } + } + lwp_pid_lock_release(); + + if (lwp->parent != NULL) + dfs_seq_printf(seq,"%d ",lwp->parent->pid); + else + dfs_seq_printf(seq,"0 "); + + dfs_seq_printf(seq, "1 1 0 -1 4194560 48245 133976064 732 425574 "); + dfs_seq_printf(seq,"%llu ",user_time_lwp);//utime + dfs_seq_printf(seq,"%llu ",system_time_lwp);//stime + dfs_seq_printf(seq, "1204291 518742 20 0 1 0 50 "); + dfs_seq_printf(seq, "%d ",rt_aspace_count_vsz(lwp->aspace));//VSZ + dfs_seq_printf(seq, "1422 18446744073709551615 "); + dfs_seq_printf(seq, "1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 "); + dfs_seq_printf(seq, "%d ", lwp_oncpu);//CPU + dfs_seq_printf(seq, "0 0 0 0 0 0 0 0 0 0 0 0 0"); + dfs_seq_printf(seq,"\n"); + } + else + { + lwp_pid_lock_release(); + } + + return 0; +} + +static int cmdline_single_show(struct dfs_seq_file *seq, void *data) +{ + struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data; + struct rt_lwp *lwp; + char** argv; + + lwp_pid_lock_take(); + lwp = lwp_from_pid_locked(dentry->pid); + argv = lwp_get_command_line_args(lwp); + lwp_pid_lock_release(); + + if (argv) + { + for (int i = 0; argv[i] != NULL; i++) + { + dfs_seq_printf(seq, "%s ", argv[i]); + } + dfs_seq_puts(seq, "\n"); + + lwp_free_command_line_args(argv); + } + else + { + dfs_seq_puts(seq, "error\n"); + } + + return 0; +} + +struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *name) +{ + struct proc_dentry *dentry = RT_NULL; + char num[DIRENT_NAME_MAX]; + struct rt_lwp *lwp; + struct dfs_fdtable *table; + + lwp_pid_lock_take(); + lwp = lwp_from_pid_locked(parent->pid); + table = lwp ? &lwp->fdt : RT_NULL; + lwp_pid_lock_release(); + + if (!table) + { + return RT_NULL; + } + + dfs_file_lock(); + for (int i = 0; i < table->maxfd; i++) + { + struct dfs_file *file = table->fds[i]; + if (file) + { + rt_snprintf(num, DIRENT_NAME_MAX, "%d", i); + if (rt_strcmp(num, name) == 0) + { + dentry = rt_calloc(1, sizeof(struct proc_dentry)); + if (dentry) + { + dentry->mode = (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH)); + dentry->ref_count = 1; + dentry->name = rt_strdup(name); + dentry->data = (void *)dfs_dentry_full_path(file->dentry); + + if (dentry->data == RT_NULL) + { + //todo add vnode->data + if (file->vnode->type == FT_SOCKET) + dentry->data = (void *)rt_strdup("socket"); + else if (file->vnode->type == FT_USER) + dentry->data = (void *)rt_strdup("user"); + else if (file->vnode->type == FT_DEVICE) + dentry->data = (void *)rt_strdup("device"); + else + dentry->data = (void *)rt_strdup("unknown"); + } + + dentry->pid = parent->pid; + break; + } + } + } + } + dfs_file_unlock(); + + return dentry; +} + +int proc_pid_fd_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count) +{ + int ret = 0, index = 0; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + struct rt_lwp *lwp; + struct dfs_fdtable *table; + + lwp_pid_lock_take(); + lwp = lwp_from_pid_locked(entry->pid); + LWP_LOCK(lwp); + table = lwp ? &lwp->fdt : RT_NULL; + + if (!table->fds) + { + LWP_UNLOCK(lwp); + lwp_pid_lock_release(); + return 0; + } + + count = (count / sizeof(struct dirent)); + if (count == 0) + { + LWP_UNLOCK(lwp); + lwp_pid_lock_release(); + return -EINVAL; + } + + dfs_file_lock(); + for (int i = 0; i < table->maxfd; i++) + { + struct dfs_file *df = table->fds[i]; + if (df) + { + if (index >= file->fpos) + { + struct dirent *d = dirp + index - file->fpos; + + d->d_type = DT_SYMLINK; + d->d_reclen = (rt_uint16_t)sizeof(struct dirent); + rt_snprintf(d->d_name, DIRENT_NAME_MAX, "%d", i); + d->d_namlen = rt_strlen(d->d_name); + + ret++; + } + + index++; + if (index - file->fpos >= count) + { + break; + } + } + } + dfs_file_unlock(); + LWP_UNLOCK(lwp); + lwp_pid_lock_release(); + + if (ret > 0) + { + file->fpos = index; + ret = ret * sizeof(struct dirent); + } + + return ret; +} + +static const struct proc_ops proc_pid_fd_ops = { + .lookup = proc_pid_fd_lookup, +}; + +static const struct dfs_file_ops proc_pid_fd_fops = { + .getdents = proc_pid_fd_getdents, +}; + +int proc_pid_exe_readlink(struct proc_dentry *dentry, char *buf, int len) +{ + struct rt_lwp *lwp; + + lwp = lwp_self(); + len = rt_snprintf(buf, len, "%s", lwp ? lwp->exe_file : "null"); + + return len; +} + +static const struct proc_ops proc_pid_exe_ops = { + .readlink = proc_pid_exe_readlink, +}; + +int proc_pid_cwd_readlink(struct proc_dentry *dentry, char *buf, int len) +{ + struct rt_lwp *lwp; + + lwp = lwp_self(); + len = rt_snprintf(buf, len, "%s", lwp ? lwp->working_directory : "null"); + + return len; +} + +static const struct proc_ops proc_pid_cwd_ops = { + .readlink = proc_pid_cwd_readlink, +}; + +static struct pid_dentry pid_dentry_base[] = { + {"cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0}, + {"cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0}, + {"exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0}, + {"fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0}, + {"mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts"}, + {"stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0}, +}; + +int proc_pid(int pid) +{ + char pid_str[64] = {0}; + struct proc_dentry *dentry; + + rt_snprintf(pid_str, 64, "%d", pid); + pid_str[63] = 0; + + dentry = proc_mkdir(pid_str, 0); + if (dentry) + { + struct proc_dentry *ent; + + dentry->pid = pid; + for (int j = 0; j < sizeof(pid_dentry_base) / sizeof(struct pid_dentry); j++) + { + if (S_ISDIR(pid_dentry_base[j].mode)) + { + ent = proc_mkdir_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry, + pid_dentry_base[j].fops, pid_dentry_base[j].data); + } + else if (S_ISLNK(pid_dentry_base[j].mode)) + { + if (pid_dentry_base[j].data == RT_NULL) + { + pid_dentry_base[j].data = "NULL"; + } + + ent = proc_symlink(pid_dentry_base[j].name, dentry, pid_dentry_base[j].data); + } + else + { + ent = proc_create_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry, + pid_dentry_base[j].fops, pid_dentry_base[j].data); + } + + if (ent) + { + if (pid_dentry_base[j].ops) + { + ent->ops = pid_dentry_base[j].ops; + } + + if (pid_dentry_base[j].seq_ops) + { + ent->seq_ops = pid_dentry_base[j].seq_ops; + } + + if (pid_dentry_base[j].single_show) + { + ent->single_show = pid_dentry_base[j].single_show; + } + + proc_release(ent); + } + } + proc_release(dentry); + } + + return 0; +} + +int msh_proc_pid(int argc, char **argv) +{ + if (argc > 1) + { + for (int i = 1; i <= argc - 1; i++) + { + proc_pid(atoi(argv[i])); + } + } + + return 0; +} +MSH_CMD_EXPORT_ALIAS(msh_proc_pid, proc_pid, proc pid); + +#endif diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_self.c b/components/dfs/dfs_v2/filesystems/procfs/proc_self.c new file mode 100644 index 000000000000..a1082ea19235 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_self.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + +#if defined(RT_USING_SMART) + +#include + + +int proc_self_readlink(struct proc_dentry *dentry, char *buf, int len) +{ + struct rt_lwp *lwp = RT_NULL; + + lwp = lwp_self(); + if (lwp) + { + rt_snprintf(buf, len, "%d", lwp_to_pid(lwp)); + buf[len - 1] = 0; + return rt_strlen(buf); + } + else + { + rt_snprintf(buf, len, "null"); + buf[len - 1] = 0; + return rt_strlen(buf); + } + + return -1; +} + +static const struct proc_ops proc_pid_fd_ops = { + .readlink = proc_self_readlink, +}; + +int proc_self_init(void) +{ + struct proc_dentry *ent; + + ent = proc_symlink("self", NULL, "NULL"); + if (ent) + { + ent->ops = &proc_pid_fd_ops; + } + proc_release(ent); + + return 0; +} +INIT_ENV_EXPORT(proc_self_init); + +#endif diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c b/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c new file mode 100644 index 000000000000..aeba99de5134 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + + return NULL + (i == 0); +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + + *index = i; + + return NULL; +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + int i; + rt_cpu_t pcpu; + rt_uint64_t user_total = 0; + rt_uint64_t system_total = 0; + rt_uint64_t idle_total = 0; + + for (i = 0; i < RT_CPUS_NR; i++) + { + pcpu = rt_cpu_index(i); + user_total = user_total + pcpu->cpu_stat.user; + system_total = system_total + pcpu->cpu_stat.system; + idle_total = idle_total + pcpu->cpu_stat.idle; + } + dfs_seq_printf(seq, "cpu %llu 0 %llu %llu 0 0 0 0 0 0\n", user_total, system_total, idle_total); + + for (i = 0; i < RT_CPUS_NR; i++) + { + pcpu = rt_cpu_index(i); + dfs_seq_printf(seq, "cpu%d ",i); + dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.user);//user + dfs_seq_printf(seq, "0 ");//nice + dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.system);//system + dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.idle);//idle + dfs_seq_printf(seq, "0 ");//iowait + dfs_seq_printf(seq, "0 ");//irq + dfs_seq_printf(seq, "0 ");//softirq + dfs_seq_printf(seq, "0 0 0\n");//steal,guest,guest_nice + + } + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +rt_weak const struct dfs_seq_ops *stat_get_seq_ops(void) +{ + return &seq_ops; +} + +static int proc_open(struct dfs_file *file) +{ + return dfs_seq_open(file, stat_get_seq_ops()); +} + +static int proc_close(struct dfs_file *file) +{ + return dfs_seq_release(file); +} + +static const struct dfs_file_ops file_ops = { + .open = proc_open, + .read = dfs_seq_read, + .lseek = dfs_seq_lseek, + .close = proc_close, +}; + +int proc_stat_init(void) +{ + struct proc_dentry *dentry = proc_create_data("stat", 0, NULL, &file_ops, NULL); + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_stat_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_tty.c b/components/dfs/dfs_v2/filesystems/procfs/proc_tty.c new file mode 100644 index 000000000000..a79a3b69edb1 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_tty.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + + +static void *seq_start(struct dfs_seq_file *seq, off_t *index) +{ + off_t i = *index; // seq->index + + return NULL + (i == 0); +} + +static void seq_stop(struct dfs_seq_file *seq, void *data) +{ +} + +static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index) +{ + /* data: The return value of the start or next*/ + off_t i = *index + 1; // seq->index + + *index = i; + + return NULL; +} + +static int seq_show(struct dfs_seq_file *seq, void *data) +{ + /* data: The return value of the start or next*/ + dfs_seq_puts(seq, "todo\n"); + + return 0; +} + +static const struct dfs_seq_ops seq_ops = { + .start = seq_start, + .stop = seq_stop, + .next = seq_next, + .show = seq_show, +}; + +void proc_tty_register_driver(void *driver) +{ + //todo +} + +void proc_tty_unregister_driver(void *driver) +{ + //todo +} + +int proc_tty_init(void) +{ + struct proc_dentry *dentry; + + dentry = proc_mkdir("tty", NULL); + if (!dentry) + return -1; + + proc_release(dentry); + + dentry = proc_mkdir("tty/ldisc", NULL); + proc_release(dentry); + + dentry = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL); + proc_release(dentry); + + dentry = proc_create_data("tty/ldiscs", 0, NULL, NULL, NULL); + if (dentry) + { + dentry->seq_ops = &seq_ops; + } + proc_release(dentry); + + dentry = proc_create_data("tty/drivers", 0, NULL, NULL, NULL); + if (dentry) + { + dentry->seq_ops = &seq_ops; + } + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_tty_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c b/components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c new file mode 100644 index 000000000000..f16ab72b6672 --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + + +static int single_show(struct dfs_seq_file *seq, void *data) +{ + dfs_seq_printf(seq, "%lu.%02lu %lu.%02lu\n", + (unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100, + (unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100); + + return 0; +} + +int proc_uptime_init(void) +{ + struct proc_dentry *dentry = proc_create_single_data("uptime", 0, NULL, single_show, NULL); + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_uptime_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_version.c b/components/dfs/dfs_v2/filesystems/procfs/proc_version.c new file mode 100644 index 000000000000..1ca803543efb --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/proc_version.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include "proc.h" +#include "procfs.h" + +#include +#include + +#include +#include + +#include + + +static int single_show(struct dfs_seq_file *seq, void *data) +{ + dfs_seq_puts(seq, "\n \\ | /\n"); +#ifdef RT_USING_SMART + dfs_seq_puts(seq, "- RT - Thread Smart Operating System\n"); +#else + dfs_seq_puts(seq, "- RT - Thread Operating System\n"); +#endif + dfs_seq_printf(seq, " / | \\ %d.%d.%d build %s %s\n", + (rt_int32_t)RT_VERSION_MAJOR, (rt_int32_t)RT_VERSION_MINOR, (rt_int32_t)RT_VERSION_PATCH, + __DATE__, __TIME__); + dfs_seq_puts(seq, " 2006 - 2022 Copyright by RT-Thread team\n"); + + return 0; +} + +int proc_version_init(void) +{ + struct proc_dentry *dentry = proc_create_single_data("version", 0, NULL, single_show, NULL); + proc_release(dentry); + + return 0; +} +INIT_ENV_EXPORT(proc_version_init); diff --git a/components/dfs/dfs_v2/filesystems/procfs/procfs.c b/components/dfs/dfs_v2/filesystems/procfs/procfs.c new file mode 100644 index 000000000000..965e16412c2b --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/procfs.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "proc.h" +#include "procfs.h" + +#define PROC_DEBUG(...) //rt_kprintf + +static int dfs_procfs_open(struct dfs_file *file) +{ + rt_err_t ret = RT_EOK; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + + RT_ASSERT(file->vnode->ref_count > 0); + if (file->vnode->ref_count > 1) + { + file->fpos = 0; + return ret; + } + + if (entry->fops && entry->fops->open) + { + ret = entry->fops->open(file); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_close(struct dfs_file *file) +{ + rt_err_t ret = RT_EOK; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + RT_ASSERT(file->vnode->ref_count > 0); + if (file->vnode->ref_count > 1) + { + return ret; + } + + if (entry && entry->fops && entry->fops->close) + { + ret = entry->fops->close(file); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static ssize_t dfs_procfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos) +{ + ssize_t ret = -RT_ERROR; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (entry && entry->fops && entry->fops->read) + { + ret = entry->fops->read(file, buf, count, pos); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static ssize_t dfs_procfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos) +{ + ssize_t ret = -RT_ERROR; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (entry && entry->fops && entry->fops->write) + { + ret = entry->fops->write(file, buf, count, pos); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_ioctl(struct dfs_file *file, int cmd, void *args) +{ + int ret = -RT_ERROR; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (entry && entry->fops && entry->fops->ioctl) + { + ret = entry->fops->ioctl(file, cmd, args); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count) +{ + int ret = 0; + rt_uint32_t index = 0; + struct dirent *d; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (entry) + { + struct proc_dentry *iter = RT_NULL, *tmp; + + /* make integer count */ + count = (count / sizeof(struct dirent)); + if (count == 0) + { + return -EINVAL; + } + + dfs_vfs_for_each_subnode(iter, tmp, entry, node) + { + if (iter == RT_NULL) + { + break; + } + + if (index >= file->fpos) + { + d = dirp + index - file->fpos; + + if (S_ISDIR(entry->mode)) + { + d->d_type = DT_DIR; + } + else if (S_ISLNK(entry->mode)) + { + d->d_type = DT_SYMLINK; + } + else + { + d->d_type = DT_REG; + } + + d->d_namlen = rt_strlen(iter->name); + d->d_reclen = (rt_uint16_t)sizeof(struct dirent); + rt_strncpy(d->d_name, iter->name, rt_strlen(iter->name) + 1); + + ret ++; + } + + index++; + if (index - file->fpos >= count) + { + break; + } + } + + if (ret > 0) + { + file->fpos = index; + } + + if (entry->fops && entry->fops->getdents && ret < count) + { + int r; + + file->fpos -= index; + + r = entry->fops->getdents(file, dirp + ret, (count - ret) * sizeof(struct dirent)); + + ret = ret * sizeof(struct dirent); + + if (r > 0) + { + ret += r; + } + + file->fpos += index; + } + else + { + ret = ret * sizeof(struct dirent); + } + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_poll(struct dfs_file *file, struct rt_pollreq *req) +{ + int ret = -RT_ERROR; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (entry && entry->fops && entry->fops->poll) + { + ret = entry->fops->poll(file, req); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_flush(struct dfs_file *file) +{ + int ret = -RT_ERROR; + struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data; + + if (entry && entry->fops && entry->fops->flush) + { + ret = entry->fops->flush(file); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data) +{ + RT_ASSERT(mnt != RT_NULL); + + return RT_EOK; +} + +static int dfs_procfs_umount(struct dfs_mnt *mnt) +{ + RT_ASSERT(mnt != RT_NULL); + + return RT_EOK; +} + +static int dfs_procfs_readlink(struct dfs_dentry *dentry, char *buf, int len) +{ + int ret = 0; + struct proc_dentry *entry = dfs_proc_find(dentry->pathname); + + if (entry) + { + if (S_ISLNK(entry->mode) && entry->data) + { + if (entry->ops && entry->ops->readlink) + { + ret = entry->ops->readlink(entry, buf, len); + } + else + { + rt_strncpy(buf, (const char *)entry->data, len); + buf[len - 1] = '\0'; + ret = rt_strlen(buf); + } + } + + proc_release(entry); + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_unlink(struct dfs_dentry *dentry) +{ + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, -1); + return -RT_ERROR; +} + +static int dfs_procfs_stat(struct dfs_dentry *dentry, struct stat *st) +{ + int ret = RT_EOK; + struct dfs_vnode *vnode; + + if (dentry && dentry->vnode) + { + vnode = dentry->vnode; + + st->st_dev = (dev_t)(dentry->mnt->dev_id); + st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry); + + st->st_gid = vnode->gid; + st->st_uid = vnode->uid; + st->st_mode = vnode->mode; + st->st_nlink = vnode->nlink; + st->st_size = vnode->size; + st->st_mtim.tv_nsec = vnode->mtime.tv_nsec; + st->st_mtim.tv_sec = vnode->mtime.tv_sec; + st->st_ctim.tv_nsec = vnode->ctime.tv_nsec; + st->st_ctim.tv_sec = vnode->ctime.tv_sec; + st->st_atim.tv_nsec = vnode->atime.tv_nsec; + st->st_atim.tv_sec = vnode->atime.tv_sec; + } + + PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret); + + return ret; +} + +static int dfs_procfs_statfs(struct dfs_mnt *mnt, struct statfs *buf) +{ + if (mnt && buf) + { + buf->f_bsize = 512; + buf->f_blocks = 2048 * 64; // 64M + buf->f_bfree = buf->f_blocks; + buf->f_bavail = buf->f_bfree; + } + + PROC_DEBUG(" %s %d\n", __func__, __LINE__); + + return RT_EOK; +} + +static struct dfs_vnode *dfs_procfs_lookup(struct dfs_dentry *dentry) +{ + struct dfs_vnode *vnode = RT_NULL; + struct proc_dentry *entry = dfs_proc_find(dentry->pathname); + + if (entry) + { + vnode = dfs_vnode_create(); + if (vnode) + { + vnode->nlink = 1; + vnode->size = 0; + if (S_ISDIR(entry->mode)) + { + vnode->mode = entry->mode; + vnode->type = FT_DIRECTORY; + } + else if (S_ISLNK(entry->mode)) + { + vnode->mode = entry->mode; + vnode->type = FT_SYMLINK; + } + else + { + vnode->mode = entry->mode; + vnode->type = FT_REGULAR; + } + + vnode->data = entry; + vnode->mnt = dentry->mnt; + } + + proc_release(entry); + } + + PROC_DEBUG(" %s %d >> %s\n", __func__, __LINE__, dentry->pathname); + + return vnode; +} + +static struct dfs_vnode *dfs_procfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode) +{ + return RT_NULL; +} + +static int dfs_procfs_free_vnode(struct dfs_vnode *vnode) +{ + return 0; +} + +static const struct dfs_file_ops _dev_fops = +{ + .open = dfs_procfs_open, + .close = dfs_procfs_close, + .lseek = generic_dfs_lseek, + .read = dfs_procfs_read, + .write = dfs_procfs_write, + .ioctl = dfs_procfs_ioctl, + .getdents = dfs_procfs_getdents, + .poll = dfs_procfs_poll, + .flush = dfs_procfs_flush, +}; + +static const struct dfs_filesystem_ops _procfs_ops = +{ + .name = "procfs", + + .default_fops = &_dev_fops, + + .mount = dfs_procfs_mount, + .umount = dfs_procfs_umount, + .readlink = dfs_procfs_readlink, + .unlink = dfs_procfs_unlink, + .stat = dfs_procfs_stat, + .statfs = dfs_procfs_statfs, + .lookup = dfs_procfs_lookup, + .create_vnode = dfs_procfs_create_vnode, + .free_vnode = dfs_procfs_free_vnode, +}; + +static struct dfs_filesystem_type _procfs = +{ + .fs_ops = &_procfs_ops, +}; + +int dfs_procfs_init(void) +{ + /* register procfs file system */ + dfs_register(&_procfs); + + return 0; +} +INIT_COMPONENT_EXPORT(dfs_procfs_init); + +int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos) +{ + if (file->fpos >= file->vnode->size) + { + return 0; + } + + if (file->data) + { + count = file->vnode->size - file->fpos >= count ? count : file->vnode->size - file->fpos; + rt_strncpy(buf, file->data + file->fpos, count); + + file->fpos += count; + *pos = file->fpos; + } + else + { + return 0; + } + + return count; +} diff --git a/components/dfs/dfs_v2/filesystems/procfs/procfs.h b/components/dfs/dfs_v2/filesystems/procfs/procfs.h new file mode 100644 index 000000000000..6e921ae300ff --- /dev/null +++ b/components/dfs/dfs_v2/filesystems/procfs/procfs.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __PROC_FS_H__ +#define __PROC_FS_H__ + +#include + +int dfs_procfs_init(void); + +int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos); + +#endif