9
0
Fork 0

Merge branch 'work/automount' into next

This commit is contained in:
Sascha Hauer 2012-03-20 14:15:14 +01:00
commit 62f9b9d623
12 changed files with 371 additions and 118 deletions

View File

@ -181,6 +181,16 @@ config CMD_NANDTEST
select PARTITION_NEED_MTD
prompt "nandtest"
config CMD_AUTOMOUNT
tristate
select FS_AUTOMOUNT
prompt "automount"
help
automount allows it to automatically execute a script when a certain
directory is accessed for the first time. The script should then make
this directory available (discover USB devices, bring network interface
up and finally mount the filesystem).
endmenu
menu "console "

View File

@ -64,3 +64,4 @@ obj-$(CONFIG_CMD_OFTREE) += oftree.o
obj-$(CONFIG_CMD_MAGICVAR) += magicvar.o
obj-$(CONFIG_CMD_IOMEM) += iomem.o
obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o
obj-$(CONFIG_CMD_AUTOMOUNT) += automount.o

66
commands/automount.c Normal file
View File

@ -0,0 +1,66 @@
/*
* automount.c - automount devices
*
* Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation.
*/
#include <common.h>
#include <command.h>
#include <fs.h>
#include <errno.h>
#include <getopt.h>
static int do_automount(int argc, char *argv[])
{
int opt, ret;
while ((opt = getopt(argc, argv, "lr:")) > 0) {
switch (opt) {
case 'l':
automount_print();
return 0;
case 'r':
automount_remove(optarg);
return 0;
}
}
if (argc != 3)
return COMMAND_ERROR_USAGE;
ret = automount_add(argv[1], argv[2]);
if (ret)
printf("adding automountpoint failed: %s\n",
strerror(-ret));
return ret ? 1 : 0;
}
BAREBOX_CMD_HELP_START(automount)
BAREBOX_CMD_HELP_USAGE("automount [OPTIONS] <PATH> <cmd>\n")
BAREBOX_CMD_HELP_SHORT("execute <cmd> when <PATH> is first accessed\n")
BAREBOX_CMD_HELP_OPT("-l", "List currently registered automountpoints\n")
BAREBOX_CMD_HELP_OPT("-r <PATH>", "remove an automountpoint\n")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(automount)
.cmd = do_automount,
.usage = "automount [OPTIONS] <PATH> <cmd>\n",
BAREBOX_CMD_HELP(cmd_automount_help)
BAREBOX_CMD_END

View File

@ -33,14 +33,14 @@
static int do_mount(int argc, char *argv[])
{
int ret = 0;
struct mtab_entry *entry;
struct fs_device_d *fsdev;
if (argc == 1) {
for_each_mtab_entry(entry) {
for_each_fs_device(fsdev) {
printf("%s on %s type %s\n",
entry->parent_device ? dev_name(entry->parent_device) : "none",
entry->path,
entry->dev->name);
fsdev->parent_device ? dev_name(fsdev->parent_device) : "none",
fsdev->path,
fsdev->dev.name);
}
return 0;
}

View File

@ -40,16 +40,19 @@
#include <fs.h>
#include <linux/stat.h>
#include <libgen.h>
#include <getopt.h>
#define SIZE_REMAINING ((ulong)-1)
#define PART_ADD_DEVNAME (1 << 0)
static int mtd_part_do_parse_one(char *devname, const char *partstr,
char **endp, unsigned long *offset,
off_t devsize, size_t *retsize)
off_t devsize, size_t *retsize, unsigned int pflags)
{
ulong size;
char *end;
char buf[PATH_MAX];
char buf[PATH_MAX] = {};
unsigned long flags = 0;
int ret;
@ -78,7 +81,8 @@ static int mtd_part_do_parse_one(char *devname, const char *partstr,
return -EINVAL;
}
sprintf(buf, "%s.", devname);
if (pflags & PART_ADD_DEVNAME)
sprintf(buf, "%s.", devname);
memcpy(buf + strlen(buf), partstr, end - partstr);
end++;
@ -114,24 +118,35 @@ static int do_addpart(int argc, char *argv[])
unsigned long offset = 0;
off_t devsize;
struct stat s;
int opt;
unsigned int flags = PART_ADD_DEVNAME;
if (argc != 3)
while ((opt = getopt(argc, argv, "n")) > 0) {
switch (opt) {
case 'n':
flags &= ~PART_ADD_DEVNAME;
break;
}
}
if (argc != optind + 2)
return COMMAND_ERROR_USAGE;
if (stat(argv[1], &s)) {
if (stat(argv[optind], &s)) {
perror("addpart");
return 1;
}
devsize = s.st_size;
devname = basename(argv[1]);
devname = basename(argv[optind]);
endp = argv[2];
endp = argv[optind + 1];
while (1) {
size_t size = 0;
if (mtd_part_do_parse_one(devname, endp, &endp, &offset, devsize, &size))
if (mtd_part_do_parse_one(devname, endp, &endp, &offset,
devsize, &size, flags))
return 1;
offset += size;
@ -152,6 +167,8 @@ static int do_addpart(int argc, char *argv[])
BAREBOX_CMD_HELP_START(addpart)
BAREBOX_CMD_HELP_USAGE("addpart <device> <part_desc>\n")
BAREBOX_CMD_HELP_SHORT("Add a partition description to a device.\n")
BAREBOX_CMD_HELP_OPT ("-n", "no prefix. Do not prepend the device name as prefix before the partition name\n")
BAREBOX_CMD_HELP_OPT ("<device>", "device being worked on\n")
BAREBOX_CMD_HELP_OPT ("<device>", "device being worked on\n")
BAREBOX_CMD_HELP_OPT ("<part_desc>", "size1[@offset1](name1)[ro],size2[@offset2](name2)[ro],...\n")
BAREBOX_CMD_HELP_END

View File

@ -22,17 +22,35 @@
#include <common.h>
#include <command.h>
#include <usb/usb.h>
#include <getopt.h>
static int scanned;
static int do_usb(int argc, char *argv[])
{
usb_rescan();
int opt;
while ((opt = getopt(argc, argv, "f")) > 0) {
switch (opt) {
case 'f':
scanned = 0;
break;
}
}
if (!scanned) {
usb_rescan();
scanned = 1;
}
return 0;
}
static const __maybe_unused char cmd_usb_help[] =
"Usage: usb\n"
"(re-)detect USB devices\n";
BAREBOX_CMD_HELP_START(usb)
BAREBOX_CMD_HELP_USAGE("usb [-f]\n")
BAREBOX_CMD_HELP_SHORT("Scan for USB devices.\n")
BAREBOX_CMD_HELP_OPT("-f", "force. Rescan if if if have scanned once\n")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(usb)
.cmd = do_usb,

View File

@ -1678,10 +1678,25 @@ BAREBOX_CMD_END
static int do_source(int argc, char *argv[])
{
char *path;
int ret;
if (argc < 2)
return COMMAND_ERROR_USAGE;
return source_script(argv[1], argc - 1, argv + 1);
if (strchr(argv[1], '/')) {
path = xstrdup(argv[1]);
} else {
path = find_execable(argv[1]);
if (!path)
return 1;
}
ret = source_script(path, argc - 1, argv + 1);
free(path);
return ret;
}
static const char *source_aliases[] = { ".", NULL};

View File

@ -1,6 +1,9 @@
menu "Filesystem support "
config FS_AUTOMOUNT
bool
config FS_CRAMFS
bool
select ZLIB

View File

@ -376,6 +376,7 @@ 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;
@ -383,13 +384,24 @@ static int fat_probe(struct device_d *dev)
backingstore += 5;
priv->cdev = cdev_open(backingstore, O_RDWR);
if (!priv->cdev)
return -EINVAL;
if (!priv->cdev) {
ret = -ENOENT;
goto err_open;
}
priv->fat.userdata = priv;
f_mount(&priv->fat);
ret = f_mount(&priv->fat);
if (ret)
goto err_mount;
return 0;
err_mount:
cdev_close(priv->cdev);
err_open:
free(priv);
return ret;
}
static void fat_remove(struct device_d *dev)

View File

@ -1699,9 +1699,7 @@ int f_mount (
{
fs->fs_type = 0; /* Clear new fs object */
chk_mounted(fs, 0);
return 0;
return chk_mounted(fs, 0);
}
/*

282
fs/fs.c
View File

@ -167,21 +167,21 @@ char *normalise_path(const char *pathname)
}
EXPORT_SYMBOL(normalise_path);
LIST_HEAD(mtab_list);
static struct mtab_entry *mtab_root;
LIST_HEAD(fs_device_list);
static struct fs_device_d *fs_dev_root;
static struct mtab_entry *get_mtab_entry_by_path(const char *path)
static struct fs_device_d *get_fsdevice_by_path(const char *path)
{
struct mtab_entry *e = NULL;
struct fs_device_d *fsdev = NULL;
for_each_mtab_entry(e) {
int len = strlen(e->path);
if (!strncmp(path, e->path, len) &&
for_each_fs_device(fsdev) {
int len = strlen(fsdev->path);
if (!strncmp(path, fsdev->path, len) &&
(path[len] == '/' || path[len] == 0))
return e;
return fsdev;
}
return mtab_root;
return fs_dev_root;
}
static FILE files[MAX_FILES];
@ -216,20 +216,134 @@ static int check_fd(int fd)
return 0;
}
static struct device_d *get_fs_device_by_path(char **path)
#ifdef CONFIG_FS_AUTOMOUNT
#define AUTOMOUNT_IS_FILE (1 << 0)
struct automount {
char *path;
char *cmd;
struct list_head list;
unsigned int flags;
};
static LIST_HEAD(automount_list);
void automount_remove(const char *_path)
{
struct device_d *dev;
struct mtab_entry *e;
char *path = normalise_path(_path);
struct automount *am;
e = get_mtab_entry_by_path(*path);
if (!e)
list_for_each_entry(am, &automount_list, list) {
if (!strcmp(path, am->path))
goto found;
}
return;
found:
list_del(&am->list);
free(am->path);
free(am->cmd);
free(am);
}
EXPORT_SYMBOL(automount_remove);
int automount_add(const char *path, const char *cmd)
{
struct automount *am = xzalloc(sizeof(*am));
struct stat s;
int ret;
am->path = normalise_path(path);
am->cmd = xstrdup(cmd);
ret = stat(path, &s);
if (!ret) {
/*
* If it exists it must be a directory
*/
if (!S_ISDIR(s.st_mode))
return -ENOTDIR;
} else {
am->flags |= AUTOMOUNT_IS_FILE;
}
list_add_tail(&am->list, &automount_list);
return 0;
}
EXPORT_SYMBOL(automount_add);
void automount_print(void)
{
struct automount *am;
list_for_each_entry(am, &automount_list, list)
printf("%-20s %s\n", am->path, am->cmd);
}
EXPORT_SYMBOL(automount_print);
static void automount_mount(const char *path, int instat)
{
struct automount *am;
int ret;
list_for_each_entry(am, &automount_list, list) {
char *cmd;
int len_path = strlen(path);
int len_am_path = strlen(am->path);
/*
* stat is a bit special. We do not want to trigger
* automount when someone calls stat() on the automount
* directory itself.
*/
if (instat && !(am->flags & AUTOMOUNT_IS_FILE) &&
len_path == len_am_path) {
continue;
}
if (len_path < len_am_path)
continue;
if (strncmp(path, am->path, len_am_path))
continue;
if (*(path + len_am_path) != 0 && *(path + len_am_path) != '/')
continue;
cmd = asprintf("%s %s", am->cmd, am->path);
ret = run_command(cmd, 0);
free(cmd);
if (ret)
printf("running automount command '%s' failed\n",
am->cmd);
else
automount_remove(am->path);
return;
}
}
#else
static void automount_mount(const char *path, int instat)
{
}
#endif /* CONFIG_FS_AUTOMOUNT */
static struct fs_device_d *get_fs_device_and_root_path(char **path)
{
struct fs_device_d *fsdev;
automount_mount(*path, 0);
fsdev = get_fsdevice_by_path(*path);
if (!fsdev)
return NULL;
if (e != mtab_root)
*path += strlen(e->path);
if (fsdev != fs_dev_root)
*path += strlen(fsdev->path);
dev = e->dev;
return dev;
return fsdev;
}
static int dir_is_empty(const char *pathname)
@ -336,7 +450,7 @@ EXPORT_SYMBOL(chdir);
int unlink(const char *pathname)
{
struct device_d *dev;
struct fs_device_d *fsdev;
struct fs_driver_d *fsdrv;
char *p = normalise_path(pathname);
char *freep = p;
@ -344,17 +458,17 @@ int unlink(const char *pathname)
if (path_check_prereq(pathname, S_IFREG))
goto out;
dev = get_fs_device_by_path(&p);
if (!dev)
fsdev = get_fs_device_and_root_path(&p);
if (!fsdev)
goto out;
fsdrv = dev_to_fs_driver(dev);
fsdrv = fsdev->driver;
if (!fsdrv->unlink) {
errno = -ENOSYS;
goto out;
}
errno = fsdrv->unlink(dev, p);
errno = fsdrv->unlink(&fsdev->dev, p);
out:
free(freep);
return errno;
@ -363,23 +477,23 @@ EXPORT_SYMBOL(unlink);
int open(const char *pathname, int flags, ...)
{
struct device_d *dev;
struct fs_device_d *fsdev;
struct fs_driver_d *fsdrv;
FILE *f;
int exist;
int exist_err;
struct stat s;
char *path = normalise_path(pathname);
char *freep = path;
exist = (stat(path, &s) == 0) ? 1 : 0;
exist_err = stat(path, &s);
if (exist && S_ISDIR(s.st_mode)) {
if (!exist_err && S_ISDIR(s.st_mode)) {
errno = -EISDIR;
goto out1;
}
if (!exist && !(flags & O_CREAT)) {
errno = -ENOENT;
if (exist_err && !(flags & O_CREAT)) {
errno = exist_err;
goto out1;
}
@ -389,13 +503,13 @@ int open(const char *pathname, int flags, ...)
goto out1;
}
dev = get_fs_device_by_path(&path);
if (!dev)
fsdev = get_fs_device_and_root_path(&path);
if (!fsdev)
goto out;
fsdrv = dev_to_fs_driver(dev);
fsdrv = fsdev->driver;
f->dev = dev;
f->dev = &fsdev->dev;
f->flags = flags;
if ((flags & O_ACCMODE) && !fsdrv->write) {
@ -403,22 +517,22 @@ int open(const char *pathname, int flags, ...)
goto out;
}
if (!exist) {
if (exist_err) {
if (NULL != fsdrv->create)
errno = fsdrv->create(dev, path,
errno = fsdrv->create(&fsdev->dev, path,
S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
else
errno = -EROFS;
if (errno)
goto out;
}
errno = fsdrv->open(dev, f, path);
errno = fsdrv->open(&fsdev->dev, f, path);
if (errno)
goto out;
if (flags & O_TRUNC) {
errno = fsdrv->truncate(dev, f, 0);
errno = fsdrv->truncate(&fsdev->dev, f, 0);
f->size = 0;
if (errno)
goto out;
@ -705,7 +819,7 @@ static int fs_match(struct device_d *dev, struct driver_d *drv)
static int fs_probe(struct device_d *dev)
{
struct fs_device_d *fsdev = dev_to_fs_device(dev);
struct mtab_entry *entry = &fsdev->mtab;
struct fs_driver_d *fsdrv = dev_to_fs_driver(dev);
int ret;
ret = dev->driver->probe(dev);
@ -714,15 +828,15 @@ static int fs_probe(struct device_d *dev)
if (fsdev->cdev) {
dev_add_child(fsdev->cdev->dev, &fsdev->dev);
entry->parent_device = fsdev->cdev->dev;
fsdev->parent_device = fsdev->cdev->dev;
}
entry->dev = &fsdev->dev;
fsdev->driver = fsdrv;
list_add_tail(&entry->list, &mtab_list);
list_add_tail(&fsdev->list, &fs_device_list);
if (!mtab_root)
mtab_root = entry;
if (!fs_dev_root)
fs_dev_root = fsdev;
return 0;
}
@ -730,17 +844,16 @@ static int fs_probe(struct device_d *dev)
static void fs_remove(struct device_d *dev)
{
struct fs_device_d *fsdev = dev_to_fs_device(dev);
struct mtab_entry *entry = &fsdev->mtab;
if (fsdev->dev.driver) {
dev->driver->remove(dev);
list_del(&entry->list);
list_del(&fsdev->list);
}
free(entry->path);
free(fsdev->path);
if (entry == mtab_root)
mtab_root = NULL;
if (fsdev == fs_dev_root)
fs_dev_root = NULL;
free(fsdev->backingstore);
free(fsdev);
@ -777,10 +890,9 @@ int mount(const char *device, const char *fsname, const char *_path)
debug("mount: %s on %s type %s\n", device, path, fsname);
if (mtab_root) {
struct mtab_entry *entry;
entry = get_mtab_entry_by_path(path);
if (entry != mtab_root) {
if (fs_dev_root) {
fsdev = get_fsdevice_by_path(path);
if (fsdev != fs_dev_root) {
printf("sorry, no nested mounts\n");
errno = -EBUSY;
goto err_free_path;
@ -799,7 +911,7 @@ int mount(const char *device, const char *fsname, const char *_path)
fsdev->backingstore = xstrdup(device);
safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME);
fsdev->dev.id = get_free_deviceid(fsdev->dev.name);
fsdev->mtab.path = xstrdup(path);
fsdev->path = xstrdup(path);
fsdev->dev.bus = &fs_bus;
if (!strncmp(device, "/dev/", 5))
@ -836,29 +948,29 @@ EXPORT_SYMBOL(mount);
int umount(const char *pathname)
{
struct mtab_entry *entry = NULL, *e;
struct fs_device_d *fsdev = NULL, *f;
char *p = normalise_path(pathname);
for_each_mtab_entry(e) {
if (!strcmp(p, e->path)) {
entry = e;
for_each_fs_device(f) {
if (!strcmp(p, f->path)) {
fsdev = f;
break;
}
}
free(p);
if (e == mtab_root && !list_is_singular(&mtab_list)) {
if (f == fs_dev_root && !list_is_singular(&fs_device_list)) {
errno = -EBUSY;
return errno;
}
if (!entry) {
if (!fsdev) {
errno = -EFAULT;
return errno;
}
unregister_device(entry->dev);
unregister_device(&fsdev->dev);
return 0;
}
@ -867,7 +979,7 @@ EXPORT_SYMBOL(umount);
DIR *opendir(const char *pathname)
{
DIR *dir = NULL;
struct device_d *dev;
struct fs_device_d *fsdev;
struct fs_driver_d *fsdrv;
char *p = normalise_path(pathname);
char *freep = p;
@ -875,16 +987,16 @@ DIR *opendir(const char *pathname)
if (path_check_prereq(pathname, S_IFDIR))
goto out;
dev = get_fs_device_by_path(&p);
if (!dev)
fsdev = get_fs_device_and_root_path(&p);
if (!fsdev)
goto out;
fsdrv = dev_to_fs_driver(dev);
fsdrv = fsdev->driver;
debug("opendir: fsdrv: %p\n",fsdrv);
dir = fsdrv->opendir(dev, p);
dir = fsdrv->opendir(&fsdev->dev, p);
if (dir) {
dir->dev = dev;
dir->dev = &fsdev->dev;
dir->fsdrv = fsdrv;
}
@ -918,23 +1030,25 @@ int stat(const char *filename, struct stat *s)
{
struct device_d *dev;
struct fs_driver_d *fsdrv;
struct mtab_entry *e;
struct fs_device_d *fsdev;
char *f = normalise_path(filename);
char *freep = f;
automount_mount(f, 1);
memset(s, 0, sizeof(struct stat));
e = get_mtab_entry_by_path(f);
if (!e) {
fsdev = get_fsdevice_by_path(f);
if (!fsdev) {
errno = -ENOENT;
goto out;
}
if (e != mtab_root && strcmp(f, e->path)) {
f += strlen(e->path);
dev = e->dev;
if (fsdev != fs_dev_root && strcmp(f, fsdev->path)) {
f += strlen(fsdev->path);
dev = &fsdev->dev;
} else
dev = mtab_root->dev;
dev = &fs_dev_root->dev;
fsdrv = dev_to_fs_driver(dev);
@ -951,20 +1065,20 @@ EXPORT_SYMBOL(stat);
int mkdir (const char *pathname, mode_t mode)
{
struct fs_driver_d *fsdrv;
struct device_d *dev;
struct fs_device_d *fsdev;
char *p = normalise_path(pathname);
char *freep = p;
if (path_check_prereq(pathname, S_UB_DOES_NOT_EXIST))
goto out;
dev = get_fs_device_by_path(&p);
if (!dev)
fsdev = get_fs_device_and_root_path(&p);
if (!fsdev)
goto out;
fsdrv = dev_to_fs_driver(dev);
fsdrv = fsdev->driver;
if (fsdrv->mkdir) {
errno = fsdrv->mkdir(dev, p);
errno = fsdrv->mkdir(&fsdev->dev, p);
goto out;
}
@ -978,20 +1092,20 @@ EXPORT_SYMBOL(mkdir);
int rmdir (const char *pathname)
{
struct fs_driver_d *fsdrv;
struct device_d *dev;
struct fs_device_d *fsdev;
char *p = normalise_path(pathname);
char *freep = p;
if (path_check_prereq(pathname, S_IFDIR | S_UB_IS_EMPTY))
goto out;
dev = get_fs_device_by_path(&p);
if (!dev)
fsdev = get_fs_device_and_root_path(&p);
if (!fsdev)
goto out;
fsdrv = dev_to_fs_driver(dev);
fsdrv = fsdev->driver;
if (fsdrv->rmdir) {
errno = fsdrv->rmdir(dev, p);
errno = fsdrv->rmdir(&fsdev->dev, p);
goto out;
}

View File

@ -77,15 +77,8 @@ struct fs_driver_d {
#define dev_to_fs_driver(d) container_of(d->driver, struct fs_driver_d, drv)
#define dev_to_fs_device(d) container_of(d, struct fs_device_d, dev)
struct mtab_entry {
char *path;
struct device_d *dev;
struct device_d *parent_device;
struct list_head list;
};
extern struct list_head mtab_list;
#define for_each_mtab_entry(e) list_for_each_entry(e, &mtab_list, list)
extern struct list_head fs_device_list;
#define for_each_fs_device(f) list_for_each_entry(f, &fs_device_list, list)
struct fs_device_d {
char *backingstore; /* the device we are associated with */
@ -94,7 +87,9 @@ struct fs_device_d {
struct fs_driver_d *driver;
struct cdev *cdev;
struct mtab_entry mtab;
char *path;
struct device_d *parent_device;
struct list_head list;
};
/*
@ -165,4 +160,8 @@ char *normalise_path(const char *path);
/* Register a new filesystem driver */
int register_fs_driver(struct fs_driver_d *fsdrv);
void automount_remove(const char *_path);
int automount_add(const char *path, const char *cmd);
void automount_print(void);
#endif /* __FS_H */