1  /*
       2   * isosize.c - Andries Brouwer, 000608
       3   *
       4   * use header info to find size of iso9660 file system
       5   * output a number - useful in scripts
       6   *
       7   * Synopsis:
       8   *    isosize [-x] [-d <num>] <filename>
       9   *        where "-x" gives length in sectors and sector size while
      10   *              without this argument the size is given in bytes
      11   *        without "-x" gives length in bytes unless "-d <num>" is
      12   *		given. In the latter case the length in bytes divided
      13   *		by <num> is given
      14   *
      15   *  Version 2.03 2000/12/21
      16   *     - add "-d <num>" option and use long long to fix things > 2 GB
      17   *  Version 2.02 2000/10/11
      18   *     - error messages on IO failures [D. Gilbert]
      19   *
      20   */
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <getopt.h>
      24  #include <fcntl.h>
      25  #include <unistd.h>
      26  #include <errno.h>
      27  
      28  #include "nls.h"
      29  #include "c.h"
      30  #include "strutils.h"
      31  #include "closestream.h"
      32  #include "iso9660.h"
      33  
      34  #define ISOSIZE_EXIT_ALLFAILED	32
      35  #define ISOSIZE_EXIT_SOMEOK	64
      36  
      37  static int is_iso(int fd)
      38  {
      39  	char label[8];
      40  
      41  	if (pread(fd, &label, 8, 0x8000) == -1)
      42  		return 1;
      43  	return memcmp(&label, &"\1CD001\1", 8);
      44  }
      45  
      46  static int isosize(int argc, char *filenamep, int xflag, long divisor)
      47  {
      48  	int fd, nsecs, ssize, rc = -1;
      49  	unsigned char volume_space_size[8];
      50  	unsigned char logical_block_size[4];
      51  
      52  	if ((fd = open(filenamep, O_RDONLY)) < 0) {
      53  		warn(_("cannot open %s"), filenamep);
      54  		goto done;
      55  	}
      56  	if (is_iso(fd))
      57  		warnx(_("%s: might not be an ISO filesystem"), filenamep);
      58  
      59  	if (pread(fd, volume_space_size, sizeof(volume_space_size), 0x8050) != sizeof(volume_space_size) ||
      60  	    pread(fd, logical_block_size, sizeof(logical_block_size), 0x8080) != sizeof(logical_block_size)) {
      61  		if (errno)
      62  			warn(_("read error on %s"), filenamep);
      63  		else
      64  			warnx(_("read error on %s"), filenamep);
      65  		goto done;
      66  	}
      67  
      68  	nsecs = isonum_733(volume_space_size, xflag);
      69  	/* isonum_723 returns nowadays always 2048 */
      70  	ssize = isonum_723(logical_block_size, xflag);
      71  
      72  	if (1 < argc)
      73  		printf("%s: ", filenamep);
      74  	if (xflag)
      75  		printf(_("sector count: %d, sector size: %d\n"), nsecs, ssize);
      76  	else {
      77  		long long product = nsecs;
      78  
      79  		if (divisor == 0)
      80  			printf("%lld\n", product * ssize);
      81  		else if (divisor == ssize)
      82  			printf("%d\n", nsecs);
      83  		else
      84  			printf("%lld\n", (product * ssize) / divisor);
      85  	}
      86  
      87  	rc = 0;
      88  done:
      89  	if (fd >= 0)
      90  		close(fd);
      91  	return rc;
      92  }
      93  
      94  static void __attribute__((__noreturn__)) usage(void)
      95  {
      96  
      97  	fputs(USAGE_HEADER, stdout);
      98  	fprintf(stdout,
      99  		_(" %s [options] <iso9660_image_file> ...\n"),
     100  		program_invocation_short_name);
     101  
     102  	fputs(USAGE_SEPARATOR, stdout);
     103  	fputs(_("Show the length of an ISO-9660 filesystem.\n"), stdout);
     104  
     105  	fputs(USAGE_OPTIONS, stdout);
     106  	fputs(_(" -d, --divisor=<number>  divide the amount of bytes by <number>\n"), stdout);
     107  	fputs(_(" -x, --sectors           show sector count and size\n"), stdout);
     108  
     109  	printf(USAGE_HELP_OPTIONS(25));
     110  	printf(USAGE_MAN_TAIL("isosize(8)"));
     111  
     112  	exit(EXIT_SUCCESS);
     113  }
     114  
     115  int main(int argc, char **argv)
     116  {
     117  	int j, ct_err = 0, ct, opt, xflag = 0;
     118  	long divisor = 0;
     119  
     120  	static const struct option longopts[] = {
     121  		{"divisor", required_argument, NULL, 'd'},
     122  		{"sectors", no_argument,       NULL, 'x'},
     123  		{"version", no_argument,       NULL, 'V'},
     124  		{"help",    no_argument,       NULL, 'h'},
     125  		{NULL, 0, NULL, 0}
     126  	};
     127  
     128  	setlocale(LC_ALL, "");
     129  	bindtextdomain(PACKAGE, LOCALEDIR);
     130  	textdomain(PACKAGE);
     131  	close_stdout_atexit();
     132  
     133  	while ((opt = getopt_long(argc, argv, "d:xVh", longopts, NULL)) != -1) {
     134  		switch (opt) {
     135  		case 'd':
     136  			divisor =
     137  			    strtol_or_err(optarg,
     138  					  _("invalid divisor argument"));
     139  			break;
     140  		case 'x':
     141  			xflag = 1;
     142  			break;
     143  		case 'V':
     144  			print_version(EXIT_SUCCESS);
     145  		case 'h':
     146  			usage();
     147  		default:
     148  			errtryhelp(EXIT_FAILURE);
     149  		}
     150  	}
     151  
     152  	ct = argc - optind;
     153  
     154  	if (ct <= 0) {
     155  		warnx(_("no device specified"));
     156  		errtryhelp(EXIT_FAILURE);
     157  	}
     158  
     159  	for (j = optind; j < argc; j++) {
     160  		if (isosize(ct, argv[j], xflag, divisor) != 0)
     161  			ct_err++;
     162  	}
     163  
     164  	return	ct == ct_err	? ISOSIZE_EXIT_ALLFAILED :	/* all failed */
     165  		ct_err		? ISOSIZE_EXIT_SOMEOK :		/* some ok */
     166  		EXIT_SUCCESS;					/* all success */
     167  }