chiark / gitweb /
dvd-sector-copy.c: Fix botched debugging code.
[dvdrip] / lib.c
1 #include "lib.h"
2
3 const char *prog = "<unset>";
4
5 void set_prog(const char *p)
6   { const char *q = strrchr(p, '/'); prog = q ? q + 1 : p; }
7
8 void vmoan(const char *fmt, va_list ap)
9   { vmoan_syserr(0, fmt, ap); }
10
11 void vmoan_syserr(int err, const char *fmt, va_list ap)
12 {
13   fprintf(stderr, "%s: ", prog);
14   vfprintf(stderr, fmt, ap);
15   if (err) fprintf(stderr, ": %s", strerror(errno));
16   fputc('\n', stderr);
17 }
18
19 void moan(const char *fmt, ...)
20   { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); }
21
22 void moan_syserr(int err, const char *fmt, ...)
23   { va_list ap; va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap); }
24
25 void bail(const char *fmt, ...)
26   { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); exit(2); }
27
28 void bail_syserr(int err, const char *fmt, ...)
29 {
30   va_list ap;
31
32   va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap);
33   exit(2);
34 }
35
36 void sit(double t)
37 {
38   struct timeval tv;
39   double whole = floor(t);
40
41   if (t) {
42     tv.tv_sec = whole; tv.tv_usec = floor((t - whole)*1.0e6) + 1;
43     if (select(0, 0, 0, 0, &tv) < 0) bail_syserr(errno, "failed to sleep");
44   }
45 }
46
47 void carefully_write(int fd, const void *buf, size_t sz)
48 {
49   const unsigned char *p = buf;
50   ssize_t n;
51
52   if (fd < 0) return;
53   while (sz) {
54     n = write(fd, p, sz);
55     if (n < 0) {
56       if (errno == EINTR) continue;
57       bail_syserr(errno, "failed to write to output file");
58     }
59     if (!n) bail("unexpected short write to output file");
60     p += n; sz -= n;
61   }
62 }
63
64 void open_file_on_demand(const char *file, FILE **fp_inout, const char *what)
65 {
66   FILE *fp;
67
68   if (!*fp_inout) {
69     fp = fopen(file, "w");
70     if (!fp) bail_syserr(errno, "failed to open %s file `%s'", what, file);
71     fprintf(fp, "## %s\n\n", what);
72     *fp_inout = fp;
73   }
74 }
75
76 void check_write(FILE *fp, const char *what)
77 {
78   fflush(fp);
79   if (ferror(fp)) bail_syserr(errno, "error writing %s file", what);
80 }
81
82 void carefully_fclose(FILE *fp, const char *what)
83 {
84   if (fp && (ferror(fp) || fclose(fp)))
85     bail_syserr(errno, "error writing %s file", what);
86 }
87
88 off_t device_size(int fd, const char *file, int *blksz_out)
89 {
90   struct stat st;
91   uint64_t volsz;
92
93   if (fstat(fd, &st))
94     bail_syserr(errno, "failed to obtain status for `%s'", file);
95   if (S_ISREG(st.st_mode))
96     volsz = st.st_size;
97   else if (S_ISBLK(st.st_mode)) {
98     if (ioctl(fd, BLKGETSIZE64, &volsz))
99       bail_syserr(errno, "failed to get volume size for `%s'", file);
100     if (ioctl(fd, BLKSSZGET, blksz_out))
101       bail_syserr(errno, "failed to get block size for `%s'", file);
102   } else
103     bail("can't read size for `%s': expected file or block device", file);
104   return ((off_t)volsz);
105 }
106
107 void store_filename(char *buf, ident id)
108 {
109   switch (id_kind(id)) {
110     case RAW:
111       sprintf(buf, "#<raw device>");
112       break;
113     case IFO:
114       if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.IFO");
115       else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id));
116       break;
117     case BUP:
118       if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.BUP");
119       else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id));
120       break;
121     case VOB:
122       if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.VOB");
123       else
124         sprintf(buf, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id), id_part(id));
125       break;
126     default:
127       abort();
128   }
129 }
130
131 static char *copy_string(char *p, const char *q)
132 {
133   while (*q) *p++ = *q++;
134   *p = 0; return (p);
135 }
136
137 static char *copy_hex(char *p, const unsigned char *q, size_t sz)
138 {
139   while (sz) {
140     sprintf(p, "%02x", *q);
141     p += 2; q++; sz--;
142   }
143   return (p);
144 }
145
146 int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file)
147 {
148   char volid[33];
149   unsigned char volsetid[16], discid[16];
150   int rc;
151   size_t n;
152
153   rc = DVDUDFVolumeInfo(dvd,
154                         volid, sizeof(volid),
155                         volsetid, sizeof(volsetid));
156   if (!rc) {
157     p = copy_string(p, volid);
158     *p++ = '-';
159     for (n = sizeof(volsetid); n && !volsetid[n - 1]; n--);
160     p = copy_hex(p, volsetid, n);
161   } else if (f&DIF_MUSTVOLINF) {
162     if (file) moan("failed to read volume info for `%s'", file);
163     else moan("failed to read volume info");
164     return (-1);
165   } else
166     p = copy_string(p, "<error reading volume info>");
167
168   *p++ = ':';
169   rc = DVDDiscID(dvd, discid);
170   if (!rc)
171     p = copy_hex(p, discid, sizeof(discid));
172   else if (f&DIF_MUSTIFOHASH) {
173     if (file) moan("failed to determine disc id of `%s'", file);
174     else moan("failed to determine disc id");
175     return (-1);
176   } else
177     p = copy_string(p, "<error reading disc-id>");
178
179   return (0);
180 }
181
182 struct progress_state progress = PROGRESS_STATE_INIT;
183 static struct banner_progress_item banner_progress;
184
185 static void render_banner_progress(struct progress_item *item,
186                             struct progress_render_state *render)
187 {
188   struct banner_progress_item *bi = (struct banner_progress_item *)item;
189
190   progress_putleft(render, " %s", bi->msg);
191   progress_shownotice(render, 4, 7);
192 }
193
194 void show_banner(const char *msg)
195 {
196   banner_progress._base.render = render_banner_progress;
197   progress_additem(&progress, &banner_progress._base);
198   banner_progress.msg = msg;
199   progress_update(&progress);
200 }
201
202 void hide_banner(void)
203 {
204   if (!progress_removeitem(&progress, &banner_progress._base))
205     progress_update(&progress);
206 }
207
208 #ifdef notdef
209 static void logfn(void *p, dvd_logger_level_t lev,
210                   const char *fmt, va_list ap)
211 {
212   switch (lev) {
213     case DVD_LOGGER_LEVEL_ERROR:
214       fprintf("%s (libdvdread error): ", prog);
215       break;
216     case DVD_LOGGER_LEVEL_WARN:
217       fprintf("%s (libdvdread warning): ", prog);
218       break;
219     default:
220       return;
221   }
222   vfprintf(stderr, fmt, ap);
223   fputc('\n', stderr);
224 }
225 static const dvd_logger_cb logger = { logfn };
226 #endif
227
228 void open_dvd(const char *device, int *fd_out, dvd_reader_t **dvd_out)
229 {
230   int fd;
231   dvd_reader_t *dvd;
232   int bannerp = 0;
233
234   for (;;) {
235     fd = open(device, O_RDONLY);
236     if (fd >= 0 || errno != ENOMEDIUM) break;
237     if (!bannerp) {
238       show_banner("Waiting for disc to be inserted...");
239       bannerp = 1;
240     }
241     sit(0.2);
242   }
243   if (bannerp) hide_banner();
244   if (fd < 0) bail_syserr(errno, "failed to open device `%s'", device);
245   if (dvd_out) {
246 #ifdef notdef
247     dvd = DVDOpen2(0, &logger, device);
248 #else
249     dvd = DVDOpen(device);
250 #endif
251     if (!dvd) bail("failed to open DVD on `%s'", device);
252     *dvd_out = dvd;
253   }
254   if (fd_out) *fd_out = fd;
255   else close(fd);
256 }