3 const char *prog
= "<unset>";
5 void set_prog(const char *p
)
6 { const char *q
= strrchr(p
, '/'); prog
= q ? q
+ 1 : p
; }
8 void vmoan(const char *fmt
, va_list ap
)
9 { vmoan_syserr(0, fmt
, ap
); }
11 void vmoan_syserr(int err
, const char *fmt
, va_list ap
)
13 fprintf(stderr
, "%s: ", prog
);
14 vfprintf(stderr
, fmt
, ap
);
15 if (err
) fprintf(stderr
, ": %s", strerror(errno
));
19 void moan(const char *fmt
, ...)
20 { va_list ap
; va_start(ap
, fmt
); vmoan(fmt
, ap
); va_end(ap
); }
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
); }
25 void bail(const char *fmt
, ...)
26 { va_list ap
; va_start(ap
, fmt
); vmoan(fmt
, ap
); va_end(ap
); exit(2); }
28 void bail_syserr(int err
, const char *fmt
, ...)
32 va_start(ap
, fmt
); vmoan_syserr(err
, fmt
, ap
); va_end(ap
);
39 double whole
= floor(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");
47 void carefully_write(int fd
, const void *buf
, size_t sz
)
49 const unsigned char *p
= buf
;
56 if (errno
== EINTR
) continue;
57 bail_syserr(errno
, "failed to write to output file");
59 if (!n
) bail("unexpected short write to output file");
64 void open_file_on_demand(const char *file
, FILE **fp_inout
, const char *what
)
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
);
76 void check_write(FILE *fp
, const char *what
)
79 if (ferror(fp
)) bail_syserr(errno
, "error writing %s file", what
);
82 void carefully_fclose(FILE *fp
, const char *what
)
84 if (fp
&& (ferror(fp
) || fclose(fp
)))
85 bail_syserr(errno
, "error writing %s file", what
);
88 off_t
device_size(int fd
, const char *file
, int *blksz_out
)
94 bail_syserr(errno
, "failed to obtain status for `%s'", file
);
95 if (S_ISREG(st
.st_mode
))
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
);
103 bail("can't read size for `%s': expected file or block device", file
);
104 return ((off_t
)volsz
);
107 void store_filename(char *buf
, ident id
)
109 switch (id_kind(id
)) {
111 sprintf(buf
, "#<raw device>");
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
));
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
));
122 if (!id_title(id
)) sprintf(buf
, "/VIDEO_TS/VIDEO_TS.VOB");
124 sprintf(buf
, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id
), id_part(id
));
131 static char *copy_string(char *p
, const char *q
)
133 while (*q
) *p
++ = *q
++;
137 static char *copy_hex(char *p
, const unsigned char *q
, size_t sz
)
140 sprintf(p
, "%02x", *q
);
146 int dvd_id(char *p
, dvd_reader_t
*dvd
, unsigned f
, const char *file
)
149 unsigned char volsetid
[16], discid
[16];
153 rc
= DVDUDFVolumeInfo(dvd
,
154 volid
, sizeof(volid
),
155 volsetid
, sizeof(volsetid
));
157 p
= copy_string(p
, volid
);
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");
166 p
= copy_string(p
, "<error reading volume info>");
169 rc
= DVDDiscID(dvd
, discid
);
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");
177 p
= copy_string(p
, "<error reading disc-id>");
182 struct progress_state progress
= PROGRESS_STATE_INIT
;
183 static struct banner_progress_item banner_progress
;
185 static void render_banner_progress(struct progress_item
*item
,
186 struct progress_render_state
*render
)
188 struct banner_progress_item
*bi
= (struct banner_progress_item
*)item
;
190 progress_putleft(render
, " %s", bi
->msg
);
191 progress_shownotice(render
, 4, 7);
194 void show_banner(const char *msg
)
196 banner_progress
._base
.render
= render_banner_progress
;
197 progress_additem(&progress
, &banner_progress
._base
);
198 banner_progress
.msg
= msg
;
199 progress_update(&progress
);
202 void hide_banner(void)
204 if (!progress_removeitem(&progress
, &banner_progress
._base
))
205 progress_update(&progress
);
209 static void logfn(void *p
, dvd_logger_level_t lev
,
210 const char *fmt
, va_list ap
)
213 case DVD_LOGGER_LEVEL_ERROR
:
214 fprintf("%s (libdvdread error): ", prog
);
216 case DVD_LOGGER_LEVEL_WARN
:
217 fprintf("%s (libdvdread warning): ", prog
);
222 vfprintf(stderr
, fmt
, ap
);
225 static const dvd_logger_cb logger
= { logfn
};
228 void open_dvd(const char *device
, int *fd_out
, dvd_reader_t
**dvd_out
)
235 fd
= open(device
, O_RDONLY
);
236 if (fd
>= 0 || errno
!= ENOMEDIUM
) break;
238 show_banner("Waiting for disc to be inserted...");
243 if (bannerp
) hide_banner();
244 if (fd
< 0) bail_syserr(errno
, "failed to open device `%s'", device
);
247 dvd
= DVDOpen2(0, &logger
, device
);
249 dvd
= DVDOpen(device
);
251 if (!dvd
) bail("failed to open DVD on `%s'", device
);
254 if (fd_out
) *fd_out
= fd
;