source: rtems/c/src/lib/libbsp/shared/umon/tfsDriver.c @ 3b18c26

4.115
Last change on this file since 3b18c26 was 3b18c26, checked in by Wendell Silva <silvawp@…>, on 02/11/12 at 19:35:53

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