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

5
Last change on this file since 504a5822 was 504a5822, checked in by Sebastian Huber <sebastian.huber@…>, on 03/07/17 at 13:53:15

bsps/umon: Fix format warnings

  • Property mode set to 100644
File size: 15.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 *  Modifications to support reference counting in the file system are
7 *  Copyright (c) 2012 embedded brains GmbH.
8 *
9 *  This code was derived from the tftpDriver.c code written by
10 *  W. Eric Norum, which was apparently derived from the IMFS driver.
11 *
12 *  This code was reformatted by Joel Sherrill from OAR Corporation and
13 *  Fernando Nicodemos <fgnicodemos@terra.com.br> from NCB - Sistemas
14 *  Embarcados Ltda. (Brazil) to be more compliant with RTEMS coding
15 *  standards and to eliminate C++ style comments.
16 *
17 *  The license and distribution terms for this file may be
18 *  found in the file LICENSE in this distribution or at
19 *  http://www.rtems.org/license/LICENSE.
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <inttypes.h>
29#include <rtems.h>
30#include <rtems/libio.h>
31#include <rtems/libio_.h>
32#include <rtems/seterr.h>
33#include <rtems/bspIo.h>
34#include <rtems/umon.h>
35
36#include <umon/tfs.h>
37#include <umon/monlib.h>
38
39#ifdef RTEMS_TFS_DRIVER_DEBUG
40#define RTEMS_TFS_DEBUG 1
41#else
42#define RTEMS_TFS_DEBUG 0
43#endif
44
45#define MAXFILESIZE 0x4000
46#define MAXTFDS  15
47
48/* Define these for thread safety...
49 */
50#ifndef newlib_tfdlock
51#define newlib_tfdlock()
52#endif
53
54#ifndef newlib_tfdunlock
55#define newlib_tfdunlock()
56#endif
57
58/* TFS file descriptor info:
59 */
60struct tfdinfo {
61  int   inuse;
62  int   tfd;
63  char *buf;
64  char  name[TFSNAMESIZE+1];
65  char  info[TFSNAMESIZE+1];
66} tfdtable[MAXTFDS];
67
68/*
69 * Pathname prefix
70 */
71char TFS_PATHNAME_PREFIX[128];
72
73static const rtems_filesystem_operations_table  rtems_tfs_ops;
74static const rtems_filesystem_file_handlers_r   rtems_tfs_handlers;
75
76static bool rtems_tfs_is_directory(
77    const char *path,
78    size_t pathlen
79)
80{
81    return path [pathlen - 1] == '/';
82}
83
84static int rtems_tfs_mount_me(
85  rtems_filesystem_mount_table_entry_t *mt_entry,
86  const void                           *data
87)
88{
89  char *root_path = strdup("/");
90
91  if (root_path == NULL) {
92    rtems_set_errno_and_return_minus_one(ENOMEM);
93  }
94
95  mt_entry->ops = &rtems_tfs_ops;
96  mt_entry->mt_fs_root->location.handlers = &rtems_tfs_handlers;
97  mt_entry->mt_fs_root->location.node_access = root_path;
98
99  return 0;
100}
101
102/* Initialize the TFS-RTEMS file system
103 */
104int rtems_initialize_tfs_filesystem(
105  const char *path
106)
107{
108  int status;
109
110  if (!path) {
111    printk( "TFS: No mount point specified\n" );
112    return -1;
113  }
114
115  strncpy( TFS_PATHNAME_PREFIX, path, sizeof(TFS_PATHNAME_PREFIX) );
116
117  status = mkdir( TFS_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
118  if ( status == -1 ) {
119    printk( "TFS: Unable to mkdir %s\n", TFS_PATHNAME_PREFIX );
120    return status;
121  }
122
123  if (rtems_filesystem_register( "tfs", rtems_tfs_mount_me ) < 0)
124    return -1;
125
126  status = mount( "umon", TFS_PATHNAME_PREFIX, "tfs", RTEMS_FILESYSTEM_READ_WRITE, NULL);
127
128  if (status < 0) {
129    printk( "TFS: Unable to mount on %s\n", TFS_PATHNAME_PREFIX );
130    perror("TFS mount failed");
131  }
132
133  return(status);
134}
135
136/*
137 * Convert a path to canonical form
138 */
139static void fixPath(char *path)
140{
141  char *inp, *outp, *base;
142
143  outp = inp = path;
144  base = NULL;
145  for (;;) {
146    if (inp[0] == '.') {
147      if (inp[1] == '\0')
148          break;
149      if (inp[1] == '/') {
150          inp += 2;
151          continue;
152      }
153      if (inp[1] == '.') {
154        if (inp[2] == '\0') {
155          if ((base != NULL) && (outp > base)) {
156            outp--;
157            while ((outp > base) && (outp[-1] != '/'))
158              outp--;
159          }
160          break;
161        }
162        if (inp[2] == '/') {
163          inp += 3;
164          if (base == NULL)
165            continue;
166          if (outp > base) {
167            outp--;
168            while ((outp > base) && (outp[-1] != '/'))
169              outp--;
170          }
171          continue;
172        }
173      }
174    }
175    if (base == NULL)
176      base = inp;
177    while (inp[0] != '/') {
178      if ((*outp++ = *inp++) == '\0')
179        return;
180    }
181    *outp++ = '/';
182    while (inp[0] == '/')
183      inp++;
184  }
185  *outp = '\0';
186}
187
188static void rtems_tfs_eval_path(rtems_filesystem_eval_path_context_t *self)
189{
190  int eval_flags = rtems_filesystem_eval_path_get_flags(self);
191
192  if ((eval_flags & RTEMS_FS_MAKE) == 0) {
193    int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE;
194
195    if ((eval_flags & rw) != rw) {
196      rtems_filesystem_location_info_t *currentloc =
197        rtems_filesystem_eval_path_get_currentloc(self);
198      char *current = currentloc->node_access;
199      size_t currentlen = strlen(current);
200      const char *path = rtems_filesystem_eval_path_get_path(self);
201      size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self);
202      size_t len = currentlen + pathlen;
203
204      rtems_filesystem_eval_path_clear_path(self);
205
206      current = realloc(current, len + 1);
207      if (current != NULL) {
208        memcpy(current + currentlen, path, pathlen);
209        current [len] = '\0';
210        if (!rtems_tfs_is_directory(current, len)) {
211          fixPath (current);
212        }
213        currentloc->node_access = current;
214      } else {
215        rtems_filesystem_eval_path_error(self, ENOMEM);
216      }
217    } else {
218      rtems_filesystem_eval_path_error(self, EINVAL);
219    }
220  } else {
221    rtems_filesystem_eval_path_error(self, EIO);
222  }
223}
224
225/*
226 * The routine which does most of the work for the IMFS open handler
227 * The full_path_name here is all text AFTER the TFS_PATHNAME_PREFIX
228 * string, so if the filename is "/TFS/abc", the full_path_name string
229 * is "abc"...
230 *
231 * Attempts to remap the incoming flags to TFS equivalent.
232 * Its not a perfect mapping, but gets pretty close.
233 * A comma-delimited path is supported to allow the user
234 * to specify TFS-stuff (flag string, info string, and a buffer).
235 * For example:
236 *  abc,e,script,0x400000
237 *  This is a file called "abc" that will have the TFS 'e' flag
238 *  and the TFS info field of "script".  The storage buffer is
239 *  supplied by the user at 0x400000.
240 */
241static int rtems_tfs_open_worker(
242  rtems_libio_t *iop,
243  char          *path,
244  int            oflag,
245  mode_t         mode
246)
247{
248  static int beenhere = 0;
249  long flagmode;
250  int  tfdidx, tfd;
251  struct tfdinfo *tip;
252  char *buf, *fstr, *istr, *bstr, pathcopy[TFSNAMESIZE*3+1];
253
254  if (RTEMS_TFS_DEBUG)
255    printk("_open_r(%s,0x%x,0x%" PRIx32 ")\n",path,oflag,mode);
256
257  if (!beenhere) {
258    newlib_tfdlock();
259    for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++)
260      tfdtable[tfdidx].inuse = 0;
261
262    tfdtable[0].inuse = 1;    /* fake entry for stdin */
263    tfdtable[1].inuse = 1;    /* fake entry for stdout */
264    tfdtable[2].inuse = 1;    /* fake entry for stderr */
265    newlib_tfdunlock();
266    beenhere = 1;
267  }
268
269  istr = fstr = bstr = buf = (char *)0;
270
271  /* Copy the incoming path to a local array so that we can safely
272   * modify the string...
273    */
274  if (strlen(path) > TFSNAMESIZE*3) {
275    return(ENAMETOOLONG);
276  }
277  strcpy(pathcopy,path);
278
279  /* The incoming string may have commas that are used to delimit the
280   * name from the TFS flag string, TFS info string and buffer.
281   * Check for the commas and test for maximum string length...
282   */
283  fstr = strchr(pathcopy,',');
284  if (fstr)  {
285    *fstr++ = 0;
286    istr = strchr(fstr,',');
287    if (istr) {
288      *istr++ = 0;
289      bstr = strchr(istr,',');
290      if (bstr)
291        *bstr++ = 0;
292    }
293  }
294  if (strlen(pathcopy) > TFSNAMESIZE) {
295    return(ENAMETOOLONG);
296  }
297  if (istr) {
298    if (strlen(istr) > TFSNAMESIZE) {
299      return(ENAMETOOLONG);
300    }
301  }
302
303  /* If O_EXCL and O_CREAT are set, then fail if the file exists...
304   */
305  if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
306    if (mon_tfsstat((char *)pathcopy)) {
307      return(EEXIST);
308    }
309  }
310
311  /* Only a few flag combinations are supported...
312   * O_RDONLY             Simple read-only
313   * O_WRONLY | O_APPEND       Each write starts at end of file
314   * O_WRONLY | O_TRUNC       If file exists, truncate it
315   * O_WRONLY | O_CREAT       Create if it doesn't exist
316   * O_WRONLY | O_CREAT | O_EXCL   Fail if file exists
317   */
318  switch(oflag & O_ACCMODE) {
319    case O_RDONLY:
320      flagmode = TFS_RDONLY;
321      break;
322    case O_WRONLY|O_APPEND:
323      flagmode = TFS_APPEND;
324      break;
325    case O_WRONLY|O_TRUNC:
326    case O_WRONLY|O_CREAT|O_TRUNC:
327      mon_tfsunlink((char *)pathcopy);
328      flagmode = TFS_CREATE|TFS_APPEND;
329      break;
330    case O_WRONLY|O_CREAT:
331    case O_WRONLY|O_CREAT|O_APPEND:
332      flagmode = TFS_CREATE|TFS_APPEND;
333      break;
334    case O_RDWR:
335    case O_WRONLY|O_CREAT|O_EXCL:
336      flagmode = TFS_CREATE|TFS_APPEND;
337      break;
338    default:
339      printk("_open_r(): flag 0x%i not supported\n",oflag);
340      return(ENOTSUP);
341  }
342
343  /* Find an open slot in our tfd table:
344   */
345  newlib_tfdlock();
346  for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++) {
347    if (tfdtable[tfdidx].inuse == 0)
348      break;
349  }
350  if (tfdidx == MAXTFDS) {
351    newlib_tfdunlock();
352    return(EMFILE);
353  }
354  tip = &tfdtable[tfdidx];
355  tip->inuse = 1;
356  newlib_tfdunlock();
357
358  /* If file is opened for something other than O_RDONLY, then
359   * we need to allocate a buffer for the file..
360   * WARNING: It is the user's responsibility to make sure that
361   * the file size does not exceed this buffer.  Note that the
362   * buffer may be specified as part of the comma-delimited path.
363   */
364  if (flagmode == TFS_RDONLY) {
365    buf = (char *)0;
366  } else {
367    if (bstr)
368      buf = (char *)strtol(bstr,0,0);
369    else
370      buf = malloc(MAXFILESIZE);
371    if (!buf) {
372      newlib_tfdlock();
373      tip->inuse = 0;
374      newlib_tfdunlock();
375      return(ENOMEM);
376    }
377  }
378
379  /* Deal with tfs flags and tfs info fields if necessary:
380   */
381  if (fstr) {
382    long bflag;
383
384    bflag = mon_tfsctrl(TFS_FATOB,(long)fstr,0);
385    if (bflag == -1) {
386      return(EINVAL);
387    }
388    flagmode |= bflag;
389  }
390
391  if (istr)
392    strcpy(tip->info,istr);
393  else
394    tip->info[0] = 0;
395
396  tfd = mon_tfsopen((char *)pathcopy,flagmode,buf);
397  if (tfd >= 0) {
398    tip->tfd = tfd;
399    tip->buf = buf;
400    strcpy(tip->name,pathcopy);
401    iop->data0 = (uint32_t)tfdidx;
402    return(0);
403  } else {
404    printk("%s: %s\n",pathcopy,
405      (char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
406  }
407
408  if (buf)
409    free(buf);
410
411  newlib_tfdlock();
412  tip->inuse = 0;
413  newlib_tfdunlock();
414  return(EINVAL);
415}
416
417/*
418 * The IMFS open handler
419 */
420static int rtems_tfs_open(
421  rtems_libio_t *iop,
422  const char    *new_name,
423  int            oflag,
424  mode_t         mode
425)
426{
427  char *full_path_name;
428  int err;
429
430  full_path_name = iop->pathinfo.node_access;
431
432  if (RTEMS_TFS_DEBUG)
433    printk("rtems_tfs_open(%s)\n",full_path_name);
434
435  if (rtems_tfs_is_directory(full_path_name, strlen(full_path_name))) {
436    rtems_set_errno_and_return_minus_one (ENOTSUP);
437  }
438
439  err = rtems_tfs_open_worker (iop, full_path_name, oflag, mode);
440  if (err != 0) {
441     rtems_set_errno_and_return_minus_one (err);
442  }
443
444  return err;
445}
446
447/*
448 * Read from an open TFS file...
449 */
450static ssize_t rtems_tfs_read(
451  rtems_libio_t *iop,
452  void          *buffer,
453  size_t         count
454)
455{
456  int  ret, fd;
457
458  fd = (int) iop->data0;
459
460  if (RTEMS_TFS_DEBUG)
461    printk("_read_r(%d,%zi)\n",fd,count);
462
463  if ((fd < 3) || (fd >= MAXTFDS))
464    return(EBADF);
465
466  ret = mon_tfsread(tfdtable[fd].tfd,buffer,count);
467  if (ret == TFSERR_EOF)
468    ret = 0;
469
470  return(ret);
471}
472
473/*
474 * Close the open tfs file.
475 */
476static int rtems_tfs_close(
477  rtems_libio_t *iop
478)
479{
480  int  fd;
481  char *info;
482  struct tfdinfo *tip;
483
484  fd = (int)iop->data0;
485
486  if (RTEMS_TFS_DEBUG)
487    printk("rtems_tfs_close(%d)\n",fd);
488
489  if ((fd < 3) || (fd >= MAXTFDS)) {
490    rtems_set_errno_and_return_minus_one (EBADF);
491  }
492
493  tip = &tfdtable[fd];
494
495  if (tip->info[0])
496    info = tip->info;
497  else
498    info = (char *)0;
499
500  mon_tfsclose(tip->tfd,info);
501
502  if (tip->buf)
503    free(tip->buf);
504
505  newlib_tfdlock();
506  tip->inuse = 0;
507  newlib_tfdunlock();
508  return RTEMS_SUCCESSFUL;
509}
510
511static ssize_t rtems_tfs_write(
512  rtems_libio_t *iop,
513  const void    *buffer,
514  size_t         count
515)
516{
517  int  ret, fd;
518
519  fd = (int) iop->data0;
520
521  if (RTEMS_TFS_DEBUG)
522    printk("rtems_tfs_write(%d,%zi)\n",fd,count);
523
524  if ((fd <= 0) || (fd >= MAXTFDS)) {
525    rtems_set_errno_and_return_minus_one (EBADF);
526  }
527
528  ret = mon_tfswrite(tfdtable[fd].tfd,(char *)buffer,count);
529  if (ret < 0)
530    return(-1);
531
532  return(ret);
533}
534
535static off_t rtems_tfs_lseek(
536  rtems_libio_t *iop,
537  off_t          offset,
538  int            whence
539)
540{
541  int ret, fd;
542
543  fd = (int) iop->data0;
544
545  if (RTEMS_TFS_DEBUG)
546    printk("rtems_tfs_lseek(%d,%ld,%d)\n",fd,(long)offset,whence);
547
548  switch (whence) {
549    case SEEK_END:
550      printk("rtems_tfs_lseek doesn't support SEEK_END\n");
551      return(-1);
552    case SEEK_CUR:
553      whence = TFS_CURRENT;
554      break;
555    case SEEK_SET:
556      whence = TFS_BEGIN;
557      break;
558  }
559  ret = mon_tfsseek(tfdtable[fd].tfd,offset,whence);
560
561  if (ret < 0)
562    return(-1);
563
564  return (off_t)ret;
565}
566
567/*
568 *
569 */
570static int rtems_tfs_ftruncate(
571  rtems_libio_t *iop,
572  off_t          count
573)
574{
575  int ret, fd;
576
577  fd = (int) iop->data0;
578  ret = mon_tfstruncate(tfdtable[fd].tfd,count);
579  if (ret != TFS_OKAY)
580    return(-1);
581
582  return(0);
583}
584
585static int rtems_tfs_ioctl(
586  rtems_libio_t *iop,
587  uint32_t       cmd,
588  void          *buf
589)
590{
591  int ret;
592
593  ret = mon_tfsctrl(cmd,(long)buf,0);
594  if (ret != TFS_OKAY)
595    return(-1);
596
597  return(0);
598}
599
600static int rtems_tfs_fstat(
601  const rtems_filesystem_location_info_t *loc,
602  struct stat *buf
603)
604{
605  const char *path = loc->node_access;
606  size_t pathlen = strlen(path);
607
608  buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO
609    | (rtems_tfs_is_directory(path, pathlen) ?  S_IFDIR : S_IFREG);
610
611  return 0;
612}
613
614static int rtems_tfs_clone_node_info(
615  rtems_filesystem_location_info_t *loc
616)
617{
618  int rv = 0;
619
620  loc->node_access = strdup(loc->node_access);
621
622  if (loc->node_access == NULL) {
623    errno = ENOMEM;
624    rv = -1;
625  }
626
627  return rv;
628}
629
630static void rtems_tfs_free_node_info(
631  const rtems_filesystem_location_info_t *loc
632)
633{
634  free(loc->node_access);
635}
636
637static bool rtems_tfs_are_nodes_equal(
638  const rtems_filesystem_location_info_t *a,
639  const rtems_filesystem_location_info_t *b
640)
641{
642  return strcmp(a->node_access, b->node_access) == 0;
643}
644
645static const rtems_filesystem_operations_table  rtems_tfs_ops = {
646  .lock_h = rtems_filesystem_default_lock,
647  .unlock_h = rtems_filesystem_default_unlock,
648  .eval_path_h = rtems_tfs_eval_path,
649  .link_h = rtems_filesystem_default_link,
650  .are_nodes_equal_h = rtems_tfs_are_nodes_equal,
651  .mknod_h = rtems_filesystem_default_mknod,
652  .rmnod_h = rtems_filesystem_default_rmnod,
653  .fchmod_h = rtems_filesystem_default_fchmod,
654  .chown_h = rtems_filesystem_default_chown,
655  .clonenod_h = rtems_tfs_clone_node_info,
656  .freenod_h = rtems_tfs_free_node_info,
657  .mount_h = rtems_filesystem_default_mount,
658  .unmount_h = rtems_filesystem_default_unmount,
659  .fsunmount_me_h = rtems_filesystem_default_fsunmount,
660  .utime_h = rtems_filesystem_default_utime,
661  .symlink_h = rtems_filesystem_default_symlink,
662  .readlink_h = rtems_filesystem_default_readlink,
663  .rename_h = rtems_filesystem_default_rename,
664  .statvfs_h = rtems_filesystem_default_statvfs
665};
666
667static const rtems_filesystem_file_handlers_r rtems_tfs_handlers = {
668  .open_h = rtems_tfs_open,
669  .close_h = rtems_tfs_close,
670  .read_h = rtems_tfs_read,
671  .write_h = rtems_tfs_write,
672  .ioctl_h = rtems_tfs_ioctl,
673  .lseek_h = rtems_tfs_lseek,
674  .fstat_h = rtems_tfs_fstat,
675  .ftruncate_h = rtems_tfs_ftruncate,
676  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
677  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
678  .fcntl_h = rtems_filesystem_default_fcntl,
679  .kqfilter_h = rtems_filesystem_default_kqfilter,
680  .poll_h = rtems_filesystem_default_poll,
681  .readv_h = rtems_filesystem_default_readv,
682  .writev_h = rtems_filesystem_default_writev
683};
Note: See TracBrowser for help on using the repository browser.