summaryrefslogblamecommitdiffstats
path: root/testsuites/samples/fileio/init.c
blob: b0ebc69629ebc65025401c99e6c0055ed50149b5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608











                                                                       
                            



                                                           
                                         
  
        

   



                    








                      
                     
                        
                        
                  
                         

                              


                              
 
                























































































































                                                                      






                                                      

                                     



                                                                

                                     



                                                                

                                     



                                                                

                                     



                                                                

                                     



                                                                

                                     



                                                                

                                     



                                                                

                                     




                                                                
                                          





                        

























































































































































































































































































































































































                                                                              
                      
                   
                   





                      
                                                               


                                           

                            
             
                                                      


   


                                           
                                    
 
         
 




                                                       


























                                                                  
              
                  








                                    
                  




                                
                  




                                                    























                                                                   

                                         




                                                         

                                                  
                                                
    
 

                      
                                        





                                                      
                                              








                                            
                 






                                              
                                                



                             
                                
















                                                           
                                  


                       
                     










                                                    
                 



















                                                                             
                                                    


                                    
                                    


                    
 
                                                   
 
                                                                 
              
 
                                                       














                                                               
                                                                
 
                      
                     
                             

                                              
                  
   
                                         

                 
                                         

                          
                                  
                  







                    
                                   


                   

                           




                                                    
                      
                                         
                                                    
                                          
                                           
 






                                         
                                                     





                                      
                   





                                                   
                    







                                                                            
                   











                                                                            
                   















                                                                           
                    


































                                                                               
                    






                                    
                                                    
                 
        





                                                         

                                      


                                                
                                                   
                
                    

























                                                               
                                  


                   
                           




                                                    
                      
 






                                         
                                                     





                                      
                   





                                                   
                    







                                                                            
                   















                                                                           
                    









                                                                             
                    






                                      
                                                    
                 
        



                         
                                    

                    
                                                   
                
                    










                                                            
                                           
















                                                               
                              


















                                                    
                   




                                     
                          

             
                          

             
                           

             
                                      

             
                        


                
                            





                                                          
 



           
  

                       
                 





                                         




                                  



                           

                                                 


                                                
                                               


                                                             
                                        

                                                       
                                       

                                           
                                        
 
 
                      



                                                                  
                                              







                                           
                                                  







                                                                
                                                   


                                          
 




                                                            
                                   

                                 

                              
      
 










                                                           
/*  Init
 *
 *  This routine is the initialization task for this test program.
 *  It is called from init_exec and has the responsibility for creating
 *  and starting the tasks that make up the test.  If the time of day
 *  clock is required for the test, it should also be set to a known
 *  value by this function.
 *
 *  Input parameters:  NONE
 *
 *  Output parameters:  NONE
 *
 *  COPYRIGHT (c) 1989-2011.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id$
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define CONFIGURE_INIT
#include "system.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <rtems.h>
#include <fcntl.h>
#include <inttypes.h>
#include <rtems/error.h>
#include <rtems/dosfs.h>
#include <ctype.h>
#include <rtems/bdpart.h>
#include <rtems/libcsupport.h>
#include <rtems/fsmount.h>
#include <rtems/ramdisk.h>
#include <rtems/nvdisk.h>
#include <rtems/nvdisk-sram.h>

#if FILEIO_BUILD

/**
 * Let the IO system allocation the next available major number.
 */
#define RTEMS_DRIVER_AUTO_MAJOR (0)

/*
 * RAM disk driver so you can create a RAM disk from the shell prompt.
 */
/**
 * The RAM Disk configuration.
 */
rtems_ramdisk_config rtems_ramdisk_configuration[] =
{
  {
    block_size: 512,
    block_num:  1024,
    location:   NULL
  }
};

/**
 * The number of RAM Disk configurations.
 */
size_t rtems_ramdisk_configuration_size = 1;

/**
 * Create the RAM Disk Driver entry.
 */
rtems_driver_address_table rtems_ramdisk_io_ops = {
  initialization_entry: ramdisk_initialize,
  open_entry:           rtems_blkdev_generic_open,
  close_entry:          rtems_blkdev_generic_close,
  read_entry:           rtems_blkdev_generic_read,
  write_entry:          rtems_blkdev_generic_write,
  control_entry:        rtems_blkdev_generic_ioctl
};

/**
 * The NV Device descriptor. For this test it is just DRAM.
 */
rtems_nvdisk_device_desc rtems_nv_heap_device_descriptor[] =
{
  {
    flags:  0,
    base:   0,
    size:   1 * 1024 * 1024,
    nv_ops: &rtems_nvdisk_sram_handlers
  }
};

/**
 * The NV Disk configuration.
 */
const rtems_nvdisk_config rtems_nvdisk_configuration[] =
{
  {
    block_size:         512,
    device_count:       1,
    devices:            &rtems_nv_heap_device_descriptor[0],
    flags:              0,
    info_level:         0
  }
};

/**
 * The number of NV Disk configurations.
 */
uint32_t rtems_nvdisk_configuration_size = 1;

/**
 * Create the NV Disk Driver entry.
 */
rtems_driver_address_table rtems_nvdisk_io_ops = {
  initialization_entry: rtems_nvdisk_initialize,
  open_entry:           rtems_blkdev_generic_open,
  close_entry:          rtems_blkdev_generic_close,
  read_entry:           rtems_blkdev_generic_read,
  write_entry:          rtems_blkdev_generic_write,
  control_entry:        rtems_blkdev_generic_ioctl
};

int
setup_nvdisk (const char* mntpath)
{
  rtems_device_major_number major;
  rtems_status_code         sc;

  /*
   * For our test we do not have any static RAM or EEPROM devices so
   * we allocate the memory from the heap.
   */
  rtems_nv_heap_device_descriptor[0].base =
    malloc (rtems_nv_heap_device_descriptor[0].size);

  if (!rtems_nv_heap_device_descriptor[0].base)
  {
    printf ("error: no memory for NV disk\n");
    return 1;
  }
  
  /*
   * Register the NV Disk driver.
   */
  printf ("Register NV Disk Driver: ");
  sc = rtems_io_register_driver (RTEMS_DRIVER_AUTO_MAJOR,
                                 &rtems_nvdisk_io_ops,
                                 &major);
  if (sc != RTEMS_SUCCESSFUL)
  {
    printf ("error: nvdisk driver not initialised: %s\n",
            rtems_status_text (sc));
    return 1;
  }
  
  printf ("successful\n");

  return 0;
}

/*
 * Table of FAT file systems that will be mounted
 * with the "fsmount" function.
 * See cpukit/libmisc/fsmount for definition of fields
 */
fstab_t fs_table[] = {
  {
    "/dev/hda1","/mnt/hda1", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  },
  {
    "/dev/hda2","/mnt/hda2", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  },
  {
    "/dev/hda3","/mnt/hda3", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  },
  {
    "/dev/hda4","/mnt/hda4", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  },
  {
    "/dev/hdc1","/mnt/hdc1", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  },
  {
    "/dev/hdc2","/mnt/hdc2", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  },
  {
    "/dev/hdc3","/mnt/hdc3", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  },
  {
    "/dev/hdc4","/mnt/hdc4", "dosfs",
    RTEMS_FILESYSTEM_READ_WRITE,
    FSMOUNT_MNT_OK | FSMOUNT_MNTPNT_CRTERR | FSMOUNT_MNT_FAILED,
    0
  }
};

#define MIN(a,b) (((a) > (b)) ? (b) : (a))

#define USE_SHELL

#ifdef USE_SHELL
#include <rtems/shell.h>

int
shell_nvdisk_trace (int argc, char* argv[])
{
  const char* driver;
  int         level;

  if (argc != 3)
  {
    printf ("error: invalid number of options\n");
    return 1;
  }

  driver = argv[1];
  level  = strtoul (argv[2], 0, 0);
  
  int fd = open (driver, O_WRONLY, 0);
  if (fd < 0)
  {
    printf ("error: driver open failed: %s\n", strerror (errno));
    return 1;
  }
  
  if (ioctl (fd, RTEMS_NVDISK_IOCTL_INFO_LEVEL, level) < 0)
  {
    printf ("error: driver set level failed: %s\n", strerror (errno));
    return 1;
  }
  
  close (fd);
  
  return 0;
}

int
shell_nvdisk_erase (int argc, char* argv[])
{
  const char* driver = NULL;
  int         arg;
  int         fd;
  
  for (arg = 1; arg < argc; arg++)
  {
    if (argv[arg][0] == '-')
    {
      printf ("error: invalid option: %s\n", argv[arg]);
      return 1;
    }
    else
    {
      if (!driver)
        driver = argv[arg];
      else
      {
        printf ("error: only one driver name allowed: %s\n", argv[arg]);
        return 1;
      }
    }
  }
  
  printf ("erase nv disk: %s\n", driver);
  
  fd = open (driver, O_WRONLY, 0);
  if (fd < 0)
  {
    printf ("error: nvdisk driver open failed: %s\n", strerror (errno));
    return 1;
  }
  
  if (ioctl (fd, RTEMS_NVDISK_IOCTL_ERASE_DISK) < 0)
  {
    printf ("error: nvdisk driver erase failed: %s\n", strerror (errno));
    return 1;
  }
  
  close (fd);
  
  printf ("nvdisk erased successful\n");

  return 0;
}

int
shell_bdbuf_trace (int argc, char* argv[])
{
#if RTEMS_BDBUF_TRACE
  extern bool rtems_bdbuf_tracer;
  rtems_bdbuf_tracer = !rtems_bdbuf_tracer;
  printf ("bdbuf trace: %d\n", rtems_bdbuf_tracer);
#else
  printf ("bdbuf trace disabled. Rebuild with enabled.\n");
#endif
  return 0;
}

int
disk_test_set_block_size (dev_t dev, size_t size)
{
  rtems_disk_device* dd;
  int                rc;
  
  dd = rtems_disk_obtain (dev);
  if (!dd)
  {
    printf ("error: cannot obtain disk\n");
    return 1;
  }
  
  rc = dd->ioctl (dd, RTEMS_BLKIO_SETBLKSIZE, &size);

  rtems_disk_release (dd);

  return rc;
}

int
disk_test_write_blocks (dev_t dev, int start, int count, size_t size)
{
  int                 block;
  uint32_t*           ip;
  uint32_t            value = 0;
  int                 i;
  rtems_bdbuf_buffer* bd;
  rtems_status_code   sc;
  
  if (disk_test_set_block_size (dev, size) < 0)
  {
    printf ("error: set block size failed: %s\n", strerror (errno));
    return 1;
  }

  for (block = start; block < (start + count); block++)
  {
    sc = rtems_bdbuf_read (dev, block, &bd);
    if (sc != RTEMS_SUCCESSFUL)
    {
      printf ("error: get block %d bd failed: %s\n",
              block, rtems_status_text (sc));
      return 1;
    }

    ip = (uint32_t*) bd->buffer;
    for (i = 0; i < (size / sizeof (uint32_t)); i++, ip++, value++)
      *ip = (size << 16) | value;

    sc = rtems_bdbuf_release_modified (bd);
    if (sc != RTEMS_SUCCESSFUL)
    {
      printf ("error: release block %d bd failed: %s\n",
              block, rtems_status_text (sc));
      return 1;
    }
  }

  return 0;
}

int
disk_test_block_sizes (int argc, char *argv[])
{
  struct stat st;
  char*       name;
  int         start;
  int         count;
  int         size;
  
  if (argc != (4 + 1))
  {
    printf ("error: need to supply a device path, start, block and size\n");
    return 1;
  }

  name = argv[1];
  
  if (stat (name, &st) < 0)
  {
    printf ("error: stat '%s' failed: %s\n", name, strerror (errno));
    return 1;
  }

  start = strtoul (argv[2], 0, 0);
  count = strtoul (argv[3], 0, 0);
  size  = strtoul (argv[4], 0, 0);
  
  return disk_test_write_blocks (st.st_rdev, start, count, size);
}

size_t
parse_size_arg (const char* arg)
{
  size_t size;
  size_t scalar = 1;
  
  size = strtoul (arg, 0, 0);
  switch (arg[strlen (arg) - 1])
  {
    case 'M':
      scalar = 1000 * 1024;
      break;
    case 'm':
      scalar = 1000000;
      break;
    case 'K':
      scalar = 1024;
      break;
    case 'k':
      scalar = 1000;
      break;
    default:
      printf ("error: invalid scalar (M/m/K/k): %c\n", arg[strlen (arg) - 1]);
      return 0;
  }
  return size * scalar;
 }

int
create_ramdisk (int argc, char *argv[])
{
  rtems_device_major_number major;
  rtems_status_code         sc;
  int                       arg;
  size_t                    size = 0;
  size_t                    block_size = 0;

  for (arg = 0; arg < argc; ++arg)
  {
    if (argv[arg][0] == '-')
    {
      switch (argv[arg][0])
      {
        case 's':
          ++arg;
          if (arg == argc)
          {
            printf ("error: -s needs a size\n");
            return 1;
          }
          size = parse_size_arg (argv[arg]);
          if (size == 0)
            return 1;
          break;
        case 'b':
          ++arg;
          if (arg == argc)
          {
            printf ("error: -b needs a size\n");
            return 1;
          }
          block_size = parse_size_arg (argv[arg]);
          if (size == 0)
            return 1;
          break;
        default:
          printf ("error: invalid option: %s\n", argv[arg]);
          return 1;
      }
    }
  }

  if (block_size)
    rtems_ramdisk_configuration[0].block_size = block_size;
  if (size)
    rtems_ramdisk_configuration[0].block_num =
      size / rtems_ramdisk_configuration[0].block_size;
    
  /*
   * Register the RAM Disk driver.
   */
  printf ("Register RAM Disk Driver [blocks=%" PRIu32 \
          " block-size=%" PRIu32"]:",
          rtems_ramdisk_configuration[0].block_num,
          rtems_ramdisk_configuration[0].block_size);
  
  sc = rtems_io_register_driver (RTEMS_DRIVER_AUTO_MAJOR,
                                 &rtems_ramdisk_io_ops,
                                 &major);
  if (sc != RTEMS_SUCCESSFUL)
  {
    printf ("error: ramdisk driver not initialised: %s\n",
            rtems_status_text (sc));
    return 1;
  }
  
  printf ("successful\n");

  return 0;
}

int
create_nvdisk (int argc, char *argv[])
{
  rtems_device_major_number major;
  rtems_status_code         sc;
  int                       arg;
  size_t                    size = 0;
#if ADD_WHEN_NVDISK_HAS_CHANGED
  size_t                    block_size = 0;
#endif
  
  for (arg = 0; arg < argc; ++arg)
  {
    if (argv[arg][0] == '-')
    {
      switch (argv[arg][0])
      {
        case 's':
          ++arg;
          if (arg == argc)
          {
            printf ("error: -s needs a size\n");
            return 1;
          }
          size = parse_size_arg (argv[arg]);
          if (size == 0)
            return 1;
          break;
#if ADD_WHEN_NVDISK_HAS_CHANGED
        case 'b':
          ++arg;
          if (arg == argc)
          {
            printf ("error: -b needs a size\n");
            return 1;
          }
          block_size = parse_size_arg (argv[arg]);
          if (size == 0)
            return 1;
          break;
#endif
        default:
          printf ("error: invalid option: %s\n", argv[arg]);
          return 1;
      }
    }
  }

#if ADD_WHEN_NVDISK_HAS_CHANGED
  if (block_size)
    rtems_nvdisk_configuration[0].block_size = block_size;
#endif
  if (size)
    rtems_nv_heap_device_descriptor[0].size = size;
    
  /*
   * For our test we do not have any static RAM or EEPROM devices so
   * we allocate the memory from the heap.
   */
  rtems_nv_heap_device_descriptor[0].base =
    malloc (rtems_nv_heap_device_descriptor[0].size);

  if (!rtems_nv_heap_device_descriptor[0].base)
  {
    printf ("error: no memory for NV disk\n");
    return 1;
  }
  
  /*
   * Register the RAM Disk driver.
   */
  printf ("Register NV Disk Driver [size=%" PRIu32 \
          " block-size=%" PRIu32"]:",
          rtems_nv_heap_device_descriptor[0].size,
          rtems_nvdisk_configuration[0].block_size);
  
  sc = rtems_io_register_driver (RTEMS_DRIVER_AUTO_MAJOR,
                                 &rtems_nvdisk_io_ops,
                                 &major);
  if (sc != RTEMS_SUCCESSFUL)
  {
    printf ("error: nvdisk driver not initialised: %s\n",
            rtems_status_text (sc));
    return 1;
  }
  
  printf ("successful\n");

  return 0;
}

static void writeFile(
  const char *name,
  mode_t      mode,
  const char *contents
)
{
  int sc;
  sc = setuid(0);
  if ( sc ) {
    printf( "setuid failed: %s: %s\n", name, strerror(errno) );
  }

  rtems_shell_write_file( name, contents );

  sc = chmod ( name, mode );
  if ( sc ) {
    printf( "chmod %s: %s\n", name, strerror(errno) );
  }
}

#define writeScript( _name, _contents ) \
        writeFile( _name, 0777, _contents )

static void fileio_start_shell(void)
{
  int sc;

  sc = mkdir("/scripts", 0777);
  if ( sc ) {
    printf( "mkdir /scripts: %s:\n", strerror(errno) );
  }

  sc = mkdir("/etc", 0777);
  if ( sc ) {
    printf( "mkdir /etc: %s:\n", strerror(errno) );
  }

  printf(
    "Creating /etc/passwd and group with three useable accounts\n"
    "root/pwd , test/pwd, rtems/NO PASSWORD"
  );

  writeFile(
    "/etc/passwd",
    0644,
    "root:7QR4o148UPtb.:0:0:root::/:/bin/sh\n"
    "rtems:*:1:1:RTEMS Application::/:/bin/sh\n"
    "test:8Yy.AaxynxbLI:2:2:test account::/:/bin/sh\n"
    "tty:!:3:3:tty owner::/:/bin/false\n"
  );
  writeFile(
    "/etc/group",
    0644,
    "root:x:0:root\n"
    "rtems:x:1:rtems\n"
    "test:x:2:test\n"
    "tty:x:3:tty\n"
  );

  writeScript(
    "/scripts/js",
    "#! joel\n"
    "\n"
    "date\n"
    "echo Script successfully ran\n"
    "date\n"
    "stackuse\n"
  );

  writeScript(
    "/scripts/j1",
    "#! joel -s 20480 -t JESS\n"
    "stackuse\n"
  );

  rtems_shell_write_file(
    "/scripts/j2",
    "echo j2 TEST FILE\n"
    "echo j2   SHOULD BE non-executable AND\n"
    "echo j2   DOES NOT have the magic first line\n"
  );

  rtems_shell_add_cmd ("mkrd", "files",
                       "Create a RAM disk driver", create_ramdisk);
  rtems_shell_add_cmd ("mknvd", "files",
                       "Create a NV disk driver", create_nvdisk);
  rtems_shell_add_cmd ("nverase", "misc",
                       "nverase driver", shell_nvdisk_erase);
  rtems_shell_add_cmd ("nvtrace", "misc",
                       "nvtrace driver level", shell_nvdisk_trace);
  rtems_shell_add_cmd ("bdbuftrace", "files",
                       "bdbuf trace toggle", shell_bdbuf_trace);
  rtems_shell_add_cmd ("td", "files",
                       "Test disk", disk_test_block_sizes);
#if RTEMS_RFS_TRACE
  rtems_shell_add_cmd ("rfs", "files",
                       "RFS trace",
                       rtems_rfs_trace_shell_command);
#endif
#if RTEMS_RFS_RTEMS_TRACE
  rtems_shell_add_cmd ("rrfs", "files",
                       "RTEMS RFS trace",
                       rtems_rfs_rtems_trace_shell_command);
#endif

  printf("\n =========================\n");
  printf(" starting shell\n");
  printf(" =========================\n");
  rtems_shell_init(
    "SHLL",                          /* task_name */
    RTEMS_MINIMUM_STACK_SIZE * 4,    /* task_stacksize */
    100,                             /* task_priority */
    "/dev/console",                  /* devname */
    false,                           /* forever */
    true,                            /* wait */
    NULL                             /* login */
  );
}
#endif /* USE_SHELL */

static void fileio_print_free_heap(void)
{
  printf("--- unused dynamic memory: %lu bytes ---\n",
	 (unsigned long) malloc_free_space());
}


static void fileio_part_table_initialize(void)
{
  char devname[64];
  rtems_status_code rc;

  printf(" =========================\n");
  printf(" Initialize partition table\n");
  printf(" =========================\n");
  fileio_print_free_heap();
  printf(" Enter device to initialize ==>");
  fflush(stdout);
  fgets(devname,sizeof(devname)-1,stdin);
  while (devname[strlen(devname)-1] == '\n') {
    devname[strlen(devname)-1] = '\0';
  }
  /*
   * call function
   */
  rc = rtems_bdpart_register_from_disk(devname);
  printf("result = %d\n",rc);
  fileio_print_free_heap();
}

static void fileio_fsmount(void)
{
  rtems_status_code rc;

  printf(" =========================\n");
  printf(" Process fsmount table\n");
  printf(" =========================\n");
  fileio_print_free_heap();
  /*
   * call function
   */
  rc = rtems_fsmount( fs_table,
		      sizeof(fs_table)/sizeof(fs_table[0]),
		      NULL);
  printf("result = %d\n",rc);
  fileio_print_free_heap();
}

static void fileio_list_file(void)
{
  char fname[1024];
  char *buf_ptr = NULL;
  ssize_t   flen = 0;
  int fd = -1;
  ssize_t n;
  size_t buf_size = 100;

  rtems_interval start_tick,curr_tick,ticks_per_sec;

  printf(" =========================\n");
  printf(" LIST FILE ...            \n");
  printf(" =========================\n");
  fileio_print_free_heap();
  printf(" Enter filename to list ==>");
  fflush(stdout);
  fgets(fname,sizeof(fname)-1,stdin);
  while (fname[strlen(fname)-1] == '\n') {
    fname[strlen(fname)-1] = '\0';
  }
  /*
   * allocate buffer of given size
   */
  if (buf_size > 0) {
    buf_ptr = malloc(buf_size);
  }

  if (buf_ptr != NULL) {
    printf("\n Trying to open file \"%s\" for read\n",fname);
    fd = open(fname,O_RDONLY);
    if (fd < 0) {
      printf("*** file open failed, errno = %d(%s)\n",errno,strerror(errno));
    }
  }

  if (fd >= 0) {
    start_tick = rtems_clock_get_ticks_since_boot();
    do {
      n = read(fd,buf_ptr,buf_size);
      if (n > 0) {
	write(1,buf_ptr,(size_t) n);
	flen += n;
      }
    } while (n > 0);

    curr_tick = rtems_clock_get_ticks_since_boot();

    printf("\n ******** End of file reached, flen = %zd\n",flen);
    close(fd);

    ticks_per_sec = rtems_clock_get_ticks_per_second();
    printf("time elapsed for read:  %g seconds\n",
	   ((double)curr_tick-start_tick)/ticks_per_sec);
  }
  /*
   * free buffer
   */
  if (buf_ptr != NULL) {
    free(buf_ptr);
  }
  fileio_print_free_heap();
}

/*
 * convert a size string (like 34K or 12M) to actual byte count
 */
static bool fileio_str2size(const char *str,uint32_t   *res_ptr)
{
  bool failed = false;
  unsigned long size;
  unsigned char suffix = ' ';

  if (1 > sscanf(str,"%lu%c",&size,&suffix)) {
    failed = true;
  }
  else if (toupper((int)suffix) == 'K') {
    size *= 1024;
  }
  else if (toupper((int)suffix) == 'M') {
    size *= 1024UL*1024UL;
  }
  else if (isalpha((int)suffix)) {
    failed = true;
  }

  if (!failed) {
    *res_ptr = size;
  }
  return failed;
}

static void fileio_write_file(void)
{
  char fname[1024];
  char tmp_str[32];
  uint32_t   file_size = 0;
  uint32_t   buf_size  = 0;
  size_t curr_pos,bytes_to_copy;
  int fd = -1;
  ssize_t n;
  rtems_interval start_tick,curr_tick,ticks_per_sec;
  char *bufptr = NULL;
  bool failed = false;
  static const char write_test_string[] =
    "The quick brown fox jumps over the lazy dog\n";
  static const char write_block_string[] =
    "\n----- end of write buffer ------\n";

  printf(" =========================\n");
  printf(" WRITE FILE ...           \n");
  printf(" =========================\n");
  fileio_print_free_heap();
  /*
   * get number of ticks per second
   */
  ticks_per_sec = rtems_clock_get_ticks_per_second();

  /*
   * get path to file to write
   */
  if (!failed) {
    printf("Enter path/filename ==>");
    fflush(stdout);
    fgets(fname,sizeof(fname)-1,stdin);
    while (fname[strlen(fname)-1] == '\n') {
      fname[strlen(fname)-1] = '\0';
    }
    if (0 == strlen(fname)) {
      printf("*** no filename entered, aborted\n");
      failed = true;
    }
  }
  /*
   * get total file size to write
   */
  if (!failed) {
    printf("use suffix K for Kbytes, M for Mbytes or no suffix for bytes:\n"
	   "Enter filesize to write ==>");
    fflush(stdout);
    fgets(tmp_str,sizeof(tmp_str)-1,stdin);
    failed = fileio_str2size(tmp_str,&file_size);
    if (failed) {
      printf("*** illegal file size, aborted\n");
    }
  }
  /*
   * get block size to write
   */
  if (!failed) {
    printf("use suffix K for Kbytes, M for Mbytes or no suffix for bytes:\n"
	   "Enter block size to use for write calls ==>");
    fflush(stdout);
    fgets(tmp_str,sizeof(tmp_str)-1,stdin);
    failed = fileio_str2size(tmp_str,&buf_size);
    if (failed) {
      printf("*** illegal block size, aborted\n");
    }
  }

  /*
   * allocate buffer
   */
  if (!failed) {
    printf("... allocating %lu bytes of buffer for write data\n",
	   (unsigned long)buf_size);
    bufptr = malloc(buf_size+1); /* extra space for terminating NUL char */
    if (bufptr == NULL) {
      printf("*** malloc failed, aborted\n");
      failed = true;
    }
  }
  /*
   * fill buffer with test pattern
   */
  if (!failed) {
    printf("... filling buffer with write data\n");
    curr_pos = 0;
    /*
     * fill buffer with test string
     */
    while (curr_pos < buf_size) {
      bytes_to_copy = MIN(buf_size-curr_pos,
			  sizeof(write_test_string)-1);
      memcpy(bufptr+curr_pos,write_test_string,bytes_to_copy);
      curr_pos += bytes_to_copy;
    }
    /*
     * put "end" mark at end of buffer
     */
    bytes_to_copy = sizeof(write_block_string)-1;
    if (buf_size >= bytes_to_copy) {
      memcpy(bufptr+buf_size-bytes_to_copy,
	     write_block_string,
	     bytes_to_copy);
    }
  }
  /*
   * create file
   */
  if (!failed) {
    printf("... creating file \"%s\"\n",fname);
    fd = open(fname,O_WRONLY | O_CREAT | O_TRUNC,S_IREAD|S_IWRITE);
    if (fd < 0) {
      printf("*** file create failed, errno = %d(%s)\n",errno,strerror(errno));
      failed = true;
    }
  }
  /*
   * write file
   */
  if (!failed) {
    printf("... writing to file\n");
    start_tick = rtems_clock_get_ticks_since_boot();
    curr_pos = 0;
    do {
      bytes_to_copy = buf_size;
      do {
	n = write(fd,
	  bufptr + (buf_size-bytes_to_copy),
		  MIN(bytes_to_copy,file_size-curr_pos));
	if (n > 0) {
	  bytes_to_copy -= (size_t) n;
	  curr_pos      += (size_t) n;
	}
      } while ((bytes_to_copy > 0)  && (n > 0));
    } while ((file_size > curr_pos) && (n > 0));
    curr_tick = rtems_clock_get_ticks_since_boot();
    if (n < 0) {
      failed = true;
      printf("*** file write failed, "
	     "%lu bytes written, "
	     "errno = %d(%s)\n",
	     (unsigned long)curr_pos,errno,strerror(errno));
    }
    else {
      printf("time elapsed for write:  %g seconds\n",
	     ((double)curr_tick-start_tick)/ticks_per_sec);
      printf("write data rate: %g KBytes/second\n",
	     (((double)file_size) / 1024.0 /
	      (((double)curr_tick-start_tick)/ticks_per_sec)));
    }
  }
  if (fd >= 0) {
    printf("... closing file\n");
    close(fd);
  }
  if (bufptr != NULL) {
    printf("... deallocating buffer\n");
    free(bufptr);
    bufptr = NULL;
  }
  printf("\n ******** End of file write\n");
  fileio_print_free_heap();
}

static void fileio_read_file(void)
{
  char fname[1024];
  char tmp_str[32];
  uint32_t   buf_size  = 0;
  size_t curr_pos;
  int fd = -1;
  ssize_t n;
  rtems_interval start_tick,curr_tick,ticks_per_sec;
  char *bufptr = NULL;
  bool failed = false;

  printf(" =========================\n");
  printf(" READ FILE ...            \n");
  printf(" =========================\n");
  fileio_print_free_heap();
  /*
   * get number of ticks per second
   */
  ticks_per_sec = rtems_clock_get_ticks_per_second();

  /*
   * get path to file to read
   */
  if (!failed) {
    printf("Enter path/filename ==>");
    fflush(stdout);
    fgets(fname,sizeof(fname)-1,stdin);
    while (fname[strlen(fname)-1] == '\n') {
      fname[strlen(fname)-1] = '\0';
    }
    if (0 == strlen(fname)) {
      printf("*** no filename entered, aborted\n");
      failed = true;
    }
  }
  /*
   * get block size to read
   */
  if (!failed) {
    printf("use suffix K for Kbytes, M for Mbytes or no suffix for bytes:\n"
	   "Enter block size to use for read calls ==>");
    fflush(stdout);
    fgets(tmp_str,sizeof(tmp_str)-1,stdin);
    failed = fileio_str2size(tmp_str,&buf_size);
    if (failed) {
      printf("*** illegal block size, aborted\n");
    }
  }

  /*
   * allocate buffer
   */
  if (!failed) {
    printf("... allocating %lu bytes of buffer for write data\n",
	   (unsigned long)buf_size);
    bufptr = malloc(buf_size+1); /* extra space for terminating NUL char */
    if (bufptr == NULL) {
      printf("*** malloc failed, aborted\n");
      failed = true;
    }
  }
  /*
   * open file
   */
  if (!failed) {
    printf("... opening file \"%s\"\n",fname);
    fd = open(fname,O_RDONLY);
    if (fd < 0) {
      printf("*** file open failed, errno = %d(%s)\n",errno,strerror(errno));
      failed = true;
    }
  }
  /*
   * read file
   */
  if (!failed) {
    printf("... reading from file\n");
    start_tick = rtems_clock_get_ticks_since_boot();
    curr_pos = 0;
    do {
      n = read(fd,
	       bufptr,
	       buf_size);
      if (n > 0) {
	curr_pos      += (size_t) n;
      }
    } while (n > 0);
    curr_tick = rtems_clock_get_ticks_since_boot();
    if (n < 0) {
      failed = true;
      printf("*** file read failed, "
	     "%lu bytes read, "
	     "errno = %d(%s)\n",
	     (unsigned long)curr_pos,errno,strerror(errno));
    }
    else {
      printf("%lu bytes read\n",
	     (unsigned long)curr_pos);
      printf("time elapsed for read:  %g seconds\n",
	     ((double)curr_tick-start_tick)/ticks_per_sec);
      printf("read data rate: %g KBytes/second\n",
	     (((double)curr_pos) / 1024.0 /
	      (((double)curr_tick-start_tick)/ticks_per_sec)));
    }
  }
  if (fd >= 0) {
    printf("... closing file\n");
    close(fd);
  }
  if (bufptr != NULL) {
    printf("... deallocating buffer\n");
    free(bufptr);
    bufptr = NULL;
  }
  printf("\n ******** End of file read\n");
  fileio_print_free_heap();

}

static void fileio_menu (void)
{
  char inbuf[10];

  /*
   * Wait for characters from console terminal
   */
  for (;;) {
    printf(" =========================\n");
    printf(" RTEMS FILE I/O Test Menu \n");
    printf(" =========================\n");
    printf("   p -> part_table_initialize\n");
    printf("   f -> mount all disks in fs_table\n");
    printf("   l -> list  file\n");
    printf("   r -> read  file\n");
    printf("   w -> write file\n");
#ifdef USE_SHELL
    printf("   s -> start shell\n");
#endif
    printf("   Enter your selection ==>");
    fflush(stdout);

    inbuf[0] = '\0';
    fgets(inbuf,sizeof(inbuf),stdin);
    switch (inbuf[0]) {
    case 'l':
      fileio_list_file ();
      break;
    case 'r':
      fileio_read_file ();
      break;
    case 'w':
      fileio_write_file ();
      break;
    case 'p':
      fileio_part_table_initialize ();
      break;
    case 'f':
      fileio_fsmount ();
      break;
#ifdef USE_SHELL
    case 's':
      fileio_start_shell ();
      break;
#endif
    default:
      printf("Selection `%c` not implemented\n",inbuf[0]);
      break;
    }

  }
  exit (0);
}

/*
 * RTEMS File Menu Task
 */
static rtems_task
fileio_task (rtems_task_argument ignored)
{
  fileio_menu();
}

/*
 * RTEMS Startup Task
 */
rtems_task
Init (rtems_task_argument ignored)
{
  rtems_name Task_name;
  rtems_id   Task_id;
  rtems_status_code status;

  puts( "\n\n*** FILE I/O SAMPLE AND TEST ***" );

  Task_name = rtems_build_name('F','M','N','U');

  status = rtems_task_create(
    Task_name, 1, RTEMS_MINIMUM_STACK_SIZE * 2,
    RTEMS_DEFAULT_MODES ,
    RTEMS_FLOATING_POINT | RTEMS_DEFAULT_ATTRIBUTES, &Task_id
  );
  directive_failed( status, "create" ); 

  status = rtems_task_start( Task_id, fileio_task, 1 );
  directive_failed( status, "start" ); 

  status = rtems_task_delete( RTEMS_SELF );
  directive_failed( status, "delete" ); 
}

#if defined(USE_SHELL)
/*
 *  RTEMS Shell Configuration -- Add a command and an alias for it
 */

static int main_usercmd(int argc, char **argv)
{
  int i;
  printf( "UserCommand: argc=%d\n", argc );
  for (i=0 ; i<argc ; i++ )
    printf( "argv[%d]= %s\n", i, argv[i] );
  return 0;
}

static rtems_shell_cmd_t Shell_USERCMD_Command = {
  "usercmd",                                       /* name */
  "usercmd n1 [n2 [n3...]]     # echo arguments",  /* usage */
  "user",                                          /* topic */
  main_usercmd,                                    /* command */
  NULL,                                            /* alias */
  NULL                                             /* next */
};

static rtems_shell_alias_t Shell_USERECHO_Alias = {
  "usercmd",                 /* command */
  "userecho"                 /* alias */
};


#define CONFIGURE_SHELL_USER_COMMANDS &Shell_USERCMD_Command
#define CONFIGURE_SHELL_USER_ALIASES &Shell_USERECHO_Alias
#define CONFIGURE_SHELL_COMMANDS_INIT
#define CONFIGURE_SHELL_COMMANDS_ALL
#define CONFIGURE_SHELL_MOUNT_MSDOS
#define CONFIGURE_SHELL_MOUNT_RFS
#define CONFIGURE_SHELL_DEBUGRFS

#include <rtems/shellconfig.h>
#endif

#else
/*
 * RTEMS Startup Task
 */
rtems_task
Init (rtems_task_argument ignored)
{
  puts( "\n\n*** FILE I/O SAMPLE AND TEST ***" );
  puts( "\n\n*** NOT ENOUGH MEMORY TO BUILD AND RUN ***" );
}
#endif