Esempio n. 1
0
int
get_var (FILE *fp, char **name, char **value)
{
  static char *buffer;
  static size_t bufsize = OFF_T_STRSIZE_BOUND;
  char *p, *q;

  buffer = emalloc (bufsize);
  do
    {
      size_t len, s;

      if (!fgets (buffer, bufsize, fp))
	return 0;
      len = strlen (buffer);
      if (len == 0)
	return 0;

      s = string_to_size (buffer, &p);
      if (*p != ' ')
	die (1, "malformed header: expected space but found %s", p);
      if (buffer[len-1] != '\n')
	{
	  if (bufsize < s + 1)
	    {
	      bufsize = s + 1;
	      buffer = realloc (buffer, bufsize);
	      if (!buffer)
		die (1, "not enough memory");
	    }
	  if (!fgets (buffer + len, s - len + 1, fp))
	    die (1, "unexpected end of file or read error");
	}
      p++;
    }
  while (memcmp (p, "GNU.sparse.", 11));

  p += 11;
  q = strchr (p, '=');
  if (!q)
    die (1, "malformed header: expected '=' not found");
  *q++ = 0;
  q[strlen (q) - 1] = 0;
  *name = p;
  *value = q;
  return 1;
}
Esempio n. 2
0
void
read_map (FILE *ifp)
{
  size_t i;
  char nbuf[OFF_T_STRSIZE_BOUND];

  if (verbose)
    printf ("Reading v.1.0 sparse map\n");

  get_line (nbuf, sizeof nbuf, ifp);
  sparse_map_size = string_to_size (nbuf, NULL);
  sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);

  for (i = 0; i < sparse_map_size; i++)
    {
      get_line (nbuf, sizeof nbuf, ifp);
      sparse_map[i].offset = string_to_off (nbuf, NULL);
      get_line (nbuf, sizeof nbuf, ifp);
      sparse_map[i].numbytes = string_to_off (nbuf, NULL);
    }

  fseeko (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE,
	  SEEK_SET);
}
Esempio n. 3
0
///
/// It all starts here.
///
int32_t
main(int32_t ac, char *av[])
{
	for (int32_t i = 1; i < ac; ++i) {
		if (av[i][0] == '-') {
			switch (av[i][1]) {
			case 'r':
				rand_flag = true;
				break;

			default:
				fprintf(stderr, "invalid option: %s\n", av[i]);
				usage();
				return 1;
			}
		} else if (device == 0) {
			device = av[i];
		} else if (block_size == 0) {
			if (!string_to_size(av[i], &block_size)) {
				fprintf(stderr, "invalid block size: %s\n", av[i]);
				usage();
				return 1;
			}
		} else if (limit == 0) {
			if (!string_to_size(av[i], &limit)) {
				fprintf(stderr, "invalid limit: %s\n", av[i]);
				usage();
				return 1;
			}
		} else if (size == 0) {
			if (!string_to_size(av[i], &size)) {
				fprintf(stderr, "invalid size: %s\n", av[i]);
				usage();
				return 1;
			}
		}
	}

	bool err = false;

	if (device == 0) {
		fprintf(stderr, "missing device\n");
		err = true;
	}

	if (block_size == 0) {
		fprintf(stderr, "missing block size\n");
		err = true;
	}

	if (limit == 0) {
		fprintf(stderr, "missing limit\n");
		err = true;
	}

	if (size == 0) {
		fprintf(stderr, "missing size\n");
		err = true;
	}

	if (block_size != 0 && limit % block_size != 0) {
		fprintf(stderr, "limit must be a multiple of block size\n");
		err = true;
	}

	if (block_size != 0 && size % block_size != 0) {
		fprintf(stderr, "size must be a multiple of block size\n");
		err = true;
	}

	if (block_size != 0 && limit / block_size % 3 == 0) {
		fprintf(stderr, "limit must be relatively prime with random "
				"multiplier %lu\n", rand_mult);
		err = true;
	}

	if (err) {
		usage();
		return 1;
	}

	int32_t ret_val = 1;
	printf("reading %lu byte(s) from %s, block size = %lu, limit = %lu (%s)\n",
			size, device, block_size, limit, rand_flag ? "random" : "linear");
	uint8_t *buffer = malloc(block_size + 16384);

	if (buffer == 0) {
		fprintf(stderr, "cannot allocate block buffer\n");
		goto cleanup0;
	}

	uint64_t buff_off = (((uint64_t)buffer + 16383) & (uint64_t)~16383) - (uint64_t)buffer;
	printf("(buffer at %p, offset is %lu, effective buffer at %p)\n", buffer,
			buff_off, buffer + buff_off);
	int32_t fd = open(device, O_RDONLY | O_DIRECT);

	if (fd < 0) {
		fprintf(stderr, "cannot open device %s: %d, %s\n", device, errno,
				strerror(errno));
		goto cleanup1;
	}

	const uint64_t block_limit = limit / block_size;
	uint64_t count = 0;
	uint64_t start;

	if (!get_time(&start)) {
		fprintf(stderr, "cannot get start time\n");
		goto cleanup2;
	}

	uint64_t last_now = 0;

	while (count < size) {
		uint64_t block_count = count / block_size;

		if (rand_flag) {
			block_count = block_count * rand_mult;
		}

		block_count = block_count % block_limit;
		uint64_t seek = block_count * block_size;

		if (lseek(fd, (off_t)seek, SEEK_SET) < 0) {
			fprintf(stderr, "error while seeking to %lu: %d, %s\n", seek, errno,
					strerror(errno));
			goto cleanup2;
		}

		ssize_t res = read(fd, buffer + buff_off, block_size);

		if (res != (ssize_t)block_size) {
			fprintf(stderr, "error while reading at %lu: %ld byte(s) read\n", seek,
					res);

			if (res < 0) {
				fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
			}

			goto cleanup2;
		}

		count += block_size;
		uint64_t now;

		if (!get_time(&now)) {
			fprintf(stderr, "cannot get current time\n");
			goto cleanup2;
		}

		if (now - last_now >= 5000 || count == size) {
			uint32_t perc = (uint32_t)(count * 100 / size);
			printf("%d%% complete\n", perc);
			last_now = now;
		}
	}

	uint64_t end;

	if (!get_time(&end)) {
		fprintf(stderr, "cannot get end time\n");
		goto cleanup2;
	}

	float sec = (float)(end - start) / (float)1000.0;
	float speed = (float)size / sec / (float)1024.0 / (float)1024.0;
	float iops = (float)(size / block_size) / sec;
	printf("%.1f s, %.1f MiB/s, %.1f IOPS\n", sec, speed, iops);
	ret_val = 0;

cleanup2:
	close(fd);

cleanup1:
	free(buffer);

cleanup0:
	return ret_val;
}
Esempio n. 4
0
void
read_xheader (char *name)
{
  char *kw, *val;
  FILE *fp = fopen (name, "r");
  char *expect = NULL;
  size_t i = 0;

  if (verbose)
    printf ("Reading extended header file\n");

  while (get_var (fp, &kw, &val))
    {
      if (verbose)
	printf ("Found variable GNU.sparse.%s = %s\n", kw, val);

      if (expect && strcmp (kw, expect))
	die (1, "bad keyword sequence: expected '%s' but found '%s'",
	     expect, kw);
      expect = NULL;
      if (strcmp (kw, "name") == 0)
	{
	  outname = emalloc (strlen (val) + 1);
	  strcpy (outname, val);
	}
      else if (strcmp (kw, "major") == 0)
	{
	  version_major = string_to_size (val, NULL);
	}
      else if (strcmp (kw, "minor") == 0)
	{
	  version_minor = string_to_size (val, NULL);
	}
      else if (strcmp (kw, "realsize") == 0
	       || strcmp (kw, "size") == 0)
	{
	  outsize = string_to_off (val, NULL);
	}
      else if (strcmp (kw, "numblocks") == 0)
	{
	  sparse_map_size = string_to_size (val, NULL);
	  sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
	}
      else if (strcmp (kw, "offset") == 0)
	{
	  sparse_map[i].offset = string_to_off (val, NULL);
	  expect = "numbytes";
	}
      else if (strcmp (kw, "numbytes") == 0)
	{
	  sparse_map[i++].numbytes = string_to_off (val, NULL);
	}
      else if (strcmp (kw, "map") == 0)
	{
	  for (i = 0; i < sparse_map_size; i++)
	    {
	      sparse_map[i].offset = string_to_off (val, &val);
	      if (*val != ',')
		die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
		     *val);
	      sparse_map[i].numbytes = string_to_off (val+1, &val);
	      if (*val != ',')
		{
		  if (!(*val == 0 && i == sparse_map_size-1))
		    die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
			 *val);
		}
	      else
		val++;
	    }
	  if (*val)
	    die (1, "bad GNU.sparse.map: garbage at the end");
	}
    }
  if (expect)
    die (1, "bad keyword sequence: expected '%s' not found", expect);
  if (version_major == 0 && sparse_map_size == 0)
    die (1, "size of the sparse map unknown");
  if (i != sparse_map_size)
    die (1, "not all sparse entries supplied");
  fclose (fp);
}