{ const char *q = strrchr(p, '/'); prog = q ? q + 1 : p; }
void vmoan(const char *fmt, va_list ap)
- { fprintf(stderr, "%s: ", prog); vfprintf(stderr, fmt, ap); }
+ { vmoan_syserr(0, fmt, ap); }
-__attribute__((format(printf, 1, 2)))
-void moan(const char *fmt, ...)
+void vmoan_syserr(int err, const char *fmt, va_list ap)
{
- va_list ap;
-
- va_start(ap, fmt); vmoan(fmt, ap); va_end(ap);
+ fprintf(stderr, "%s: ", prog);
+ vfprintf(stderr, fmt, ap);
+ if (err) fprintf(stderr, ": %s", strerror(errno));
fputc('\n', stderr);
}
-__attribute__((noreturn, format(printf, 1, 2)))
-void bail(const char *fmt, ...)
-{
- va_list ap;
+void moan(const char *fmt, ...)
+ { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); }
- va_start(ap, fmt); vmoan(fmt, ap); va_end(ap);
- fputc('\n', stderr);
- exit(2);
-}
+void moan_syserr(int err, const char *fmt, ...)
+ { va_list ap; va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap); }
+
+void bail(const char *fmt, ...)
+ { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); exit(2); }
-__attribute__((noreturn, format(printf, 2, 3)))
void bail_syserr(int err, const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt); vmoan(fmt, ap); va_end(ap);
- if (err) fprintf(stderr, ": %s", strerror(errno));
- fputc('\n', stderr);
+ va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap);
exit(2);
}
}
}
+void carefully_write(int fd, const void *buf, size_t sz)
+{
+ const unsigned char *p = buf;
+ ssize_t n;
+
+ if (fd < 0) return;
+ while (sz) {
+ n = write(fd, p, sz);
+ if (n < 0) {
+ if (errno == EINTR) continue;
+ bail_syserr(errno, "failed to write to output file");
+ }
+ if (!n) bail("unexpected short write to output file");
+ p += n; sz -= n;
+ }
+}
+
+void open_file_on_demand(const char *file, FILE **fp_inout, const char *what)
+{
+ FILE *fp;
+
+ if (!*fp_inout) {
+ fp = fopen(file, "w");
+ if (!fp) bail_syserr(errno, "failed to open %s file `%s'", what, file);
+ fprintf(fp, "## %s\n\n", what);
+ *fp_inout = fp;
+ }
+}
+
+void check_write(FILE *fp, const char *what)
+{
+ fflush(fp);
+ if (ferror(fp)) bail_syserr(errno, "error writing %s file", what);
+}
+
+void carefully_fclose(FILE *fp, const char *what)
+{
+ if (fp && (ferror(fp) || fclose(fp)))
+ bail_syserr(errno, "error writing %s file", what);
+}
+
+off_t device_size(int fd, const char *file, int *blksz_out)
+{
+ struct stat st;
+ uint64_t volsz;
+
+ if (fstat(fd, &st))
+ bail_syserr(errno, "failed to obtain status for `%s'", file);
+ if (S_ISREG(st.st_mode))
+ volsz = st.st_size;
+ else if (S_ISBLK(st.st_mode)) {
+ if (ioctl(fd, BLKGETSIZE64, &volsz))
+ bail_syserr(errno, "failed to get volume size for `%s'", file);
+ if (ioctl(fd, BLKSSZGET, blksz_out))
+ bail_syserr(errno, "failed to get block size for `%s'", file);
+ } else
+ bail("can't read size for `%s': expected file or block device", file);
+ return ((off_t)volsz);
+}
+
void store_filename(char *buf, ident id)
{
switch (id_kind(id)) {
}
}
+static char *copy_string(char *p, const char *q)
+{
+ while (*q) *p++ = *q++;
+ *p = 0; return (p);
+}
+
+static char *copy_hex(char *p, const unsigned char *q, size_t sz)
+{
+ while (sz) {
+ sprintf(p, "%02x", *q);
+ p += 2; q++; sz--;
+ }
+ return (p);
+}
+
+int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file)
+{
+ char volid[33];
+ unsigned char volsetid[16], discid[16];
+ int rc;
+ size_t n;
+
+ rc = DVDUDFVolumeInfo(dvd,
+ volid, sizeof(volid),
+ volsetid, sizeof(volsetid));
+ if (!rc) {
+ p = copy_string(p, volid);
+ *p++ = '-';
+ for (n = sizeof(volsetid); n && !volsetid[n - 1]; n--);
+ p = copy_hex(p, volsetid, n);
+ } else if (f&DIF_MUSTVOLINF) {
+ if (file) moan("failed to read volume info for `%s'", file);
+ else moan("failed to read volume info");
+ return (-1);
+ } else
+ p = copy_string(p, "<error reading volume info>");
+
+ *p++ = ':';
+ rc = DVDDiscID(dvd, discid);
+ if (!rc)
+ p = copy_hex(p, discid, sizeof(discid));
+ else if (f&DIF_MUSTIFOHASH) {
+ if (file) moan("failed to determine disc id of `%s'", file);
+ else moan("failed to determine disc id");
+ return (-1);
+ } else
+ p = copy_string(p, "<error reading disc-id>");
+
+ return (0);
+}
+
struct progress_state progress = PROGRESS_STATE_INIT;
static struct banner_progress_item banner_progress;