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

4.104.11
Last change on this file since ba6f12b7 was ba6f12b7, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 12, 2009 at 5:20:42 PM

2009-06-12 Joel Sherrill <joel.sherrill@…>

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