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