Diff for /qemu/qemu-io.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2018/04/24 17:35:06 version 1.1.1.3, 2018/04/24 18:24:46
Line 84  dump_buffer(const void *buffer, int64_t  Line 84  dump_buffer(const void *buffer, int64_t 
         for (i = 0, p = buffer; i < len; i += 16) {          for (i = 0, p = buffer; i < len; i += 16) {
                 const uint8_t *s = p;                  const uint8_t *s = p;
   
                 printf("%08llx:  ", (unsigned long long)offset + i);                  printf("%08" PRIx64 ":  ", offset + i);
                 for (j = 0; j < 16 && i + j < len; j++, p++)                  for (j = 0; j < 16 && i + j < len; j++, p++)
                         printf("%02x ", *p);                          printf("%02x ", *p);
                 printf(" ");                  printf(" ");
Line 108  print_report(const char *op, struct time Line 108  print_report(const char *op, struct time
         if (!Cflag) {          if (!Cflag) {
                 cvtstr((double)total, s1, sizeof(s1));                  cvtstr((double)total, s1, sizeof(s1));
                 cvtstr(tdiv((double)total, *t), s2, sizeof(s2));                  cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
                 printf("%s %d/%d bytes at offset %lld\n",                  printf("%s %d/%d bytes at offset %" PRId64 "\n",
                         op, total, count, (long long)offset);                         op, total, count, offset);
                 printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",                  printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
                         s1, cnt, ts, s2, tdiv((double)cnt, *t));                          s1, cnt, ts, s2, tdiv((double)cnt, *t));
         } else {/* bytes,ops,time,bytes/sec,ops/sec */          } else {/* bytes,ops,time,bytes/sec,ops/sec */
Line 135  create_iovec(QEMUIOVector *qiov, char ** Line 135  create_iovec(QEMUIOVector *qiov, char **
   
         for (i = 0; i < nr_iov; i++) {          for (i = 0; i < nr_iov; i++) {
                 char *arg = argv[i];                  char *arg = argv[i];
                 long long len;                  uint64_t len;
   
                 len = cvtnum(arg);                  len = cvtnum(arg);
                 if (len < 0) {                  if (len < 0) {
Line 150  create_iovec(QEMUIOVector *qiov, char ** Line 150  create_iovec(QEMUIOVector *qiov, char **
                 }                  }
   
                 if (len & 0x1ff) {                  if (len & 0x1ff) {
                         printf("length argument %lld is not sector aligned\n",                          printf("length argument %" PRId64
                                 len);                                 " is not sector aligned\n", len);
                         goto fail;                          goto fail;
                 }                  }
   
Line 267  static int do_aio_writev(QEMUIOVector *q Line 267  static int do_aio_writev(QEMUIOVector *q
         return async_ret < 0 ? async_ret : 1;          return async_ret < 0 ? async_ret : 1;
 }  }
   
   struct multiwrite_async_ret {
           int num_done;
           int error;
   };
   
   static void multiwrite_cb(void *opaque, int ret)
   {
           struct multiwrite_async_ret *async_ret = opaque;
   
           async_ret->num_done++;
           if (ret < 0) {
                   async_ret->error = ret;
           }
   }
   
   static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
   {
           int i, ret;
           struct multiwrite_async_ret async_ret = {
                   .num_done = 0,
                   .error = 0,
           };
   
           *total = 0;
           for (i = 0; i < num_reqs; i++) {
                   reqs[i].cb = multiwrite_cb;
                   reqs[i].opaque = &async_ret;
                   *total += reqs[i].qiov->size;
           }
   
           ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
           if (ret < 0) {
                   return ret;
           }
   
           while (async_ret.num_done < num_reqs) {
                   qemu_aio_wait();
           }
   
           return async_ret.error < 0 ? async_ret.error : 1;
   }
   
 static void  static void
 read_help(void)  read_help(void)
Line 398  read_f(int argc, char **argv) Line 439  read_f(int argc, char **argv)
   
         if (!pflag)          if (!pflag)
                 if (offset & 0x1ff) {                  if (offset & 0x1ff) {
                         printf("offset %lld is not sector aligned\n",                          printf("offset %" PRId64 " is not sector aligned\n",
                                 (long long)offset);                                 offset);
                         return 0;                          return 0;
   
                 if (count & 0x1ff) {                  if (count & 0x1ff) {
Line 429  read_f(int argc, char **argv) Line 470  read_f(int argc, char **argv)
                 void* cmp_buf = malloc(pattern_count);                  void* cmp_buf = malloc(pattern_count);
                 memset(cmp_buf, pattern, pattern_count);                  memset(cmp_buf, pattern, pattern_count);
                 if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {                  if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
                         printf("Pattern verification failed at offset %lld, "                          printf("Pattern verification failed at offset %"
                                 "%d bytes\n",                                 PRId64 ", %d bytes\n",
                                 (long long) offset + pattern_offset, pattern_count);                                 offset + pattern_offset, pattern_count);
                 }                  }
                 free(cmp_buf);                  free(cmp_buf);
         }          }
Line 492  readv_f(int argc, char **argv) Line 533  readv_f(int argc, char **argv)
         int c, cnt;          int c, cnt;
         char *buf;          char *buf;
         int64_t offset;          int64_t offset;
         int total;          /* Some compilers get confused and warn if this is not initialized.  */
           int total = 0;
         int nr_iov;          int nr_iov;
         QEMUIOVector qiov;          QEMUIOVector qiov;
         int pattern = 0;          int pattern = 0;
Line 532  readv_f(int argc, char **argv) Line 574  readv_f(int argc, char **argv)
         optind++;          optind++;
   
         if (offset & 0x1ff) {          if (offset & 0x1ff) {
                 printf("offset %lld is not sector aligned\n",                  printf("offset %" PRId64 " is not sector aligned\n",
                         (long long)offset);                         offset);
                 return 0;                  return 0;
         }          }
   
Line 553  readv_f(int argc, char **argv) Line 595  readv_f(int argc, char **argv)
                 void* cmp_buf = malloc(qiov.size);                  void* cmp_buf = malloc(qiov.size);
                 memset(cmp_buf, pattern, qiov.size);                  memset(cmp_buf, pattern, qiov.size);
                 if (memcmp(buf, cmp_buf, qiov.size)) {                  if (memcmp(buf, cmp_buf, qiov.size)) {
                         printf("Pattern verification failed at offset %lld, "                          printf("Pattern verification failed at offset %"
                                 "%zd bytes\n",                                 PRId64 ", %zd bytes\n",
                                 (long long) offset, qiov.size);                                 offset, qiov.size);
                 }                  }
                 free(cmp_buf);                  free(cmp_buf);
         }          }
Line 668  write_f(int argc, char **argv) Line 710  write_f(int argc, char **argv)
   
         if (!pflag) {          if (!pflag) {
                 if (offset & 0x1ff) {                  if (offset & 0x1ff) {
                         printf("offset %lld is not sector aligned\n",                          printf("offset %" PRId64 " is not sector aligned\n",
                                 (long long)offset);                                 offset);
                         return 0;                          return 0;
                 }                  }
   
Line 747  writev_f(int argc, char **argv) Line 789  writev_f(int argc, char **argv)
         int c, cnt;          int c, cnt;
         char *buf;          char *buf;
         int64_t offset;          int64_t offset;
         int total;          /* Some compilers get confused and warn if this is not initialized.  */
           int total = 0;
         int nr_iov;          int nr_iov;
         int pattern = 0xcd;          int pattern = 0xcd;
         QEMUIOVector qiov;          QEMUIOVector qiov;
Line 781  writev_f(int argc, char **argv) Line 824  writev_f(int argc, char **argv)
         optind++;          optind++;
   
         if (offset & 0x1ff) {          if (offset & 0x1ff) {
                 printf("offset %lld is not sector aligned\n",                  printf("offset %" PRId64 " is not sector aligned\n",
                         (long long)offset);                         offset);
                 return 0;                  return 0;
         }          }
   
Line 809  out: Line 852  out:
         return 0;          return 0;
 }  }
   
   static void
   multiwrite_help(void)
   {
           printf(
   "\n"
   " writes a range of bytes from the given offset source from multiple buffers,\n"
   " in a batch of requests that may be merged by qemu\n"
   "\n"
   " Example:\n"
   " 'multiwrite 512 1k 1k ; 4k 1k' \n"
   "  writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
   "\n"
   " Writes into a segment of the currently open file, using a buffer\n"
   " filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
   " by one for each request contained in the multiwrite command.\n"
   " -P, -- use different pattern to fill file\n"
   " -C, -- report statistics in a machine parsable format\n"
   " -q, -- quiet mode, do not show I/O statistics\n"
   "\n");
   }
   
   static int multiwrite_f(int argc, char **argv);
   
   static const cmdinfo_t multiwrite_cmd = {
           .name           = "multiwrite",
           .cfunc          = multiwrite_f,
           .argmin         = 2,
           .argmax         = -1,
           .args           = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
           .oneline        = "issues multiple write requests at once",
           .help           = multiwrite_help,
   };
   
   static int
   multiwrite_f(int argc, char **argv)
   {
           struct timeval t1, t2;
           int Cflag = 0, qflag = 0;
           int c, cnt;
           char **buf;
           int64_t offset, first_offset = 0;
           /* Some compilers get confused and warn if this is not initialized.  */
           int total = 0;
           int nr_iov;
           int nr_reqs;
           int pattern = 0xcd;
           QEMUIOVector *qiovs;
           int i;
           BlockRequest *reqs;
   
           while ((c = getopt(argc, argv, "CqP:")) != EOF) {
                   switch (c) {
                   case 'C':
                           Cflag = 1;
                           break;
                   case 'q':
                           qflag = 1;
                           break;
                   case 'P':
                           pattern = parse_pattern(optarg);
                           if (pattern < 0)
                                   return 0;
                           break;
                   default:
                           return command_usage(&writev_cmd);
                   }
           }
   
           if (optind > argc - 2)
                   return command_usage(&writev_cmd);
   
           nr_reqs = 1;
           for (i = optind; i < argc; i++) {
                   if (!strcmp(argv[i], ";")) {
                           nr_reqs++;
                   }
           }
   
           reqs = qemu_malloc(nr_reqs * sizeof(*reqs));
           buf = qemu_malloc(nr_reqs * sizeof(*buf));
           qiovs = qemu_malloc(nr_reqs * sizeof(*qiovs));
   
           for (i = 0; i < nr_reqs; i++) {
                   int j;
   
                   /* Read the offset of the request */
                   offset = cvtnum(argv[optind]);
                   if (offset < 0) {
                           printf("non-numeric offset argument -- %s\n", argv[optind]);
                           return 0;
                   }
                   optind++;
   
                   if (offset & 0x1ff) {
                           printf("offset %lld is not sector aligned\n",
                                   (long long)offset);
                           return 0;
                   }
   
           if (i == 0) {
               first_offset = offset;
           }
   
                   /* Read lengths for qiov entries */
                   for (j = optind; j < argc; j++) {
                           if (!strcmp(argv[j], ";")) {
                                   break;
                           }
                   }
   
                   nr_iov = j - optind;
   
                   /* Build request */
                   reqs[i].qiov = &qiovs[i];
                   buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
                   reqs[i].sector = offset >> 9;
                   reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
   
                   optind = j + 1;
   
                   offset += reqs[i].qiov->size;
                   pattern++;
           }
   
           gettimeofday(&t1, NULL);
           cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
           gettimeofday(&t2, NULL);
   
           if (cnt < 0) {
                   printf("aio_multiwrite failed: %s\n", strerror(-cnt));
                   goto out;
           }
   
           if (qflag)
                   goto out;
   
           /* Finally, report back -- -C gives a parsable format */
           t2 = tsub(t2, t1);
           print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
   out:
           for (i = 0; i < nr_reqs; i++) {
                   qemu_io_free(buf[i]);
                   qemu_iovec_destroy(&qiovs[i]);
           }
           qemu_free(buf);
           qemu_free(reqs);
           qemu_free(qiovs);
           return 0;
   }
   
 struct aio_ctx {  struct aio_ctx {
         QEMUIOVector qiov;          QEMUIOVector qiov;
         int64_t offset;          int64_t offset;
Line 866  aio_read_done(void *opaque, int ret) Line 1059  aio_read_done(void *opaque, int ret)
   
                 memset(cmp_buf, ctx->pattern, ctx->qiov.size);                  memset(cmp_buf, ctx->pattern, ctx->qiov.size);
                 if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {                  if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
                         printf("Pattern verification failed at offset %lld, "                          printf("Pattern verification failed at offset %"
                                 "%zd bytes\n",                                 PRId64 ", %zd bytes\n",
                                 (long long) ctx->offset, ctx->qiov.size);                                 ctx->offset, ctx->qiov.size);
                 }                  }
                 free(cmp_buf);                  free(cmp_buf);
         }          }
Line 902  aio_read_help(void) Line 1095  aio_read_help(void)
 "\n"  "\n"
 " Reads a segment of the currently open file, optionally dumping it to the\n"  " Reads a segment of the currently open file, optionally dumping it to the\n"
 " standard output stream (with -v option) for subsequent inspection.\n"  " standard output stream (with -v option) for subsequent inspection.\n"
 " The read is performed asynchronously and should the aio_flush command \n"  " The read is performed asynchronously and the aio_flush command must be\n"
 " should be used to ensure all outstanding aio requests have been completed\n"  " used to ensure all outstanding aio requests have been completed\n"
 " -C, -- report statistics in a machine parsable format\n"  " -C, -- report statistics in a machine parsable format\n"
 " -P, -- use a pattern to verify read data\n"  " -P, -- use a pattern to verify read data\n"
 " -v, -- dump buffer to standard output\n"  " -v, -- dump buffer to standard output\n"
Line 967  aio_read_f(int argc, char **argv) Line 1160  aio_read_f(int argc, char **argv)
         optind++;          optind++;
   
         if (ctx->offset & 0x1ff) {          if (ctx->offset & 0x1ff) {
                 printf("offset %lld is not sector aligned\n",                  printf("offset %" PRId64 " is not sector aligned\n",
                         (long long)ctx->offset);                         ctx->offset);
                 free(ctx);                  free(ctx);
                 return 0;                  return 0;
         }          }
Line 1001  aio_write_help(void) Line 1194  aio_write_help(void)
 "\n"  "\n"
 " Writes into a segment of the currently open file, using a buffer\n"  " Writes into a segment of the currently open file, using a buffer\n"
 " filled with a set pattern (0xcdcdcdcd).\n"  " filled with a set pattern (0xcdcdcdcd).\n"
 " The write is performed asynchronously and should the aio_flush command \n"  " The write is performed asynchronously and the aio_flush command must be\n"
 " should be used to ensure all outstanding aio requests have been completed\n"  " used to ensure all outstanding aio requests have been completed\n"
 " -P, -- use different pattern to fill file\n"  " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"  " -C, -- report statistics in a machine parsable format\n"
 " -q, -- quite mode, do not show I/O statistics\n"  " -q, -- quite mode, do not show I/O statistics\n"
Line 1062  aio_write_f(int argc, char **argv) Line 1255  aio_write_f(int argc, char **argv)
         optind++;          optind++;
   
         if (ctx->offset & 0x1ff) {          if (ctx->offset & 0x1ff) {
                 printf("offset %lld is not sector aligned\n",                  printf("offset %" PRId64 " is not sector aligned\n",
                         (long long)ctx->offset);                         ctx->offset);
                 free(ctx);                  free(ctx);
                 return 0;                  return 0;
         }          }
Line 1093  aio_flush_f(int argc, char **argv) Line 1286  aio_flush_f(int argc, char **argv)
 static const cmdinfo_t aio_flush_cmd = {  static const cmdinfo_t aio_flush_cmd = {
         .name           = "aio_flush",          .name           = "aio_flush",
         .cfunc          = aio_flush_f,          .cfunc          = aio_flush_f,
         .oneline        = "completes all outstanding aio requets"          .oneline        = "completes all outstanding aio requests"
 };  };
   
 static int  static int
Line 1124  truncate_f(int argc, char **argv) Line 1317  truncate_f(int argc, char **argv)
   
         ret = bdrv_truncate(bs, offset);          ret = bdrv_truncate(bs, offset);
         if (ret < 0) {          if (ret < 0) {
                 printf("truncate: %s", strerror(ret));                  printf("truncate: %s\n", strerror(-ret));
                 return 0;                  return 0;
         }          }
   
Line 1149  length_f(int argc, char **argv) Line 1342  length_f(int argc, char **argv)
   
         size = bdrv_getlength(bs);          size = bdrv_getlength(bs);
         if (size < 0) {          if (size < 0) {
                 printf("getlength: %s", strerror(size));                  printf("getlength: %s\n", strerror(-size));
                 return 0;                  return 0;
         }          }
   
Line 1212  alloc_f(int argc, char **argv) Line 1405  alloc_f(int argc, char **argv)
   
         offset = cvtnum(argv[1]);          offset = cvtnum(argv[1]);
         if (offset & 0x1ff) {          if (offset & 0x1ff) {
                 printf("offset %lld is not sector aligned\n",                  printf("offset %" PRId64 " is not sector aligned\n",
                         (long long)offset);                         offset);
                 return 0;                  return 0;
         }          }
   
Line 1274  static int openfile(char *name, int flag Line 1467  static int openfile(char *name, int flag
                 return 1;                  return 1;
         }          }
   
         bs = bdrv_new("hda");  
         if (!bs)  
                 return 1;  
   
         if (growable) {          if (growable) {
                 flags |= BDRV_O_FILE;                  if (bdrv_file_open(&bs, name, flags)) {
         }                          fprintf(stderr, "%s: can't open device %s\n", progname, name);
                           return 1;
         if (bdrv_open(bs, name, flags) == -1) {                  }
                 fprintf(stderr, "%s: can't open device %s\n", progname, name);          } else {
                 bs = NULL;                  bs = bdrv_new("hda");
                 return 1;                  if (!bs)
                           return 1;
   
                   if (bdrv_open(bs, name, flags, NULL) < 0) {
                           fprintf(stderr, "%s: can't open device %s\n", progname, name);
                           bs = NULL;
                           return 1;
                   }
         }          }
   
         if (growable) {  
                 bs->growable = 1;  
         }  
         return 0;          return 0;
 }  }
   
Line 1305  open_help(void) Line 1498  open_help(void)
 " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"  " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
 "\n"  "\n"
 " Opens a file for subsequent use by all of the other qemu-io commands.\n"  " Opens a file for subsequent use by all of the other qemu-io commands.\n"
 " -C, -- create new file if it doesn't exist\n"  
 " -r, -- open file read-only\n"  " -r, -- open file read-only\n"
 " -s, -- use snapshot file\n"  " -s, -- use snapshot file\n"
 " -n, -- disable host cache\n"  " -n, -- disable host cache\n"
Line 1335  open_f(int argc, char **argv) Line 1527  open_f(int argc, char **argv)
         int growable = 0;          int growable = 0;
         int c;          int c;
   
         while ((c = getopt(argc, argv, "snCrg")) != EOF) {          while ((c = getopt(argc, argv, "snrg")) != EOF) {
                 switch (c) {                  switch (c) {
                 case 's':                  case 's':
                         flags |= BDRV_O_SNAPSHOT;                          flags |= BDRV_O_SNAPSHOT;
Line 1343  open_f(int argc, char **argv) Line 1535  open_f(int argc, char **argv)
                 case 'n':                  case 'n':
                         flags |= BDRV_O_NOCACHE;                          flags |= BDRV_O_NOCACHE;
                         break;                          break;
                 case 'C':  
                         flags |= BDRV_O_CREAT;  
                         break;  
                 case 'r':                  case 'r':
                         readonly = 1;                          readonly = 1;
                         break;                          break;
Line 1357  open_f(int argc, char **argv) Line 1546  open_f(int argc, char **argv)
                 }                  }
         }          }
   
         if (readonly)          if (!readonly) {
                 flags |= BDRV_O_RDONLY;              flags |= BDRV_O_RDWR;
         else          }
                 flags |= BDRV_O_RDWR;  
   
         if (optind != argc - 1)          if (optind != argc - 1)
                 return command_usage(&open_cmd);                  return command_usage(&open_cmd);
Line 1394  init_check_command( Line 1582  init_check_command(
 static void usage(const char *name)  static void usage(const char *name)
 {  {
         printf(          printf(
 "Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n"  "Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
 "QEMU Disk exerciser\n"  "QEMU Disk exerciser\n"
 "\n"  "\n"
 "  -C, --create         create new file if it doesn't exist\n"  
 "  -c, --cmd            command to execute\n"  "  -c, --cmd            command to execute\n"
 "  -r, --read-only      export read-only\n"  "  -r, --read-only      export read-only\n"
 "  -s, --snapshot       use snapshot file\n"  "  -s, --snapshot       use snapshot file\n"
Line 1416  int main(int argc, char **argv) Line 1603  int main(int argc, char **argv)
 {  {
         int readonly = 0;          int readonly = 0;
         int growable = 0;          int growable = 0;
         const char *sopt = "hVc:Crsnmgk";          const char *sopt = "hVc:rsnmgk";
         struct option lopt[] = {          const struct option lopt[] = {
                 { "help", 0, NULL, 'h' },                  { "help", 0, NULL, 'h' },
                 { "version", 0, NULL, 'V' },                  { "version", 0, NULL, 'V' },
                 { "offset", 1, NULL, 'o' },                  { "offset", 1, NULL, 'o' },
                 { "cmd", 1, NULL, 'c' },                  { "cmd", 1, NULL, 'c' },
                 { "create", 0, NULL, 'C' },  
                 { "read-only", 0, NULL, 'r' },                  { "read-only", 0, NULL, 'r' },
                 { "snapshot", 0, NULL, 's' },                  { "snapshot", 0, NULL, 's' },
                 { "nocache", 0, NULL, 'n' },                  { "nocache", 0, NULL, 'n' },
Line 1448  int main(int argc, char **argv) Line 1634  int main(int argc, char **argv)
                 case 'c':                  case 'c':
                         add_user_command(optarg);                          add_user_command(optarg);
                         break;                          break;
                 case 'C':  
                         flags |= BDRV_O_CREAT;  
                         break;  
                 case 'r':                  case 'r':
                         readonly = 1;                          readonly = 1;
                         break;                          break;
Line 1491  int main(int argc, char **argv) Line 1674  int main(int argc, char **argv)
         add_command(&readv_cmd);          add_command(&readv_cmd);
         add_command(&write_cmd);          add_command(&write_cmd);
         add_command(&writev_cmd);          add_command(&writev_cmd);
           add_command(&multiwrite_cmd);
         add_command(&aio_read_cmd);          add_command(&aio_read_cmd);
         add_command(&aio_write_cmd);          add_command(&aio_write_cmd);
         add_command(&aio_flush_cmd);          add_command(&aio_flush_cmd);
Line 1504  int main(int argc, char **argv) Line 1688  int main(int argc, char **argv)
         add_check_command(init_check_command);          add_check_command(init_check_command);
   
         /* open the device */          /* open the device */
         if (readonly)          if (!readonly) {
                 flags |= BDRV_O_RDONLY;              flags |= BDRV_O_RDWR;
         else          }
                 flags |= BDRV_O_RDWR;  
   
         if ((argc - optind) == 1)          if ((argc - optind) == 1)
                 openfile(argv[optind], flags, growable);                  openfile(argv[optind], flags, growable);

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


unix.superglobalmegacorp.com