source: rtems/c/src/lib/libbsp/shared/umon/tfsDriver.c @ 508632a

4.115
Last change on this file since 508632a was 508632a, checked in by Sebastian Huber <sebastian.huber@…>, on 07/27/10 at 10:18:22

2010-07-27 Sebastian Huber <sebastian.huber@…>

  • umon/tfsDriver.c: Update for LibIO API changes.
  • Property mode set to 100644
File size: 17.4 KB
Line 
1/*
2 *  tfsDriver.c - MicroMonitor TFS Hookup to RTEMS FS
3 *
4 *  Initial release: Oct 1, 2004   by Ed Sutter
5 *
6 *  This code was derived from the tftpDriver.c code written by
7 *  W. Eric Norum, which was apparently derived from the IMFS driver.
8 *
9 *  This code was reformatted by Joel Sherrill from OAR Corporation and
10 *  Fernando Nicodemos <fgnicodemos@terra.com.br> from NCB - Sistemas
11 *  Embarcados Ltda. (Brazil) to be more compliant with RTEMS coding
12 *  standards and to eliminate C++ style comments.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.com/license/LICENSE.
17 *
18 *  $Id$
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <inttypes.h>
28#include <rtems.h>
29#include <rtems/libio.h>
30#include <rtems/libio_.h>
31#include <rtems/seterr.h>
32#include <rtems/bspIo.h>
33
34#include <umon/tfs.h>
35#include <umon/monlib.h>
36
37#ifdef RTEMS_TFS_DRIVER_DEBUG
38#define RTEMS_TFS_DEBUG 1
39#else
40#define RTEMS_TFS_DEBUG 0
41#endif
42
43#define MAXFILESIZE 0x4000
44#define MAXTFDS  15
45
46/* Define these for thread safety...
47 */
48#ifndef newlib_tfdlock
49#define newlib_tfdlock()
50#endif
51
52#ifndef newlib_tfdunlock
53#define newlib_tfdunlock()
54#endif
55
56/* TFS file descriptor info:
57 */
58struct tfdinfo {
59  int   inuse;
60  int   tfd;
61  char *buf;
62  char  name[TFSNAMESIZE+1];
63  char  info[TFSNAMESIZE+1];
64} tfdtable[MAXTFDS];
65
66/*
67 * Pathname prefix
68 */
69char TFS_PATHNAME_PREFIX[128];
70
71/*
72 * Root node_access value
73 * By using the address of a local static variable
74 * we ensure a unique value for this identifier.
75 */
76#define ROOT_NODE_ACCESS    (&tfs_mutex)
77
78/* Number of streams open at the same time
79 */
80static rtems_id tfs_mutex;
81
82extern rtems_filesystem_operations_table  rtems_tfs_ops;
83extern rtems_filesystem_file_handlers_r   rtems_tfs_handlers;
84
85/* Direct copy from the IMFS.  Look at this.
86 */
87
88rtems_filesystem_limits_and_options_t rtems_tfs_limits_and_options = {
89  5,   /* link_max */
90  6,   /* max_canon */
91  7,   /* max_input */
92  255, /* name_max */
93  255, /* path_max */
94  2,   /* pipe_buf */
95  1,   /* posix_async_io */
96  2,   /* posix_chown_restrictions */
97  3,   /* posix_no_trunc */
98  4,   /* posix_prio_io */
99  5,   /* posix_sync_io */
100  6    /* posix_vdisable */
101};
102
103static int rtems_tfs_mount_me(
104  rtems_filesystem_mount_table_entry_t *mt_entry,
105  const void                           *data
106)
107{
108  rtems_status_code  sc;
109
110  mt_entry->mt_fs_root.handlers = &rtems_tfs_handlers;
111  mt_entry->mt_fs_root.ops      = &rtems_tfs_ops;
112
113  /* We have no TFS specific data to maintain.  This filesystem
114   * may only be mounted once. And we maintain no real filesystem
115   * nodes, so there is no real root.
116   */
117
118  mt_entry->fs_info                = NULL;
119  mt_entry->mt_fs_root.node_access = ROOT_NODE_ACCESS;
120
121  /* These need to be looked at for full POSIX semantics.
122   */
123
124  mt_entry->pathconf_limits_and_options = rtems_tfs_limits_and_options;
125
126
127  /*  Now allocate a semaphore for mutual exclusion.
128   *  NOTE:  This could be in an fsinfo for this filesystem type.
129   */
130
131  sc = rtems_semaphore_create (
132    rtems_build_name('U', 'M', 'O', 'N'),
133    1,
134    RTEMS_FIFO |
135      RTEMS_BINARY_SEMAPHORE |
136      RTEMS_NO_INHERIT_PRIORITY |
137      RTEMS_NO_PRIORITY_CEILING |
138      RTEMS_LOCAL,
139    0,
140    &tfs_mutex);
141
142  if (sc != RTEMS_SUCCESSFUL)
143    rtems_set_errno_and_return_minus_one( ENOMEM );
144
145  return 0;
146}
147
148/* Initialize the TFS-RTEMS file system
149 */
150int rtems_initialize_tfs_filesystem(
151  const char *path
152)
153{
154  int status;
155
156  if (!path) {
157    printk( "TFS: No mount point specified\n" );
158    return -1;
159  }
160
161  strncpy( TFS_PATHNAME_PREFIX, path, sizeof(TFS_PATHNAME_PREFIX) );
162
163  status = mkdir( TFS_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
164  if ( status == -1 ) {
165    printk( "TFS: Unable to mkdir %s\n", TFS_PATHNAME_PREFIX );
166    return status;
167  }
168
169  if (rtems_filesystem_register( "tfs", rtems_tfs_mount_me ) < 0)
170    return -1;
171 
172  status = mount( "umon", TFS_PATHNAME_PREFIX, "tfs", RTEMS_FILESYSTEM_READ_WRITE, NULL);
173
174  if (status < 0) {
175    printk( "TFS: Unable to mount on %s\n", TFS_PATHNAME_PREFIX );
176    perror("TFS mount failed");
177  }
178
179  return(status);
180}
181
182static int rtems_tfs_evaluate_for_make(
183  const char                         *path,
184  rtems_filesystem_location_info_t   *pathloc,
185  const char                        **name
186)
187{
188  pathloc->node_access = NULL;
189  rtems_set_errno_and_return_minus_one( EIO );
190}
191
192/*
193 * Convert a path to canonical form
194 */
195static void fixPath(char *path)
196{
197  char *inp, *outp, *base;
198
199  outp = inp = path;
200  base = NULL;
201  for (;;) {
202    if (inp[0] == '.') {
203      if (inp[1] == '\0')
204          break;
205      if (inp[1] == '/') {
206          inp += 2;
207          continue;
208      }
209      if (inp[1] == '.') {
210        if (inp[2] == '\0') {
211          if ((base != NULL) && (outp > base)) {
212            outp--;
213            while ((outp > base) && (outp[-1] != '/'))
214              outp--;
215          }
216          break;
217        }
218        if (inp[2] == '/') {
219          inp += 3;
220          if (base == NULL)
221            continue;
222          if (outp > base) {
223            outp--;
224            while ((outp > base) && (outp[-1] != '/'))
225              outp--;
226          }
227          continue;
228        }
229      }
230    }
231    if (base == NULL)
232      base = inp;
233    while (inp[0] != '/') {
234      if ((*outp++ = *inp++) == '\0')
235        return;
236    }
237    *outp++ = '/';
238    while (inp[0] == '/')
239      inp++;
240  }
241  *outp = '\0';
242}
243
244static int rtems_tfs_eval_path(
245  const char                        *pathname,
246  size_t                             pathnamelen,
247  int                                flags,
248  rtems_filesystem_location_info_t  *pathloc
249)
250{
251  pathloc->handlers    = &rtems_tfs_handlers;
252
253  /*
254   * Hack to provide the illusion of directories inside the TFS file system.
255   * Paths ending in a / are assumed to be directories.
256   */
257  if (pathname[strlen(pathname)-1] == '/') {
258    int isRelative = (pathloc->node_access != ROOT_NODE_ACCESS);
259    char *cp;
260
261    /*
262     * Reject attempts to open() directories
263     */
264    if (flags & RTEMS_LIBIO_PERMS_RDWR)
265      rtems_set_errno_and_return_minus_one( EISDIR );
266    if (isRelative) {
267      cp = malloc (strlen(pathloc->node_access)+strlen(pathname)+1);
268      if (cp == NULL)
269        rtems_set_errno_and_return_minus_one( ENOMEM );
270      strcpy (cp, pathloc->node_access);
271      strcat (cp, pathname);
272    } else {
273      cp = strdup (pathname);
274      if (cp == NULL)
275        rtems_set_errno_and_return_minus_one( ENOMEM );
276    }
277    fixPath (cp);
278    pathloc->node_access = cp;
279    return 0;
280  }
281  if (pathloc->node_access != ROOT_NODE_ACCESS)
282    pathloc->node_access = 0;
283
284  /*
285   * Reject it if it's not read-only or write-only.
286   */
287  flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;
288  if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
289    rtems_set_errno_and_return_minus_one( EINVAL );
290  return 0;
291}
292
293/*
294 * The routine which does most of the work for the IMFS open handler
295 * The full_path_name here is all text AFTER the TFS_PATHNAME_PREFIX
296 * string, so if the filename is "/TFS/abc", the full_path_name string
297 * is "abc"...
298 *
299 * Attempts to remap the incoming flags to TFS equivalent.
300 * Its not a perfect mapping, but gets pretty close.
301 * A comma-delimited path is supported to allow the user
302 * to specify TFS-stuff (flag string, info string, and a buffer).
303 * For example:
304 *  abc,e,script,0x400000
305 *  This is a file called "abc" that will have the TFS 'e' flag
306 *  and the TFS info field of "script".  The storage buffer is
307 *  supplied by the user at 0x400000.
308 */
309static int rtems_tfs_open_worker(
310  rtems_libio_t *iop,
311  char          *path,
312  uint32_t       flags,
313  uint32_t       mode
314)
315{
316  static int beenhere = 0;
317  long flagmode;
318  int  tfdidx, tfd;
319  struct tfdinfo *tip;
320  char *buf, *fstr, *istr, *bstr, pathcopy[TFSNAMESIZE*3+1];
321
322  if (RTEMS_TFS_DEBUG)
323    printk("_open_r(%s,0x%" PRIx32 ",0x%" PRIx32 ")\n",path,flags,mode);
324
325  if (!beenhere) {
326    newlib_tfdlock();
327    for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++)
328      tfdtable[tfdidx].inuse = 0;
329
330    tfdtable[0].inuse = 1;    /* fake entry for stdin */
331    tfdtable[1].inuse = 1;    /* fake entry for stdout */
332    tfdtable[2].inuse = 1;    /* fake entry for stderr */
333    newlib_tfdunlock();
334    beenhere = 1;
335  }
336
337  istr = fstr = bstr = buf = (char *)0;
338
339  /* Copy the incoming path to a local array so that we can safely
340   * modify the string...
341    */
342  if (strlen(path) > TFSNAMESIZE*3) {
343    return(ENAMETOOLONG);
344  }
345  strcpy(pathcopy,path);
346
347  /* The incoming string may have commas that are used to delimit the
348   * name from the TFS flag string, TFS info string and buffer.
349   * Check for the commas and test for maximum string length...
350   */
351  fstr = strchr(pathcopy,',');
352  if (fstr)  {
353    *fstr++ = 0;
354    istr = strchr(fstr,',');
355    if (istr) {
356      *istr++ = 0;
357      bstr = strchr(istr,',');
358      if (bstr)
359        *bstr++ = 0;
360    }
361  }
362  if (strlen(pathcopy) > TFSNAMESIZE) {
363    return(ENAMETOOLONG);
364  }
365  if (istr) {
366    if (strlen(istr) > TFSNAMESIZE) {
367      return(ENAMETOOLONG);
368    }
369  }
370
371  /* If O_EXCL and O_CREAT are set, then fail if the file exists...
372   */
373  if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
374    if (mon_tfsstat((char *)pathcopy)) {
375      return(EEXIST);
376    }
377  }
378
379  /* Only a few flag combinations are supported...
380   * O_RDONLY             Simple read-only
381   * O_WRONLY | O_APPEND       Each write starts at end of file
382   * O_WRONLY | O_TRUNC       If file exists, truncate it
383   * O_WRONLY | O_CREAT       Create if it doesn't exist
384   * O_WRONLY | O_CREAT | O_EXCL   Fail if file exists
385   */
386  switch(flags & O_ACCMODE) {
387    case O_RDONLY:
388      flagmode = TFS_RDONLY;
389      break;
390    case O_WRONLY|O_APPEND:
391      flagmode = TFS_APPEND;
392      break;
393    case O_WRONLY|O_TRUNC:
394    case O_WRONLY|O_CREAT|O_TRUNC:
395      mon_tfsunlink((char *)pathcopy);
396      flagmode = TFS_CREATE|TFS_APPEND;
397      break;
398    case O_WRONLY|O_CREAT:
399    case O_WRONLY|O_CREAT|O_APPEND:
400      flagmode = TFS_CREATE|TFS_APPEND;
401      break;
402    case O_RDWR:
403    case O_WRONLY|O_CREAT|O_EXCL:
404      flagmode = TFS_CREATE|TFS_APPEND;
405      break;
406    default:
407      printk("_open_r(): flag 0x%" PRIx32 " not supported\n",flags);
408      return(ENOTSUP);
409  }
410
411  /* Find an open slot in our tfd table:
412   */
413  newlib_tfdlock();
414  for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++) {
415    if (tfdtable[tfdidx].inuse == 0)
416      break;
417  }
418  if (tfdidx == MAXTFDS) {
419    newlib_tfdunlock();
420    return(EMFILE);
421  }
422  tip = &tfdtable[tfdidx];
423  tip->inuse = 1;
424  newlib_tfdunlock();
425
426  /* If file is opened for something other than O_RDONLY, then
427   * we need to allocate a buffer for the file..
428   * WARNING: It is the user's responsibility to make sure that
429   * the file size does not exceed this buffer.  Note that the
430   * buffer may be specified as part of the comma-delimited path.
431   */
432  if (flagmode == TFS_RDONLY) {
433    buf = (char *)0;
434  } else {
435    if (bstr)
436      buf = (char *)strtol(bstr,0,0);
437    else
438      buf = malloc(MAXFILESIZE);
439    if (!buf) {
440      newlib_tfdlock();
441      tip->inuse = 0;
442      newlib_tfdunlock();
443      return(ENOMEM);
444    }
445  }
446
447  /* Deal with tfs flags and tfs info fields if necessary:
448   */
449  if (fstr) {
450    long bflag;
451
452    bflag = mon_tfsctrl(TFS_FATOB,(long)fstr,0);
453    if (bflag == -1) {
454      return(EINVAL);
455    }
456    flagmode |= bflag;
457  }
458
459  if (istr)
460    strcpy(tip->info,istr);
461  else
462    tip->info[0] = 0;
463
464  tfd = mon_tfsopen((char *)pathcopy,flagmode,buf);
465  if (tfd >= 0) {
466    tip->tfd = tfd;
467    tip->buf = buf;
468    strcpy(tip->name,pathcopy);
469    iop->data0 = (void *)tfdidx;
470    return(0);
471  } else {
472    printk("%s: %s\n",pathcopy,
473      (char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
474  }
475
476  if (buf)
477    free(buf);
478
479  newlib_tfdlock();
480  tip->inuse = 0;
481  newlib_tfdunlock();
482  return(EINVAL);
483}
484
485/*
486 * The IMFS open handler
487 */
488static int rtems_tfs_open(
489  rtems_libio_t *iop,
490  const char    *new_name,
491  uint32_t       flags,
492  uint32_t       mode
493)
494{
495  char *full_path_name;
496  char *s1;
497  int err;
498
499  if (RTEMS_TFS_DEBUG)
500    printk("rtems_tfs_open(%s)\n",new_name);
501
502  /*
503   * Tack the `current directory' on to relative paths.
504   * We know that the current directory ends in a / character.
505   */
506  if (*new_name == '/') {
507    /*
508     * Skip the TFS filesystem prefix.
509     */
510    int len = strlen (TFS_PATHNAME_PREFIX);
511    if (strncmp (new_name, TFS_PATHNAME_PREFIX, len))
512      return ENOENT;
513    new_name += len;
514    s1 = "";
515  } else {
516    s1 = rtems_filesystem_current.node_access;
517  }
518  full_path_name = malloc (strlen (s1) + strlen (new_name) + 1);
519  if (full_path_name == NULL)
520    return ENOMEM;
521  strcpy (full_path_name, s1);
522  strcat (full_path_name, new_name);
523  fixPath (full_path_name);
524  err = rtems_tfs_open_worker (iop, full_path_name, flags, mode);
525  free (full_path_name);
526  return err;
527}
528
529/*
530 * Read from an open TFS file...
531 */
532static ssize_t rtems_tfs_read(
533  rtems_libio_t *iop,
534  void          *buffer,
535  uint32_t       count
536)
537{
538  int  ret, fd;
539
540  fd = (int) iop->data0;
541
542  if (RTEMS_TFS_DEBUG)
543    printk("_read_r(%d,%" PRId32 ")\n",fd,count);
544
545  if ((fd < 3) || (fd >= MAXTFDS))
546    return(EBADF);
547
548  ret = mon_tfsread(tfdtable[fd].tfd,buffer,count);
549  if (ret == TFSERR_EOF)
550    ret = 0;
551
552  return(ret);
553}
554
555/*
556 * Close the open tfs file.
557 */
558static int rtems_tfs_close(
559  rtems_libio_t *iop
560)
561{
562  int  fd;
563  char *info;
564  struct tfdinfo *tip;
565
566  fd = (int)iop->data0;
567
568  if (RTEMS_TFS_DEBUG)
569    printk("rtems_tfs_close(%d)\n",fd);
570
571  if ((fd < 3) || (fd >= MAXTFDS)) {
572    rtems_set_errno_and_return_minus_one (EBADF);
573  }
574
575  tip = &tfdtable[fd];
576
577  if (tip->info[0])
578    info = tip->info;
579  else
580    info = (char *)0;
581
582  mon_tfsclose(tip->tfd,info);
583
584  if (tip->buf)
585    free(tip->buf);
586
587  newlib_tfdlock();
588  tip->inuse = 0;
589  newlib_tfdunlock();
590  return RTEMS_SUCCESSFUL;
591}
592
593static ssize_t rtems_tfs_write(
594  rtems_libio_t *iop,
595  const void    *buffer,
596  uint32_t       count
597)
598{
599  int  ret, fd;
600
601  fd = (int) iop->data0;
602
603  if (RTEMS_TFS_DEBUG)
604    printk("rtems_tfs_write(%d,%" PRId32" )\n",fd,count);
605
606  if ((fd <= 0) || (fd >= MAXTFDS)) {
607    rtems_set_errno_and_return_minus_one (EBADF);
608  }
609
610  ret = mon_tfswrite(tfdtable[fd].tfd,(char *)buffer,count);
611  if (ret < 0)
612    return(-1);
613
614  return(ret);
615}
616
617static rtems_off64_t rtems_tfs_lseek(
618  rtems_libio_t *iop,
619  rtems_off64_t  offset,
620  int            whence
621)
622{
623  int ret, fd;
624
625  fd = (int) iop->data0;
626
627  if (RTEMS_TFS_DEBUG)
628    printk("rtems_tfs_lseek(%d,%ld,%d)\n",fd,(long)offset,whence);
629
630  switch (whence) {
631    case SEEK_END:
632      printk("rtems_tfs_lseek doesn't support SEEK_END\n");
633      return(-1);
634    case SEEK_CUR:
635      whence = TFS_CURRENT;
636      break;
637    case SEEK_SET:
638      whence = TFS_BEGIN;
639      break;
640  }
641  ret = mon_tfsseek(tfdtable[fd].tfd,offset,whence);
642
643  if (ret < 0)
644    return(-1);
645
646  return (rtems_off64_t)ret;
647}
648
649/*
650 *
651 */
652static int rtems_tfs_ftruncate(
653  rtems_libio_t *iop,
654  rtems_off64_t  count
655)
656{
657  int ret, fd;
658
659  fd = (int) iop->data0;
660  ret = mon_tfstruncate(tfdtable[fd].tfd,count);
661  if (ret != TFS_OKAY)
662    return(-1);
663
664  return(0);
665}
666
667static int rtems_tfs_ioctl(
668  rtems_libio_t *iop,
669  uint32_t       cmd,
670  void          *buf
671)
672{
673  int  fd, ret;
674
675  fd = (int) iop->data0;
676  ret = mon_tfsctrl(cmd,(long)buf,0);
677  return(-1);
678}
679
680static rtems_filesystem_node_types_t rtems_tfs_node_type(
681  rtems_filesystem_location_info_t *pathloc
682)
683{
684  if ((pathloc->node_access == NULL) ||
685      (pathloc->node_access == ROOT_NODE_ACCESS))
686    return RTEMS_FILESYSTEM_MEMORY_FILE;
687  return RTEMS_FILESYSTEM_DIRECTORY;
688}
689
690static int rtems_tfs_free_node_info(
691
692rtems_filesystem_location_info_t *pathloc)
693{
694  if (pathloc->node_access && (pathloc->node_access != ROOT_NODE_ACCESS)) {
695    free (pathloc->node_access);
696    pathloc->node_access = NULL;
697  }
698  return 0;
699}
700
701
702rtems_filesystem_operations_table  rtems_tfs_ops = {
703  rtems_tfs_eval_path,                    /* eval_path */
704  rtems_tfs_evaluate_for_make,            /* evaluate_for_make */
705  rtems_filesystem_default_link,          /* link */
706  rtems_filesystem_default_unlink,        /* unlink */
707  rtems_tfs_node_type,                    /* node_type */
708  rtems_filesystem_default_mknod,         /* mknod */
709  rtems_filesystem_default_chown,         /* chown */
710  rtems_tfs_free_node_info,               /* freenodinfo */
711  rtems_filesystem_default_mount,         /* mount */
712  rtems_tfs_mount_me,                     /* initialize */
713  rtems_filesystem_default_unmount,       /* unmount */
714  rtems_filesystem_default_fsunmount,     /* fsunmount */
715  rtems_filesystem_default_utime,         /* utime */
716  rtems_filesystem_default_evaluate_link, /* evaluate_link */
717  rtems_filesystem_default_symlink,       /* symlink */
718  rtems_filesystem_default_readlink,      /* readlin */
719  rtems_filesystem_default_rename,        /* rename */
720  rtems_filesystem_default_statvfs        /* statvfs */
721};
722
723rtems_filesystem_file_handlers_r rtems_tfs_handlers = {
724  rtems_tfs_open,                     /* open */
725  rtems_tfs_close,                    /* close */
726  rtems_tfs_read,                     /* read */
727  rtems_tfs_write,                    /* write */
728  rtems_tfs_ioctl,                    /* ioctl */
729  rtems_tfs_lseek,                    /* lseek */
730  rtems_filesystem_default_fstat,     /* fstat */
731  rtems_filesystem_default_fchmod,    /* fchmod */
732  rtems_tfs_ftruncate,                /* ftruncate */
733  rtems_filesystem_default_fpathconf, /* fpathconf */
734  rtems_filesystem_default_fsync,     /* fsync */
735  rtems_filesystem_default_fdatasync, /* fdatasync */
736  rtems_filesystem_default_fcntl,     /* fcntl */
737  rtems_filesystem_default_rmnod      /* rmnod */
738};
Note: See TracBrowser for help on using the repository browser.