File: | src/usr.bin/cdio/rip.c |
Warning: | line 171, column 9 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: rip.c,v 1.18 2019/06/28 13:35:00 deraadt Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2007 Alexey Vatchenko <av@bsdua.org> | |||
5 | * | |||
6 | * Permission to use, copy, modify, and distribute this software for any | |||
7 | * purpose with or without fee is hereby granted, provided that the above | |||
8 | * copyright notice and this permission notice appear in all copies. | |||
9 | * | |||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
17 | */ | |||
18 | #include <sys/types.h> | |||
19 | #include <sys/signal.h> | |||
20 | #include <sys/device.h> | |||
21 | ||||
22 | #include <sys/cdio.h> | |||
23 | #include <sys/ioctl.h> | |||
24 | #include <sys/scsiio.h> | |||
25 | #include <sys/stat.h> | |||
26 | #include <sys/time.h> | |||
27 | ||||
28 | #include <scsi/scsi_all.h> | |||
29 | #include <scsi/scsi_disk.h> | |||
30 | #include <scsi/scsiconf.h> | |||
31 | #include <scsi/cd.h> | |||
32 | ||||
33 | #include <ctype.h> | |||
34 | #include <err.h> | |||
35 | #include <errno(*__errno()).h> | |||
36 | #include <fcntl.h> | |||
37 | #include <sndio.h> | |||
38 | #include <stdio.h> | |||
39 | #include <stdlib.h> | |||
40 | #include <string.h> | |||
41 | #include <time.h> | |||
42 | #include <unistd.h> | |||
43 | ||||
44 | #include "extern.h" | |||
45 | ||||
46 | extern int fd; | |||
47 | extern int msf; | |||
48 | extern struct cd_toc_entry *toc_buffer; | |||
49 | ||||
50 | extern u_int msf2lba(u_char m, u_char s, u_char f); | |||
51 | extern int read_toc_entrys(int size); | |||
52 | ||||
53 | /* | |||
54 | * Arguments parser | |||
55 | */ | |||
56 | TAILQ_HEAD(track_pair_head, track_pair)struct track_pair_head { struct track_pair *tqh_first; struct track_pair **tqh_last; }; | |||
57 | ||||
58 | static int _parse_val(char *start, char *nxt, int *val); | |||
59 | static int _parse_pair(char *start, char *nxt, int *val1, int *val2); | |||
60 | static int _add_pair(struct track_pair_head *head, int val1, int val2, | |||
61 | int issorted); | |||
62 | ||||
63 | struct track_pair { | |||
64 | u_char start; | |||
65 | u_char end; | |||
66 | TAILQ_ENTRY(track_pair)struct { struct track_pair *tqe_next; struct track_pair **tqe_prev ; } list; | |||
67 | }; | |||
68 | ||||
69 | void parse_tracks_init(struct track_pair_head *head); | |||
70 | void parse_tracks_final(struct track_pair_head *head); | |||
71 | int parse_tracks(struct track_pair_head *head, u_char first, u_char last, | |||
72 | const char *arg, int issorted); | |||
73 | int parse_tracks_add(struct track_pair_head *head, u_char first, | |||
74 | u_char last, int issorted); | |||
75 | ||||
76 | /* | |||
77 | * Tracks ripping | |||
78 | */ | |||
79 | /* Header of the canonical WAVE file */ | |||
80 | static u_char wavehdr[44] = { | |||
81 | 'R', 'I', 'F', 'F', 0x0, 0x0, 0x0, 0x0, 'W', 'A', 'V', 'E', | |||
82 | 'f', 'm', 't', ' ', 0x10, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, | |||
83 | 0x44, 0xac, 0x0, 0x0, 0x10, 0xb1, 0x2, 0x0, 0x4, 0x0, 0x10, 0x0, | |||
84 | 'd', 'a', 't', 'a', 0x0, 0x0, 0x0, 0x0 | |||
85 | }; | |||
86 | ||||
87 | static int write_sector(int, u_char *, u_int32_t); | |||
88 | ||||
89 | int read_data_sector(u_int32_t, u_char *, u_int32_t); | |||
90 | ||||
91 | struct track { | |||
92 | int fd; /* descriptor of output file */ | |||
93 | struct sio_hdl *hdl; /* sndio handle */ | |||
94 | struct sio_par par; /* sndio parameters */ | |||
95 | u_int track; /* track number */ | |||
96 | char name[12]; /* output file name, i.e. trackXX.wav/trackXX.dat */ | |||
97 | u_char isaudio; /* true if audio track, otherwise it's data track */ | |||
98 | u_int32_t start_lba; /* starting address of this track */ | |||
99 | u_int32_t end_lba; /* starting address of the next track */ | |||
100 | }; | |||
101 | ||||
102 | int read_track(struct track *); | |||
103 | ||||
104 | int rip_next_track(struct track *); | |||
105 | int play_next_track(struct track *); | |||
106 | ||||
107 | static int rip_tracks_loop(struct track_pair *tp, u_int n_tracks, | |||
108 | int (*next_track)(struct track *)); | |||
109 | ||||
110 | int rip_tracks(char *arg, int (*next_track)(struct track *), | |||
111 | int issorted); | |||
112 | ||||
113 | /* Next-Track function exit codes */ | |||
114 | #define NXTRACK_OK0 0 | |||
115 | #define NXTRACK_FAIL1 1 | |||
116 | #define NXTRACK_SKIP2 2 | |||
117 | ||||
118 | static int | |||
119 | _parse_val(char *start, char *nxt, int *val) | |||
120 | { | |||
121 | char *p; | |||
122 | int i, base, n; | |||
123 | ||||
124 | n = nxt - start; | |||
125 | ||||
126 | if (n > 3 || n < 1) | |||
127 | return (-1); | |||
128 | for (p = start; p < nxt; p++) { | |||
129 | if (!isdigit((unsigned char)*p)) | |||
130 | return (-1); | |||
131 | } | |||
132 | ||||
133 | *val = 0; | |||
134 | base = 1; | |||
135 | for (i = 0; i < n; i++) { | |||
136 | *val += base * (start[n - i - 1] - '0'); | |||
137 | base *= 10; | |||
138 | } | |||
139 | return (0); | |||
140 | } | |||
141 | ||||
142 | static int | |||
143 | _parse_pair(char *start, char *nxt, int *val1, int *val2) | |||
144 | { | |||
145 | char *p, *delim; | |||
146 | int error; | |||
147 | ||||
148 | delim = NULL((void *)0); | |||
149 | p = start; | |||
150 | while (p < nxt) { | |||
151 | if (*p == '-') | |||
152 | delim = p; | |||
153 | p++; | |||
154 | } | |||
155 | ||||
156 | if (delim
| |||
157 | error = 0; | |||
158 | if (delim - start < 1) | |||
159 | *val1 = -1; | |||
160 | else | |||
161 | error = _parse_val(start, delim, val1); | |||
162 | ||||
163 | if (error == 0) { | |||
164 | if ((nxt - delim - 1) < 1) | |||
165 | *val2 = -1; | |||
166 | else | |||
167 | error = _parse_val(delim + 1, nxt, val2); | |||
168 | } | |||
169 | } else { | |||
170 | error = _parse_val(start, nxt, val1); | |||
171 | *val2 = *val1; | |||
| ||||
172 | } | |||
173 | ||||
174 | if (error == 0) { | |||
175 | if (*val1 > 99 || *val2 > 99) | |||
176 | error = -1; | |||
177 | } | |||
178 | ||||
179 | return (error); | |||
180 | } | |||
181 | ||||
182 | static int | |||
183 | _add_pair(struct track_pair_head *head, int val1, int val2, int issorted) | |||
184 | { | |||
185 | u_char v1, v2, v3; | |||
186 | struct track_pair *tp, *entry; | |||
187 | int fix; | |||
188 | ||||
189 | v1 = (u_char)val1; | |||
190 | v2 = (u_char)val2; | |||
191 | ||||
192 | if (issorted) { | |||
193 | /* 1. Fix order */ | |||
194 | if (v1 > v2) { | |||
195 | v3 = v1; | |||
196 | v1 = v2; | |||
197 | v2 = v3; | |||
198 | } | |||
199 | ||||
200 | /* 2. Find closest range and fix it */ | |||
201 | fix = 0; | |||
202 | TAILQ_FOREACH(entry, head, list)for((entry) = ((head)->tqh_first); (entry) != ((void *)0); (entry) = ((entry)->list.tqe_next)) { | |||
203 | if (v1 + 1 == entry->start || v1 == entry->start) | |||
204 | fix = 1; | |||
205 | else if (v1 > entry->start && v1 <= entry->end + 1) | |||
206 | fix = 1; | |||
207 | else if (v2 + 1 == entry->start || v2 == entry->start) | |||
208 | fix = 1; | |||
209 | else if (v2 > entry->start && v2 <= entry->end + 1) | |||
210 | fix = 1; | |||
211 | if (fix) | |||
212 | break; | |||
213 | } | |||
214 | ||||
215 | if (fix) { | |||
216 | if (v1 < entry->start) | |||
217 | entry->start = v1; | |||
218 | if (v2 > entry->end) | |||
219 | entry->end = v2; | |||
220 | ||||
221 | return (0); | |||
222 | } | |||
223 | } | |||
224 | ||||
225 | tp = malloc(sizeof(*tp)); | |||
226 | if (tp == NULL((void *)0)) | |||
227 | return (-1); | |||
228 | ||||
229 | tp->start = v1; | |||
230 | tp->end = v2; | |||
231 | TAILQ_INSERT_TAIL(head, tp, list)do { (tp)->list.tqe_next = ((void *)0); (tp)->list.tqe_prev = (head)->tqh_last; *(head)->tqh_last = (tp); (head)-> tqh_last = &(tp)->list.tqe_next; } while (0); | |||
232 | ||||
233 | return (0); | |||
234 | } | |||
235 | ||||
236 | void | |||
237 | parse_tracks_init(struct track_pair_head *head) | |||
238 | { | |||
239 | ||||
240 | memset(head, 0, sizeof(*head)); | |||
241 | TAILQ_INIT(head)do { (head)->tqh_first = ((void *)0); (head)->tqh_last = &(head)->tqh_first; } while (0); | |||
242 | } | |||
243 | ||||
244 | void | |||
245 | parse_tracks_final(struct track_pair_head *head) | |||
246 | { | |||
247 | struct track_pair *tp; | |||
248 | ||||
249 | while ((tp = TAILQ_FIRST(head)((head)->tqh_first)) != NULL((void *)0)) { | |||
250 | TAILQ_REMOVE(head, tp, list)do { if (((tp)->list.tqe_next) != ((void *)0)) (tp)->list .tqe_next->list.tqe_prev = (tp)->list.tqe_prev; else (head )->tqh_last = (tp)->list.tqe_prev; *(tp)->list.tqe_prev = (tp)->list.tqe_next; ; ; } while (0); | |||
251 | free(tp); | |||
252 | } | |||
253 | } | |||
254 | ||||
255 | int | |||
256 | parse_tracks(struct track_pair_head *head, u_char first, u_char last, | |||
257 | const char *arg, int issorted) | |||
258 | { | |||
259 | char *p, *nxt; | |||
260 | int error, val1, val2; | |||
261 | ||||
262 | p = (char *)arg; | |||
263 | for (;;) { | |||
264 | /* Skip trailing spaces */ | |||
265 | while (*p != '\0' && isspace((unsigned char)*p)) | |||
266 | ++p; | |||
267 | if (*p == '\0') | |||
268 | break; | |||
269 | ||||
270 | /* Search for the next space symbol */ | |||
271 | nxt = p; | |||
272 | while (*nxt != '\0' && !isspace((unsigned char)*nxt)) | |||
273 | ++nxt; | |||
274 | /* ``nxt'' can't be equal to ``p'' here */ | |||
275 | error = _parse_pair(p, nxt, &val1, &val2); | |||
276 | if (error != 0) | |||
277 | break; /* parse error */ | |||
278 | ||||
279 | if (val1 == -1) | |||
280 | val1 = first; | |||
281 | if (val2 == -1) | |||
282 | val2 = last; | |||
283 | ||||
284 | error = _add_pair(head, val1, val2, issorted); | |||
285 | if (error != 0) | |||
286 | break; /* allocation error */ | |||
287 | ||||
288 | p = nxt; | |||
289 | } | |||
290 | ||||
291 | return (0); | |||
292 | } | |||
293 | ||||
294 | int | |||
295 | parse_tracks_add(struct track_pair_head *head, u_char first, u_char last, | |||
296 | int issorted) | |||
297 | { | |||
298 | ||||
299 | return _add_pair(head, first, last, issorted); | |||
300 | } | |||
301 | ||||
302 | static int | |||
303 | write_sector(int fd, u_char *sec, u_int32_t secsize) | |||
304 | { | |||
305 | ssize_t res; | |||
306 | ||||
307 | while (secsize > 0) { | |||
308 | res = write(fd, sec, secsize); | |||
309 | if (res == -1) | |||
310 | return (-1); | |||
311 | ||||
312 | sec += res; | |||
313 | secsize -= res; | |||
314 | } | |||
315 | ||||
316 | return (0); | |||
317 | } | |||
318 | ||||
319 | /* | |||
320 | * ERRORS | |||
321 | * The function can return | |||
322 | * [EBUSY] Device is busy. | |||
323 | * [ETIMEDOUT] Operation timeout. | |||
324 | * [EIO] Any other errors. | |||
325 | * [EAGAIN] The operation must be made again. XXX - not implemented | |||
326 | */ | |||
327 | int | |||
328 | read_data_sector(u_int32_t lba, u_char *sec, u_int32_t secsize) | |||
329 | { | |||
330 | scsireq_t scr; | |||
331 | u_char *cmd; | |||
332 | int error; | |||
333 | ||||
334 | memset(&scr, 0, sizeof(scr)); | |||
335 | ||||
336 | cmd = (u_char *)scr.cmd; | |||
337 | cmd[0] = 0xbe; /* READ CD */ | |||
338 | _lto4b(lba, cmd + 2); /* Starting Logical Block Address */ | |||
339 | _lto3b(1, cmd + 6); /* Transfer Length in Blocks */ | |||
340 | cmd[9] = 0x10; /* User Data field */ | |||
341 | ||||
342 | scr.flags = SCCMD_ESCAPE0x00000010 | SCCMD_READ0x00000001; | |||
343 | scr.databuf = sec; | |||
344 | scr.datalen = secsize; | |||
345 | scr.cmdlen = 12; | |||
346 | scr.timeout = 120000; | |||
347 | scr.senselen = SENSEBUFLEN48; | |||
348 | ||||
349 | /* XXX - what's wrong with DVD? */ | |||
350 | ||||
351 | error = ioctl(fd, SCIOCCOMMAND(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (scsireq_t) & 0x1fff) << 16) | ((('Q')) << 8) | ((1))), &scr); | |||
352 | if (error == -1) | |||
353 | return (EIO5); | |||
354 | else if (scr.retsts == SCCMD_BUSY0x02) | |||
355 | return (EBUSY16); | |||
356 | else if (scr.retsts == SCCMD_TIMEOUT0x01) | |||
357 | return (ETIMEDOUT60); | |||
358 | else if (scr.retsts != SCCMD_OK0x00) | |||
359 | return (EIO5); | |||
360 | ||||
361 | return (0); | |||
362 | } | |||
363 | ||||
364 | int | |||
365 | read_track(struct track *ti) | |||
366 | { | |||
367 | struct timespec ts, ots, ats; | |||
368 | u_int32_t i, blksize, n_sec; | |||
369 | u_char *sec; | |||
370 | int error; | |||
371 | ||||
372 | n_sec = ti->end_lba - ti->start_lba; | |||
373 | blksize = (ti->isaudio) ? 2352 : 2048; | |||
374 | sec = malloc(blksize); | |||
375 | if (sec == NULL((void *)0)) | |||
376 | return (-1); | |||
377 | ||||
378 | timespecclear(&ots)(&ots)->tv_sec = (&ots)->tv_nsec = 0; | |||
379 | ats.tv_sec = 1; | |||
380 | ats.tv_nsec = 0; | |||
381 | ||||
382 | for (i = 0; i < n_sec; ) { | |||
383 | clock_gettime(CLOCK_MONOTONIC3, &ts); | |||
384 | if (timespeccmp(&ts, &ots, >)(((&ts)->tv_sec == (&ots)->tv_sec) ? ((&ts) ->tv_nsec > (&ots)->tv_nsec) : ((&ts)->tv_sec > (&ots)->tv_sec))) { | |||
385 | fprintf(stderr(&__sF[2]), "\rtrack %u '%c' %08u/%08u %3u%%", | |||
386 | ti->track, | |||
387 | (ti->isaudio) ? 'a' : 'd', i, n_sec, | |||
388 | 100 * i / n_sec); | |||
389 | timespecadd(&ts, &ats, &ots)do { (&ots)->tv_sec = (&ts)->tv_sec + (&ats )->tv_sec; (&ots)->tv_nsec = (&ts)->tv_nsec + (&ats)->tv_nsec; if ((&ots)->tv_nsec >= 1000000000L ) { (&ots)->tv_sec++; (&ots)->tv_nsec -= 1000000000L ; } } while (0); | |||
390 | } | |||
391 | ||||
392 | error = read_data_sector(i + ti->start_lba, sec, blksize); | |||
393 | if (error == 0) { | |||
394 | if (ti->fd >= 0 && | |||
395 | (write_sector(ti->fd, sec, blksize) != 0)) { | |||
396 | free(sec); | |||
397 | warnx("\nerror while writing to the %s file", | |||
398 | ti->name); | |||
399 | return (-1); | |||
400 | } | |||
401 | if (ti->hdl != NULL((void *)0) && | |||
402 | (sio_write(ti->hdl, sec, blksize) == 0)) { | |||
403 | sio_close(ti->hdl); | |||
404 | ti->hdl = NULL((void *)0); | |||
405 | warnx("\nerror while writing to audio output"); | |||
406 | return (-1); | |||
407 | } | |||
408 | ||||
409 | i++; | |||
410 | } else if (error != EAGAIN35) { | |||
411 | free(sec); | |||
412 | warnx("\nerror while reading from device"); | |||
413 | return (-1); | |||
414 | } | |||
415 | } | |||
416 | ||||
417 | free(sec); | |||
418 | fprintf(stderr(&__sF[2]), "\rtrack %u '%c' %08u/%08u 100%%\n", | |||
419 | ti->track, | |||
420 | (ti->isaudio) ? 'a' : 'd', i, n_sec); | |||
421 | return (0); | |||
422 | } | |||
423 | ||||
424 | int | |||
425 | rip_next_track(struct track *info) | |||
426 | { | |||
427 | int error; | |||
428 | u_int32_t size; | |||
429 | ||||
430 | info->fd = open(info->name, O_CREAT0x0200 | O_TRUNC0x0400 | O_RDWR0x0002, | |||
431 | S_IRUSR0000400 | S_IWUSR0000200); | |||
432 | if (info->fd == -1) { | |||
433 | warnx("can't open %s file", info->name); | |||
434 | return (NXTRACK_FAIL1); | |||
435 | } | |||
436 | ||||
437 | if (info->isaudio) { | |||
438 | /* | |||
439 | * Prepend audio track with Wave header | |||
440 | */ | |||
441 | size = 2352 * (info->end_lba - info->start_lba); | |||
442 | *(u_int32_t *)(wavehdr + 4) = htole32(size + 36)((__uint32_t)(size + 36)); | |||
443 | *(u_int32_t *)(wavehdr + 40) = htole32(size)((__uint32_t)(size)); | |||
444 | error = write_sector(info->fd, wavehdr, sizeof(wavehdr)); | |||
445 | if (error == -1) { | |||
446 | warnx("can't write WAVE header for %s file", | |||
447 | info->name); | |||
448 | return (NXTRACK_FAIL1); | |||
449 | } | |||
450 | } | |||
451 | ||||
452 | return (NXTRACK_OK0); | |||
453 | } | |||
454 | ||||
455 | int | |||
456 | play_next_track(struct track *info) | |||
457 | { | |||
458 | if (!info->isaudio) | |||
459 | return (NXTRACK_SKIP2); | |||
460 | ||||
461 | if (info->hdl != NULL((void *)0)) | |||
462 | return (NXTRACK_OK0); | |||
463 | ||||
464 | info->hdl = sio_open(NULL((void *)0), SIO_PLAY1, 0); | |||
465 | if (info->hdl == NULL((void *)0)) { | |||
466 | warnx("could not open audio backend"); | |||
467 | goto bad; | |||
468 | } | |||
469 | ||||
470 | sio_initpar(&info->par); | |||
471 | ||||
472 | info->par.rate = 44100; | |||
473 | info->par.pchan = 2; | |||
474 | info->par.bits = 16; | |||
475 | info->par.sig = 1; | |||
476 | info->par.le = 1; | |||
477 | info->par.appbufsz = info->par.rate * 3 / 4; | |||
478 | ||||
479 | if (sio_setpar(info->hdl, &info->par) == 0) { | |||
480 | warnx("could not set audio parameters"); | |||
481 | goto bad; | |||
482 | } | |||
483 | ||||
484 | if (sio_getpar(info->hdl, &info->par) == 0) { | |||
485 | warnx("could not get audio parameters"); | |||
486 | goto bad; | |||
487 | } | |||
488 | ||||
489 | if (info->par.le != 1 || | |||
490 | info->par.sig != 1 || | |||
491 | info->par.bits != 16 || | |||
492 | info->par.pchan != 2 || | |||
493 | (info->par.rate > 44100 * 1.05 || info->par.rate < 44100 * 0.95)) { | |||
494 | warnx("could not configure audio parameters as desired"); | |||
495 | goto bad; | |||
496 | } | |||
497 | ||||
498 | if (sio_start(info->hdl) == 0) { | |||
499 | warnx("could not start audio output"); | |||
500 | goto bad; | |||
501 | } | |||
502 | ||||
503 | return (NXTRACK_OK0); | |||
504 | ||||
505 | bad: | |||
506 | if (info->hdl != NULL((void *)0)) { | |||
507 | sio_close(info->hdl); | |||
508 | info->hdl = NULL((void *)0); | |||
509 | } | |||
510 | return (NXTRACK_FAIL1); | |||
511 | } | |||
512 | ||||
513 | static int | |||
514 | rip_tracks_loop(struct track_pair *tp, u_int n_tracks, | |||
515 | int (*next_track)(struct track *)) | |||
516 | { | |||
517 | struct track info; | |||
518 | u_char trk; | |||
519 | u_int i; | |||
520 | char order; | |||
521 | int error; | |||
522 | ||||
523 | info.fd = -1; | |||
524 | info.hdl = NULL((void *)0); | |||
525 | ||||
526 | order = (tp->start > tp->end) ? -1 : 1; | |||
527 | trk = tp->start; | |||
528 | for (;;) { | |||
529 | error = 0; | |||
530 | for (i = 0; i < n_tracks; i++) { | |||
531 | if (trk == toc_buffer[i].track) | |||
532 | break; | |||
533 | } | |||
534 | ||||
535 | if (i != n_tracks) { | |||
536 | /* Track is found */ | |||
537 | info.track = toc_buffer[i].track; | |||
538 | info.isaudio = (toc_buffer[i].control & 4) == 0; | |||
539 | snprintf(info.name, sizeof(info.name), "track%02u.%s", | |||
540 | toc_buffer[i].track, | |||
541 | (info.isaudio) ? "wav" : "dat"); | |||
542 | ||||
543 | if (msf) { | |||
544 | info.start_lba = msf2lba( | |||
545 | toc_buffer[i].addr.msf.minute, | |||
546 | toc_buffer[i].addr.msf.second, | |||
547 | toc_buffer[i].addr.msf.frame); | |||
548 | info.end_lba = msf2lba( | |||
549 | toc_buffer[i + 1].addr.msf.minute, | |||
550 | toc_buffer[i + 1].addr.msf.second, | |||
551 | toc_buffer[i + 1].addr.msf.frame); | |||
552 | } else { | |||
553 | info.start_lba = toc_buffer[i].addr.lba; | |||
554 | info.end_lba = toc_buffer[i + 1].addr.lba; | |||
555 | } | |||
556 | ||||
557 | error = next_track(&info); | |||
558 | if (error == NXTRACK_FAIL1) { | |||
559 | error = -1; | |||
560 | break; | |||
561 | } else if (error != NXTRACK_SKIP2) { | |||
562 | error = read_track(&info); | |||
563 | if (info.fd >= 0) { | |||
564 | close(info.fd); | |||
565 | info.fd = -1; | |||
566 | } | |||
567 | if (error != 0) { | |||
568 | warnx("can't rip %u track", | |||
569 | toc_buffer[i].track); | |||
570 | break; | |||
571 | } | |||
572 | } | |||
573 | } | |||
574 | ||||
575 | if (trk == tp->end) | |||
576 | break; | |||
577 | trk += order; | |||
578 | } | |||
579 | ||||
580 | if (info.hdl != NULL((void *)0)) { | |||
581 | sio_close(info.hdl); | |||
582 | info.hdl = NULL((void *)0); | |||
583 | } | |||
584 | ||||
585 | return (error); | |||
586 | } | |||
587 | ||||
588 | int | |||
589 | rip_tracks(char *arg, int (*next_track)(struct track *), int issorted) | |||
590 | { | |||
591 | struct track_pair_head list; | |||
592 | struct track_pair *tp; | |||
593 | struct ioc_toc_header h; | |||
594 | u_int n; | |||
595 | int rc; | |||
596 | ||||
597 | rc = ioctl(fd, CDIOREADTOCHEADER((unsigned long)0x40000000 | ((sizeof(struct ioc_toc_header) & 0x1fff) << 16) | ((('c')) << 8) | ((4))), &h); | |||
598 | if (rc == -1) | |||
599 | return (rc); | |||
600 | ||||
601 | if (h.starting_track > h.ending_track) { | |||
602 | warnx("TOC starting_track > TOC ending_track"); | |||
603 | return (0); | |||
604 | } | |||
605 | ||||
606 | n = h.ending_track - h.starting_track + 1; | |||
607 | rc = read_toc_entrys((n + 1) * sizeof(struct cd_toc_entry)); | |||
608 | if (rc < 0) | |||
609 | return (rc); | |||
610 | ||||
611 | parse_tracks_init(&list); | |||
612 | /* We assume that all spaces are skipped in ``arg''. */ | |||
613 | if (arg == NULL((void *)0) || *arg == '\0') { | |||
614 | rc = parse_tracks_add(&list, h.starting_track, h.ending_track, | |||
615 | 0); | |||
616 | } else { | |||
617 | rc = parse_tracks(&list, h.starting_track, h.ending_track, arg, | |||
618 | issorted); | |||
619 | } | |||
620 | if (rc < 0) { | |||
621 | warnx("can't create track list"); | |||
622 | parse_tracks_final(&list); | |||
623 | return (rc); | |||
624 | } | |||
625 | ||||
626 | TAILQ_FOREACH(tp, &list, list)for((tp) = ((&list)->tqh_first); (tp) != ((void *)0); ( tp) = ((tp)->list.tqe_next)) { | |||
627 | rc = rip_tracks_loop(tp, n, next_track); | |||
628 | if (rc < 0) | |||
629 | break; | |||
630 | } | |||
631 | ||||
632 | parse_tracks_final(&list); | |||
633 | return (0); | |||
634 | } | |||
635 | ||||
636 | int | |||
637 | cdrip(char *arg) | |||
638 | { | |||
639 | return rip_tracks(arg, rip_next_track, 1); | |||
640 | } | |||
641 | ||||
642 | int | |||
643 | cdplay(char *arg) | |||
644 | { | |||
645 | return rip_tracks(arg, play_next_track, 0); | |||
| ||||
646 | } |