rtt更新
This commit is contained in:
@@ -162,20 +162,32 @@ endif
|
||||
bool "Using devfs for device objects"
|
||||
default y
|
||||
|
||||
config RT_USING_DFS_ROMFS
|
||||
if RT_USING_DFS_V1
|
||||
config RT_USING_DFS_ISO9660
|
||||
bool "Using ISO9660 filesystem"
|
||||
depends on RT_USING_MEMHEAP
|
||||
default n
|
||||
endif
|
||||
|
||||
menuconfig RT_USING_DFS_ROMFS
|
||||
bool "Enable ReadOnly file system on flash"
|
||||
default n
|
||||
|
||||
config RT_USING_DFS_ROMFS_USER_ROOT
|
||||
bool "Use user's romfs root"
|
||||
depends on RT_USING_DFS_ROMFS
|
||||
default n
|
||||
if RT_USING_DFS_ROMFS
|
||||
config RT_USING_DFS_ROMFS_USER_ROOT
|
||||
bool "Use user's romfs root"
|
||||
depends on RT_USING_DFS_V1
|
||||
default n
|
||||
endif
|
||||
|
||||
if RT_USING_SMART
|
||||
config RT_USING_DFS_PTYFS
|
||||
bool "Using Pseudo-Teletype Filesystem (UNIX98 PTY)"
|
||||
depends on RT_USING_DFS_DEVFS
|
||||
default y
|
||||
config RT_USING_DFS_PROCFS
|
||||
bool "Enable proc file system"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_DFS_CROMFS
|
||||
|
@@ -1,4 +1,6 @@
|
||||
from building import *
|
||||
from gcc import *
|
||||
import rtconfig
|
||||
import os
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
@@ -6,6 +8,7 @@ src = []
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + "/include"]
|
||||
group = []
|
||||
LOCAL_CFLAGS = ''
|
||||
|
||||
if GetDepend('RT_USING_DFS') and not GetDepend('RT_USING_DFS_V2'):
|
||||
src = ['src/dfs.c', 'src/dfs_file.c', 'src/dfs_fs.c']
|
||||
@@ -13,7 +16,12 @@ if GetDepend('RT_USING_DFS') and not GetDepend('RT_USING_DFS_V2'):
|
||||
if GetDepend('DFS_USING_POSIX'):
|
||||
src += ['src/dfs_posix.c']
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS'], CPPPATH = CPPPATH)
|
||||
if rtconfig.PLATFORM in GetGCCLikePLATFORM():
|
||||
LOCAL_CFLAGS += ' -std=c99'
|
||||
elif rtconfig.PLATFORM in ['armcc']:
|
||||
LOCAL_CFLAGS += ' --c99'
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS'], CPPPATH = CPPPATH, LOCAL_CFLAGS = LOCAL_CFLAGS)
|
||||
|
||||
# search in the file system implementation
|
||||
list = os.listdir(cwd)
|
||||
|
@@ -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_ISO9660'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtservice.h>
|
||||
|
||||
#define DBG_TAG "dfs.iso9660"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "dfs_iso9660.h"
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
#include <posix/string.h>
|
||||
#include <drivers/misc.h>
|
||||
#include <drivers/byteorder.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#define ISO9660_FSTYPE_DIR 0040000
|
||||
#define ISO9660_FSTYPE_REG 0100000
|
||||
#define ISO9660_FSTYPE_SYMLINK 0120000
|
||||
#define ISO9660_FSTYPE_MASK 0170000
|
||||
|
||||
#define ISO9660_BLKSZ 2048
|
||||
|
||||
#define ISO9660_VOLDESC_BOOT 0
|
||||
#define ISO9660_VOLDESC_PRIMARY 1
|
||||
#define ISO9660_VOLDESC_SUPP 2
|
||||
#define ISO9660_VOLDESC_PART 3
|
||||
#define ISO9660_VOLDESC_END 255
|
||||
|
||||
rt_packed(struct iso9660_voldesc
|
||||
{
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t magic[5];
|
||||
rt_uint8_t version;
|
||||
});
|
||||
|
||||
rt_packed(struct iso9660_date2
|
||||
{
|
||||
rt_uint8_t year;
|
||||
rt_uint8_t month;
|
||||
rt_uint8_t day;
|
||||
rt_uint8_t hour;
|
||||
rt_uint8_t minute;
|
||||
rt_uint8_t second;
|
||||
rt_uint8_t offset;
|
||||
});
|
||||
|
||||
/* Directory entry */
|
||||
rt_packed(struct iso9660_dir
|
||||
{
|
||||
rt_uint8_t len;
|
||||
rt_uint8_t ext_sectors;
|
||||
rt_le32_t first_sector;
|
||||
rt_le32_t first_sector_be;
|
||||
rt_le32_t size;
|
||||
rt_le32_t size_be;
|
||||
struct iso9660_date2 mtime;
|
||||
#define FLAG_TYPE_PLAIN 0
|
||||
#define FLAG_TYPE_DIR 2
|
||||
#define FLAG_TYPE 3
|
||||
#define FLAG_MORE_EXTENTS 0x80
|
||||
rt_uint8_t flags;
|
||||
rt_uint8_t file_unit_size;
|
||||
rt_uint8_t interleave_gap_size;
|
||||
rt_le16_t vol_seq_num;
|
||||
rt_le16_t vol_seq_num_be;
|
||||
#define MAX_NAMELEN 255
|
||||
rt_uint8_t namelen;
|
||||
char name[0];
|
||||
});
|
||||
|
||||
rt_packed(struct iso9660_date
|
||||
{
|
||||
rt_uint8_t year[4];
|
||||
rt_uint8_t month[2];
|
||||
rt_uint8_t day[2];
|
||||
rt_uint8_t hour[2];
|
||||
rt_uint8_t minute[2];
|
||||
rt_uint8_t second[2];
|
||||
rt_uint8_t hundredth[2];
|
||||
rt_uint8_t offset;
|
||||
});
|
||||
|
||||
/* Common volume descriptor */
|
||||
rt_packed(struct iso9660_common_voldesc
|
||||
{
|
||||
struct iso9660_voldesc voldesc;
|
||||
rt_uint8_t sysname[33];
|
||||
rt_uint8_t volname[32];
|
||||
rt_uint8_t unused2[8];
|
||||
rt_le32_t vol_space_size_le;
|
||||
rt_le32_t vol_space_size_be;
|
||||
rt_uint8_t escape[32];
|
||||
rt_le16_t vol_set_size_le;
|
||||
rt_le16_t vol_set_size_be;
|
||||
rt_le16_t vol_seq_num_le;
|
||||
rt_le16_t vol_seq_num_be;
|
||||
rt_le16_t logical_block_size_le;
|
||||
rt_le16_t logical_block_size_be;
|
||||
rt_le32_t path_table_size;
|
||||
rt_le32_t path_table_size_be;
|
||||
rt_le32_t path_table;
|
||||
rt_le32_t path_table_be;
|
||||
rt_uint8_t unused3[8];
|
||||
struct iso9660_dir rootdir;
|
||||
rt_uint8_t unused4[624];
|
||||
struct iso9660_date created;
|
||||
struct iso9660_date modified;
|
||||
rt_uint8_t unused5[0 /* 1201 */];
|
||||
});
|
||||
|
||||
struct iso9660
|
||||
{
|
||||
struct rt_device *dev;
|
||||
|
||||
rt_uint8_t joliet;
|
||||
rt_uint8_t swap[ISO9660_BLKSZ];
|
||||
|
||||
struct iso9660_common_voldesc primary, supp;
|
||||
};
|
||||
|
||||
struct iso9660_fd
|
||||
{
|
||||
struct iso9660 *iso;
|
||||
|
||||
struct iso9660_dir dirent;
|
||||
};
|
||||
|
||||
struct iso9660_iterate
|
||||
{
|
||||
struct iso9660_fd *fd;
|
||||
|
||||
int i, index, count;
|
||||
struct dirent *dirp;
|
||||
};
|
||||
|
||||
static void iso9660_convert_string(char *dest, rt_uint16_t *src, int len)
|
||||
{
|
||||
/* UTF16 to ASCII */
|
||||
len >>= 1;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
rt_uint16_t utf16 = rt_be16_to_cpu(*src++);
|
||||
|
||||
if (utf16 < 0x80)
|
||||
{
|
||||
*dest++ = (rt_uint8_t)utf16;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest++ = '?';
|
||||
}
|
||||
}
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
static void iso9660_convert_lower(char *dest, rt_uint8_t *src, int len)
|
||||
{
|
||||
for (int i = 0; i < len; ++i, ++src)
|
||||
{
|
||||
if (*src >= 'A' && *src <= 'Z')
|
||||
{
|
||||
*dest++ = *src - ('A' - 'a');
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest++ = *src;
|
||||
}
|
||||
}
|
||||
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
static time_t iso9660_convert_unixtime(struct iso9660_date *date)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
tm.tm_sec = (date->second[0] - '0') * 10 + (date->second[1] - '0');
|
||||
tm.tm_min = (date->minute[0] - '0') * 10 + (date->minute[1] - '0');
|
||||
tm.tm_hour = (date->hour[0] - '0') * 10 + (date->hour[1] - '0');
|
||||
tm.tm_mday = (date->day[0] - '0') * 10 + (date->day[1] - '0');
|
||||
tm.tm_mon = (date->month[0] - '0') * 10 + (date->month[1] - '0');
|
||||
tm.tm_year = (date->year[0] - '0') * 1000 + (date->year[1] - '0') * 100 +
|
||||
(date->year[2] - '0') * 10 + (date->year[3] - '0');
|
||||
tm.tm_wday = 0;
|
||||
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
||||
static time_t iso9660_convert_unixtime2(struct iso9660_date2 *date)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
tm.tm_sec = date->second;
|
||||
tm.tm_min = date->minute;
|
||||
tm.tm_hour = date->hour;
|
||||
tm.tm_mday = date->day;
|
||||
tm.tm_mon = date->month;
|
||||
tm.tm_year = date->year + 1900;
|
||||
tm.tm_wday = 0;
|
||||
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
||||
static struct iso9660_fd *iso9660_lookup(struct iso9660 *iso, const char *path,
|
||||
struct iso9660_iterate *it)
|
||||
{
|
||||
rt_uint32_t lba;
|
||||
rt_size_t sz, len, namelen;
|
||||
char sname[MAX_NAMELEN];
|
||||
struct iso9660_fd *fd;
|
||||
struct iso9660_dir *dirent;
|
||||
|
||||
if (it)
|
||||
{
|
||||
fd = it->fd;
|
||||
iso = fd->iso;
|
||||
dirent = &fd->dirent;
|
||||
|
||||
/* No next entry, always goon */
|
||||
len = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(fd = rt_malloc(sizeof(*fd))))
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
fd->iso = iso;
|
||||
dirent = iso->joliet ? &iso->supp.rootdir : &iso->primary.rootdir;
|
||||
|
||||
if (!rt_strcmp(path, "/"))
|
||||
{
|
||||
rt_memcpy(&fd->dirent, dirent, sizeof(*dirent));
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Skip the first '/' */
|
||||
++path;
|
||||
len = strchrnul(path, '/') - path;
|
||||
}
|
||||
|
||||
lba = rt_le32_to_cpu(dirent->first_sector);
|
||||
if (rt_device_read(iso->dev, lba, iso->swap, 1) <= 0)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
dirent = (void *)iso->swap;
|
||||
sz = 0;
|
||||
|
||||
do {
|
||||
/* Ignore "." and ".." */
|
||||
do {
|
||||
rt_uint32_t dlen = rt_le32_to_cpu(dirent->len);
|
||||
|
||||
dirent = (void *)dirent + dlen;
|
||||
sz += dlen;
|
||||
|
||||
if (ISO9660_BLKSZ - sz < sizeof(*dirent))
|
||||
{
|
||||
/* Sector end, goto the next sector */
|
||||
if (rt_device_read(iso->dev, ++lba, iso->swap, 1) <= 0)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
dirent = (void *)iso->swap;
|
||||
sz = 0;
|
||||
}
|
||||
|
||||
if (rt_le32_to_cpu(dirent->first_sector) == 0)
|
||||
{
|
||||
/* Is end, no found. */
|
||||
goto _fail;
|
||||
}
|
||||
} while (dirent->name[0] >> 1 == 0 && rt_le32_to_cpu(dirent->namelen) == 1);
|
||||
|
||||
namelen = rt_le32_to_cpu(dirent->namelen);
|
||||
|
||||
if (iso->joliet)
|
||||
{
|
||||
iso9660_convert_string(sname, (rt_uint16_t *)dirent->name, namelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(rt_le32_to_cpu(dirent->flags) & FLAG_TYPE_DIR))
|
||||
{
|
||||
/* Remove ";1" */
|
||||
namelen -= 2;
|
||||
}
|
||||
|
||||
iso9660_convert_lower(sname, (rt_uint8_t *)dirent->name, namelen);
|
||||
}
|
||||
|
||||
if (it)
|
||||
{
|
||||
if (it->i < it->index)
|
||||
{
|
||||
goto _next;
|
||||
}
|
||||
|
||||
if ((rt_le32_to_cpu(dirent->flags) & FLAG_TYPE) == FLAG_TYPE_DIR)
|
||||
{
|
||||
it->dirp->d_type = DT_DIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->dirp->d_type = DT_REG;
|
||||
}
|
||||
|
||||
it->dirp->d_namlen = namelen;
|
||||
rt_strncpy(it->dirp->d_name, sname, namelen);
|
||||
it->dirp->d_name[namelen] = '\0';
|
||||
it->dirp->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
|
||||
++it->dirp;
|
||||
|
||||
_next:
|
||||
++it->i;
|
||||
|
||||
if (it->i - it->index >= it->count)
|
||||
{
|
||||
/* Iterate end */
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* No next entry */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rt_strncmp(sname, path, len))
|
||||
{
|
||||
/* The end of path, found ok */
|
||||
if (!path[len])
|
||||
{
|
||||
rt_memcpy(&fd->dirent, dirent, sizeof(*dirent));
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
lba = rt_le32_to_cpu(dirent->first_sector);
|
||||
if (rt_device_read(iso->dev, lba, iso->swap, 1) <= 0)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
dirent = (void *)iso->swap;
|
||||
sz = 0;
|
||||
|
||||
path += len + 1;
|
||||
len = strchrnul(path, '/') - path;
|
||||
}
|
||||
} while (len);
|
||||
|
||||
_fail:
|
||||
if (!it)
|
||||
{
|
||||
rt_free(fd);
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_open(struct dfs_file *fd)
|
||||
{
|
||||
struct iso9660 *iso = fd->vnode->fs->data;
|
||||
|
||||
fd->vnode->data = iso9660_lookup(iso, fd->vnode->path, RT_NULL);
|
||||
|
||||
return fd->vnode->data ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_close(struct dfs_file *fd)
|
||||
{
|
||||
struct iso9660_fd *iso_fd = fd->vnode->data;
|
||||
|
||||
rt_free(iso_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_read(struct dfs_file *fd, void *buf, size_t count)
|
||||
{
|
||||
rt_uint32_t pos;
|
||||
void *buf_ptr;
|
||||
ssize_t read_blk, toread_blk;
|
||||
size_t rcount = 0, remain, size;
|
||||
struct iso9660_fd *iso_fd = fd->vnode->data;
|
||||
struct iso9660 *iso = iso_fd->iso;
|
||||
|
||||
if (fd->pos + count > rt_le32_to_cpu(iso_fd->dirent.size))
|
||||
{
|
||||
count = rt_le32_to_cpu(iso_fd->dirent.size) - fd->pos;
|
||||
}
|
||||
pos = rt_le32_to_cpu(iso_fd->dirent.first_sector);
|
||||
|
||||
/* Align to a sector */
|
||||
if (fd->pos)
|
||||
{
|
||||
pos += fd->pos / ISO9660_BLKSZ;
|
||||
remain = fd->pos & (ISO9660_BLKSZ - 1);
|
||||
|
||||
if (rt_device_read(iso->dev, pos, iso->swap, 1) <= 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
size = rt_min_t(size_t, ISO9660_BLKSZ - remain, count);
|
||||
rt_memcpy(buf, &iso->swap[remain], size);
|
||||
rcount += size;
|
||||
count -= size;
|
||||
buf += size;
|
||||
pos += 1;
|
||||
fd->pos += size;
|
||||
|
||||
if (!count)
|
||||
{
|
||||
goto _end;
|
||||
}
|
||||
}
|
||||
|
||||
remain = count & (ISO9660_BLKSZ - 1);
|
||||
count = rt_max_t(size_t, count / ISO9660_BLKSZ, 1);
|
||||
|
||||
while ((ssize_t)count > 0)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
buf_ptr = iso->swap;
|
||||
toread_blk = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf_ptr = buf;
|
||||
toread_blk = count;
|
||||
}
|
||||
|
||||
read_blk = rt_device_read(iso->dev, pos, buf_ptr, toread_blk);
|
||||
|
||||
if (read_blk <= 0)
|
||||
{
|
||||
return (int)read_blk;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
size = remain;
|
||||
rt_memcpy(buf, iso->swap, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = read_blk * ISO9660_BLKSZ;
|
||||
}
|
||||
|
||||
rcount += size;
|
||||
count -= read_blk;
|
||||
buf += size;
|
||||
pos += read_blk;
|
||||
fd->pos += size;
|
||||
}
|
||||
|
||||
_end:
|
||||
return rcount;
|
||||
}
|
||||
|
||||
static off_t dfs_iso9660_lseek(struct dfs_file *fd, off_t offset)
|
||||
{
|
||||
int ret = -EIO;
|
||||
|
||||
if (offset <= fd->vnode->size)
|
||||
{
|
||||
fd->pos = offset;
|
||||
ret = fd->pos;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_getdents(struct dfs_file *fd, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
struct iso9660_iterate it;
|
||||
struct iso9660_fd *iso_fd = fd->vnode->data;
|
||||
|
||||
count = (count / sizeof(struct dirent));
|
||||
|
||||
if (!count)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
it.fd = iso_fd;
|
||||
it.i = 0;
|
||||
it.index = fd->pos;
|
||||
it.count = count;
|
||||
it.dirp = dirp;
|
||||
|
||||
iso9660_lookup(RT_NULL, RT_NULL, &it);
|
||||
|
||||
count = it.i - it.index;
|
||||
if (count > 0)
|
||||
{
|
||||
fd->pos += count;
|
||||
}
|
||||
|
||||
count *= sizeof(struct dirent);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _iso9660_fops =
|
||||
{
|
||||
.open = dfs_iso9660_open,
|
||||
.close = dfs_iso9660_close,
|
||||
.read = dfs_iso9660_read,
|
||||
.lseek = dfs_iso9660_lseek,
|
||||
.getdents = dfs_iso9660_getdents,
|
||||
};
|
||||
|
||||
static int dfs_iso9660_mount(struct dfs_filesystem *fs,
|
||||
unsigned long rwflag, const void *data)
|
||||
{
|
||||
int err;
|
||||
struct iso9660 *iso;
|
||||
struct iso9660_voldesc *voldesc;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
|
||||
if (!(iso = rt_malloc(sizeof(*iso))))
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
iso->dev = fs->dev_id;
|
||||
rt_device_control(iso->dev, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
|
||||
|
||||
if (geometry.bytes_per_sector != ISO9660_BLKSZ)
|
||||
{
|
||||
LOG_E("%s: Logical block size = %d is not supported",
|
||||
iso->dev->parent.name, geometry.bytes_per_sector);
|
||||
|
||||
err = -EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
iso->primary.rootdir.first_sector = 0;
|
||||
iso->supp.rootdir.first_sector = 0;
|
||||
|
||||
/* LBA 0-15 is the bootloader's information */
|
||||
for (int lba = 16; ; ++lba)
|
||||
{
|
||||
if (rt_device_read(iso->dev, lba, &iso->swap, 1) <= 0)
|
||||
{
|
||||
err = -EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
voldesc = (void *)iso->swap;
|
||||
|
||||
if (rt_strncmp((char *)voldesc->magic, "CD001", 5))
|
||||
{
|
||||
LOG_E("%s: Invalid magic \"%s\"", voldesc->magic);
|
||||
|
||||
err = -EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if (voldesc->type == ISO9660_VOLDESC_BOOT)
|
||||
{
|
||||
LOG_D("System Name: %s", ((struct iso9660_common_voldesc *)voldesc)->sysname);
|
||||
LOG_D("Volume Name: %s", ((struct iso9660_common_voldesc *)voldesc)->volname);
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_PRIMARY)
|
||||
{
|
||||
iso->joliet = 0;
|
||||
rt_memcpy(&iso->primary, &iso->swap, sizeof(iso->primary));
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_SUPP)
|
||||
{
|
||||
rt_memcpy(&iso->supp, &iso->swap, sizeof(iso->supp));
|
||||
|
||||
if (iso->supp.escape[0] == 0x25 && iso->supp.escape[1] == 0x2f)
|
||||
{
|
||||
if (iso->supp.escape[2] == 0x40)
|
||||
{
|
||||
iso->joliet = 1;
|
||||
}
|
||||
else if (iso->supp.escape[2] == 0x43)
|
||||
{
|
||||
iso->joliet = 2;
|
||||
}
|
||||
else if (iso->supp.escape[2] == 0x45)
|
||||
{
|
||||
iso->joliet = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_PART)
|
||||
{
|
||||
LOG_D("System Name: %s", ((struct iso9660_common_voldesc *)voldesc)->sysname);
|
||||
LOG_D("Volume Name: %s", ((struct iso9660_common_voldesc *)voldesc)->volname);
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_END)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iso->primary.rootdir.first_sector || !iso->supp.rootdir.first_sector)
|
||||
{
|
||||
LOG_E("No primary or secondary partition found");
|
||||
|
||||
err = -EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
fs->data = iso;
|
||||
|
||||
return 0;
|
||||
|
||||
_fail:
|
||||
rt_free(iso);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_unmount(struct dfs_filesystem *fs)
|
||||
{
|
||||
struct iso9660 *iso = fs->data;
|
||||
|
||||
rt_free(iso);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_stat(struct dfs_filesystem *fs,
|
||||
const char *filename, struct stat *st)
|
||||
{
|
||||
struct iso9660 *iso = fs->data;
|
||||
struct iso9660_fd *fd = iso9660_lookup(iso, filename, RT_NULL);
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
st->st_dev = 0;
|
||||
st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
|
||||
S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
|
||||
if ((fd->dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
|
||||
{
|
||||
st->st_mode &= ~S_IFREG;
|
||||
st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
}
|
||||
|
||||
st->st_atime = iso9660_convert_unixtime(iso->joliet ?
|
||||
&iso->supp.created : &iso->primary.created);
|
||||
st->st_mtime = iso9660_convert_unixtime2(&fd->dirent.mtime);
|
||||
st->st_size = rt_le32_to_cpu(fd->dirent.size);
|
||||
|
||||
rt_free(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_filesystem_ops _iso9660 =
|
||||
{
|
||||
.name = "iso9660",
|
||||
.flags = DFS_FS_FLAG_DEFAULT,
|
||||
.fops = &_iso9660_fops,
|
||||
|
||||
.mount = dfs_iso9660_mount,
|
||||
.unmount = dfs_iso9660_unmount,
|
||||
|
||||
.stat = dfs_iso9660_stat,
|
||||
};
|
||||
|
||||
int dfs_iso9660_init(void)
|
||||
{
|
||||
/* register iso9660 file system */
|
||||
return dfs_register(&_iso9660);
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_iso9660_init);
|
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __DFS_ISO9660_H__
|
||||
#define __DFS_ISO9660_H__
|
||||
|
||||
int dfs_iso9660_init(void);
|
||||
|
||||
#endif /* __DFS_ISO9660_H__ */
|
@@ -92,7 +92,7 @@ struct ramfs_dirent *dfs_ramfs_lookup(struct dfs_ramfs *ramfs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
ssize_t dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
{
|
||||
rt_size_t length;
|
||||
struct ramfs_dirent *dirent;
|
||||
@@ -114,7 +114,7 @@ int dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
return length;
|
||||
}
|
||||
|
||||
int dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
ssize_t dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
{
|
||||
struct ramfs_dirent *dirent;
|
||||
struct dfs_ramfs *ramfs;
|
||||
@@ -151,7 +151,7 @@ int dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
return count;
|
||||
}
|
||||
|
||||
int dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
|
||||
off_t dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
|
||||
{
|
||||
if (offset <= (off_t)file->vnode->size)
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -107,7 +107,8 @@ int dfs_init(void)
|
||||
INIT_PREV_EXPORT(dfs_init);
|
||||
|
||||
/**
|
||||
* this function will lock device file system.
|
||||
* @brief this function will lock device file system.
|
||||
* this lock (fslock) is used for protecting filesystem_operation_table and filesystem_table.
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
@@ -126,6 +127,12 @@ void dfs_lock(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief this function will lock file descriptors.
|
||||
* this lock (fdlock) is used for protecting fd table (_fdtab).
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
void dfs_file_lock(void)
|
||||
{
|
||||
rt_err_t result = -RT_EBUSY;
|
||||
@@ -142,7 +149,7 @@ void dfs_file_lock(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will lock device file system.
|
||||
* @brief this function will unlock device file system.
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
@@ -151,33 +158,56 @@ void dfs_unlock(void)
|
||||
rt_mutex_release(&fslock);
|
||||
}
|
||||
|
||||
#ifdef DFS_USING_POSIX
|
||||
|
||||
/**
|
||||
* @brief this function will unlock fd table.
|
||||
*/
|
||||
void dfs_file_unlock(void)
|
||||
{
|
||||
rt_mutex_release(&fdlock);
|
||||
}
|
||||
|
||||
#ifdef DFS_USING_POSIX
|
||||
/**
|
||||
* @brief Expand the file descriptor table to accommodate a specific file descriptor.
|
||||
*
|
||||
* This function ensures that the file descriptor table in the given `dfs_fdtable` structure
|
||||
* has sufficient capacity to include the specified file descriptor `fd`. If the table
|
||||
* needs to be expanded, it reallocates memory and initializes new slots to `NULL`.
|
||||
*
|
||||
* @param fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
|
||||
* @param fd The file descriptor that the table must accommodate.
|
||||
* @return int
|
||||
* - The input file descriptor `fd` if it is within the current or newly expanded table's capacity.
|
||||
* - `-1` if the requested file descriptor exceeds `DFS_FD_MAX` or memory allocation fails.
|
||||
*/
|
||||
static int fd_slot_expand(struct dfs_fdtable *fdt, int fd)
|
||||
{
|
||||
int nr;
|
||||
int index;
|
||||
struct dfs_file **fds = NULL;
|
||||
|
||||
/* If the file descriptor is already within the current capacity, no expansion is needed.*/
|
||||
if (fd < fdt->maxfd)
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* If the file descriptor exceeds the maximum allowable limit, return an error.*/
|
||||
if (fd >= DFS_FD_MAX)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate the new capacity, rounding up to the nearest multiple of 4.*/
|
||||
nr = ((fd + 4) & ~3);
|
||||
|
||||
/* Ensure the new capacity does not exceed the maximum limit.*/
|
||||
if (nr > DFS_FD_MAX)
|
||||
{
|
||||
nr = DFS_FD_MAX;
|
||||
}
|
||||
|
||||
/* Attempt to reallocate the file descriptor table to the new capacity.*/
|
||||
fds = (struct dfs_file **)rt_realloc(fdt->fds, nr * sizeof(struct dfs_file *));
|
||||
if (!fds)
|
||||
{
|
||||
@@ -189,12 +219,23 @@ static int fd_slot_expand(struct dfs_fdtable *fdt, int fd)
|
||||
{
|
||||
fds[index] = NULL;
|
||||
}
|
||||
|
||||
/* Update the file descriptor table and its capacity.*/
|
||||
fdt->fds = fds;
|
||||
fdt->maxfd = nr;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a file descriptor slot starting from a specified index.
|
||||
*
|
||||
* @param fdt fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
|
||||
* @param startfd The starting index for the search for an empty slot.
|
||||
* @return int
|
||||
* - The index of the first available slot if successful.
|
||||
* - `-1` if no slot is available or if table expansion fails
|
||||
*/
|
||||
static int fd_slot_alloc(struct dfs_fdtable *fdt, int startfd)
|
||||
{
|
||||
int idx;
|
||||
@@ -219,6 +260,17 @@ static int fd_slot_alloc(struct dfs_fdtable *fdt, int startfd)
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a new file descriptor and associate it with a newly allocated `struct dfs_file`.
|
||||
*
|
||||
* @param fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
|
||||
* @param startfd The starting index for searching an available file descriptor slot.
|
||||
*
|
||||
* @return
|
||||
* - The index of the allocated file descriptor if successful.
|
||||
* - `-1` if no slot is available or memory allocation fails.
|
||||
*/
|
||||
static int fd_alloc(struct dfs_fdtable *fdt, int startfd)
|
||||
{
|
||||
int idx;
|
||||
@@ -323,7 +375,11 @@ struct dfs_file *fd_get(int fd)
|
||||
/**
|
||||
* @ingroup Fd
|
||||
*
|
||||
* This function will put the file descriptor.
|
||||
* @brief This function will release the file descriptor.
|
||||
*
|
||||
* This function releases a file descriptor slot in the file descriptor table, decrements reference
|
||||
* counts, and cleans up resources associated with the `dfs_file` and `dfs_vnode` structures when applicable.
|
||||
*
|
||||
*/
|
||||
void fdt_fd_release(struct dfs_fdtable* fdt, int fd)
|
||||
{
|
||||
@@ -378,6 +434,20 @@ void fd_release(int fd)
|
||||
fdt_fd_release(fdt, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Duplicates a file descriptor.
|
||||
*
|
||||
* This function duplicates an existing file descriptor (`oldfd`) and returns
|
||||
* a new file descriptor that refers to the same underlying file object.
|
||||
*
|
||||
* @param oldfd The file descriptor to duplicate. It must be a valid file
|
||||
* descriptor within the range of allocated descriptors.
|
||||
*
|
||||
* @return The new file descriptor if successful, or a negative value
|
||||
* (e.g., -1) if an error occurs.
|
||||
*
|
||||
* @see sys_dup2()
|
||||
*/
|
||||
rt_err_t sys_dup(int oldfd)
|
||||
{
|
||||
int newfd = -1;
|
||||
@@ -470,6 +540,23 @@ int fd_is_open(const char *pathname)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Duplicates a file descriptor to a specified file descriptor.
|
||||
*
|
||||
* This function duplicates an existing file descriptor (`oldfd`) and assigns it
|
||||
* to the specified file descriptor (`newfd`).
|
||||
*
|
||||
* @param oldfd The file descriptor to duplicate. It must be a valid and open file
|
||||
* descriptor within the range of allocated descriptors.
|
||||
* @param newfd The target file descriptor. If `newfd` is already in use, it will
|
||||
* be closed before duplication. If `newfd` exceeds the current file
|
||||
* descriptor table size, the table will be expanded to accommodate it.
|
||||
*
|
||||
* @return The value of `newfd` on success, or a negative value (e.g., -1) if an
|
||||
* error occurs.
|
||||
*
|
||||
* @see sys_dup()
|
||||
*/
|
||||
rt_err_t sys_dup2(int oldfd, int newfd)
|
||||
{
|
||||
struct dfs_fdtable *fdt = NULL;
|
||||
@@ -550,6 +637,10 @@ static int fd_get_fd_index_form_fdt(struct dfs_fdtable *fdt, struct dfs_file *fi
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get fd (index) by dfs file object.
|
||||
*
|
||||
*/
|
||||
int fd_get_fd_index(struct dfs_file *file)
|
||||
{
|
||||
struct dfs_fdtable *fdt;
|
||||
@@ -558,6 +649,21 @@ int fd_get_fd_index(struct dfs_file *file)
|
||||
return fd_get_fd_index_form_fdt(fdt, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associates a file descriptor with a file object.
|
||||
*
|
||||
* This function associates a given file descriptor (`fd`) with a specified
|
||||
* file object (`file`) in the file descriptor table (`fdt`).
|
||||
*
|
||||
* @param fdt The file descriptor table to operate on. It must be a valid
|
||||
* and initialized `dfs_fdtable` structure.
|
||||
* @param fd The file descriptor to associate. It must be within the range
|
||||
* of allocated file descriptors and currently unoccupied.
|
||||
* @param file The file object to associate with the file descriptor. It must
|
||||
* be a valid and initialized `dfs_file` structure.
|
||||
*
|
||||
* @return The value of `fd` on success, or -1 if an error occurs.
|
||||
*/
|
||||
int fd_associate(struct dfs_fdtable *fdt, int fd, struct dfs_file *file)
|
||||
{
|
||||
int retfd = -1;
|
||||
@@ -591,6 +697,10 @@ exit:
|
||||
return retfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief initialize a dfs file object.
|
||||
*
|
||||
*/
|
||||
void fd_init(struct dfs_file *fd)
|
||||
{
|
||||
if (fd)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -18,10 +18,12 @@
|
||||
|
||||
#define DFS_VNODE_HASH_NR 128
|
||||
|
||||
/*dfs vnode manager, for saving and searching vnodes.*/
|
||||
struct dfs_vnode_mgr
|
||||
{
|
||||
struct rt_mutex lock;
|
||||
rt_list_t head[DFS_VNODE_HASH_NR];
|
||||
struct rt_mutex lock; /* mutex for protecting dfs vnode lists */
|
||||
rt_list_t head[DFS_VNODE_HASH_NR]; /* a group of dfs vnode lists, the dfs vnode is inserted to one of the lists
|
||||
according to path string's hash-value mod DFS_VNODE_HASH_NR. */
|
||||
};
|
||||
|
||||
static struct dfs_vnode_mgr dfs_fm;
|
||||
@@ -36,6 +38,10 @@ void dfs_fm_unlock(void)
|
||||
rt_mutex_release(&dfs_fm.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize dfs vnode manager structure, including a lock and hash tables for vnode.
|
||||
*
|
||||
*/
|
||||
void dfs_vnode_mgr_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -47,6 +53,23 @@ void dfs_vnode_mgr_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize a DFS vnode structure.
|
||||
*
|
||||
* @param vnode Pointer to the DFS vnode structure to be initialized.
|
||||
* The caller must ensure this is a valid, allocated structure.
|
||||
* @param type The type of the vnode, representing its role or category (e.g., regular file, directory).
|
||||
* @param fops Pointer to the file operations structure associated with this vnode.
|
||||
* This structure defines the behavior of the vnode for operations such as open, read, write, etc.
|
||||
* If `fops` is NULL, the vnode will have no associated file operations.
|
||||
*
|
||||
* @return 0 on success, or a negative error code on failure.
|
||||
*
|
||||
* @note The caller should ensure that:
|
||||
* - The `vnode` pointer is valid and properly allocated.
|
||||
* - The `fops` pointer (if not NULL) points to a valid `struct dfs_file_ops`
|
||||
* instance, where all necessary function pointers are properly set.
|
||||
*/
|
||||
int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops *fops)
|
||||
{
|
||||
if (vnode)
|
||||
@@ -64,7 +87,7 @@ int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops
|
||||
/* BKDR Hash Function */
|
||||
static unsigned int bkdr_hash(const char *str)
|
||||
{
|
||||
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
|
||||
unsigned int seed = 131; /* 31 131 1313 13131 131313 etc..*/
|
||||
unsigned int hash = 0;
|
||||
|
||||
while (*str)
|
||||
@@ -75,6 +98,22 @@ static unsigned int bkdr_hash(const char *str)
|
||||
return (hash % DFS_VNODE_HASH_NR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find a DFS vnode by its path.
|
||||
*
|
||||
* This function searches for a vnode in the vnode hash table using the specified path.
|
||||
* If found, it returns a pointer to the vnode and updates the hash head if required.
|
||||
*
|
||||
* @param path The file path to search for. This should be a valid null-terminated string.
|
||||
* @param hash_head Pointer to a location where the hash table head associated with the vnode
|
||||
* can be stored. This can be NULL if the hash head is not needed.
|
||||
*
|
||||
* @return Pointer to the DFS vnode if found, or NULL if no vnode matches the specified path.
|
||||
*
|
||||
* @note The caller must ensure that:
|
||||
* - The `path` pointer is valid and points to a properly null-terminated string.
|
||||
* - If `hash_head` is not NULL, it points to a valid location to store the hash head.
|
||||
*/
|
||||
static struct dfs_vnode *dfs_vnode_find(const char *path, rt_list_t **hash_head)
|
||||
{
|
||||
struct dfs_vnode *vnode = NULL;
|
||||
@@ -329,11 +368,12 @@ int dfs_file_close(struct dfs_file *fd)
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will perform a io control on a file descriptor.
|
||||
* this function will perform an io control on a file descriptor.
|
||||
*
|
||||
* @param fd the file descriptor.
|
||||
* @param cmd the command to send to file descriptor.
|
||||
* @param args the argument to send to file descriptor.
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
*
|
||||
* @return 0 on successful, -1 on failed.
|
||||
*/
|
||||
@@ -846,7 +886,7 @@ void cat(const char *filename)
|
||||
{
|
||||
buffer[length] = '\0';
|
||||
rt_device_t out_device = rt_console_get_device();
|
||||
rt_device_write(out_device, 0, (void *)buffer, sizeof(buffer));
|
||||
rt_device_write(out_device, 0, (void *)buffer, length);
|
||||
}
|
||||
} while (length > 0);
|
||||
rt_kprintf("\n");
|
||||
@@ -1026,14 +1066,14 @@ void copy(const char *src, const char *dst)
|
||||
flag |= FLAG_DST_IS_FILE;
|
||||
}
|
||||
|
||||
//2. check status
|
||||
/*2. check status*/
|
||||
if ((flag & FLAG_SRC_IS_DIR) && (flag & FLAG_DST_IS_FILE))
|
||||
{
|
||||
rt_kprintf("cp faild, cp dir to file is not permitted!\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
//3. do copy
|
||||
/*3. do copy*/
|
||||
if (flag & FLAG_SRC_IS_FILE)
|
||||
{
|
||||
if (flag & FLAG_DST_IS_DIR)
|
||||
@@ -1053,7 +1093,7 @@ void copy(const char *src, const char *dst)
|
||||
copyfile(src, dst);
|
||||
}
|
||||
}
|
||||
else //flag & FLAG_SRC_IS_DIR
|
||||
else /*flag & FLAG_SRC_IS_DIR*/
|
||||
{
|
||||
if (flag & FLAG_DST_IS_DIR)
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -322,8 +322,8 @@ int dfs_mount(const char *device_name,
|
||||
/* open device, but do not check the status of device */
|
||||
if (dev_id != NULL)
|
||||
{
|
||||
if (rt_device_open(fs->dev_id,
|
||||
RT_DEVICE_OFLAG_RDWR) != RT_EOK)
|
||||
if (rt_device_open(fs->dev_id, RT_DEVICE_OFLAG_RDWR) != RT_EOK &&
|
||||
rt_device_open(fs->dev_id, RT_DEVICE_OFLAG_RDONLY) != RT_EOK)
|
||||
{
|
||||
/* The underlying device has error, clear the entry. */
|
||||
dfs_lock();
|
||||
@@ -529,7 +529,8 @@ int dfs_mount_device(rt_device_t dev)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
if(dev == RT_NULL) {
|
||||
if(dev == RT_NULL)
|
||||
{
|
||||
rt_kprintf("the device is NULL to be mounted.\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
@@ -538,7 +539,8 @@ int dfs_mount_device(rt_device_t dev)
|
||||
{
|
||||
if (mount_table[index].path == NULL) break;
|
||||
|
||||
if(strcmp(mount_table[index].device_name, dev->parent.name) == 0) {
|
||||
if(strcmp(mount_table[index].device_name, dev->parent.name) == 0)
|
||||
{
|
||||
if (dfs_mount(mount_table[index].device_name,
|
||||
mount_table[index].path,
|
||||
mount_table[index].filesystemtype,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -28,7 +28,17 @@
|
||||
* return a file descriptor according specified flags.
|
||||
*
|
||||
* @param file the path name of file.
|
||||
* @param flags the file open flags.
|
||||
* @param flags the file open flags. Common values include:
|
||||
* - Access modes (mutually exclusive):
|
||||
* - `O_RDONLY`: Open for read-only access.
|
||||
* - `O_WRONLY`: Open for write-only access.
|
||||
* - `O_RDWR`: Open for both reading and writing.
|
||||
* - File status flags (can be combined with bitwise OR `|`):
|
||||
* - `O_CREAT`: Create the file if it does not exist. Requires a `mode` argument.
|
||||
* - `O_TRUNC`: Truncate the file to zero length if it already exists.
|
||||
* - `O_APPEND`: Append writes to the end of the file.
|
||||
* - `O_EXCL`: Ensure that `O_CREAT` creates the file exclusively.
|
||||
* - Other platform-specific flags
|
||||
*
|
||||
* @return the non-negative integer on successful open, others for failed.
|
||||
*/
|
||||
@@ -65,6 +75,22 @@ RTM_EXPORT(open);
|
||||
#ifndef AT_FDCWD
|
||||
#define AT_FDCWD (-100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Opens a file relative to a directory file descriptor.
|
||||
*
|
||||
* @param dirfd The file descriptor of the directory to base the relative path on.
|
||||
* @param pathname The path to the file to be opened, relative to the directory specified by `dirfd`.
|
||||
* Can be an absolute path (in which case `dirfd` is ignored).
|
||||
* @param flags File access and status flags (e.g., `O_RDONLY`, `O_WRONLY`, `O_CREAT`).
|
||||
*
|
||||
* @return On success, returns a new file descriptor for the opened file.
|
||||
* On failure, returns `-1` and sets `errno` to indicate the error.
|
||||
*
|
||||
* @note When using relative paths, ensure `dirfd` is a valid directory descriptor.
|
||||
* When `pathname` is absolute, the `dirfd` argument is ignored.
|
||||
*
|
||||
*/
|
||||
int openat(int dirfd, const char *path, int flag, ...)
|
||||
{
|
||||
struct dfs_file *d;
|
||||
@@ -241,14 +267,22 @@ ssize_t write(int fd, const void *buf, size_t len)
|
||||
RTM_EXPORT(write);
|
||||
|
||||
/**
|
||||
* this function is a POSIX compliant version, which will seek the offset for
|
||||
* this function is a POSIX compliant version, which will Reposition the file offset for
|
||||
* an open file descriptor.
|
||||
*
|
||||
* @param fd the file descriptor.
|
||||
* @param offset the offset to be seeked.
|
||||
* @param whence the directory of seek.
|
||||
* The `lseek` function sets the file offset for the file descriptor `fd`
|
||||
* to a new value, determined by the `offset` and `whence` parameters.
|
||||
* It can be used to seek to specific positions in a file for reading or writing.
|
||||
*
|
||||
* @return the current read/write position in the file, or -1 on failed.
|
||||
* @param fd the file descriptor.
|
||||
* @param offset The offset, in bytes, to set the file position.
|
||||
* The meaning of `offset` depends on the value of `whence`.
|
||||
* @param whence the directive of seek. It can be one of:
|
||||
* - `SEEK_SET`: Set the offset to `offset` bytes from the beginning of the file.
|
||||
* - `SEEK_CUR`: Set the offset to its current location plus `offset` bytes.
|
||||
* - `SEEK_END`: Set the offset to the size of the file plus `offset` bytes.
|
||||
*
|
||||
* @return the resulting read/write position in the file, or -1 on failed.
|
||||
*/
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
@@ -436,9 +470,15 @@ RTM_EXPORT(fsync);
|
||||
* control functions on devices.
|
||||
*
|
||||
* @param fildes the file description
|
||||
* @param cmd the specified command
|
||||
* @param cmd the specified command, Common values include:
|
||||
* - `F_DUPFD`: Duplicate a file descriptor.
|
||||
* - `F_GETFD`: Get the file descriptor flags.
|
||||
* - `F_SETFD`: Set the file descriptor flags.
|
||||
* - `F_GETFL`: Get the file status flags.
|
||||
* - `F_SETFL`: Set the file status flags.
|
||||
* @param ... represents the additional information that is needed by this
|
||||
* specific device to perform the requested function.
|
||||
* specific device to perform the requested function. For example:
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
*
|
||||
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
|
||||
* set to indicate the error.
|
||||
@@ -595,7 +635,7 @@ RTM_EXPORT(fstatfs);
|
||||
* this function is a POSIX compliant version, which will make a directory
|
||||
*
|
||||
* @param path the directory path to be made.
|
||||
* @param mode
|
||||
* @param mode The permission mode for the new directory (unused here, can be set to 0).
|
||||
*
|
||||
* @return 0 on successful, others on failed.
|
||||
*/
|
||||
|
@@ -786,18 +786,18 @@ static ssize_t dfs_cromfs_read(struct dfs_file *file, void *buf, size_t count, o
|
||||
rt_err_t result = RT_EOK;
|
||||
file_info *fi = NULL;
|
||||
cromfs_info *ci = NULL;
|
||||
uint32_t length = 0;
|
||||
ssize_t length = 0;
|
||||
|
||||
ci = (cromfs_info *)file->dentry->mnt->data;
|
||||
fi = (file_info *)file->vnode->data;
|
||||
|
||||
if (count < file->vnode->size - *pos)
|
||||
if ((off_t)count < (off_t)file->vnode->size - *pos)
|
||||
{
|
||||
length = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = file->vnode->size - *pos;
|
||||
length = (off_t)file->vnode->size - *pos;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
|
@@ -11,6 +11,9 @@
|
||||
#ifndef __DFS_CROMFS_H__
|
||||
#define __DFS_CROMFS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int dfs_cromfs_init(void);
|
||||
uint8_t *cromfs_get_partition_data(uint32_t *len);
|
||||
|
||||
#endif /*__DFS_CROMFS_H__*/
|
||||
|
@@ -77,6 +77,7 @@ static int dfs_devfs_open(struct dfs_file *file)
|
||||
}
|
||||
}
|
||||
}
|
||||
rt_free(device_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -113,6 +114,29 @@ static int dfs_devfs_close(struct dfs_file *file)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_ubase_t _get_unit_shift(rt_device_t device)
|
||||
{
|
||||
rt_ubase_t shift = 0;
|
||||
|
||||
/**
|
||||
* transfer unit size from POSIX RW(in bytes) to rt_device_R/W
|
||||
* (block size for blk device, otherwise in bytes).
|
||||
*/
|
||||
if (device->type == RT_Device_Class_Block)
|
||||
{
|
||||
struct rt_device_blk_geometry geometry = {0};
|
||||
|
||||
/* default to 512 */
|
||||
shift = 9;
|
||||
if (!rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry))
|
||||
{
|
||||
shift = __rt_ffs(geometry.block_size) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
static ssize_t dfs_devfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
ssize_t ret = -RT_EIO;
|
||||
@@ -135,9 +159,14 @@ static ssize_t dfs_devfs_read(struct dfs_file *file, void *buf, size_t count, of
|
||||
if (device->ops)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
/* read device data */
|
||||
ret = rt_device_read(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
rt_ubase_t shift = _get_unit_shift(device);
|
||||
|
||||
ret = rt_device_read(device, *pos, buf, count >> shift);
|
||||
if (ret > 0)
|
||||
{
|
||||
ret <<= shift;
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,9 +198,15 @@ static ssize_t dfs_devfs_write(struct dfs_file *file, const void *buf, size_t co
|
||||
if (device->ops)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
rt_ubase_t shift = _get_unit_shift(device);
|
||||
|
||||
/* read device data */
|
||||
ret = rt_device_write(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
ret = rt_device_write(device, *pos, buf, count >> shift);
|
||||
if (ret > 0)
|
||||
{
|
||||
ret <<= shift;
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +300,7 @@ static int dfs_devfs_flush(struct dfs_file *file)
|
||||
|
||||
static off_t dfs_devfs_lseek(struct dfs_file *file, off_t offset, int wherece)
|
||||
{
|
||||
off_t ret = 0;
|
||||
off_t ret = -EPERM;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
@@ -408,16 +443,16 @@ mode_t dfs_devfs_device_to_mode(struct rt_device *device)
|
||||
switch (device->type)
|
||||
{
|
||||
case RT_Device_Class_Char:
|
||||
mode = S_IFCHR | 0777;
|
||||
mode = S_IFCHR | 0666;
|
||||
break;
|
||||
case RT_Device_Class_Block:
|
||||
mode = S_IFBLK | 0777;
|
||||
mode = S_IFBLK | 0666;
|
||||
break;
|
||||
case RT_Device_Class_Pipe:
|
||||
mode = S_IFIFO | 0777;
|
||||
mode = S_IFIFO | 0666;
|
||||
break;
|
||||
default:
|
||||
mode = S_IFCHR | 0777;
|
||||
mode = S_IFCHR | 0666;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <dfs_vfs.h>
|
||||
#include <devfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -34,10 +35,9 @@ struct devtmpfs_file
|
||||
char name[DIRENT_NAME_MAX]; /* file name */
|
||||
|
||||
rt_uint32_t type; /* file type */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
struct dfs_vfs_node node; /* file node in the devtmpfs */
|
||||
|
||||
struct devtmpfs_sb *sb; /* superblock ptr */
|
||||
struct devtmpfs_sb *sb; /* superblock ptr */
|
||||
|
||||
rt_uint32_t mode;
|
||||
char *link;
|
||||
@@ -48,7 +48,6 @@ struct devtmpfs_sb
|
||||
rt_uint32_t magic; /* TMPFS_MAGIC */
|
||||
struct devtmpfs_file root; /* root dir */
|
||||
rt_size_t df_size; /* df size */
|
||||
rt_list_t sibling; /* sb sibling list */
|
||||
struct rt_spinlock lock; /* tmpfs lock */
|
||||
};
|
||||
|
||||
@@ -111,15 +110,13 @@ static int _get_subdir(const char *path, char *name)
|
||||
#if 0
|
||||
static int _free_subdir(struct devtmpfs_file *dfile)
|
||||
{
|
||||
struct devtmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct devtmpfs_file *file, *tmp;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
@@ -134,7 +131,7 @@ static int _free_subdir(struct devtmpfs_file *dfile)
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(file->sibling));
|
||||
dfs_vfs_remove_node(&file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
@@ -152,14 +149,12 @@ static int devtmpfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void
|
||||
{
|
||||
superblock->df_size = sizeof(struct devtmpfs_sb);
|
||||
superblock->magic = TMPFS_MAGIC;
|
||||
rt_list_init(&superblock->sibling);
|
||||
|
||||
superblock->root.name[0] = '/';
|
||||
superblock->root.sb = superblock;
|
||||
superblock->root.type = TMPFS_TYPE_DIR;
|
||||
superblock->root.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
dfs_vfs_init_node(&superblock->root.node);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
@@ -193,8 +188,7 @@ static struct devtmpfs_file *devtmpfs_file_lookup(struct devtmpfs_sb *superblock
|
||||
{
|
||||
const char *subpath, *curpath, *filename = RT_NULL;
|
||||
char subdir_name[DIRENT_NAME_MAX];
|
||||
struct devtmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
struct devtmpfs_file *file, *curfile, *tmp;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
@@ -222,9 +216,8 @@ find_subpath:
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
@@ -293,7 +286,9 @@ static int devtmpfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||
|
||||
static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
struct devtmpfs_file *d_file;
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct devtmpfs_file *d_file, *n_file = RT_NULL, *tmp;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(file);
|
||||
@@ -306,11 +301,6 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_
|
||||
d_file = devtmpfs_file_lookup(superblock, file->dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct devtmpfs_file *n_file;
|
||||
rt_list_t *list;
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
@@ -322,12 +312,10 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||
{
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
|
||||
d = dirp + count;
|
||||
if (n_file->type == TMPFS_TYPE_FILE)
|
||||
{
|
||||
@@ -378,8 +366,7 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
||||
|
||||
strncpy(l_file->name, linkpath, DIRENT_NAME_MAX - 1);
|
||||
|
||||
rt_list_init(&(l_file->subdirs));
|
||||
rt_list_init(&(l_file->sibling));
|
||||
dfs_vfs_init_node(&l_file->node);
|
||||
l_file->sb = superblock;
|
||||
l_file->type = TMPFS_TYPE_FILE;
|
||||
l_file->mode = p_file->mode;
|
||||
@@ -388,7 +375,7 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
||||
l_file->link = rt_strdup(target);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(l_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &l_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
}
|
||||
@@ -460,7 +447,7 @@ static int devtmpfs_unlink(struct dfs_dentry *dentry)
|
||||
}
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(d_file);
|
||||
@@ -537,8 +524,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
||||
|
||||
strncpy(d_file->name, file_name, DIRENT_NAME_MAX);
|
||||
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
dfs_vfs_init_node(&d_file->node);
|
||||
d_file->sb = superblock;
|
||||
|
||||
vnode->nlink = 1;
|
||||
@@ -563,7 +549,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
||||
d_file->mode = vnode->mode;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
|
||||
|
166
rt-thread/components/dfs/dfs_v2/filesystems/procfs/README.md
Normal file
166
rt-thread/components/dfs/dfs_v2/filesystems/procfs/README.md
Normal file
@@ -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”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
| parent | 指定创建目录的起始节点 |
|
||||
| fops | 文件操作接口配置 |
|
||||
| data | 私有数据 |
|
||||
|
||||
- proc_mkdir_mode
|
||||
|
||||
创建一个目录,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
| parent | 指定创建目录的起始节点 |
|
||||
|
||||
- proc_mkdir
|
||||
|
||||
创建一个目录,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
|
||||
- proc_create_data
|
||||
|
||||
创建一个文件,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
| parent | 指定创建文件的起始节点 |
|
||||
| fops | 文件操作接口配置 |
|
||||
| data | 私有数据 |
|
||||
|
||||
- proc_symlink
|
||||
|
||||
创建一个符号链接,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 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`
|
@@ -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')
|
733
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.c
Normal file
733
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.c
Normal file
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
* 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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* 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.sibling = RT_LIST_OBJECT_INIT(_proc_root.node.sibling),
|
||||
.node.subnode = RT_LIST_OBJECT_INIT(_proc_root.node.subnode),
|
||||
|
||||
.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;
|
||||
|
||||
dfs_vfs_for_each_subnode(dentry, tmp, (*parent), node)
|
||||
{
|
||||
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);
|
||||
dfs_vfs_init_node(&dentry->node);
|
||||
}
|
||||
}
|
||||
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->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);
|
75
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.h
Normal file
75
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.h
Normal file
@@ -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 <dfs_file.h>
|
||||
#include <dfs_seq_file.h>
|
||||
#include <dfs_vfs.h>
|
||||
|
||||
#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
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_fs.h>
|
||||
|
||||
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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <mm_page.h>
|
||||
|
||||
|
||||
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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <mm_page.h>
|
||||
|
||||
|
||||
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);
|
101
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
Normal file
101
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
Normal file
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
|
||||
|
||||
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);
|
107
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_net.c
Normal file
107
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_net.c
Normal file
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
#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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#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);
|
449
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
Normal file
449
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
Normal file
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lwp_internal.h"
|
||||
#include <dfs_dentry.h>
|
||||
#include "lwp_internal.h"
|
||||
|
||||
#if defined(RT_USING_SMART)
|
||||
|
||||
#include "lwp.h"
|
||||
#include "lwp_pid.h"
|
||||
#include <lwp_user_mm.h>
|
||||
|
||||
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
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
#if defined(RT_USING_SMART)
|
||||
|
||||
#include <lwp.h>
|
||||
|
||||
|
||||
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
|
114
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
Normal file
114
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
Normal file
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
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);
|
100
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_tty.c
Normal file
100
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_tty.c
Normal file
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
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);
|
@@ -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 <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
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);
|
447
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.c
Normal file
447
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_posix.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
#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->ref_count > 0);
|
||||
|
||||
// this file is opened and in an fdtable
|
||||
if (file->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 _procfs_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 = &_procfs_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;
|
||||
}
|
19
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.h
Normal file
19
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.h
Normal file
@@ -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 <dfs_file.h>
|
||||
|
||||
int dfs_procfs_init(void);
|
||||
|
||||
int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos);
|
||||
|
||||
#endif
|
@@ -262,7 +262,7 @@ ptsno_t ptyfs_register_pts(rt_device_t ptmx, rt_device_t pts)
|
||||
pts_file = rt_calloc(1, sizeof(struct ptyfs_file));
|
||||
if (pts_file)
|
||||
{
|
||||
snprintf(pts_file->basename, DIRENT_NAME_MAX, "%lu", rc);
|
||||
snprintf(pts_file->basename, DIRENT_NAME_MAX, "%lu", (unsigned long)rc);
|
||||
ptyfile_init(pts_file, sb, 0, PTYFS_TYPE_FILE_SLAVE,
|
||||
PTS_DEFAULT_FILE_MODE, pts);
|
||||
ptyfile_add_to_root(sb, pts_file);
|
||||
@@ -296,7 +296,7 @@ rt_err_t ptyfs_unregister_pts(rt_device_t ptmx, ptsno_t ptsno)
|
||||
else
|
||||
{
|
||||
/* get path and findout device */
|
||||
snprintf(path_buf, sizeof(path_buf), "%lu", ptsno);
|
||||
snprintf(path_buf, sizeof(path_buf), "%lu", (unsigned long)ptsno);
|
||||
pts_file = ptyfile_lookup(sb, path_buf);
|
||||
if (pts_file)
|
||||
{
|
||||
|
@@ -365,6 +365,7 @@ static const struct dfs_file_ops _rom_fops =
|
||||
{
|
||||
.open = dfs_romfs_open,
|
||||
.close = dfs_romfs_close,
|
||||
.ioctl = dfs_romfs_ioctl,
|
||||
.lseek = generic_dfs_lseek,
|
||||
.read = dfs_romfs_read,
|
||||
.getdents = dfs_romfs_getdents,
|
||||
|
@@ -99,15 +99,13 @@ static int _get_subdir(const char *path, char *name)
|
||||
|
||||
static int _free_subdir(struct tmpfs_file *dfile)
|
||||
{
|
||||
struct tmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct tmpfs_file *file = RT_NULL, *tmp;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
@@ -122,7 +120,7 @@ static int _free_subdir(struct tmpfs_file *dfile)
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(file->sibling));
|
||||
dfs_vfs_remove_node(&file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
@@ -141,13 +139,11 @@ static int dfs_tmpfs_mount(struct dfs_mnt *mnt,
|
||||
{
|
||||
superblock->df_size = sizeof(struct tmpfs_sb);
|
||||
superblock->magic = TMPFS_MAGIC;
|
||||
rt_list_init(&superblock->sibling);
|
||||
|
||||
superblock->root.name[0] = '/';
|
||||
superblock->root.sb = superblock;
|
||||
superblock->root.type = TMPFS_TYPE_DIR;
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
dfs_vfs_init_node(&superblock->root.node);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
@@ -236,8 +232,7 @@ struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock,
|
||||
{
|
||||
const char *subpath, *curpath, *filename = RT_NULL;
|
||||
char subdir_name[TMPFS_NAME_MAX];
|
||||
struct tmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
struct tmpfs_file *file, *curfile, *tmp;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
@@ -265,9 +260,8 @@ find_subpath:
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
@@ -503,8 +497,7 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct tmpfs_file *d_file, *n_file;
|
||||
rt_list_t *list;
|
||||
struct tmpfs_file *d_file, *n_file, *tmp;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
@@ -527,9 +520,8 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
d = dirp + count;
|
||||
@@ -573,7 +565,7 @@ static int dfs_tmpfs_unlink(struct dfs_dentry *dentry)
|
||||
return -ENOENT;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
if (rt_atomic_load(&(dentry->ref_count)) == 1)
|
||||
@@ -631,13 +623,13 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne
|
||||
RT_ASSERT(p_file != NULL);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(parent_path);
|
||||
@@ -745,8 +737,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
dfs_vfs_init_node(&d_file->node);
|
||||
d_file->data = NULL;
|
||||
d_file->size = 0;
|
||||
d_file->sb = superblock;
|
||||
@@ -767,7 +758,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
||||
#endif
|
||||
}
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
vnode->mnt = dentry->mnt;
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#define __DFS_TMPFS_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs_vfs.h>
|
||||
|
||||
#define TMPFS_NAME_MAX 32
|
||||
#define TMPFS_MAGIC 0x0B0B0B0B
|
||||
@@ -25,8 +26,7 @@ struct tmpfs_file
|
||||
{
|
||||
rt_uint32_t type; /* file type */
|
||||
char name[TMPFS_NAME_MAX]; /* file name */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
struct dfs_vfs_node node; /* file node in the tmpfs */
|
||||
struct tmpfs_sb *sb; /* superblock ptr */
|
||||
rt_uint8_t *data; /* file date ptr */
|
||||
rt_size_t size; /* file size */
|
||||
|
@@ -20,6 +20,38 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define MS_RDONLY 1
|
||||
#define MS_NOSUID 2
|
||||
#define MS_NODEV 4
|
||||
#define MS_NOEXEC 8
|
||||
#define MS_SYNCHRONOUS 16
|
||||
#define MS_REMOUNT 32
|
||||
#define MS_MANDLOCK 64
|
||||
#define MS_DIRSYNC 128
|
||||
#define MS_NOATIME 1024
|
||||
#define MS_NODIRATIME 2048
|
||||
#define MS_BIND 4096
|
||||
#define MS_MOVE 8192
|
||||
#define MS_REC 16384
|
||||
#define MS_SILENT 32768
|
||||
#define MS_POSIXACL (1<<16)
|
||||
#define MS_UNBINDABLE (1<<17)
|
||||
#define MS_PRIVATE (1<<18)
|
||||
#define MS_SLAVE (1<<19)
|
||||
#define MS_SHARED (1<<20)
|
||||
#define MS_RELATIME (1<<21)
|
||||
#define MS_KERNMOUNT (1<<22)
|
||||
#define MS_I_VERSION (1<<23)
|
||||
#define MS_STRICTATIME (1<<24)
|
||||
#define MS_LAZYTIME (1<<25)
|
||||
#define MS_NOREMOTELOCK (1<<27)
|
||||
#define MS_NOSEC (1<<28)
|
||||
#define MS_BORN (1<<29)
|
||||
#define MS_ACTIVE (1<<30)
|
||||
#define MS_NOUSER (1U<<31)
|
||||
|
||||
#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME)
|
||||
|
||||
/* file system partition table */
|
||||
struct dfs_partition
|
||||
{
|
||||
@@ -87,6 +119,7 @@ int dfs_unregister(struct dfs_filesystem_type *fs);
|
||||
int dfs_register(struct dfs_filesystem_type *fs);
|
||||
const char *dfs_filesystem_get_mounted_path(struct rt_device *device);
|
||||
|
||||
int dfs_remount(const char *path, rt_ubase_t flags, void *data);
|
||||
int dfs_mount(const char *device_name,
|
||||
const char *path,
|
||||
const char *filesystemtype,
|
||||
|
@@ -39,6 +39,8 @@ struct dfs_mnt
|
||||
#define MNT_IS_UMOUNT 0x8 /* the mnt is unmount */
|
||||
#define MNT_IS_LOCKED 0x10 /* the mnt is locked */
|
||||
#define MNT_FORCE 0x20 /* the mnt force unmount */
|
||||
#define MNT_LAZY_UMNT 0x40 /* the mnt has pending umount */
|
||||
#define MNT_RDONLY 0x80 /* the mnt is read only */
|
||||
|
||||
rt_atomic_t ref_count; /* reference count */
|
||||
|
||||
@@ -60,9 +62,16 @@ const char *dfs_mnt_get_mounted_path(struct rt_device *device);
|
||||
struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt);
|
||||
int dfs_mnt_unref(struct dfs_mnt* mnt);
|
||||
|
||||
int dfs_mnt_umount(struct dfs_mnt *mnt, int flags);
|
||||
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags);
|
||||
|
||||
rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath);
|
||||
|
||||
int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter);
|
||||
int dfs_mnt_umount_iter(rt_bool_t (*filter)(struct dfs_mnt *mnt, void *parameter), void *parameter);
|
||||
|
||||
typedef void (*dfs_mnt_umnt_cb_t)(struct dfs_mnt *mnt);
|
||||
RT_OBJECT_HOOKLIST_DECLARE(dfs_mnt_umnt_cb_t, dfs_mnt_umnt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -118,6 +118,7 @@ int dfs_aspace_mmap_write(struct dfs_file *file, struct rt_varea *varea, void *d
|
||||
|
||||
void dfs_pcache_release(size_t count);
|
||||
void dfs_pcache_unmount(struct dfs_mnt *mnt);
|
||||
void dfs_pcache_clean(struct dfs_mnt *mnt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -56,7 +56,7 @@ static inline void dfs_seq_setwidth(struct dfs_seq_file *seq, size_t size)
|
||||
|
||||
int dfs_seq_open(struct dfs_file *file, const struct dfs_seq_ops *ops);
|
||||
ssize_t dfs_seq_read(struct dfs_file *file, void *buf, size_t size, off_t *pos);
|
||||
ssize_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence);
|
||||
off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence);
|
||||
int dfs_seq_release(struct dfs_file *file);
|
||||
int dfs_seq_write(struct dfs_seq_file *seq, const void *data, size_t len);
|
||||
|
||||
|
50
rt-thread/components/dfs/dfs_v2/include/dfs_vfs.h
Normal file
50
rt-thread/components/dfs/dfs_v2/include/dfs_vfs.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __DFS_VFS_H__
|
||||
#define __DFS_VFS_H__
|
||||
|
||||
#include "dfs_file.h"
|
||||
#include "dfs_fs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct dfs_vfs_node
|
||||
{
|
||||
rt_list_t subnode; /* file subnode list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
};
|
||||
|
||||
rt_inline void dfs_vfs_init_node(struct dfs_vfs_node *node)
|
||||
{
|
||||
rt_list_init(&node->subnode);
|
||||
rt_list_init(&node->sibling);
|
||||
}
|
||||
|
||||
rt_inline void dfs_vfs_append_node(struct dfs_vfs_node *dir, struct dfs_vfs_node *node)
|
||||
{
|
||||
rt_list_insert_after(&(dir->subnode), &(node->sibling));
|
||||
}
|
||||
|
||||
rt_inline void dfs_vfs_remove_node(struct dfs_vfs_node *node)
|
||||
{
|
||||
rt_list_remove(&(node->sibling));
|
||||
}
|
||||
|
||||
#define dfs_vfs_for_each_subnode(node, tmp, dir, member) \
|
||||
rt_list_for_each_entry_safe(node, tmp, &dir->member.subnode, member.sibling)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__DFS_VFS_H__*/
|
@@ -537,6 +537,7 @@ int dfs_dup(int oldfd, int startfd)
|
||||
fdt = dfs_fdtable_get();
|
||||
if ((oldfd < 0) || (oldfd >= fdt->maxfd))
|
||||
{
|
||||
rt_set_errno(-EBADF);
|
||||
goto exit;
|
||||
}
|
||||
if (!fdt->fds[oldfd])
|
||||
@@ -668,12 +669,17 @@ sysret_t sys_dup(int oldfd)
|
||||
int sys_dup(int oldfd)
|
||||
#endif
|
||||
{
|
||||
int err = 0;
|
||||
int newfd = dfs_dup(oldfd, (dfs_fdtable_get() == &_fdtab) ? DFS_STDIO_OFFSET : 0);
|
||||
if(newfd < 0)
|
||||
{
|
||||
err = rt_get_errno();
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
return (sysret_t)newfd;
|
||||
return err < 0 ? err : newfd;
|
||||
#else
|
||||
return newfd;
|
||||
return err < 0 ? err : newfd;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -1379,6 +1379,7 @@ int dfs_file_link(const char *oldname, const char *newname)
|
||||
|
||||
if (dfs_file_isdir(oldname) == 0)
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1567,6 +1568,10 @@ int dfs_file_symlink(const char *target, const char *linkpath)
|
||||
rt_free(parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
}
|
||||
|
||||
if (fullpath != linkpath)
|
||||
rt_free(fullpath);
|
||||
|
@@ -95,6 +95,52 @@ int dfs_unregister(struct dfs_filesystem_type *fs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define REMNT_UNSUPP_FLAGS (~(MS_REMOUNT | MS_RMT_MASK))
|
||||
int dfs_remount(const char *path, rt_ubase_t flags, void *data)
|
||||
{
|
||||
int rc = 0;
|
||||
char *fullpath = RT_NULL;
|
||||
struct dfs_mnt *mnt = RT_NULL;
|
||||
|
||||
if (flags & REMNT_UNSUPP_FLAGS)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fullpath = dfs_normalize_path(RT_NULL, path);
|
||||
if (!fullpath)
|
||||
{
|
||||
rc = -ENOENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
dfs_lock();
|
||||
dfs_mnt_setflags(mnt, flags);
|
||||
dfs_unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat buf = {0};
|
||||
if (dfs_file_stat(fullpath, &buf) == 0 && S_ISBLK(buf.st_mode))
|
||||
{
|
||||
/* path was not already mounted on target */
|
||||
rc = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* path is not a directory */
|
||||
rc = -ENOTDIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* parent(mount path)
|
||||
* mnt_parent <- - - - - - - +
|
||||
@@ -127,7 +173,7 @@ int dfs_mount(const char *device_name,
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(ENOENT);
|
||||
rt_set_errno(ENODEV);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
@@ -300,7 +346,7 @@ int dfs_mount(const char *device_name,
|
||||
|
||||
int dfs_umount(const char *specialfile, int flags)
|
||||
{
|
||||
int ret = -RT_ERROR;
|
||||
int ret = -1;
|
||||
char *fullpath = RT_NULL;
|
||||
struct dfs_mnt *mnt = RT_NULL;
|
||||
|
||||
@@ -314,7 +360,7 @@ int dfs_umount(const char *specialfile, int flags)
|
||||
if (strcmp(mnt->fullpath, fullpath) == 0)
|
||||
{
|
||||
/* is the mount point */
|
||||
rt_atomic_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
||||
rt_base_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
||||
|
||||
if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
|
||||
{
|
||||
@@ -327,17 +373,19 @@ int dfs_umount(const char *specialfile, int flags)
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("the file system is busy!");
|
||||
LOG_I("the file system is busy!");
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("the path:%s is not a mountpoint!", fullpath);
|
||||
LOG_I("the path:%s is not a mountpoint!", fullpath);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("no filesystem found.");
|
||||
LOG_I("no filesystem found.");
|
||||
}
|
||||
rt_free(fullpath);
|
||||
}
|
||||
|
@@ -10,17 +10,21 @@
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "dfs.h"
|
||||
#include "dfs_mnt.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_private.h"
|
||||
|
||||
#include <dfs.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <dfs_pcache.h>
|
||||
|
||||
#define DBG_TAG "DFS.mnt"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct dfs_mnt *_root_mnt = RT_NULL;
|
||||
|
||||
RT_OBJECT_HOOKLIST_DEFINE(dfs_mnt_umnt);
|
||||
|
||||
/*
|
||||
* mnt tree structure
|
||||
*
|
||||
@@ -75,6 +79,7 @@ int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child)
|
||||
child = _root_mnt;
|
||||
rt_atomic_sub(&(_root_mnt->parent->ref_count), 1);
|
||||
rt_atomic_sub(&(_root_mnt->ref_count), 1);
|
||||
_root_mnt->flags &= ~MNT_IS_LOCKED;
|
||||
|
||||
_root_mnt = dfs_mnt_ref(mnt);
|
||||
mnt->parent = dfs_mnt_ref(mnt);
|
||||
@@ -242,21 +247,24 @@ struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt)
|
||||
return mnt;
|
||||
}
|
||||
|
||||
int dfs_mnt_unref(struct dfs_mnt* mnt)
|
||||
int dfs_mnt_unref(struct dfs_mnt *mnt)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
rt_base_t ref_count;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
rt_atomic_sub(&(mnt->ref_count), 1);
|
||||
ref_count = rt_atomic_sub(&(mnt->ref_count), 1) - 1;
|
||||
|
||||
if (rt_atomic_load(&(mnt->ref_count)) == 0)
|
||||
if (ref_count == 0)
|
||||
{
|
||||
dfs_lock();
|
||||
|
||||
if (mnt->flags & MNT_IS_UMOUNT)
|
||||
{
|
||||
mnt->fs_ops->umount(mnt);
|
||||
|
||||
RT_OBJECT_HOOKLIST_CALL(dfs_mnt_umnt, (mnt));
|
||||
}
|
||||
|
||||
/* free full path */
|
||||
@@ -278,6 +286,21 @@ int dfs_mnt_unref(struct dfs_mnt* mnt)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (flags & MS_RDONLY)
|
||||
{
|
||||
mnt->flags |= MNT_RDONLY;
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
dfs_pcache_clean(mnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int dfs_mnt_destroy(struct dfs_mnt* mnt)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
@@ -13,17 +13,19 @@
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "dfs_pcache.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_mnt.h"
|
||||
#include "mm_page.h"
|
||||
#include <mmu.h>
|
||||
#include <tlb.h>
|
||||
#include <dfs_pcache.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
|
||||
#include <rthw.h>
|
||||
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
|
||||
#include <mm_page.h>
|
||||
#include <mm_private.h>
|
||||
#include <mmu.h>
|
||||
#include <tlb.h>
|
||||
|
||||
#ifndef RT_PAGECACHE_COUNT
|
||||
#define RT_PAGECACHE_COUNT 4096
|
||||
#endif
|
||||
@@ -160,7 +162,7 @@ void dfs_pcache_release(size_t count)
|
||||
dfs_pcache_unlock();
|
||||
}
|
||||
|
||||
void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspace))
|
||||
{
|
||||
rt_list_t *node = RT_NULL;
|
||||
struct dfs_aspace *aspace = RT_NULL;
|
||||
@@ -175,7 +177,7 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
if (aspace && aspace->mnt == mnt)
|
||||
{
|
||||
dfs_aspace_clean(aspace);
|
||||
dfs_aspace_release(aspace);
|
||||
cb(aspace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,13 +189,28 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
if (aspace && aspace->mnt == mnt)
|
||||
{
|
||||
dfs_aspace_clean(aspace);
|
||||
dfs_aspace_release(aspace);
|
||||
cb(aspace);
|
||||
}
|
||||
}
|
||||
|
||||
dfs_pcache_unlock();
|
||||
}
|
||||
|
||||
void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
{
|
||||
_pcache_clean(mnt, dfs_aspace_release);
|
||||
}
|
||||
|
||||
static int _dummy_cb(struct dfs_aspace *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfs_pcache_clean(struct dfs_mnt *mnt)
|
||||
{
|
||||
_pcache_clean(mnt, _dummy_cb);
|
||||
}
|
||||
|
||||
static int dfs_pcache_limit_check(void)
|
||||
{
|
||||
int index = 4;
|
||||
@@ -1138,14 +1155,21 @@ int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t
|
||||
|
||||
if (file && file->vnode && file->vnode->aspace)
|
||||
{
|
||||
if (!(file->vnode->aspace->ops->write))
|
||||
return ret;
|
||||
struct dfs_vnode *vnode = file->vnode;
|
||||
struct dfs_aspace *aspace = vnode->aspace;
|
||||
|
||||
struct dfs_page *page;
|
||||
char *ptr = (char *)buf;
|
||||
|
||||
if (!(aspace->ops->write))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
else if (aspace->mnt && (aspace->mnt->flags & MNT_RDONLY))
|
||||
{
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
while (count)
|
||||
@@ -1380,7 +1404,8 @@ int dfs_aspace_unmap(struct dfs_file *file, struct rt_varea *varea)
|
||||
|
||||
rt_varea_unmap_page(map_varea, vaddr);
|
||||
|
||||
if (varea->attr == MMU_MAP_U_RWCB && page->fpos < page->aspace->vnode->size)
|
||||
if (!rt_varea_is_private_locked(varea) &&
|
||||
page->fpos < page->aspace->vnode->size)
|
||||
{
|
||||
dfs_page_dirty(page);
|
||||
}
|
||||
@@ -1425,7 +1450,7 @@ int dfs_aspace_page_unmap(struct dfs_file *file, struct rt_varea *varea, void *v
|
||||
|
||||
if (map && varea->aspace == map->aspace && vaddr == map->vaddr)
|
||||
{
|
||||
if (varea->attr == MMU_MAP_U_RWCB)
|
||||
if (!rt_varea_is_private_locked(varea))
|
||||
{
|
||||
dfs_page_dirty(page);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -31,7 +31,17 @@
|
||||
* return a file descriptor according specified flags.
|
||||
*
|
||||
* @param file the path name of file.
|
||||
* @param flags the file open flags.
|
||||
* @param flags the file open flags. Common values include:
|
||||
* - Access modes (mutually exclusive):
|
||||
* - `O_RDONLY`: Open for read-only access.
|
||||
* - `O_WRONLY`: Open for write-only access.
|
||||
* - `O_RDWR`: Open for both reading and writing.
|
||||
* - File status flags (can be combined with bitwise OR `|`):
|
||||
* - `O_CREAT`: Create the file if it does not exist. Requires a `mode` argument.
|
||||
* - `O_TRUNC`: Truncate the file to zero length if it already exists.
|
||||
* - `O_APPEND`: Append writes to the end of the file.
|
||||
* - `O_EXCL`: Ensure that `O_CREAT` creates the file exclusively.
|
||||
* - Other platform-specific flags
|
||||
*
|
||||
* @return the non-negative integer on successful open, others for failed.
|
||||
*/
|
||||
@@ -81,6 +91,22 @@ RTM_EXPORT(open);
|
||||
#ifndef AT_FDCWD
|
||||
#define AT_FDCWD (-100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Opens a file relative to a directory file descriptor.
|
||||
*
|
||||
* @param dirfd The file descriptor of the directory to base the relative path on.
|
||||
* @param path The path to the file to be opened, relative to the directory specified by `dirfd`.
|
||||
* Can be an absolute path (in which case `dirfd` is ignored).
|
||||
* @param flag File access and status flags (e.g., `O_RDONLY`, `O_WRONLY`, `O_CREAT`).
|
||||
*
|
||||
* @return On success, returns a new file descriptor for the opened file.
|
||||
* On failure, returns `-1` and sets `errno` to indicate the error.
|
||||
*
|
||||
* @note When using relative paths, ensure `dirfd` is a valid directory descriptor.
|
||||
* When `pathname` is absolute, the `dirfd` argument is ignored.
|
||||
*
|
||||
*/
|
||||
int openat(int dirfd, const char *path, int flag, ...)
|
||||
{
|
||||
struct dfs_file *d;
|
||||
@@ -171,7 +197,7 @@ int utimensat(int __fd, const char *__path, const struct timespec __times[2], in
|
||||
}
|
||||
}
|
||||
|
||||
//update time
|
||||
/*update time*/
|
||||
attr.ia_valid = ATTR_ATIME_SET | ATTR_MTIME_SET;
|
||||
time(¤t_time);
|
||||
if (UTIME_NOW == __times[0].tv_nsec)
|
||||
@@ -374,14 +400,22 @@ ssize_t write(int fd, const void *buf, size_t len)
|
||||
RTM_EXPORT(write);
|
||||
|
||||
/**
|
||||
* this function is a POSIX compliant version, which will seek the offset for
|
||||
* this function is a POSIX compliant version, which will Reposition the file offset for
|
||||
* an open file descriptor.
|
||||
*
|
||||
* @param fd the file descriptor.
|
||||
* @param offset the offset to be seeked.
|
||||
* @param whence the directory of seek.
|
||||
* The `lseek` function sets the file offset for the file descriptor `fd`
|
||||
* to a new value, determined by the `offset` and `whence` parameters.
|
||||
* It can be used to seek to specific positions in a file for reading or writing.
|
||||
*
|
||||
* @return the current read/write position in the file, or -1 on failed.
|
||||
* @param fd the file descriptor.
|
||||
* @param offset The offset, in bytes, to set the file position.
|
||||
* The meaning of `offset` depends on the value of `whence`.
|
||||
* @param whence the directive of seek. It can be one of:
|
||||
* - `SEEK_SET`: Set the offset to `offset` bytes from the beginning of the file.
|
||||
* - `SEEK_CUR`: Set the offset to its current location plus `offset` bytes.
|
||||
* - `SEEK_END`: Set the offset to the size of the file plus `offset` bytes.
|
||||
*
|
||||
* @return the resulting read/write position in the file, or -1 on failed.
|
||||
*/
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
@@ -399,7 +433,7 @@ off_t lseek(int fd, off_t offset, int whence)
|
||||
result = dfs_file_lseek(file, offset, whence);
|
||||
if (result < 0)
|
||||
{
|
||||
rt_set_errno(result);
|
||||
rt_set_errno(-EPERM);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -581,9 +615,15 @@ RTM_EXPORT(fsync);
|
||||
* control functions on devices.
|
||||
*
|
||||
* @param fildes the file description
|
||||
* @param cmd the specified command
|
||||
* @param cmd the specified command, Common values include:
|
||||
* - `F_DUPFD`: Duplicate a file descriptor.
|
||||
* - `F_GETFD`: Get the file descriptor flags.
|
||||
* - `F_SETFD`: Set the file descriptor flags.
|
||||
* - `F_GETFL`: Get the file status flags.
|
||||
* - `F_SETFL`: Set the file status flags.
|
||||
* @param ... represents the additional information that is needed by this
|
||||
* specific device to perform the requested function.
|
||||
* specific device to perform the requested function. For example:
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
*
|
||||
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
|
||||
* set to indicate the error.
|
||||
@@ -765,7 +805,7 @@ RTM_EXPORT(fstatfs);
|
||||
* this function is a POSIX compliant version, which will make a directory
|
||||
*
|
||||
* @param path the directory path to be made.
|
||||
* @param mode
|
||||
* @param mode The permission mode for the new directory (unused here, can be set to 0).
|
||||
*
|
||||
* @return 0 on successful, others on failed.
|
||||
*/
|
||||
@@ -827,7 +867,7 @@ int rmdir(const char *pathname)
|
||||
|
||||
if (!pathname)
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
rt_set_errno(-EPERM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -852,7 +892,7 @@ int rmdir(const char *pathname)
|
||||
|
||||
if (dirent)
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
rt_set_errno(-EPERM);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -861,7 +901,7 @@ int rmdir(const char *pathname)
|
||||
{
|
||||
if (S_ISLNK(stat.st_mode))
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
rt_set_errno(-EPERM);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@@ -256,7 +256,7 @@ Enomem:
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ssize_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
|
||||
off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
|
||||
{
|
||||
struct dfs_seq_file *seq = file->data;
|
||||
off_t retval = -EINVAL;
|
||||
|
Reference in New Issue
Block a user