X-Git-Url: https://git.distorted.org.uk/~mdw/dvdrip/blobdiff_plain/dc53ebfaa3fb887f962b574c6bafa45b160fc765..502323844014498c5123e462f85ef56af9465f6c:/lib.c diff --git a/lib.c b/lib.c index 1c815d0..521af8d 100644 --- a/lib.c +++ b/lib.c @@ -6,35 +6,30 @@ void set_prog(const char *p) { 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); } @@ -49,6 +44,66 @@ void sit(double t) } } +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)) { @@ -73,6 +128,57 @@ void store_filename(char *buf, ident 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, ""); + + *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, ""); + + return (0); +} + struct progress_state progress = PROGRESS_STATE_INIT; static struct banner_progress_item banner_progress;