diff --git a/drivers/bch/bchdev_driver.c b/drivers/bch/bchdev_driver.c index 577128b039d..198cd334b38 100644 --- a/drivers/bch/bchdev_driver.c +++ b/drivers/bch/bchdev_driver.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/bch/bchdev_driver.c * - * Copyright (C) 2008-2009, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2009, 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without diff --git a/fs/driver/Make.defs b/fs/driver/Make.defs index 7cf8c344b3f..e280ea1580a 100644 --- a/fs/driver/Make.defs +++ b/fs/driver/Make.defs @@ -41,10 +41,13 @@ CSRCS += fs_registerdriver.c fs_unregisterdriver.c # Don't build-in block driver support if there are no mountpoints - ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) CSRCS += fs_registerblockdriver.c fs_unregisterblockdriver.c CSRCS += fs_findblockdriver.c fs_openblockdriver.c fs_closeblockdriver.c + +ifneq ($(CONFIG_DISABLE_PSEUDOFS_OPERATIONS),y) +CSRCS += fs_blockproxy.c +endif endif # System logging to a character device (or file) diff --git a/fs/driver/fs_blockproxy.c b/fs/driver/fs_blockproxy.c new file mode 100644 index 00000000000..73e72857959 --- /dev/null +++ b/fs/driver/fs_blockproxy.c @@ -0,0 +1,246 @@ +/**************************************************************************** + * fs/driver/fs_blockproxy.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(CONFIG_DISABLE_PSEUDOFS_OPERATIONS) && \ + !defined(CONFIG_DISABLE_MOUNTPOINT) + +/**************************************************************************** + * Pre-processor oDefinitions + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint32_t g_devno; +static sem_t g_devno_sem = SEM_INITIALIZER(1); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: unique_chardev + * + * Description: + * Create a unique temporary device name in the /dev/ directory of the + * psuedo-file system. We cannot use mktemp for this because it will + * attempt to open() the file. + * + * Input parameters: + * None + * + * Returned Value: + * The allocated path to the device. This must be released by the caller + * to prevent memory links. NULL will be returned only the case where + * we fail to allocate memory. + * + ****************************************************************************/ + +static FAR char *unique_chardev(void) +{ + struct stat statbuf; + char devbuf[16]; + uint32_t devno; + int ret; + + /* Loop until we get a unique device name */ + + for (; ; ) + { + /* Get the semaphore protecting the path number */ + + while (sem_wait(&g_devno_sem) < 0) + { + DEBUGASSERT(errno == EINTR); + } + + /* Get the next device number and release the semaphore */ + + devno = ++g_devno; + sem_post(&g_devno_sem); + + /* Construct the full device number */ + + devno &= 0xffffff; + snprintf(devbuf, 16, "/dev/tmp%06lx", (unsigned long)devno); + + /* Make sure that file name is not in use */ + + ret = stat(devbuf, &statbuf); + if (ret < 0) + { + DEBUGASSERT(errno == ENOENT); + return strdup(devbuf); + } + + /* It is in use, try again */ + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: block_proxy + * + * Description: + * Create a temporary char driver using drivers/bch that mediate character + * oriented accessed to the block driver. + * + * Input parameters: + * blkdev - The path to the block driver + * mode - Character driver access priviledges + * + * Returned Value: + * If positive, non-zero file descriptor is returned on success. This + * is the file descriptor of the nameless character driver that mediates + * accesses to the block driver. + * + * Errors that may be returned: + * + * ENOMEM - Failed to create a temporay path name. + * + * Plus: + * + * - Errors reported from bchdev_register() + * - Errors reported from open() or unlink() + * + ****************************************************************************/ + +int block_proxy(FAR const char *blkdev, mode_t mode) +{ + FAR char *chardev; + bool readonly; + int ret; + int fd; + + DEBUGASSERT(blkdev); + DEBUGASSERT((mode & (O_CREAT | O_EXCL | O_APPEND | O_TRUNC)) == 0); + + /* Create a unique temporary file name for the character device */ + + chardev = unique_chardev(); + if (chardev == NULL) + { + fdbg("ERROR: Failed to create temporary device name\n"); + return -ENOMEM; + } + + /* Should this character driver be read-only? */ + + readonly = ((mode & O_WROK) == 0); + + /* Wrap the block driver with an instance of the BCH driver */ + + ret = bchdev_register(blkdev, chardev, readonly); + if (ret < 0) + { + fdbg("ERROR: bchdev_register(%s, %s) failed: %d\n", + blkdev, chardev, ret); + + goto errout_with_chardev; + } + + /* Open the newly created character driver */ + + mode &= ~(O_CREAT | O_EXCL | O_APPEND | O_TRUNC); + fd = open(chardev, mode); + if (fd < 0) + { + ret = -errno; + fdbg("ERROR: Failed to open %s: %d\n", chardev, ret); + goto errout_with_bchdev; + } + + /* Unlink the character device name. The driver instance will persist, + * provided that CONFIG_DISABLE_PSEUDOFS_OPERATIONS=y (otherwise, we have + * a problem here!) + */ + + ret = unlink(chardev); + if (ret < 0) + { + ret = -errno; + fdbg("ERROR: Failed to unlink %s: %d\n", chardev, ret); + } + + /* Free the allocate character driver name and return the open file + * descriptor. + */ + + kmm_free(chardev); + return fd; + +errout_with_bchdev: + (void)unlink(chardev); + +errout_with_chardev: + kmm_free(chardev); + return ret; +} + +#endif /* !CONFIG_DISABLE_PSEUDOFS_OPERATIONS && !CONFIG_DISABLE_MOUNTPOINT */