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  */
9 
10 #include <rthw.h>
11 #include <rtdbg.h>
12 
13 #include <fcntl.h>
14 #include <errno.h>
15 
16 #include <dfs.h>
17 #include <dfs_fs.h>
18 #include <dfs_file.h>
19 #include <dfs_posix.h>
20 #include <dfs_mnt.h>
21 #include <dfs_dentry.h>
22 
23 #include "proc.h"
24 #include "procfs.h"
25 
26 #define PROC_DEBUG(...) //rt_kprintf
27 
dfs_procfs_open(struct dfs_file * file)28 static int dfs_procfs_open(struct dfs_file *file)
29 {
30     rt_err_t ret = RT_EOK;
31     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
32 
33 
34     RT_ASSERT(file->ref_count > 0);
35 
36     // this file is opened and in an fdtable
37     if (file->ref_count > 1)
38     {
39         file->fpos = 0;
40         return ret;
41     }
42 
43     if (entry->fops && entry->fops->open)
44     {
45         ret = entry->fops->open(file);
46     }
47 
48     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
49 
50     return ret;
51 }
52 
dfs_procfs_close(struct dfs_file * file)53 static int dfs_procfs_close(struct dfs_file *file)
54 {
55     rt_err_t ret = RT_EOK;
56     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
57 
58     RT_ASSERT(file->vnode->ref_count > 0);
59     if (file->vnode->ref_count > 1)
60     {
61         return ret;
62     }
63 
64     if (entry && entry->fops && entry->fops->close)
65     {
66         ret = entry->fops->close(file);
67     }
68 
69     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
70 
71     return ret;
72 }
73 
dfs_procfs_read(struct dfs_file * file,void * buf,size_t count,off_t * pos)74 static ssize_t dfs_procfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
75 {
76     ssize_t ret = -RT_ERROR;
77     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
78 
79     if (entry && entry->fops && entry->fops->read)
80     {
81         ret = entry->fops->read(file, buf, count, pos);
82     }
83 
84     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
85 
86     return ret;
87 }
88 
dfs_procfs_write(struct dfs_file * file,const void * buf,size_t count,off_t * pos)89 static ssize_t dfs_procfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
90 {
91     ssize_t ret = -RT_ERROR;
92     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
93 
94     if (entry && entry->fops && entry->fops->write)
95     {
96         ret = entry->fops->write(file, buf, count, pos);
97     }
98 
99     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
100 
101     return ret;
102 }
103 
dfs_procfs_ioctl(struct dfs_file * file,int cmd,void * args)104 static int dfs_procfs_ioctl(struct dfs_file *file, int cmd, void *args)
105 {
106     int ret = -RT_ERROR;
107     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
108 
109     if (entry && entry->fops && entry->fops->ioctl)
110     {
111         ret = entry->fops->ioctl(file, cmd, args);
112     }
113 
114     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
115 
116     return ret;
117 }
118 
dfs_procfs_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)119 static int dfs_procfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
120 {
121     int ret = 0;
122     rt_uint32_t index = 0;
123     struct dirent *d;
124     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
125 
126     if (entry)
127     {
128         struct proc_dentry *iter = RT_NULL, *tmp;
129 
130         /* make integer count */
131         count = (count / sizeof(struct dirent));
132         if (count == 0)
133         {
134             return -EINVAL;
135         }
136 
137         dfs_vfs_for_each_subnode(iter, tmp, entry, node)
138         {
139             if (iter == RT_NULL)
140             {
141                 break;
142             }
143 
144             if (index >= file->fpos)
145             {
146                 d = dirp + index - file->fpos;
147 
148                 if (S_ISDIR(entry->mode))
149                 {
150                     d->d_type = DT_DIR;
151                 }
152                 else if (S_ISLNK(entry->mode))
153                 {
154                     d->d_type = DT_SYMLINK;
155                 }
156                 else
157                 {
158                     d->d_type = DT_REG;
159                 }
160 
161                 d->d_namlen = rt_strlen(iter->name);
162                 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
163                 rt_strncpy(d->d_name, iter->name, rt_strlen(iter->name) + 1);
164 
165                 ret ++;
166             }
167 
168             index++;
169             if (index - file->fpos >= count)
170             {
171                 break;
172             }
173         }
174 
175         if (ret > 0)
176         {
177             file->fpos = index;
178         }
179 
180         if (entry->fops && entry->fops->getdents && ret < count)
181         {
182             int r;
183 
184             file->fpos -= index;
185 
186             r = entry->fops->getdents(file, dirp + ret, (count - ret) * sizeof(struct dirent));
187 
188             ret = ret * sizeof(struct dirent);
189 
190             if (r > 0)
191             {
192                 ret += r;
193             }
194 
195             file->fpos += index;
196         }
197         else
198         {
199             ret = ret * sizeof(struct dirent);
200         }
201     }
202 
203     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
204 
205     return ret;
206 }
207 
dfs_procfs_poll(struct dfs_file * file,struct rt_pollreq * req)208 static int dfs_procfs_poll(struct dfs_file *file, struct rt_pollreq *req)
209 {
210     int ret = -RT_ERROR;
211     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
212 
213     if (entry && entry->fops && entry->fops->poll)
214     {
215         ret = entry->fops->poll(file, req);
216     }
217 
218     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
219 
220     return ret;
221 }
222 
dfs_procfs_flush(struct dfs_file * file)223 static int dfs_procfs_flush(struct dfs_file *file)
224 {
225     int ret = -RT_ERROR;
226     struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
227 
228     if (entry && entry->fops && entry->fops->flush)
229     {
230         ret = entry->fops->flush(file);
231     }
232 
233     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
234 
235     return ret;
236 }
237 
dfs_procfs_mount(struct dfs_mnt * mnt,unsigned long rwflag,const void * data)238 static int dfs_procfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
239 {
240     RT_ASSERT(mnt != RT_NULL);
241 
242     return RT_EOK;
243 }
244 
dfs_procfs_umount(struct dfs_mnt * mnt)245 static int dfs_procfs_umount(struct dfs_mnt *mnt)
246 {
247     RT_ASSERT(mnt != RT_NULL);
248 
249     return RT_EOK;
250 }
251 
dfs_procfs_readlink(struct dfs_dentry * dentry,char * buf,int len)252 static int dfs_procfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
253 {
254     int ret = 0;
255     struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
256 
257     if (entry)
258     {
259         if (S_ISLNK(entry->mode) && entry->data)
260         {
261             if (entry->ops && entry->ops->readlink)
262             {
263                 ret = entry->ops->readlink(entry, buf, len);
264             }
265             else
266             {
267                 rt_strncpy(buf, (const char *)entry->data, len);
268                 buf[len - 1] = '\0';
269                 ret = rt_strlen(buf);
270             }
271         }
272 
273         proc_release(entry);
274     }
275 
276     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
277 
278     return ret;
279 }
280 
dfs_procfs_unlink(struct dfs_dentry * dentry)281 static int dfs_procfs_unlink(struct dfs_dentry *dentry)
282 {
283     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, -1);
284     return -RT_ERROR;
285 }
286 
dfs_procfs_stat(struct dfs_dentry * dentry,struct stat * st)287 static int dfs_procfs_stat(struct dfs_dentry *dentry, struct stat *st)
288 {
289     int ret = RT_EOK;
290     struct dfs_vnode *vnode;
291 
292     if (dentry && dentry->vnode)
293     {
294         vnode = dentry->vnode;
295 
296         st->st_dev = (dev_t)(rt_ubase_t)(dentry->mnt->dev_id);
297         st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
298 
299         st->st_gid = vnode->gid;
300         st->st_uid = vnode->uid;
301         st->st_mode = vnode->mode;
302         st->st_nlink = vnode->nlink;
303         st->st_size = vnode->size;
304         st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
305         st->st_mtim.tv_sec = vnode->mtime.tv_sec;
306         st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
307         st->st_ctim.tv_sec = vnode->ctime.tv_sec;
308         st->st_atim.tv_nsec = vnode->atime.tv_nsec;
309         st->st_atim.tv_sec = vnode->atime.tv_sec;
310     }
311 
312     PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
313 
314     return ret;
315 }
316 
dfs_procfs_statfs(struct dfs_mnt * mnt,struct statfs * buf)317 static int dfs_procfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
318 {
319     if (mnt && buf)
320     {
321         buf->f_bsize = 512;
322         buf->f_blocks = 2048 * 64; // 64M
323         buf->f_bfree = buf->f_blocks;
324         buf->f_bavail = buf->f_bfree;
325     }
326 
327     PROC_DEBUG(" %s %d\n", __func__, __LINE__);
328 
329     return RT_EOK;
330 }
331 
dfs_procfs_lookup(struct dfs_dentry * dentry)332 static struct dfs_vnode *dfs_procfs_lookup(struct dfs_dentry *dentry)
333 {
334     struct dfs_vnode *vnode = RT_NULL;
335     struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
336 
337     if (entry)
338     {
339         vnode = dfs_vnode_create();
340         if (vnode)
341         {
342             vnode->nlink = 1;
343             vnode->size = 0;
344             if (S_ISDIR(entry->mode))
345             {
346                 vnode->mode = entry->mode;
347                 vnode->type = FT_DIRECTORY;
348             }
349             else if (S_ISLNK(entry->mode))
350             {
351                 vnode->mode = entry->mode;
352                 vnode->type = FT_SYMLINK;
353             }
354             else
355             {
356                 vnode->mode = entry->mode;
357                 vnode->type = FT_REGULAR;
358             }
359 
360             vnode->data = entry;
361             vnode->mnt = dentry->mnt;
362         }
363 
364         proc_release(entry);
365     }
366 
367     PROC_DEBUG(" %s %d >> %s\n", __func__, __LINE__, dentry->pathname);
368 
369     return vnode;
370 }
371 
dfs_procfs_create_vnode(struct dfs_dentry * dentry,int type,mode_t mode)372 static struct dfs_vnode *dfs_procfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
373 {
374     return RT_NULL;
375 }
376 
dfs_procfs_free_vnode(struct dfs_vnode * vnode)377 static int dfs_procfs_free_vnode(struct dfs_vnode *vnode)
378 {
379     return 0;
380 }
381 
382 static const struct dfs_file_ops _procfs_fops =
383 {
384     .open = dfs_procfs_open,
385     .close = dfs_procfs_close,
386     .lseek = generic_dfs_lseek,
387     .read = dfs_procfs_read,
388     .write = dfs_procfs_write,
389     .ioctl = dfs_procfs_ioctl,
390     .getdents = dfs_procfs_getdents,
391     .poll = dfs_procfs_poll,
392     .flush = dfs_procfs_flush,
393 };
394 
395 static const struct dfs_filesystem_ops _procfs_ops =
396 {
397     .name = "procfs",
398 
399     .default_fops = &_procfs_fops,
400 
401     .mount = dfs_procfs_mount,
402     .umount = dfs_procfs_umount,
403     .readlink   = dfs_procfs_readlink,
404     .unlink = dfs_procfs_unlink,
405     .stat = dfs_procfs_stat,
406     .statfs = dfs_procfs_statfs,
407     .lookup = dfs_procfs_lookup,
408     .create_vnode = dfs_procfs_create_vnode,
409     .free_vnode = dfs_procfs_free_vnode,
410 };
411 
412 static struct dfs_filesystem_type _procfs =
413 {
414     .fs_ops = &_procfs_ops,
415 };
416 
dfs_procfs_init(void)417 int dfs_procfs_init(void)
418 {
419     /* register procfs file system */
420     dfs_register(&_procfs);
421 
422     return 0;
423 }
424 INIT_COMPONENT_EXPORT(dfs_procfs_init);
425 
proc_read_data(struct dfs_file * file,void * buf,size_t count,off_t * pos)426 int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos)
427 {
428     if (file->fpos >= file->vnode->size)
429     {
430         return 0;
431     }
432 
433     if (file->data)
434     {
435         count = file->vnode->size - file->fpos >= count ? count : file->vnode->size - file->fpos;
436         rt_strncpy(buf, file->data + file->fpos, count);
437 
438         file->fpos += count;
439         *pos = file->fpos;
440     }
441     else
442     {
443         return 0;
444     }
445 
446     return count;
447 }
448