dvd-sector-copy.c: Truncate the event list before processing a lost `stop'.
[dvdrip] / lib.c
CommitLineData
dc53ebfa
MW
1#include "lib.h"
2
3const char *prog = "<unset>";
4
5void set_prog(const char *p)
6 { const char *q = strrchr(p, '/'); prog = q ? q + 1 : p; }
7
8void vmoan(const char *fmt, va_list ap)
7ea9ce2b 9 { vmoan_syserr(0, fmt, ap); }
dc53ebfa 10
7ea9ce2b 11void vmoan_syserr(int err, const char *fmt, va_list ap)
dc53ebfa 12{
7ea9ce2b
MW
13 fprintf(stderr, "%s: ", prog);
14 vfprintf(stderr, fmt, ap);
15 if (err) fprintf(stderr, ": %s", strerror(errno));
dc53ebfa
MW
16 fputc('\n', stderr);
17}
18
7ea9ce2b
MW
19void moan(const char *fmt, ...)
20 { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); }
dc53ebfa 21
7ea9ce2b
MW
22void moan_syserr(int err, const char *fmt, ...)
23 { va_list ap; va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap); }
24
25void bail(const char *fmt, ...)
26 { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); exit(2); }
dc53ebfa 27
dc53ebfa
MW
28void bail_syserr(int err, const char *fmt, ...)
29{
30 va_list ap;
31
7ea9ce2b 32 va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap);
dc53ebfa
MW
33 exit(2);
34}
35
36void 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
00a5be1d
MW
47void 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
64void 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
76void 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
82void 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
4bd4876f
MW
88off_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
dc53ebfa
MW
107void 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
9b86c33f
MW
131static char *copy_string(char *p, const char *q)
132{
133 while (*q) *p++ = *q++;
134 *p = 0; return (p);
135}
136
137static 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
146int 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
dc53ebfa
MW
182struct progress_state progress = PROGRESS_STATE_INIT;
183static struct banner_progress_item banner_progress;
184
185static 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
194void 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
202void hide_banner(void)
203{
204 if (!progress_removeitem(&progress, &banner_progress._base))
205 progress_update(&progress);
206}
207
208#ifdef notdef
209static 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}
225static const dvd_logger_cb logger = { logfn };
226#endif
227
228void 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}