/*
* isosize.c - Andries Brouwer, 000608
*
* use header info to find size of iso9660 file system
* output a number - useful in scripts
*
* Synopsis:
* isosize [-x] [-d <num>] <filename>
* where "-x" gives length in sectors and sector size while
* without this argument the size is given in bytes
* without "-x" gives length in bytes unless "-d <num>" is
* given. In the latter case the length in bytes divided
* by <num> is given
*
* Version 2.03 2000/12/21
* - add "-d <num>" option and use long long to fix things > 2 GB
* Version 2.02 2000/10/11
* - error messages on IO failures [D. Gilbert]
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "nls.h"
#include "c.h"
#include "strutils.h"
#include "closestream.h"
#define ISOSIZE_EXIT_ALLFAILED 32
#define ISOSIZE_EXIT_SOMEOK 64
static int is_iso(int fd)
{
char label[8];
if (pread(fd, &label, 8, 0x8000) == -1)
return 1;
return memcmp(&label, &"\1CD001\1", 8);
}
static int isonum_721(unsigned char *p)
{
return ((p[0] & 0xff)
| ((p[1] & 0xff) << 8));
}
static int isonum_722(unsigned char *p)
{
return ((p[1] & 0xff)
| ((p[0] & 0xff) << 8));
}
static int isonum_723(unsigned char *p, int xflag)
{
int le = isonum_721(p);
int be = isonum_722(p + 2);
if (xflag && le != be)
/* translation is useless */
warnx("723error: le=%d be=%d", le, be);
return (le);
}
static int isonum_731(unsigned char *p)
{
return ((p[0] & 0xff)
| ((p[1] & 0xff) << 8)
| ((p[2] & 0xff) << 16)
| ((p[3] & 0xff) << 24));
}
static int isonum_732(unsigned char *p)
{
return ((p[3] & 0xff)
| ((p[2] & 0xff) << 8)
| ((p[1] & 0xff) << 16)
| ((p[0] & 0xff) << 24));
}
static int isonum_733(unsigned char *p, int xflag)
{
int le = isonum_731(p);
int be = isonum_732(p + 4);
if (xflag && le != be)
/* translation is useless */
warnx("733error: le=%d be=%d", le, be);
return (le);
}
static int isosize(int argc, char *filenamep, int xflag, long divisor)
{
int fd, nsecs, ssize, rc = -1;
unsigned char volume_space_size[8];
unsigned char logical_block_size[4];
if ((fd = open(filenamep, O_RDONLY)) < 0) {
warn(_("cannot open %s"), filenamep);
goto done;
}
if (is_iso(fd))
warnx(_("%s: might not be an ISO filesystem"), filenamep);
if (pread(fd, volume_space_size, sizeof(volume_space_size), 0x8050) != sizeof(volume_space_size) ||
pread(fd, logical_block_size, sizeof(logical_block_size), 0x8080) != sizeof(logical_block_size)) {
if (errno)
warn(_("read error on %s"), filenamep);
else
warnx(_("read error on %s"), filenamep);
goto done;
}
nsecs = isonum_733(volume_space_size, xflag);
/* isonum_723 returns nowadays always 2048 */
ssize = isonum_723(logical_block_size, xflag);
if (1 < argc)
printf("%s: ", filenamep);
if (xflag)
printf(_("sector count: %d, sector size: %d\n"), nsecs, ssize);
else {
long long product = nsecs;
if (divisor == 0)
printf("%lld\n", product * ssize);
else if (divisor == ssize)
printf("%d\n", nsecs);
else
printf("%lld\n", (product * ssize) / divisor);
}
rc = 0;
done:
if (fd >= 0)
close(fd);
return rc;
}
static void __attribute__((__noreturn__)) usage(void)
{
fputs(USAGE_HEADER, stdout);
fprintf(stdout,
_(" %s [options] <iso9660_image_file> ...\n"),
program_invocation_short_name);
fputs(USAGE_SEPARATOR, stdout);
fputs(_("Show the length of an ISO-9660 filesystem.\n"), stdout);
fputs(USAGE_OPTIONS, stdout);
fputs(_(" -d, --divisor=<number> divide the amount of bytes by <number>\n"), stdout);
fputs(_(" -x, --sectors show sector count and size\n"), stdout);
printf(USAGE_HELP_OPTIONS(25));
printf(USAGE_MAN_TAIL("isosize(8)"));
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
int j, ct_err = 0, ct, opt, xflag = 0;
long divisor = 0;
static const struct option longopts[] = {
{"divisor", required_argument, NULL, 'd'},
{"sectors", no_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
close_stdout_atexit();
while ((opt = getopt_long(argc, argv, "d:xVh", longopts, NULL)) != -1) {
switch (opt) {
case 'd':
divisor =
strtol_or_err(optarg,
_("invalid divisor argument"));
break;
case 'x':
xflag = 1;
break;
case 'V':
print_version(EXIT_SUCCESS);
case 'h':
usage();
default:
errtryhelp(EXIT_FAILURE);
}
}
ct = argc - optind;
if (ct <= 0) {
warnx(_("no device specified"));
errtryhelp(EXIT_FAILURE);
}
for (j = optind; j < argc; j++) {
if (isosize(ct, argv[j], xflag, divisor) != 0)
ct_err++;
}
return ct == ct_err ? ISOSIZE_EXIT_ALLFAILED : /* all failed */
ct_err ? ISOSIZE_EXIT_SOMEOK : /* some ok */
EXIT_SUCCESS; /* all success */
}