#include "c.h"
#include "strutils.h"
#include "closestream.h"
+#include "iso9660.h"
-#define ISODCL(from, to) (to - from + 1)
+#define ISOSIZE_EXIT_ALLFAILED 32
+#define ISOSIZE_EXIT_SOMEOK 64
-static int isonum_721(unsigned char *p)
+static int is_iso(int fd)
{
- 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));
-}
+ char label[8];
-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 */
- warn("733error: le=%d be=%d", le, be);
- return (le);
+ if (pread(fd, &label, 8, 0x8000) == -1)
+ return 1;
+ return memcmp(&label, &"\1CD001\1", 8);
}
-struct iso_primary_descriptor
-{
- unsigned char type [ISODCL ( 1, 1)]; /* 711 */
- unsigned char id [ISODCL ( 2, 6)];
- unsigned char version [ISODCL ( 7, 7)]; /* 711 */
- unsigned char unused1 [ISODCL ( 8, 8)];
- unsigned char system_id [ISODCL ( 9, 40)]; /* auchars */
- unsigned char volume_id [ISODCL ( 41, 72)]; /* duchars */
- unsigned char unused2 [ISODCL ( 73, 80)];
- unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
- unsigned char unused3 [ISODCL ( 89, 120)];
- unsigned char volume_set_size [ISODCL ( 121, 124)]; /* 723 */
- unsigned char volume_sequence_number [ISODCL ( 125, 128)]; /* 723 */
- unsigned char logical_block_size [ISODCL ( 129, 132)]; /* 723 */
- unsigned char path_table_size [ISODCL ( 133, 140)]; /* 733 */
- unsigned char type_l_path_table [ISODCL ( 141, 144)]; /* 731 */
- unsigned char opt_type_l_path_table [ISODCL ( 145, 148)]; /* 731 */
- unsigned char type_m_path_table [ISODCL ( 149, 152)]; /* 732 */
- unsigned char opt_type_m_path_table [ISODCL ( 153, 156)]; /* 732 */
- unsigned char root_directory_record [ISODCL ( 157, 190)]; /* 9.1 */
- unsigned char volume_set_id [ISODCL ( 191, 318)]; /* duchars */
- unsigned char publisher_id [ISODCL ( 319, 446)]; /* achars */
- unsigned char preparer_id [ISODCL ( 447, 574)]; /* achars */
- unsigned char application_id [ISODCL ( 575, 702)]; /* achars */
- unsigned char copyright_file_id [ISODCL ( 703, 739)]; /* 7.5 dchars */
- unsigned char abstract_file_id [ISODCL ( 740, 776)]; /* 7.5 dchars */
- unsigned char bibliographic_file_id [ISODCL ( 777, 813)]; /* 7.5 dchars */
- unsigned char creation_date [ISODCL ( 814, 830)]; /* 8.4.26.1 */
- unsigned char modification_date [ISODCL ( 831, 847)]; /* 8.4.26.1 */
- unsigned char expiration_date [ISODCL ( 848, 864)]; /* 8.4.26.1 */
- unsigned char effective_date [ISODCL ( 865, 881)]; /* 8.4.26.1 */
- unsigned char file_structure_version [ISODCL ( 882, 882)]; /* 711 */
- unsigned char unused4 [ISODCL ( 883, 883)];
- unsigned char application_data [ISODCL ( 884, 1395)];
- unsigned char unused5 [ISODCL (1396, 2048)];
-};
-
-static void isosize(char *filenamep, int xflag, long divisor)
+static int isosize(int argc, char *filenamep, int xflag, long divisor)
{
- int fd, nsecs, ssize;
- struct iso_primary_descriptor ipd;
+ 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)
- err(EXIT_FAILURE, _("cannot open %s"), filenamep);
-
- if (lseek(fd, 16 << 11, 0) == (off_t) - 1)
- err(EXIT_FAILURE, _("seek error on %s"), filenamep);
+ 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 (read(fd, &ipd, sizeof(ipd)) < 0)
- err(EXIT_FAILURE, _("read error on %s"), 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(ipd.volume_space_size, xflag);
+ nsecs = isonum_733(volume_space_size, xflag);
/* isonum_723 returns nowadays always 2048 */
- ssize = isonum_723(ipd.logical_block_size, xflag);
+ ssize = isonum_723(logical_block_size, xflag);
- if (xflag) {
+ if (1 < argc)
+ printf("%s: ", filenamep);
+ if (xflag)
printf(_("sector count: %d, sector size: %d\n"), nsecs, ssize);
- } else {
+ else {
long long product = nsecs;
if (divisor == 0)
printf("%lld\n", (product * ssize) / divisor);
}
- close(fd);
+ rc = 0;
+done:
+ if (fd >= 0)
+ close(fd);
+ return rc;
}
-static void __attribute__((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
{
- fputs(USAGE_HEADER, out);
- fprintf(out,
- _(" %s [options] iso9660_image_file\n"),
+
+ fputs(USAGE_HEADER, stdout);
+ fprintf(stdout,
+ _(" %s [options] <iso9660_image_file> ...\n"),
program_invocation_short_name);
- fputs(USAGE_OPTIONS, out);
- fputs(_(" -d, --divisor=NUM divide bytes NUM\n"), out);
- fputs(_(" -x, --sectors show sector count and size\n"), out);
- fputs(USAGE_SEPARATOR, out);
- fputs(USAGE_HELP, out);
- fputs(USAGE_VERSION, out);
- fprintf(out, USAGE_MAN_TAIL("isosize(8)"));
-
- exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+
+ 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, opt, xflag = 0;
+ int j, ct_err = 0, ct, opt, xflag = 0;
long divisor = 0;
static const struct option longopts[] = {
- {"divisor", no_argument, 0, 'd'},
- {"sectors", no_argument, 0, 'x'},
- {"version", no_argument, 0, 'V'},
- {"help", no_argument, 0, 'h'},
- {NULL, 0, 0, 0}
+ {"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);
- atexit(close_stdout);
+ close_stdout_atexit();
- while ((opt = getopt_long(argc, argv, "d:xVh", longopts, NULL)) != -1)
+ while ((opt = getopt_long(argc, argv, "d:xVh", longopts, NULL)) != -1) {
switch (opt) {
case 'd':
divisor =
xflag = 1;
break;
case 'V':
- printf(UTIL_LINUX_VERSION);
- return EXIT_SUCCESS;
+ print_version(EXIT_SUCCESS);
case 'h':
- usage(stdout);
+ usage();
default:
- usage(stderr);
+ errtryhelp(EXIT_FAILURE);
}
+ }
ct = argc - optind;
- if (ct <= 0)
- usage(stderr);
+ if (ct <= 0) {
+ warnx(_("no device specified"));
+ errtryhelp(EXIT_FAILURE);
+ }
for (j = optind; j < argc; j++) {
- if (ct > 1)
- printf("%s: ", argv[j]);
- isosize(argv[j], xflag, divisor);
+ if (isosize(ct, argv[j], xflag, divisor) != 0)
+ ct_err++;
}
- return EXIT_SUCCESS;
+ return ct == ct_err ? ISOSIZE_EXIT_ALLFAILED : /* all failed */
+ ct_err ? ISOSIZE_EXIT_SOMEOK : /* some ok */
+ EXIT_SUCCESS; /* all success */
}