devfs: Add symlink support
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
3cff8948ff
commit
8a35fddf57
|
@ -21,7 +21,7 @@
|
||||||
static int do_devinfo_subtree(struct device_d *dev, int depth)
|
static int do_devinfo_subtree(struct device_d *dev, int depth)
|
||||||
{
|
{
|
||||||
struct device_d *child;
|
struct device_d *child;
|
||||||
struct cdev *cdev;
|
struct cdev *cdev, *cdevl;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < depth; i++)
|
for (i = 0; i < depth; i++)
|
||||||
|
@ -33,11 +33,14 @@ static int do_devinfo_subtree(struct device_d *dev, int depth)
|
||||||
list_for_each_entry(cdev, &dev->cdevs, devices_list) {
|
list_for_each_entry(cdev, &dev->cdevs, devices_list) {
|
||||||
for (i = 0; i < depth + 1; i++)
|
for (i = 0; i < depth + 1; i++)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
printf("`-- 0x%08llx-0x%08llx (%10s): /dev/%s\n",
|
printf("`-- 0x%08llx-0x%08llx (%10s): /dev/%s",
|
||||||
cdev->offset,
|
cdev->offset,
|
||||||
cdev->offset + cdev->size - 1,
|
cdev->offset + cdev->size - 1,
|
||||||
size_human_readable(cdev->size),
|
size_human_readable(cdev->size),
|
||||||
cdev->name);
|
cdev->name);
|
||||||
|
list_for_each_entry(cdevl, &cdev->links, link_entry)
|
||||||
|
printf(", %s", cdevl->name);
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
|
@ -46,7 +46,18 @@ int devfs_partition_complete(struct string_list *sl, char *instr)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct cdev *cdev_by_name(const char *filename)
|
struct cdev *cdev_readlink(struct cdev *cdev)
|
||||||
|
{
|
||||||
|
if (cdev->link)
|
||||||
|
cdev = cdev->link;
|
||||||
|
|
||||||
|
/* links to links are not allowed */
|
||||||
|
BUG_ON(cdev->link);
|
||||||
|
|
||||||
|
return cdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cdev *lcdev_by_name(const char *filename)
|
||||||
{
|
{
|
||||||
struct cdev *cdev;
|
struct cdev *cdev;
|
||||||
|
|
||||||
|
@ -57,6 +68,17 @@ struct cdev *cdev_by_name(const char *filename)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cdev *cdev_by_name(const char *filename)
|
||||||
|
{
|
||||||
|
struct cdev *cdev;
|
||||||
|
|
||||||
|
cdev = lcdev_by_name(filename);
|
||||||
|
if (!cdev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return cdev_readlink(cdev);
|
||||||
|
}
|
||||||
|
|
||||||
struct cdev *cdev_by_device_node(struct device_node *node)
|
struct cdev *cdev_by_device_node(struct device_node *node)
|
||||||
{
|
{
|
||||||
struct cdev *cdev;
|
struct cdev *cdev;
|
||||||
|
@ -65,7 +87,7 @@ struct cdev *cdev_by_device_node(struct device_node *node)
|
||||||
if (!cdev->device_node)
|
if (!cdev->device_node)
|
||||||
continue;
|
continue;
|
||||||
if (cdev->device_node == node)
|
if (cdev->device_node == node)
|
||||||
return cdev;
|
return cdev_readlink(cdev);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -111,14 +133,6 @@ int cdev_find_free_index(const char *basename)
|
||||||
return -EBUSY; /* all indexes are used */
|
return -EBUSY; /* all indexes are used */
|
||||||
}
|
}
|
||||||
|
|
||||||
int cdev_do_open(struct cdev *cdev, unsigned long flags)
|
|
||||||
{
|
|
||||||
if (cdev->ops->open)
|
|
||||||
return cdev->ops->open(cdev, flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct cdev *cdev_open(const char *name, unsigned long flags)
|
struct cdev *cdev_open(const char *name, unsigned long flags)
|
||||||
{
|
{
|
||||||
struct cdev *cdev;
|
struct cdev *cdev;
|
||||||
|
@ -131,9 +145,11 @@ struct cdev *cdev_open(const char *name, unsigned long flags)
|
||||||
if (!cdev)
|
if (!cdev)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ret = cdev_do_open(cdev, flags);
|
if (cdev->ops->open) {
|
||||||
if (ret)
|
ret = cdev->ops->open(cdev, flags);
|
||||||
return NULL;
|
if (ret)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return cdev;
|
return cdev;
|
||||||
}
|
}
|
||||||
|
@ -259,6 +275,8 @@ int devfs_create(struct cdev *new)
|
||||||
if (cdev)
|
if (cdev)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&new->links);
|
||||||
|
|
||||||
list_add_tail(&new->list, &cdev_list);
|
list_add_tail(&new->list, &cdev_list);
|
||||||
if (new->dev) {
|
if (new->dev) {
|
||||||
list_add_tail(&new->devices_list, &new->dev->cdevs);
|
list_add_tail(&new->devices_list, &new->dev->cdevs);
|
||||||
|
@ -269,15 +287,47 @@ int devfs_create(struct cdev *new)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int devfs_create_link(struct cdev *cdev, const char *name)
|
||||||
|
{
|
||||||
|
struct cdev *new;
|
||||||
|
|
||||||
|
if (cdev_by_name(name))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a link to the real cdev instead of creating
|
||||||
|
* a link to a link.
|
||||||
|
*/
|
||||||
|
cdev = cdev_readlink(cdev);
|
||||||
|
|
||||||
|
new = xzalloc(sizeof(*new));
|
||||||
|
new->name = xstrdup(name);
|
||||||
|
new->link = cdev;
|
||||||
|
INIT_LIST_HEAD(&new->links);
|
||||||
|
list_add_tail(&new->list, &cdev_list);
|
||||||
|
list_add_tail(&new->link_entry, &cdev->links);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int devfs_remove(struct cdev *cdev)
|
int devfs_remove(struct cdev *cdev)
|
||||||
{
|
{
|
||||||
|
struct cdev *c, *tmp;
|
||||||
|
|
||||||
if (cdev->open)
|
if (cdev->open)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
list_del(&cdev->list);
|
list_del(&cdev->list);
|
||||||
|
|
||||||
if (cdev->dev)
|
if (cdev->dev)
|
||||||
list_del(&cdev->devices_list);
|
list_del(&cdev->devices_list);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(c, tmp, &cdev->links, link_entry)
|
||||||
|
devfs_remove(c);
|
||||||
|
|
||||||
|
if (cdev->link)
|
||||||
|
free(cdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
27
fs/devfs.c
27
fs/devfs.c
|
@ -212,12 +212,18 @@ static int devfs_stat(struct device_d *_dev, const char *filename, struct stat *
|
||||||
{
|
{
|
||||||
struct cdev *cdev;
|
struct cdev *cdev;
|
||||||
|
|
||||||
cdev = cdev_by_name(filename + 1);
|
cdev = lcdev_by_name(filename + 1);
|
||||||
if (!cdev)
|
if (!cdev)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
s->st_mode = S_IFCHR;
|
s->st_mode = S_IFCHR;
|
||||||
s->st_size = cdev->size;
|
s->st_size = cdev->size;
|
||||||
|
|
||||||
|
if (cdev->link)
|
||||||
|
s->st_mode |= S_IFLNK;
|
||||||
|
|
||||||
|
cdev = cdev_readlink(cdev);
|
||||||
|
|
||||||
if (cdev->ops->write)
|
if (cdev->ops->write)
|
||||||
s->st_mode |= S_IWUSR;
|
s->st_mode |= S_IWUSR;
|
||||||
if (cdev->ops->read)
|
if (cdev->ops->read)
|
||||||
|
@ -242,6 +248,24 @@ static void devfs_delete(struct device_d *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int devfs_readlink(struct device_d *dev, const char *pathname,
|
||||||
|
char *buf, size_t bufsz)
|
||||||
|
{
|
||||||
|
struct cdev *cdev;
|
||||||
|
|
||||||
|
cdev = cdev_by_name(pathname + 1);
|
||||||
|
if (!cdev)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
while (cdev->link)
|
||||||
|
cdev = cdev->link;
|
||||||
|
|
||||||
|
bufsz = min(bufsz, strlen(cdev->name));
|
||||||
|
memcpy(buf, cdev->name, bufsz);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct fs_driver_d devfs_driver = {
|
static struct fs_driver_d devfs_driver = {
|
||||||
.read = devfs_read,
|
.read = devfs_read,
|
||||||
.write = devfs_write,
|
.write = devfs_write,
|
||||||
|
@ -258,6 +282,7 @@ static struct fs_driver_d devfs_driver = {
|
||||||
.erase = devfs_erase,
|
.erase = devfs_erase,
|
||||||
.protect = devfs_protect,
|
.protect = devfs_protect,
|
||||||
.memmap = devfs_memmap,
|
.memmap = devfs_memmap,
|
||||||
|
.readlink = devfs_readlink,
|
||||||
.flags = FS_DRIVER_NO_DEV,
|
.flags = FS_DRIVER_NO_DEV,
|
||||||
.drv = {
|
.drv = {
|
||||||
.probe = devfs_probe,
|
.probe = devfs_probe,
|
||||||
|
|
|
@ -450,13 +450,18 @@ struct cdev {
|
||||||
int open;
|
int open;
|
||||||
struct mtd_info *mtd;
|
struct mtd_info *mtd;
|
||||||
u8 dos_partition_type;
|
u8 dos_partition_type;
|
||||||
|
struct cdev *link;
|
||||||
|
struct list_head link_entry, links;
|
||||||
};
|
};
|
||||||
|
|
||||||
int devfs_create(struct cdev *);
|
int devfs_create(struct cdev *);
|
||||||
|
int devfs_create_link(struct cdev *, const char *name);
|
||||||
int devfs_remove(struct cdev *);
|
int devfs_remove(struct cdev *);
|
||||||
int cdev_find_free_index(const char *);
|
int cdev_find_free_index(const char *);
|
||||||
struct cdev *device_find_partition(struct device_d *dev, const char *name);
|
struct cdev *device_find_partition(struct device_d *dev, const char *name);
|
||||||
struct cdev *cdev_by_name(const char *filename);
|
struct cdev *cdev_by_name(const char *filename);
|
||||||
|
struct cdev *lcdev_by_name(const char *filename);
|
||||||
|
struct cdev *cdev_readlink(struct cdev *cdev);
|
||||||
struct cdev *cdev_by_device_node(struct device_node *node);
|
struct cdev *cdev_by_device_node(struct device_node *node);
|
||||||
struct cdev *cdev_open(const char *name, unsigned long flags);
|
struct cdev *cdev_open(const char *name, unsigned long flags);
|
||||||
int cdev_do_open(struct cdev *, unsigned long flags);
|
int cdev_do_open(struct cdev *, unsigned long flags);
|
||||||
|
|
Loading…
Reference in New Issue