diff --git a/commands/mount.c b/commands/mount.c index be26af84a..2e9d4bef5 100644 --- a/commands/mount.c +++ b/commands/mount.c @@ -27,33 +27,72 @@ #include #include #include +#include static int do_mount(int argc, char *argv[]) { int opt; - int ret = 0; + int ret = 0, verbose = 0; struct fs_device_d *fsdev; + struct driver_d *drv; const char *type = NULL; const char *mountpoint, *dev; - if (argc == 1) { - for_each_fs_device(fsdev) { - printf("%s on %s type %s\n", - fsdev->parent_device ? dev_name(fsdev->parent_device) : "none", - fsdev->path, - fsdev->dev.name); - } - return 0; - } - - while ((opt = getopt(argc, argv, "t:")) > 0) { + while ((opt = getopt(argc, argv, "t:va")) > 0) { switch (opt) { case 't': type = optarg; break; + case 'v': + verbose++; + break; + case 'a': + mount_all(); + break; } } + if (argc == optind) { + for_each_fs_device(fsdev) { + printf("%s on %s type %s\n", + fsdev->backingstore ? fsdev->backingstore : "none", + fsdev->path, + fsdev->dev.name); + } + + if (verbose) { + printf("\nSupported filesystems:\n\n"); + bus_for_each_driver(&fs_bus, drv) { + struct fs_driver_d * fsdrv = drv_to_fs_driver(drv); + printf("%s\n", fsdrv->drv.name); + } + } + + return 0; + } + + if (argc == optind + 1) { + struct cdev *cdev; + const char *path, *devstr; + + devstr = argv[optind]; + + if (!strncmp(devstr, "/dev/", 5)) + devstr += 5; + + cdev = cdev_by_name(devstr); + if (!cdev) + return -ENOENT; + + path = cdev_mount_default(cdev); + if (IS_ERR(path)) + return PTR_ERR(path); + + printf("mounted /dev/%s on %s\n", devstr, path); + + return 0; + } + if (argc < optind + 2) return COMMAND_ERROR_USAGE; @@ -77,10 +116,17 @@ static int do_mount(int argc, char *argv[]) } BAREBOX_CMD_HELP_START(mount) -BAREBOX_CMD_HELP_USAGE("mount [[-t ]\n") +BAREBOX_CMD_HELP_USAGE("mount [[OPTIONS] [mountpoint]]\n") +BAREBOX_CMD_HELP_OPT("-t ", "specify filesystem type\n") +BAREBOX_CMD_HELP_OPT("-a", "Mount all blockdevices.\n") +BAREBOX_CMD_HELP_OPT("-v", "be more verbose\n") BAREBOX_CMD_HELP_SHORT("Mount a filesystem of a given type to a mountpoint.\n") BAREBOX_CMD_HELP_SHORT("If no fstype is specified, try to detect it automatically.\n") BAREBOX_CMD_HELP_SHORT("If no argument is given, list mounted filesystems.\n") +BAREBOX_CMD_HELP_SHORT("With -a the mount command mounts all block devices whose filesystem\n") +BAREBOX_CMD_HELP_SHORT("can be detected automatically to /mnt/\n") +BAREBOX_CMD_HELP_SHORT("If mountpoint is not given a standard mountpoint of /mnt/devname>\n") +BAREBOX_CMD_HELP_SHORT("is used. This directoy is created automatically if necessary.\n") BAREBOX_CMD_HELP_END /** diff --git a/common/block.c b/common/block.c index ab39a3622..e522ee425 100644 --- a/common/block.c +++ b/common/block.c @@ -25,6 +25,8 @@ #define BLOCKSIZE(blk) (1 << blk->blockbits) +LIST_HEAD(block_device_list); + /* a chunk of contigous data */ struct chunk { void *data; /* data buffer */ @@ -367,6 +369,8 @@ int blockdevice_register(struct block_device *blk) if (ret) return ret; + list_add_tail(&blk->list, &block_device_list); + return 0; } @@ -387,6 +391,7 @@ int blockdevice_unregister(struct block_device *blk) } devfs_remove(&blk->cdev); + list_del(&blk->list); return 0; } diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c index 99f6d49c2..8218fcf2a 100644 --- a/fs/cramfs/cramfs.c +++ b/fs/cramfs/cramfs.c @@ -422,29 +422,33 @@ static int cramfs_probe(struct device_d *dev) { struct fs_device_d *fsdev; struct cramfs_priv *priv; + int ret; fsdev = dev_to_fs_device(dev); priv = xmalloc(sizeof(struct cramfs_priv)); dev->priv = priv; - if (strncmp(fsdev->backingstore, "/dev/", 5)) - return -ENODEV; + ret = fsdev_open_cdev(fsdev); + if (ret) + goto err_out; - priv->cdev = cdev_by_name(fsdev->backingstore + 5); - if (!priv->cdev) - return -ENODEV; + priv->cdev = fsdev->cdev; if (cramfs_read_super(priv)) { dev_info(dev, "no valid cramfs found\n"); - free(priv); - return -EINVAL; + ret = -EINVAL; } priv->curr_base = -1; cramfs_uncompress_init (); return 0; + +err_out: + free(priv); + + return ret; } static void cramfs_remove(struct device_d *dev) diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c index adc8f758e..69a7723b5 100644 --- a/fs/ext4/ext_barebox.c +++ b/fs/ext4/ext_barebox.c @@ -225,7 +225,6 @@ static int ext_readlink(struct device_d *dev, const char *pathname, static int ext_probe(struct device_d *dev) { struct fs_device_d *fsdev = dev_to_fs_device(dev); - char *backingstore = fsdev->backingstore; int ret; struct ext_filesystem *fs; @@ -234,14 +233,11 @@ static int ext_probe(struct device_d *dev) dev->priv = fs; fs->dev = dev; - if (!strncmp(backingstore , "/dev/", 5)) - backingstore += 5; - - fs->cdev = cdev_open(backingstore, O_RDWR); - if (!fs->cdev) { - ret = -ENOENT; + ret = fsdev_open_cdev(fsdev); + if (ret) goto err_open; - } + + fs->cdev = fsdev->cdev; ret = ext4fs_mount(fs); if (ret) @@ -250,7 +246,6 @@ static int ext_probe(struct device_d *dev) return 0; err_mount: - cdev_close(fs->cdev); err_open: free(fs); @@ -262,7 +257,6 @@ static void ext_remove(struct device_d *dev) struct ext_filesystem *fs = dev->priv; ext4fs_umount(fs); - cdev_close(fs->cdev); free(fs); } diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 15879c416..e65ef585a 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -373,19 +373,15 @@ static int fat_probe(struct device_d *dev) { struct fs_device_d *fsdev = dev_to_fs_device(dev); struct fat_priv *priv = xzalloc(sizeof(struct fat_priv)); - char *backingstore = fsdev->backingstore; int ret; dev->priv = priv; - if (!strncmp(backingstore , "/dev/", 5)) - backingstore += 5; - - priv->cdev = cdev_open(backingstore, O_RDWR); - if (!priv->cdev) { - ret = -ENOENT; + ret = fsdev_open_cdev(fsdev); + if (ret) goto err_open; - } + + priv->cdev = fsdev->cdev; priv->fat.userdata = priv; ret = f_mount(&priv->fat); @@ -395,7 +391,6 @@ static int fat_probe(struct device_d *dev) return 0; err_mount: - cdev_close(priv->cdev); err_open: free(priv); @@ -404,10 +399,6 @@ err_open: static void fat_remove(struct device_d *dev) { - struct fat_priv *priv = dev->priv; - - cdev_close(priv->cdev); - free(dev->priv); } diff --git a/fs/fs.c b/fs/fs.c index d913a503f..ce7b42554 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -32,6 +32,7 @@ #include #include #include +#include void *read_file(const char *filename, size_t *size) { @@ -1231,6 +1232,9 @@ static void fs_remove(struct device_d *dev) if (fsdev == fs_dev_root) fs_dev_root = NULL; + if (fsdev->cdev) + cdev_close(fsdev->cdev); + free(fsdev->backingstore); free(fsdev); } @@ -1266,10 +1270,7 @@ static const char *detect_fs(const char *filename) if (type == filetype_unknown) return NULL; - for_each_driver(drv) { - if (drv->bus != &fs_bus) - continue; - + bus_for_each_driver(&fs_bus, drv) { fdrv = drv_to_fs_driver(drv); if (type == fdrv->type) @@ -1279,6 +1280,23 @@ static const char *detect_fs(const char *filename) return NULL; } +int fsdev_open_cdev(struct fs_device_d *fsdev) +{ + const char *backingstore = fsdev->backingstore; + + if (!strncmp(backingstore , "/dev/", 5)) + backingstore += 5; + + fsdev->cdev = cdev_open(backingstore, O_RDWR); + if (!fsdev->cdev) + return -EINVAL; + + fsdev->dev.parent = fsdev->cdev->dev; + fsdev->parent_device = fsdev->cdev->dev; + + return 0; +} + /* * Mount a device to a directory. * We do this by registering a new device on which the filesystem @@ -1323,14 +1341,6 @@ int mount(const char *device, const char *fsname, const char *_path) fsdev->path = xstrdup(path); fsdev->dev.bus = &fs_bus; - if (!strncmp(device, "/dev/", 5)) - fsdev->cdev = cdev_by_name(device + 5); - - if (fsdev->cdev) { - fsdev->dev.parent = fsdev->cdev->dev; - fsdev->parent_device = fsdev->cdev->dev; - } - ret = register_device(&fsdev->dev); if (ret) goto err_register; @@ -1661,3 +1671,82 @@ ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, loff_t offse return size; } EXPORT_SYMBOL(mem_write); + +/* + * cdev_get_mount_path - return the path a cdev is mounted on + * + * If a cdev is mounted return the path it's mounted on, NULL + * otherwise. + */ +const char *cdev_get_mount_path(struct cdev *cdev) +{ + struct fs_device_d *fsdev; + + for_each_fs_device(fsdev) { + if (fsdev->cdev && fsdev->cdev == cdev) + return fsdev->path; + } + + return NULL; +} + +/* + * cdev_mount_default - mount a cdev to the default path + * + * If a cdev is already mounted return the path it's mounted on, otherwise + * mount it to /mnt/ and return the path. Returns an error pointer + * on failure. + */ +const char *cdev_mount_default(struct cdev *cdev) +{ + const char *path; + char *newpath, *devpath; + int ret; + + /* + * If this cdev is already mounted somewhere use this path + * instead of mounting it again to avoid corruption on the + * filesystem. + */ + path = cdev_get_mount_path(cdev); + if (path) + return path; + + newpath = asprintf("/mnt/%s", cdev->name); + make_directory(newpath); + + devpath = asprintf("/dev/%s", cdev->name); + + ret = mount(devpath, NULL, newpath); + + free(devpath); + + if (ret) { + free(newpath); + return ERR_PTR(ret); + } + + return cdev_get_mount_path(cdev); +} + +/* + * mount_all - iterate over block devices and mount all devices we are able to + */ +void mount_all(void) +{ + struct device_d *dev; + struct block_device *bdev; + + if (!IS_ENABLED(CONFIG_BLOCK)) + return; + + for_each_device(dev) + device_detect(dev); + + for_each_block_device(bdev) { + struct cdev *cdev = &bdev->cdev; + + list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list) + cdev_mount_default(cdev); + } +} diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index 9df8dc5cb..dfa610745 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -553,25 +553,22 @@ static int ubifs_probe(struct device_d *dev) { struct fs_device_d *fsdev = dev_to_fs_device(dev); struct ubifs_priv *priv = xzalloc(sizeof(struct ubifs_priv)); - char *backingstore = fsdev->backingstore; int ret; dev->priv = priv; - if (!strncmp(backingstore , "/dev/", 5)) - backingstore += 5; - - priv->cdev = cdev_open(backingstore, O_RDONLY); - if (!priv->cdev) { - ret = -ENOENT; + ret = fsdev_open_cdev(fsdev); + if (ret) goto err_free; - } + + priv->cdev = fsdev->cdev; priv->ubi = ubi_open_volume_cdev(priv->cdev, UBI_READONLY); if (IS_ERR(priv->ubi)) { dev_err(dev, "failed to open ubi volume: %s\n", strerror(-PTR_ERR(priv->ubi))); - return PTR_ERR(priv->ubi); + ret = PTR_ERR(priv->ubi); + goto err_free; } priv->sb = ubifs_get_super(priv->ubi, 0); @@ -596,7 +593,6 @@ static void ubifs_remove(struct device_d *dev) ubifs_umount(c); ubi_close_volume(priv->ubi); - cdev_close(priv->cdev); free(c); free(sb); diff --git a/include/block.h b/include/block.h index eb31aca4d..872a4c1bb 100644 --- a/include/block.h +++ b/include/block.h @@ -2,6 +2,7 @@ #define __BLOCK_H #include +#include struct block_device; @@ -14,6 +15,7 @@ struct chunk; struct block_device { struct device_d *dev; + struct list_head list; struct block_device_ops *ops; int blockbits; int num_blocks; @@ -26,6 +28,10 @@ struct block_device { struct cdev cdev; }; +extern struct list_head block_device_list; + +#define for_each_block_device(bdev) list_for_each_entry(bdev, &block_device_list, list) + int blockdevice_register(struct block_device *blk); int blockdevice_unregister(struct block_device *blk); diff --git a/include/fs.h b/include/fs.h index 22c07467d..99f168983 100644 --- a/include/fs.h +++ b/include/fs.h @@ -39,7 +39,6 @@ typedef struct filep { #define FS_DRIVER_NO_DEV 1 struct fs_driver_d { - char *name; int (*probe) (struct device_d *dev); int (*mkdir)(struct device_d *dev, const char *pathname); int (*rmdir)(struct device_d *dev, const char *pathname); @@ -88,6 +87,7 @@ struct fs_driver_d { extern struct list_head fs_device_list; #define for_each_fs_device(f) list_for_each_entry(f, &fs_device_list, list) +extern struct bus_type fs_bus; struct fs_device_d { char *backingstore; /* the device we are associated with */ @@ -193,4 +193,9 @@ void automount_print(void); int unlink_recursive(const char *path, char **failedpath); +int fsdev_open_cdev(struct fs_device_d *fsdev); +const char *cdev_get_mount_path(struct cdev *cdev); +const char *cdev_mount_default(struct cdev *cdev); +void mount_all(void); + #endif /* __FS_H */