/* swrite.c - SIO write command-line program.
 *
 */

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sio_fs.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <nasd/nasd_timer.h>

/* XXX supposedly an internal function, but we use it here... */
extern void _sio_warning(const char *fmt, ...);

void usage()
{
  printf("swrite [opts] source target\n");
  printf("  -t show times  -v be verbose  -b <x> set block size to <x>\n");
  exit(1);
}

int
main(int argc, char **argv)
{
  sio_file_io_list_t fl[10];
  sio_mem_io_list_t ml[10];
  sio_transfer_len_t xfer;
  sio_return_t rv;
  sio_count_t ind;
  sio_async_status_t status;
  sio_transfer_len_t bytes;
  void *buf;
  char *p;
  char *src_fname;
  char *dst_fname;
  int bsize;
  int done;
  int fd;
  int fd1;
  int nb;
  int i;
  int total_xfer = 0;
  int verbose = 0;
  int show_times = 0;
  int chunk_size;
  nasd_timer_t timer;
  int option;
  struct timeval before;
  struct timeval after;

  chunk_size = 64*1024;
  while ((option = getopt(argc, argv, "?tvb:")) != EOF) {
    switch (option) {
    case 'b':			/* set block size */
      if (sscanf(optarg, "%d", &chunk_size) != 1)
	usage();
      break;
    case 't':			/* time run */
      show_times = 1;
      break;
    case 'v':			/* be verbose */
      verbose = 1;
      break;
    default:
      usage();
      break;
    }
  }
  if (argc - optind != 2) {
    usage();
  }
  src_fname = argv[optind++];
  dst_fname = argv[optind++];

  if (verbose) {
    printf("Chunk size %d\n", chunk_size);
  }
  rv = sio_open(&fd, dst_fname,  SIO_MODE_CREATE |  SIO_MODE_WRITE |
		SIO_MODE_READ, NULL , 0);
  if (rv != SIO_SUCCESS) {
    fprintf(stderr, "swrite:(can't create %s): %s\n", 
	    dst_fname, sio_error_string(rv));
    exit (1);
  }

  fl[0].offset = 0;
  fl[0].size = 64*1024;
  fl[0].stride = 0;
  fl[0].element_cnt = 1;

  buf = (void *) malloc(64*1024);
  if ( buf == NULL ) {
    fprintf(stderr,"malloc failed\n");
    exit(1);
  }
	
  ml[0].addr = buf;
  ml[0].size = 64*1024;
  ml[0].stride = 0;
  ml[0].element_cnt = 1;

  fd1 = open(src_fname, O_RDONLY, 0);
  if (fd1 <=0) {
    fprintf(stderr,"swrite: failed to open %s\n", src_fname);
    exit(1);
  }
  done = FALSE;
  if (show_times) {
    (void) gettimeofday(&before, NULL);
    NASD_TM_START(&timer);
  }
  bytes = 0;
  while (!done) {		        
    nb = read(fd1, buf, chunk_size);
    if (nb<chunk_size)
      done=TRUE;
    fl[0].size = nb;
    ml[0].size = nb;
		
    rv = sio_sg_write(fd, fl, 1, ml, 1, &xfer);
    if (rv != SIO_SUCCESS) {
      fprintf(stderr, "sio_sg_write: %s\n", 
	      sio_error_string(rv));
    }
    total_xfer += xfer;
    if (xfer < nb) {
      _sio_warning("swrite: sg_write failed in/out=%d/%d\n",
		   nb, xfer);
      exit(1);
    }
    fl[0].offset += xfer;
    bytes += xfer;
    if (verbose) {
      /* print a . each MB */
      if (!(bytes % (1024 * 1024))) {
	write(1, ".", 1);
      }
    }
  }
  write(1, " done.\n", 7);
  if (show_times) {
    NASD_TM_STOP(&timer);
    (void) gettimeofday(&after, NULL);
  }
  if (verbose)
    printf("\n");
  if (show_times) {
    if (bytes == 0)
      printf("No data transfered.\n");
    else {
      double secs1 = (double)0;
      double secs2 = (double)0;
      double mbytes = (double)0;
      double mbps1 = (double)0;
      double mbps2 = (double)0;
      nasd_timespec_t diff2;
      nasd_timespec_t diff;
      double secs_b = (((double)before.tv_sec) +
		       ((double)before.tv_usec / (double)1000000));
      double secs_a = (((double)after.tv_sec) +
		       ((double)after.tv_usec / (double)1000000));
      
      NASD_TM_ELAPSED_TS(&timer, &diff2);
      secs2 =((double)diff2.ts_nsec/(double)1000000000.0)+(double)diff2.ts_sec;
      secs1 = secs_a - secs_b;
      mbytes = (double)bytes / (double)(1024 * 1024);
      mbps1 = mbytes / secs1;
      mbps2 = mbytes / secs2;
      printf("Transfered %g(%g)MB/s) (%" NASD_64u_FMT
	     " total bytes in %g(%g) seconds)\n", mbps1, mbps2,
	     bytes, secs1, secs2);
    }
  }
  rv = sio_close(fd);
  if (rv != SIO_SUCCESS) {
    fprintf(stderr, "sio_close: %s\n", sio_error_string(rv));
  }

  close(fd1);	
  free(buf);

  exit(0);
}

/*
 * Local variables:
 * comment-column: 40
 * c-basic-offset: 2
 * c-indentation-style: gnu
 * End:
 */
