summaryrefslogtreecommitdiffstats
path: root/bsps/arm/csb337/umon/tfsDriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/csb337/umon/tfsDriver.c')
-rw-r--r--bsps/arm/csb337/umon/tfsDriver.c683
1 files changed, 683 insertions, 0 deletions
diff --git a/bsps/arm/csb337/umon/tfsDriver.c b/bsps/arm/csb337/umon/tfsDriver.c
new file mode 100644
index 0000000000..01953469bb
--- /dev/null
+++ b/bsps/arm/csb337/umon/tfsDriver.c
@@ -0,0 +1,683 @@
+/*
+ * tfsDriver.c - MicroMonitor TFS Hookup to RTEMS FS
+ *
+ * Initial release: Oct 1, 2004 by Ed Sutter
+ *
+ * Modifications to support reference counting in the file system are
+ * Copyright (c) 2012 embedded brains GmbH.
+ *
+ * This code was derived from the tftpDriver.c code written by
+ * W. Eric Norum, which was apparently derived from the IMFS driver.
+ *
+ * This code was reformatted by Joel Sherrill from OAR Corporation and
+ * Fernando Nicodemos <fgnicodemos@terra.com.br> from NCB - Sistemas
+ * Embarcados Ltda. (Brazil) to be more compliant with RTEMS coding
+ * standards and to eliminate C++ style comments.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h>
+#include <rtems/seterr.h>
+#include <rtems/bspIo.h>
+#include <rtems/umon.h>
+
+#include <umon/tfs.h>
+#include <umon/monlib.h>
+
+#ifdef RTEMS_TFS_DRIVER_DEBUG
+#define RTEMS_TFS_DEBUG 1
+#else
+#define RTEMS_TFS_DEBUG 0
+#endif
+
+#define MAXFILESIZE 0x4000
+#define MAXTFDS 15
+
+/* Define these for thread safety...
+ */
+#ifndef newlib_tfdlock
+#define newlib_tfdlock()
+#endif
+
+#ifndef newlib_tfdunlock
+#define newlib_tfdunlock()
+#endif
+
+/* TFS file descriptor info:
+ */
+struct tfdinfo {
+ int inuse;
+ int tfd;
+ char *buf;
+ char name[TFSNAMESIZE+1];
+ char info[TFSNAMESIZE+1];
+} tfdtable[MAXTFDS];
+
+/*
+ * Pathname prefix
+ */
+char TFS_PATHNAME_PREFIX[128];
+
+static const rtems_filesystem_operations_table rtems_tfs_ops;
+static const rtems_filesystem_file_handlers_r rtems_tfs_handlers;
+
+static bool rtems_tfs_is_directory(
+ const char *path,
+ size_t pathlen
+)
+{
+ return path [pathlen - 1] == '/';
+}
+
+static int rtems_tfs_mount_me(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ const void *data
+)
+{
+ char *root_path = strdup("/");
+
+ if (root_path == NULL) {
+ rtems_set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ mt_entry->ops = &rtems_tfs_ops;
+ mt_entry->mt_fs_root->location.handlers = &rtems_tfs_handlers;
+ mt_entry->mt_fs_root->location.node_access = root_path;
+
+ return 0;
+}
+
+/* Initialize the TFS-RTEMS file system
+ */
+int rtems_initialize_tfs_filesystem(
+ const char *path
+)
+{
+ int status;
+
+ if (!path) {
+ printk( "TFS: No mount point specified\n" );
+ return -1;
+ }
+
+ strncpy( TFS_PATHNAME_PREFIX, path, sizeof(TFS_PATHNAME_PREFIX) );
+
+ status = mkdir( TFS_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
+ if ( status == -1 ) {
+ printk( "TFS: Unable to mkdir %s\n", TFS_PATHNAME_PREFIX );
+ return status;
+ }
+
+ if (rtems_filesystem_register( "tfs", rtems_tfs_mount_me ) < 0)
+ return -1;
+
+ status = mount( "umon", TFS_PATHNAME_PREFIX, "tfs", RTEMS_FILESYSTEM_READ_WRITE, NULL);
+
+ if (status < 0) {
+ printk( "TFS: Unable to mount on %s\n", TFS_PATHNAME_PREFIX );
+ perror("TFS mount failed");
+ }
+
+ return(status);
+}
+
+/*
+ * Convert a path to canonical form
+ */
+static void fixPath(char *path)
+{
+ char *inp, *outp, *base;
+
+ outp = inp = path;
+ base = NULL;
+ for (;;) {
+ if (inp[0] == '.') {
+ if (inp[1] == '\0')
+ break;
+ if (inp[1] == '/') {
+ inp += 2;
+ continue;
+ }
+ if (inp[1] == '.') {
+ if (inp[2] == '\0') {
+ if ((base != NULL) && (outp > base)) {
+ outp--;
+ while ((outp > base) && (outp[-1] != '/'))
+ outp--;
+ }
+ break;
+ }
+ if (inp[2] == '/') {
+ inp += 3;
+ if (base == NULL)
+ continue;
+ if (outp > base) {
+ outp--;
+ while ((outp > base) && (outp[-1] != '/'))
+ outp--;
+ }
+ continue;
+ }
+ }
+ }
+ if (base == NULL)
+ base = inp;
+ while (inp[0] != '/') {
+ if ((*outp++ = *inp++) == '\0')
+ return;
+ }
+ *outp++ = '/';
+ while (inp[0] == '/')
+ inp++;
+ }
+ *outp = '\0';
+}
+
+static void rtems_tfs_eval_path(rtems_filesystem_eval_path_context_t *self)
+{
+ int eval_flags = rtems_filesystem_eval_path_get_flags(self);
+
+ if ((eval_flags & RTEMS_FS_MAKE) == 0) {
+ int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE;
+
+ if ((eval_flags & rw) != rw) {
+ rtems_filesystem_location_info_t *currentloc =
+ rtems_filesystem_eval_path_get_currentloc(self);
+ char *current = currentloc->node_access;
+ size_t currentlen = strlen(current);
+ const char *path = rtems_filesystem_eval_path_get_path(self);
+ size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self);
+ size_t len = currentlen + pathlen;
+
+ rtems_filesystem_eval_path_clear_path(self);
+
+ current = realloc(current, len + 1);
+ if (current != NULL) {
+ memcpy(current + currentlen, path, pathlen);
+ current [len] = '\0';
+ if (!rtems_tfs_is_directory(current, len)) {
+ fixPath (current);
+ }
+ currentloc->node_access = current;
+ } else {
+ rtems_filesystem_eval_path_error(self, ENOMEM);
+ }
+ } else {
+ rtems_filesystem_eval_path_error(self, EINVAL);
+ }
+ } else {
+ rtems_filesystem_eval_path_error(self, EIO);
+ }
+}
+
+/*
+ * The routine which does most of the work for the IMFS open handler
+ * The full_path_name here is all text AFTER the TFS_PATHNAME_PREFIX
+ * string, so if the filename is "/TFS/abc", the full_path_name string
+ * is "abc"...
+ *
+ * Attempts to remap the incoming flags to TFS equivalent.
+ * Its not a perfect mapping, but gets pretty close.
+ * A comma-delimited path is supported to allow the user
+ * to specify TFS-stuff (flag string, info string, and a buffer).
+ * For example:
+ * abc,e,script,0x400000
+ * This is a file called "abc" that will have the TFS 'e' flag
+ * and the TFS info field of "script". The storage buffer is
+ * supplied by the user at 0x400000.
+ */
+static int rtems_tfs_open_worker(
+ rtems_libio_t *iop,
+ char *path,
+ int oflag,
+ mode_t mode
+)
+{
+ static int beenhere = 0;
+ long flagmode;
+ int tfdidx, tfd;
+ struct tfdinfo *tip;
+ char *buf, *fstr, *istr, *bstr, pathcopy[TFSNAMESIZE*3+1];
+
+ if (RTEMS_TFS_DEBUG)
+ printk("_open_r(%s,0x%x,0x%" PRIx32 ")\n",path,oflag,mode);
+
+ if (!beenhere) {
+ newlib_tfdlock();
+ for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++)
+ tfdtable[tfdidx].inuse = 0;
+
+ tfdtable[0].inuse = 1; /* fake entry for stdin */
+ tfdtable[1].inuse = 1; /* fake entry for stdout */
+ tfdtable[2].inuse = 1; /* fake entry for stderr */
+ newlib_tfdunlock();
+ beenhere = 1;
+ }
+
+ istr = fstr = bstr = buf = (char *)0;
+
+ /* Copy the incoming path to a local array so that we can safely
+ * modify the string...
+ */
+ if (strlen(path) > TFSNAMESIZE*3) {
+ return(ENAMETOOLONG);
+ }
+ strcpy(pathcopy,path);
+
+ /* The incoming string may have commas that are used to delimit the
+ * name from the TFS flag string, TFS info string and buffer.
+ * Check for the commas and test for maximum string length...
+ */
+ fstr = strchr(pathcopy,',');
+ if (fstr) {
+ *fstr++ = 0;
+ istr = strchr(fstr,',');
+ if (istr) {
+ *istr++ = 0;
+ bstr = strchr(istr,',');
+ if (bstr)
+ *bstr++ = 0;
+ }
+ }
+ if (strlen(pathcopy) > TFSNAMESIZE) {
+ return(ENAMETOOLONG);
+ }
+ if (istr) {
+ if (strlen(istr) > TFSNAMESIZE) {
+ return(ENAMETOOLONG);
+ }
+ }
+
+ /* If O_EXCL and O_CREAT are set, then fail if the file exists...
+ */
+ if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
+ if (mon_tfsstat((char *)pathcopy)) {
+ return(EEXIST);
+ }
+ }
+
+ /* Only a few flag combinations are supported...
+ * O_RDONLY Simple read-only
+ * O_WRONLY | O_APPEND Each write starts at end of file
+ * O_WRONLY | O_TRUNC If file exists, truncate it
+ * O_WRONLY | O_CREAT Create if it doesn't exist
+ * O_WRONLY | O_CREAT | O_EXCL Fail if file exists
+ */
+ switch(oflag & O_ACCMODE) {
+ case O_RDONLY:
+ flagmode = TFS_RDONLY;
+ break;
+ case O_WRONLY|O_APPEND:
+ flagmode = TFS_APPEND;
+ break;
+ case O_WRONLY|O_TRUNC:
+ case O_WRONLY|O_CREAT|O_TRUNC:
+ mon_tfsunlink((char *)pathcopy);
+ flagmode = TFS_CREATE|TFS_APPEND;
+ break;
+ case O_WRONLY|O_CREAT:
+ case O_WRONLY|O_CREAT|O_APPEND:
+ flagmode = TFS_CREATE|TFS_APPEND;
+ break;
+ case O_RDWR:
+ case O_WRONLY|O_CREAT|O_EXCL:
+ flagmode = TFS_CREATE|TFS_APPEND;
+ break;
+ default:
+ printk("_open_r(): flag 0x%i not supported\n",oflag);
+ return(ENOTSUP);
+ }
+
+ /* Find an open slot in our tfd table:
+ */
+ newlib_tfdlock();
+ for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++) {
+ if (tfdtable[tfdidx].inuse == 0)
+ break;
+ }
+ if (tfdidx == MAXTFDS) {
+ newlib_tfdunlock();
+ return(EMFILE);
+ }
+ tip = &tfdtable[tfdidx];
+ tip->inuse = 1;
+ newlib_tfdunlock();
+
+ /* If file is opened for something other than O_RDONLY, then
+ * we need to allocate a buffer for the file..
+ * WARNING: It is the user's responsibility to make sure that
+ * the file size does not exceed this buffer. Note that the
+ * buffer may be specified as part of the comma-delimited path.
+ */
+ if (flagmode == TFS_RDONLY) {
+ buf = (char *)0;
+ } else {
+ if (bstr)
+ buf = (char *)strtol(bstr,0,0);
+ else
+ buf = malloc(MAXFILESIZE);
+ if (!buf) {
+ newlib_tfdlock();
+ tip->inuse = 0;
+ newlib_tfdunlock();
+ return(ENOMEM);
+ }
+ }
+
+ /* Deal with tfs flags and tfs info fields if necessary:
+ */
+ if (fstr) {
+ long bflag;
+
+ bflag = mon_tfsctrl(TFS_FATOB,(long)fstr,0);
+ if (bflag == -1) {
+ return(EINVAL);
+ }
+ flagmode |= bflag;
+ }
+
+ if (istr)
+ strcpy(tip->info,istr);
+ else
+ tip->info[0] = 0;
+
+ tfd = mon_tfsopen((char *)pathcopy,flagmode,buf);
+ if (tfd >= 0) {
+ tip->tfd = tfd;
+ tip->buf = buf;
+ strcpy(tip->name,pathcopy);
+ iop->data0 = (uint32_t)tfdidx;
+ return(0);
+ } else {
+ printk("%s: %s\n",pathcopy,
+ (char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
+ }
+
+ if (buf)
+ free(buf);
+
+ newlib_tfdlock();
+ tip->inuse = 0;
+ newlib_tfdunlock();
+ return(EINVAL);
+}
+
+/*
+ * The IMFS open handler
+ */
+static int rtems_tfs_open(
+ rtems_libio_t *iop,
+ const char *new_name,
+ int oflag,
+ mode_t mode
+)
+{
+ char *full_path_name;
+ int err;
+
+ full_path_name = iop->pathinfo.node_access;
+
+ if (RTEMS_TFS_DEBUG)
+ printk("rtems_tfs_open(%s)\n",full_path_name);
+
+ if (rtems_tfs_is_directory(full_path_name, strlen(full_path_name))) {
+ rtems_set_errno_and_return_minus_one (ENOTSUP);
+ }
+
+ err = rtems_tfs_open_worker (iop, full_path_name, oflag, mode);
+ if (err != 0) {
+ rtems_set_errno_and_return_minus_one (err);
+ }
+
+ return err;
+}
+
+/*
+ * Read from an open TFS file...
+ */
+static ssize_t rtems_tfs_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ size_t count
+)
+{
+ int ret, fd;
+
+ fd = (int) iop->data0;
+
+ if (RTEMS_TFS_DEBUG)
+ printk("_read_r(%d,%zi)\n",fd,count);
+
+ if ((fd < 3) || (fd >= MAXTFDS))
+ return(EBADF);
+
+ ret = mon_tfsread(tfdtable[fd].tfd,buffer,count);
+ if (ret == TFSERR_EOF)
+ ret = 0;
+
+ return(ret);
+}
+
+/*
+ * Close the open tfs file.
+ */
+static int rtems_tfs_close(
+ rtems_libio_t *iop
+)
+{
+ int fd;
+ char *info;
+ struct tfdinfo *tip;
+
+ fd = (int)iop->data0;
+
+ if (RTEMS_TFS_DEBUG)
+ printk("rtems_tfs_close(%d)\n",fd);
+
+ if ((fd < 3) || (fd >= MAXTFDS)) {
+ rtems_set_errno_and_return_minus_one (EBADF);
+ }
+
+ tip = &tfdtable[fd];
+
+ if (tip->info[0])
+ info = tip->info;
+ else
+ info = (char *)0;
+
+ mon_tfsclose(tip->tfd,info);
+
+ if (tip->buf)
+ free(tip->buf);
+
+ newlib_tfdlock();
+ tip->inuse = 0;
+ newlib_tfdunlock();
+ return RTEMS_SUCCESSFUL;
+}
+
+static ssize_t rtems_tfs_write(
+ rtems_libio_t *iop,
+ const void *buffer,
+ size_t count
+)
+{
+ int ret, fd;
+
+ fd = (int) iop->data0;
+
+ if (RTEMS_TFS_DEBUG)
+ printk("rtems_tfs_write(%d,%zi)\n",fd,count);
+
+ if ((fd <= 0) || (fd >= MAXTFDS)) {
+ rtems_set_errno_and_return_minus_one (EBADF);
+ }
+
+ ret = mon_tfswrite(tfdtable[fd].tfd,(char *)buffer,count);
+ if (ret < 0)
+ return(-1);
+
+ return(ret);
+}
+
+static off_t rtems_tfs_lseek(
+ rtems_libio_t *iop,
+ off_t offset,
+ int whence
+)
+{
+ int ret, fd;
+
+ fd = (int) iop->data0;
+
+ if (RTEMS_TFS_DEBUG)
+ printk("rtems_tfs_lseek(%d,%ld,%d)\n",fd,(long)offset,whence);
+
+ switch (whence) {
+ case SEEK_END:
+ printk("rtems_tfs_lseek doesn't support SEEK_END\n");
+ return(-1);
+ case SEEK_CUR:
+ whence = TFS_CURRENT;
+ break;
+ case SEEK_SET:
+ whence = TFS_BEGIN;
+ break;
+ }
+ ret = mon_tfsseek(tfdtable[fd].tfd,offset,whence);
+
+ if (ret < 0)
+ return(-1);
+
+ return (off_t)ret;
+}
+
+/*
+ *
+ */
+static int rtems_tfs_ftruncate(
+ rtems_libio_t *iop,
+ off_t count
+)
+{
+ int ret, fd;
+
+ fd = (int) iop->data0;
+ ret = mon_tfstruncate(tfdtable[fd].tfd,count);
+ if (ret != TFS_OKAY)
+ return(-1);
+
+ return(0);
+}
+
+static int rtems_tfs_ioctl(
+ rtems_libio_t *iop,
+ uint32_t cmd,
+ void *buf
+)
+{
+ int ret;
+
+ ret = mon_tfsctrl(cmd,(long)buf,0);
+ if (ret != TFS_OKAY)
+ return(-1);
+
+ return(0);
+}
+
+static int rtems_tfs_fstat(
+ const rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+)
+{
+ const char *path = loc->node_access;
+ size_t pathlen = strlen(path);
+
+ buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO
+ | (rtems_tfs_is_directory(path, pathlen) ? S_IFDIR : S_IFREG);
+
+ return 0;
+}
+
+static int rtems_tfs_clone_node_info(
+ rtems_filesystem_location_info_t *loc
+)
+{
+ int rv = 0;
+
+ loc->node_access = strdup(loc->node_access);
+
+ if (loc->node_access == NULL) {
+ errno = ENOMEM;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+static void rtems_tfs_free_node_info(
+ const rtems_filesystem_location_info_t *loc
+)
+{
+ free(loc->node_access);
+}
+
+static bool rtems_tfs_are_nodes_equal(
+ const rtems_filesystem_location_info_t *a,
+ const rtems_filesystem_location_info_t *b
+)
+{
+ return strcmp(a->node_access, b->node_access) == 0;
+}
+
+static const rtems_filesystem_operations_table rtems_tfs_ops = {
+ .lock_h = rtems_filesystem_default_lock,
+ .unlock_h = rtems_filesystem_default_unlock,
+ .eval_path_h = rtems_tfs_eval_path,
+ .link_h = rtems_filesystem_default_link,
+ .are_nodes_equal_h = rtems_tfs_are_nodes_equal,
+ .mknod_h = rtems_filesystem_default_mknod,
+ .rmnod_h = rtems_filesystem_default_rmnod,
+ .fchmod_h = rtems_filesystem_default_fchmod,
+ .chown_h = rtems_filesystem_default_chown,
+ .clonenod_h = rtems_tfs_clone_node_info,
+ .freenod_h = rtems_tfs_free_node_info,
+ .mount_h = rtems_filesystem_default_mount,
+ .unmount_h = rtems_filesystem_default_unmount,
+ .fsunmount_me_h = rtems_filesystem_default_fsunmount,
+ .utime_h = rtems_filesystem_default_utime,
+ .symlink_h = rtems_filesystem_default_symlink,
+ .readlink_h = rtems_filesystem_default_readlink,
+ .rename_h = rtems_filesystem_default_rename,
+ .statvfs_h = rtems_filesystem_default_statvfs
+};
+
+static const rtems_filesystem_file_handlers_r rtems_tfs_handlers = {
+ .open_h = rtems_tfs_open,
+ .close_h = rtems_tfs_close,
+ .read_h = rtems_tfs_read,
+ .write_h = rtems_tfs_write,
+ .ioctl_h = rtems_tfs_ioctl,
+ .lseek_h = rtems_tfs_lseek,
+ .fstat_h = rtems_tfs_fstat,
+ .ftruncate_h = rtems_tfs_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fcntl_h = rtems_filesystem_default_fcntl,
+ .kqfilter_h = rtems_filesystem_default_kqfilter,
+ .poll_h = rtems_filesystem_default_poll,
+ .readv_h = rtems_filesystem_default_readv,
+ .writev_h = rtems_filesystem_default_writev
+};