| /* |
| * 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" |
| #include "iso9660.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 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 */ |
| } |