direct-io.hg

changeset 10703:fa143f374f3d

lomount: Major rewrite: handle large files and GPT partition.
Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author kaf24@firebug.cl.cam.ac.uk
date Fri Jul 14 13:53:59 2006 +0100 (2006-07-14)
parents ef8d08aa2072
children 3fa8b914e2b5
files tools/misc/lomount/lomount.c
line diff
     1.1 --- a/tools/misc/lomount/lomount.c	Fri Jul 14 12:00:02 2006 +0100
     1.2 +++ b/tools/misc/lomount/lomount.c	Fri Jul 14 13:53:59 2006 +0100
     1.3 @@ -4,6 +4,9 @@
     1.4   * Copyright (c) 2004 Jim Brown
     1.5   * Copyright (c) 2004 Brad Watson
     1.6   * Copyright (c) 2004 Mulyadi Santosa
     1.7 + * Major rewrite by Tristan Gingold:
     1.8 + *  - Handle GPT partitions
     1.9 + *  - Handle large files 
    1.10   *
    1.11   * Permission is hereby granted, free of charge, to any person obtaining a copy
    1.12   * of this software and associated documentation files (the "Software"), to deal
    1.13 @@ -41,6 +44,8 @@ enum
    1.14  	ERR_MOUNT		// Other failure of mount command
    1.15  };
    1.16  
    1.17 +#define _LARGEFILE_SOURCE
    1.18 +#define _FILE_OFFSET_BITS 64
    1.19  #include <unistd.h>
    1.20  #include <stdio.h>
    1.21  #include <stdlib.h>
    1.22 @@ -63,22 +68,179 @@ struct pentry
    1.23  	unsigned char end_head;
    1.24  	unsigned int  end_cylinder;
    1.25  	unsigned char end_sector;
    1.26 -	unsigned long start_sector_abs;
    1.27 -	unsigned long no_of_sectors_abs;
    1.28 +	unsigned long long start_sector_abs;
    1.29 +	unsigned long long no_of_sectors_abs;
    1.30  };
    1.31  
    1.32 -int loadptable(const char *diskimage, struct pentry parttbl[], struct pentry **exttbl, int * valid)
    1.33 +static void
    1.34 +disp_entry (struct pentry *p)
    1.35 +{
    1.36 +	printf ("%10llu - %10llu: %02x %x\n",
    1.37 +		SECSIZE * p->start_sector_abs,
    1.38 +		SECSIZE * (p->start_sector_abs + p->no_of_sectors_abs - 1),
    1.39 +		p->system,
    1.40 +		p->bootable);
    1.41 +}
    1.42 +
    1.43 +static unsigned long
    1.44 +read_le4 (unsigned char *p)
    1.45 +{
    1.46 +	return (unsigned long) p[0]
    1.47 +		| ((unsigned long) p[1] << 8)
    1.48 +		| ((unsigned long) p[2] << 16)
    1.49 +		| ((unsigned long) p[3] << 24);
    1.50 +}
    1.51 +
    1.52 +static unsigned long long
    1.53 +read_le8 (unsigned char *p)
    1.54 +{
    1.55 +	return (unsigned long long) p[0]
    1.56 +		| ((unsigned long long) p[1] << 8)
    1.57 +		| ((unsigned long long) p[2] << 16)
    1.58 +		| ((unsigned long long) p[3] << 24)
    1.59 +		| ((unsigned long long) p[4] << 32)
    1.60 +		| ((unsigned long long) p[5] << 40)
    1.61 +		| ((unsigned long long) p[6] << 48)
    1.62 +		| ((unsigned long long) p[7] << 56);
    1.63 +}
    1.64 +
    1.65 +/* Return true if the partition table is a GPT protective MBR.  */
    1.66 +static int
    1.67 +check_gpt (struct pentry *part, int nbr_part)
    1.68 +{
    1.69 +	if (nbr_part != 4)
    1.70 +		return 0;
    1.71 +	if (part[0].system == 0xee
    1.72 +	    && part[1].no_of_sectors_abs == 0
    1.73 +	    && part[2].no_of_sectors_abs == 0
    1.74 +	    && part[3].no_of_sectors_abs == 0)
    1.75 +		return 1;
    1.76 +	return 0;
    1.77 +}
    1.78 +
    1.79 +static int
    1.80 +load_gpt (const char *diskimage, struct pentry *parttbl[])
    1.81  {
    1.82  	FILE *fd;
    1.83  	size_t size;
    1.84 -	int fail = 1;
    1.85 -	int i, total_known_sectors = 0;
    1.86 +	int fail = -1;
    1.87 +	unsigned char data[SECSIZE];
    1.88 +	unsigned long long entries_lba;
    1.89 +	unsigned long entry_size;
    1.90 +	struct pentry *part;
    1.91 +	int nbr_part;
    1.92 +	unsigned long long off;
    1.93 +	int i;
    1.94 +
    1.95 +	fd = fopen(diskimage, "r");
    1.96 +	if (fd == NULL)
    1.97 +	{
    1.98 +		perror(diskimage);
    1.99 +		goto done;
   1.100 +	}
   1.101 +	fseeko (fd, SECSIZE, SEEK_SET);
   1.102 +	size = fread (&data, 1, sizeof(data), fd);
   1.103 +	if (size < (size_t)sizeof(data))
   1.104 +	{
   1.105 +		fprintf(stderr, "Could not read the GPT header of %s.\n",
   1.106 +			diskimage);
   1.107 +		goto done;
   1.108 +	}
   1.109 +
   1.110 +	if (memcmp (data, "EFI PART", 8) != 0)
   1.111 +	{
   1.112 +		fprintf (stderr, "Bad GPT signature\n");
   1.113 +		goto done;
   1.114 +	}
   1.115 +
   1.116 +	entries_lba = read_le8 (&data[72]);
   1.117 +	nbr_part = read_le4 (&data[80]);
   1.118 +	entry_size = read_le4 (&data[84]);
   1.119 +
   1.120 +#ifdef DEBUG
   1.121 +	fprintf(stderr, "lba entries: %lu, nbr_part: %u, entry_size: %lu\n",
   1.122 +		entries_lba, nbr_part, entry_size);
   1.123 +#endif
   1.124 +	part = malloc (nbr_part * sizeof (struct pentry));
   1.125 +	if (part == NULL)
   1.126 +	{
   1.127 +		fprintf(stderr,"Cannot allocate memory\n");
   1.128 +		goto done;
   1.129 +	}
   1.130 +	memset (part, 0, nbr_part * sizeof (struct pentry));
   1.131 +	*parttbl = part;
   1.132 +
   1.133 +	off = entries_lba * SECSIZE;
   1.134 +	for (i = 0; i < nbr_part; i++)
   1.135 +	{
   1.136 +		static const char unused_guid[16] = {0};
   1.137 +		fseeko (fd, off, SEEK_SET);
   1.138 +		size = fread (&data, 1, 128, fd);
   1.139 +		if (size < 128)
   1.140 +		{
   1.141 +			fprintf(stderr, "Could not read a GPT entry of %s.\n",
   1.142 +				diskimage);
   1.143 +			goto done;
   1.144 +		}
   1.145 +		if (memcmp (&data[0], unused_guid, 16) == 0)
   1.146 +		{
   1.147 +			part[i].start_sector_abs = 0;
   1.148 +			part[i].no_of_sectors_abs = 0;
   1.149 +		}
   1.150 +		else
   1.151 +		{
   1.152 +			part[i].start_sector_abs = read_le8 (&data[32]);
   1.153 +			part[i].no_of_sectors_abs = read_le8 (&data[40]);
   1.154 +#ifdef DEBUG
   1.155 +			fprintf (stderr, "%d: %llu - %llu\n", i,
   1.156 +				 part[i].start_sector_abs,
   1.157 +				 part[i].no_of_sectors_abs);
   1.158 +#endif
   1.159 +			/* Convert end to a number.  */
   1.160 +			part[i].no_of_sectors_abs -=
   1.161 +				part[i].start_sector_abs - 1;
   1.162 +		}
   1.163 +		off += entry_size;
   1.164 +	}
   1.165 +		
   1.166 +	fail = nbr_part;
   1.167 +
   1.168 +done:
   1.169 +	if (fd)
   1.170 +		fclose(fd);
   1.171 +	return fail;
   1.172 +}
   1.173 +
   1.174 +/* Read an MBR entry.  */
   1.175 +static void
   1.176 +read_mbr_record (unsigned char pi[16], struct pentry *res)
   1.177 +{
   1.178 +	res->bootable = *pi; 
   1.179 +	res->start_head  = *(pi + 1); 
   1.180 +	res->start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300);
   1.181 +	res->start_sector = *(pi + 2) & 0x3f;
   1.182 +	res->system = *(pi + 4);
   1.183 +	res->end_head = *(pi + 5);
   1.184 +	res->end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300);
   1.185 +	res->end_sector = *(pi + 6) & 0x3f;
   1.186 +	res->start_sector_abs = read_le4 (&pi[8]);
   1.187 +	res->no_of_sectors_abs = read_le4 (&pi[12]);
   1.188 +}
   1.189 +
   1.190 +/* Returns the number of partitions, -1 in case of failure.  */
   1.191 +int load_mbr(const char *diskimage, struct pentry *parttbl[])
   1.192 +{
   1.193 +	FILE *fd;
   1.194 +	size_t size;
   1.195 +	int fail = -1;
   1.196 +	int nbr_part;
   1.197 +	int i;
   1.198  	unsigned char *pi; 
   1.199  	unsigned char data [SECSIZE]; 
   1.200 -	unsigned long extent = 0, old_extent = 0, e_count = 1;
   1.201 -	struct pentry exttbls[4];
   1.202 +	unsigned long long extent;
   1.203 +	struct pentry *part;
   1.204  
   1.205 -	*valid = 0;
   1.206 +	nbr_part = 0;
   1.207  
   1.208  	fd = fopen(diskimage, "r");
   1.209  	if (fd == NULL)
   1.210 @@ -92,102 +254,61 @@ int loadptable(const char *diskimage, st
   1.211  		fprintf(stderr, "Could not read the entire first sector of %s.\n", diskimage);
   1.212  		goto done;
   1.213  	}
   1.214 +
   1.215 +	if (data [510] != 0x55 || data [511] != 0xaa)
   1.216 +	{
   1.217 +		fprintf(stderr,"MBR signature mismatch (invalid partition table?)\n");
   1.218 +		goto done;
   1.219 +	}
   1.220 +
   1.221 +	/* There is at most 4*4 + 4 = 20 entries, also there should be only
   1.222 +	   one extended partition.  */
   1.223 +	part = malloc (20 * sizeof (struct pentry));
   1.224 +	if (part == NULL)
   1.225 +	{
   1.226 +		fprintf(stderr,"Cannot allocate memory\n");
   1.227 +		goto done;
   1.228 +	}
   1.229 +	*parttbl = part;
   1.230 +
   1.231 +	/* Read MBR.  */
   1.232 +	nbr_part = 4;
   1.233  	for (i = 0; i < 4; i++)
   1.234  	{
   1.235  		pi = &data [446 + 16 * i];
   1.236 -		parttbl [i].bootable = *pi; 
   1.237 -		parttbl [i].start_head  = *(pi + 1); 
   1.238 -		parttbl [i].start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300);
   1.239 -		parttbl [i].start_sector = *(pi + 2) & 0x3f;
   1.240 -		parttbl [i].system = *(pi + 4);
   1.241 -		parttbl [i].end_head = *(pi + 5);
   1.242 -		parttbl [i].end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300);
   1.243 -		parttbl [i].end_sector = *(pi + 6) & 0x3f;
   1.244 -		parttbl [i].start_sector_abs = 
   1.245 -			(unsigned long) *(pi + 8) | ((unsigned long) *(pi + 9) << 8) | ((unsigned long) *(pi + 10) << 16) | ((unsigned long) *(pi + 11) << 24);
   1.246 -		parttbl [i].no_of_sectors_abs = 
   1.247 -			(unsigned long) *(pi + 12) | ((unsigned long) *(pi + 13) << 8) | ((unsigned long) *(pi + 14) << 16) | ((unsigned long) *(pi + 15) << 24);
   1.248 -		if (parttbl[i].system == 0xF || parttbl[i].system == 0x5)
   1.249 -		{
   1.250 -			extent = parttbl[i].start_sector_abs * SECSIZE;
   1.251 -			/* save the location of the "real" extended partition */
   1.252 -			old_extent = extent;
   1.253 -		}
   1.254 +		read_mbr_record (pi, &part[i]);
   1.255  	}
   1.256 -	*valid = (data [510] == 0x55 && data [511] == 0xaa) ? 1 : 0;
   1.257 +
   1.258 +	/* Read extended partitions.  */
   1.259  	for (i = 0; i < 4; i++)
   1.260  	{
   1.261 -		total_known_sectors += parttbl[i].no_of_sectors_abs;
   1.262 -	}
   1.263 -	/* Extended Partition layout format was obtained from
   1.264 -	http://wigner.cped.ornl.gov/the-gang/att-0520/03-Partition.htm */
   1.265 -#ifdef DEBUG
   1.266 -	if (extent != 0)
   1.267 -	{
   1.268 -		printf("extended partition detected at offset %ld\n", extent);
   1.269 -	}
   1.270 -#endif
   1.271 -	while (extent != 0)
   1.272 -	{
   1.273 -/* according to realloc(3) passing NULL as pointer is same as calling malloc() */
   1.274 -		exttbl[0] = realloc(exttbl[0], e_count * sizeof(struct pentry));
   1.275 -		fseek(fd, extent, SEEK_SET);
   1.276 -		size = fread (&data, 1, sizeof(data), fd);
   1.277 -		if (size < (size_t)sizeof(data))
   1.278 -		{
   1.279 -			fprintf(stderr, "Could not read extended partition of %s.", diskimage);
   1.280 -			goto done;
   1.281 -		}
   1.282 -	/* only first 2 entrys are used in extented partition tables */
   1.283 -		for (i = 0; i < 2; i++)
   1.284 +		if (part[i].system == 0xF || part[i].system == 0x5)
   1.285  		{
   1.286 -			pi = &data [446 + 16 * i];
   1.287 -			exttbls [i].bootable = *pi; 
   1.288 -			exttbls [i].start_head  = *(pi + 1); 
   1.289 -			exttbls [i].start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300);
   1.290 -			exttbls [i].start_sector = *(pi + 2) & 0x3f;
   1.291 -			exttbls [i].system = *(pi + 4);
   1.292 -			exttbls [i].end_head = *(pi + 5);
   1.293 -			exttbls [i].end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300);
   1.294 -			exttbls [i].end_sector = *(pi + 6) & 0x3f;
   1.295 -			exttbls [i].start_sector_abs = 
   1.296 -				(unsigned long) *(pi + 8) | ((unsigned long) *(pi + 9) << 8) | ((unsigned long) *(pi + 10) << 16) | ((unsigned long) *(pi + 11) << 24);
   1.297 -			exttbls [i].no_of_sectors_abs = 
   1.298 -				(unsigned long) *(pi + 12) | ((unsigned long) *(pi + 13) << 8) | ((unsigned long) *(pi + 14) << 16) | ((unsigned long) *(pi + 15) << 24);
   1.299 -			if (i == 0)
   1.300 +			int j;
   1.301 +
   1.302 +			extent = part[i].start_sector_abs * SECSIZE;
   1.303 +
   1.304 +			fseeko (fd, extent, SEEK_SET);
   1.305 +			size = fread (&data, 1, sizeof(data), fd);
   1.306 +			if (size < (size_t)sizeof(data))
   1.307  			{
   1.308 -				//memmove((void *)exttbl[e_count-1], (void *)exttbls[i], sizeof(struct pentry));
   1.309 -				//memmove() seems broken!
   1.310 -				exttbl[0][e_count-1].bootable = exttbls [i].bootable;
   1.311 -				exttbl[0][e_count-1].start_head  = exttbls [i].start_head;
   1.312 -				exttbl[0][e_count-1].start_cylinder = exttbls [i].start_cylinder;
   1.313 -				exttbl[0][e_count-1].start_sector = exttbls [i].start_sector;
   1.314 -				exttbl[0][e_count-1].system = exttbls [i].system;
   1.315 -				exttbl[0][e_count-1].end_head = exttbls [i].end_head;
   1.316 -				exttbl[0][e_count-1].end_cylinder = exttbls [i].end_cylinder;
   1.317 -				exttbl[0][e_count-1].end_sector = exttbls [i].end_sector;
   1.318 -				exttbl[0][e_count-1].start_sector_abs = exttbls [i].start_sector_abs;
   1.319 -				exttbl[0][e_count-1].no_of_sectors_abs = exttbls [i].no_of_sectors_abs;
   1.320 -			/* adjust for start of image instead of start of ext partition */
   1.321 -				exttbl[0][e_count-1].start_sector_abs += (extent/SECSIZE);
   1.322 -#ifdef DEBUG
   1.323 -				printf("extent %ld start_sector_abs %ld\n", extent, exttbl[0][e_count-1].start_sector_abs);
   1.324 -#endif
   1.325 -			//else if (parttbl[i].system == 0x5)
   1.326 +				fprintf(stderr, "Could not read extended partition of %s.", diskimage);
   1.327 +				goto done;
   1.328  			}
   1.329 -			else if (i == 1)
   1.330 +
   1.331 +			for (j = 0; j < 4; j++)
   1.332  			{
   1.333 -				extent = (exttbls[i].start_sector_abs * SECSIZE);
   1.334 -				if (extent)
   1.335 -					extent += old_extent;
   1.336 +				int n;
   1.337 +				pi = &data [446 + 16 * j];
   1.338 +				n = nbr_part + j;
   1.339 +				read_mbr_record (pi, &part[n]);
   1.340  			}
   1.341 +
   1.342 +			nbr_part += 4;
   1.343  		}
   1.344 -		e_count ++;
   1.345  	}
   1.346 -#ifdef DEBUG
   1.347 -	printf("e_count = %ld\n", e_count);
   1.348 -#endif
   1.349 -	fail = 0;
   1.350 +
   1.351 +	fail = nbr_part;
   1.352  
   1.353  done:
   1.354  	if (fd)
   1.355 @@ -197,8 +318,8 @@ done:
   1.356  
   1.357  void usage(void)
   1.358  {
   1.359 -	fprintf(stderr, "You must specify at least -diskimage and -partition.\n");
   1.360 -	fprintf(stderr, "All other arguments are passed through to 'mount'.\n");
   1.361 +	fprintf(stderr, "Usage: lomount [-verbose] [OPTIONS] -diskimage FILE -partition NUM [OPTIONS]\n");
   1.362 +	fprintf(stderr, "All OPTIONS are passed through to 'mount'.\n");
   1.363  	fprintf(stderr, "ex. lomount -t fs-type -diskimage hda.img -partition 1 /mnt\n");
   1.364  	exit(ERR_USAGE);
   1.365  }
   1.366 @@ -206,14 +327,17 @@ void usage(void)
   1.367  int main(int argc, char ** argv)
   1.368  {
   1.369  	int status;
   1.370 -	struct pentry perttbl [4];
   1.371 -	struct pentry *exttbl[1], *parttbl;
   1.372 +	int nbr_part;
   1.373 +	struct pentry *parttbl;
   1.374  	char buf[BUF], argv2[BUF];
   1.375 -	const char * diskimage = 0;
   1.376 -	int partition = 0, sec, num = 0, pnum = 0, i, valid;
   1.377 +	const char * diskimage = NULL;
   1.378 +	int partition = 0;
   1.379 +	unsigned long long sec, num, pnum;
   1.380 +	int i;
   1.381  	size_t argv2_len = sizeof(argv2);
   1.382 +	int verbose = 0;
   1.383 +
   1.384  	argv2[0] = '\0';
   1.385 -	exttbl[0] = NULL;
   1.386  
   1.387  	for (i = 1; i < argc; i ++)
   1.388  	{
   1.389 @@ -231,6 +355,10 @@ int main(int argc, char ** argv)
   1.390  			i++;
   1.391  			partition = atoi(argv[i]);
   1.392  		}
   1.393 +		else if (strcmp(argv[i], "-verbose")==0)
   1.394 +		{
   1.395 +			verbose++;
   1.396 +		}
   1.397  		else
   1.398  		{
   1.399  			size_t len = strlen(argv[i]);
   1.400 @@ -241,59 +369,65 @@ int main(int argc, char ** argv)
   1.401  			len -= (len+1);
   1.402  		}
   1.403  	}
   1.404 -	if (! diskimage || partition < 1)
   1.405 +	if (! diskimage || partition < 0)
   1.406  		usage();
   1.407  
   1.408 -	if (loadptable(diskimage, perttbl, exttbl, &valid))
   1.409 +	nbr_part = load_mbr(diskimage, &parttbl);
   1.410 +	if (check_gpt (parttbl, nbr_part)) {
   1.411 +		free (parttbl);
   1.412 +		nbr_part = load_gpt (diskimage, &parttbl);
   1.413 +	}
   1.414 +	if (nbr_part < 0)
   1.415  		return ERR_PART_PARSE;
   1.416 -	if (!valid)
   1.417 +	if (partition == 0)
   1.418  	{
   1.419 -		fprintf(stderr, "Warning: disk image does not appear to describe a valid partition table.\n");
   1.420 +		printf("Please specify a partition number.  Table is:\n");
   1.421 +		printf("Num      Start -        End  OS Bootable\n");
   1.422 +		for (i = 0; i < nbr_part; i++)
   1.423 +		{
   1.424 +			if (parttbl[i].no_of_sectors_abs != 0)
   1.425 +			{
   1.426 +				printf ("%2d: ", i + 1);
   1.427 +				disp_entry (&parttbl[i]);
   1.428 +			}
   1.429 +		}
   1.430 +		if (partition == 0)
   1.431 +			return 0;
   1.432  	}
   1.433  	/* NOTE: need to make sure this always rounds down */
   1.434  	//sec = total_known_sectors / sizeof_diskimage;
   1.435 -/* The above doesn't work unless the disk image is completely filled by
   1.436 -partitions ... unused space will thrown off the sector size. The calculation
   1.437 -assumes the disk image is completely filled, and that the few sectors used
   1.438 -to store the partition table/MBR are few enough that the calculated value is
   1.439 -off by (larger than) a value less than one. */
   1.440 +	/* The above doesn't work unless the disk image is completely
   1.441 +	   filled by partitions ... unused space will thrown off the
   1.442 +	   sector size. The calculation assumes the disk image is
   1.443 +	   completely filled, and that the few sectors used to store
   1.444 +	   the partition table/MBR are few enough that the calculated
   1.445 +	   value is off by (larger than) a value less than one. */
   1.446  	sec = 512; /* TODO: calculate real sector size */
   1.447  #ifdef DEBUG
   1.448  	printf("sec: %d\n", sec);
   1.449  #endif
   1.450 -	if (partition > 4)
   1.451 +	if (partition > nbr_part)
   1.452  	{
   1.453 -		if (exttbl[0] == NULL)
   1.454 -		{
   1.455 -		    fprintf(stderr, "No extended partitions were found in %s.\n", diskimage);
   1.456 -		    return ERR_NO_EPART;
   1.457 -		}
   1.458 -		parttbl = exttbl[0];
   1.459 -		if (parttbl[partition-5].no_of_sectors_abs == 0)
   1.460 -		{
   1.461 -			fprintf(stderr, "Partition %d was not found in %s.\n", partition, diskimage);
   1.462 -			return ERR_NO_PART;
   1.463 -		}
   1.464 -		partition -= 4;
   1.465 -	}
   1.466 -	else
   1.467 -	{
   1.468 -		parttbl = perttbl;
   1.469 -		if (parttbl[partition-1].no_of_sectors_abs == 0)
   1.470 -		{
   1.471 -			fprintf(stderr, "Partition %d was not found in %s.\n", partition, diskimage);
   1.472 -			return ERR_NO_PART;
   1.473 -		}
   1.474 +		fprintf(stderr, "Bad partition number\n");
   1.475 +		return ERR_NO_EPART;
   1.476  	}
   1.477  	num = parttbl[partition-1].start_sector_abs;
   1.478 +	if (num == 0)
   1.479 +	{
   1.480 +		fprintf(stderr, "Partition %d was not found in %s.\n",
   1.481 +			partition, diskimage);
   1.482 +		return ERR_NO_PART;
   1.483 +	}
   1.484 +
   1.485  	pnum = sec * num;
   1.486  #ifdef DEBUG
   1.487  	printf("offset = %d\n", pnum);
   1.488  #endif
   1.489 -	snprintf(buf, sizeof(buf), "mount -oloop,offset=%d %s %s", pnum, diskimage, argv2);
   1.490 -#ifdef DEBUG
   1.491 -	printf("%s\n", buf);
   1.492 -#endif
   1.493 +	snprintf(buf, sizeof(buf), "mount -oloop,offset=%lld %s %s",
   1.494 +		 pnum, diskimage, argv2);
   1.495 +	if (verbose)
   1.496 +		printf("%s\n", buf);
   1.497 +
   1.498  	status = system(buf);
   1.499  	if (WIFEXITED(status))
   1.500  		status = WEXITSTATUS(status);