| 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 | } |