Annotation of src/usr.bin/cdio/cdio.c, Revision 1.49
1.49 ! mjc 1: /* $OpenBSD: cdio.c,v 1.48 2006/05/31 01:14:41 mjc Exp $ */
1.28 jmc 2:
3: /* Copyright (c) 1995 Serge V. Vakulenko
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Serge V. Vakulenko.
18: * 4. The name of the author may not be used to endorse or promote products
19: * derived from this software without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31: */
32:
1.1 downsj 33: /*
34: * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>.
35: * Based on the non-X based CD player by Jean-Marc Zucconi and
36: * Andrey A. Chernov.
37: *
38: * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>.
39: *
40: * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
41: * A couple of further fixes to my own earlier "fixes".
42: *
43: * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
44: * Added an ability to specify addresses relative to the
45: * beginning of a track. This is in fact a variation of
46: * doing the simple play_msf() call.
47: *
48: * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru>
49: * New eject algorithm.
50: * Some code style reformatting.
51: *
52: * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $
53: */
54:
1.27 fgsch 55: #include <sys/param.h>
56: #include <sys/file.h>
57: #include <sys/cdio.h>
58: #include <sys/ioctl.h>
1.49 ! mjc 59: #include <sys/queue.h>
1.48 mjc 60: #include <sys/scsiio.h>
1.49 ! mjc 61: #include <sys/stat.h>
1.27 fgsch 62:
1.1 downsj 63: #include <ctype.h>
1.17 espie 64: #include <err.h>
65: #include <errno.h>
1.1 downsj 66: #include <stdio.h>
67: #include <stdlib.h>
68: #include <string.h>
69: #include <unistd.h>
1.27 fgsch 70: #include <histedit.h>
1.1 downsj 71: #include <util.h>
1.17 espie 72: #include <vis.h>
1.27 fgsch 73:
1.24 espie 74: #include "extern.h"
1.1 downsj 75:
76: #define ASTS_INVALID 0x00 /* Audio status byte not valid */
77: #define ASTS_PLAYING 0x11 /* Audio play operation in progress */
78: #define ASTS_PAUSED 0x12 /* Audio play operation paused */
79: #define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */
80: #define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */
81: #define ASTS_VOID 0x15 /* No current audio status to return */
82:
83: #ifndef DEFAULT_CD_DRIVE
1.3 deraadt 84: # define DEFAULT_CD_DRIVE "cd0"
1.1 downsj 85: #endif
86:
87: #define CMD_DEBUG 1
1.9 millert 88: #define CMD_DEVICE 2
89: #define CMD_EJECT 3
90: #define CMD_HELP 4
91: #define CMD_INFO 5
92: #define CMD_PAUSE 6
93: #define CMD_PLAY 7
94: #define CMD_QUIT 8
95: #define CMD_RESUME 9
96: #define CMD_STOP 10
97: #define CMD_VOLUME 11
98: #define CMD_CLOSE 12
99: #define CMD_RESET 13
100: #define CMD_SET 14
101: #define CMD_STATUS 15
102: #define CMD_NEXT 16
103: #define CMD_PREV 17
104: #define CMD_REPLAY 18
1.24 espie 105: #define CMD_CDDB 19
1.25 espie 106: #define CMD_CDID 20
1.48 mjc 107: #define CMD_BLANK 21
1.1 downsj 108:
109: struct cmdtab {
110: int command;
111: char *name;
1.24 espie 112: unsigned int min;
1.1 downsj 113: char *args;
114: } cmdtab[] = {
115: { CMD_CLOSE, "close", 1, "" },
1.37 alek 116: { CMD_DEBUG, "debug", 3, "on | off" },
1.9 millert 117: { CMD_DEVICE, "device", 1, "devname" },
1.1 downsj 118: { CMD_EJECT, "eject", 1, "" },
119: { CMD_HELP, "?", 1, 0 },
120: { CMD_HELP, "help", 1, "" },
121: { CMD_INFO, "info", 1, "" },
1.5 angelos 122: { CMD_NEXT, "next", 1, "" },
1.1 downsj 123: { CMD_PAUSE, "pause", 2, "" },
124: { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" },
1.47 krw 125: { CMD_PLAY, "play", 1, "[tr1] m1:s1[.f1] [tr2] [m2:s2[.f2]]" },
1.1 downsj 126: { CMD_PLAY, "play", 1, "[#block [len]]" },
1.5 angelos 127: { CMD_PREV, "previous", 2, "" },
1.1 downsj 128: { CMD_QUIT, "quit", 1, "" },
129: { CMD_RESET, "reset", 4, "" },
130: { CMD_RESUME, "resume", 1, "" },
1.6 angelos 131: { CMD_REPLAY, "replay", 3, "" },
1.1 downsj 132: { CMD_SET, "set", 2, "msf | lba" },
133: { CMD_STATUS, "status", 1, "" },
134: { CMD_STOP, "stop", 3, "" },
135: { CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" },
1.25 espie 136: { CMD_CDDB, "cddbinfo", 2, "[n]" },
1.26 fgsch 137: { CMD_CDID, "cdid", 3, "" },
1.40 millert 138: { CMD_QUIT, "exit", 2, "" },
1.48 mjc 139: { CMD_BLANK, "blank", 1, "" },
1.24 espie 140: { 0, 0, 0, 0}
1.1 downsj 141: };
142:
1.11 csapuntz 143: struct cd_toc_entry *toc_buffer;
1.1 downsj 144:
145: char *cdname;
146: int fd = -1;
147: int verbose = 1;
148: int msf = 1;
1.24 espie 149: const char *cddb_host;
1.49 ! mjc 150: char **track_names;
1.1 downsj 151:
1.27 fgsch 152: EditLine *el = NULL; /* line-editing structure */
153: History *hist = NULL; /* line-editing history */
154: void switch_el(void);
155:
1.1 downsj 156: extern char *__progname;
157:
1.19 millert 158: int setvol(int, int);
159: int read_toc_entrys(int);
160: int play_msf(int, int, int, int, int, int);
161: int play_track(int, int, int, int);
162: int get_vol(int *, int *);
163: int status(int *, int *, int *, int *);
164: int play(char *arg);
165: int info(char *arg);
1.24 espie 166: int cddbinfo(char *arg);
1.19 millert 167: int pstatus(char *arg);
168: int play_next(char *arg);
169: int play_prev(char *arg);
170: int play_same(char *arg);
171: char *input(int *);
1.27 fgsch 172: char *prompt(void);
1.24 espie 173: void prtrack(struct cd_toc_entry *e, int lastflag, char *name);
1.20 millert 174: void lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f);
1.19 millert 175: unsigned int msf2lba(u_char m, u_char s, u_char f);
176: int play_blocks(int blk, int len);
177: int run(int cmd, char *arg);
178: char *parse(char *buf, int *cmd);
1.23 espie 179: void help(void);
180: void usage(void);
181: char *strstatus(int);
1.25 espie 182: int cdid(void);
1.42 krw 183: void addmsf(u_int *, u_int *, u_int *, u_char, u_char, u_char);
1.44 krw 184: int cmpmsf(u_char, u_char, u_char, u_char, u_char, u_char);
1.43 krw 185: void toc2msf(u_int, u_char *, u_char *, u_char *);
1.1 downsj 186:
1.18 deraadt 187: void
1.30 deraadt 188: help(void)
1.1 downsj 189: {
190: struct cmdtab *c;
191: char *s, n;
192: int i;
193:
194: for (c=cmdtab; c->name; ++c) {
195: if (! c->args)
196: continue;
197: printf("\t");
198: for (i = c->min, s = c->name; *s; s++, i--) {
199: if (i > 0)
200: n = toupper(*s);
201: else
202: n = *s;
203: putchar(n);
204: }
205: if (*c->args)
1.18 deraadt 206: printf(" %s", c->args);
207: printf("\n");
1.1 downsj 208: }
1.18 deraadt 209: printf("\n\tThe word \"play\" is not required for the play commands.\n");
210: printf("\tThe plain target address is taken as a synonym for play.\n");
1.1 downsj 211: }
212:
1.18 deraadt 213: void
1.30 deraadt 214: usage(void)
1.1 downsj 215: {
1.34 jmc 216: fprintf(stderr, "usage: %s [-sv] [-d host:port] [-f device] [command args ...]\n",
1.18 deraadt 217: __progname);
218: exit(1);
1.1 downsj 219: }
220:
1.18 deraadt 221: int
1.24 espie 222: main(int argc, char **argv)
1.1 downsj 223: {
1.32 miod 224: int ch, cmd;
1.1 downsj 225: char *arg;
1.49 ! mjc 226: struct stat sb;
! 227: struct track_info *cur_track;
! 228: struct track_info *tr;
! 229: char type;
1.1 downsj 230:
1.18 deraadt 231: cdname = getenv("DISC");
1.1 downsj 232: if (! cdname)
1.18 deraadt 233: cdname = getenv("CDROM");
1.1 downsj 234:
1.24 espie 235: cddb_host = getenv("CDDB");
236: if (!cddb_host)
237: cddb_host = "freedb.freedb.org";
238:
1.32 miod 239: while ((ch = getopt(argc, argv, "svd:f:")) != -1)
240: switch (ch) {
1.1 downsj 241: case 's':
242: verbose = 0;
1.32 miod 243: break;
1.1 downsj 244: case 'v':
245: verbose = 2;
1.32 miod 246: break;
1.1 downsj 247: case 'f':
248: cdname = optarg;
1.32 miod 249: break;
1.46 krw 250: case 'd':
1.24 espie 251: cddb_host = optarg;
1.32 miod 252: break;
1.1 downsj 253: default:
1.18 deraadt 254: usage();
1.1 downsj 255: }
1.46 krw 256:
1.1 downsj 257: argc -= optind;
258: argv += optind;
259:
1.18 deraadt 260: if (argc > 0 && ! strcasecmp(*argv, "help"))
261: usage();
1.1 downsj 262:
263: if (! cdname) {
264: cdname = DEFAULT_CD_DRIVE;
1.18 deraadt 265: fprintf(stderr,
266: "No CD device name specified. Defaulting to %s.\n", cdname);
1.1 downsj 267: }
268:
1.48 mjc 269: if (argc > 0 && ! strcasecmp(*argv, "tao")) {
1.49 ! mjc 270: if (argc == 1)
! 271: usage();
! 272: SLIST_INIT(&tracks);
! 273: type = 'd';
! 274: while (argc > 1) {
! 275: tr = malloc(sizeof(struct track_info));
! 276: tr->type = type;
! 277: optreset = 1;
! 278: optind = 1;
! 279: while ((ch = getopt(argc, argv, "ad")) != -1) {
! 280: switch (ch) {
! 281: case 'a':
! 282: type = 'a';
! 283: break;
! 284: case 'd':
! 285: type = 'd';
! 286: break;
! 287: default:
! 288: usage();
! 289: }
! 290: }
! 291: tr->type = type;
! 292: argc -= optind;
! 293: argv += optind;
! 294: if (argv[0] == NULL)
1.48 mjc 295: usage();
1.49 ! mjc 296: tr->file = argv[0];
! 297: if (stat(tr->file, &sb) != 0) {
! 298: warn("cannot stat file %s",tr->file);
! 299: return (-1);
1.48 mjc 300: }
1.49 ! mjc 301: tr->sz = sb.st_size;
! 302: if (SLIST_EMPTY(&tracks))
! 303: SLIST_INSERT_HEAD(&tracks,tr,track_list);
! 304: else
! 305: SLIST_INSERT_AFTER(cur_track,tr,track_list);
! 306: cur_track = tr;
1.48 mjc 307: }
308: if (! open_cd(cdname, 1))
309: exit(1);
1.49 ! mjc 310: if (writetao(&tracks) != 0)
1.48 mjc 311: exit(1);
312: else
313: exit(0);
314: }
1.1 downsj 315: if (argc > 0) {
316: char buf[80], *p;
317: int len;
318:
319: for (p=buf; argc-->0; ++argv) {
1.29 krw 320: len = snprintf(p, buf + sizeof buf - p,
321: "%s%s", (p > buf) ? " " : "", *argv);
1.1 downsj 322:
1.36 moritz 323: if (len == -1 || len >= buf + sizeof buf - p)
1.29 krw 324: errx(1, "argument list too long.");
1.1 downsj 325:
326: p += len;
327: }
1.18 deraadt 328: arg = parse(buf, &cmd);
329: return (run(cmd, arg));
1.1 downsj 330: }
331:
332: if (verbose == 1)
1.18 deraadt 333: verbose = isatty(0);
1.1 downsj 334:
335: if (verbose) {
1.18 deraadt 336: printf("Compact Disc Control utility, version %s\n", VERSION);
337: printf("Type `?' for command list\n\n");
1.1 downsj 338: }
339:
1.27 fgsch 340: switch_el();
341:
1.1 downsj 342: for (;;) {
1.18 deraadt 343: arg = input(&cmd);
344: if (run(cmd, arg) < 0) {
1.1 downsj 345: if (verbose)
1.18 deraadt 346: warn(NULL);
347: close(fd);
1.1 downsj 348: fd = -1;
349: }
1.18 deraadt 350: fflush(stdout);
1.1 downsj 351: }
352: }
353:
1.18 deraadt 354: int
1.24 espie 355: run(int cmd, char *arg)
1.1 downsj 356: {
357: int l, r, rc;
1.9 millert 358: static char newcdname[MAXPATHLEN];
1.1 downsj 359:
360: switch (cmd) {
361:
362: case CMD_QUIT:
1.27 fgsch 363: switch_el();
1.18 deraadt 364: exit(0);
1.1 downsj 365:
366: case CMD_INFO:
1.48 mjc 367: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 368: return (0);
369:
1.18 deraadt 370: return info(arg);
1.1 downsj 371:
1.24 espie 372: case CMD_CDDB:
1.48 mjc 373: if (fd < 0 && ! open_cd(cdname, 0))
1.24 espie 374: return (0);
375:
376: return cddbinfo(arg);
377:
1.25 espie 378: case CMD_CDID:
1.48 mjc 379: if (fd < 0 && ! open_cd(cdname, 0))
1.25 espie 380: return (0);
381: return cdid();
382:
1.1 downsj 383: case CMD_STATUS:
1.48 mjc 384: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 385: return (0);
386:
1.18 deraadt 387: return pstatus(arg);
1.1 downsj 388:
389: case CMD_PAUSE:
1.48 mjc 390: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 391: return (0);
392:
1.18 deraadt 393: return ioctl(fd, CDIOCPAUSE);
1.1 downsj 394:
395: case CMD_RESUME:
1.48 mjc 396: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 397: return (0);
398:
1.18 deraadt 399: return ioctl(fd, CDIOCRESUME);
1.1 downsj 400:
401: case CMD_STOP:
1.48 mjc 402: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 403: return (0);
404:
1.18 deraadt 405: rc = ioctl(fd, CDIOCSTOP);
1.1 downsj 406:
1.18 deraadt 407: (void) ioctl(fd, CDIOCALLOW);
1.1 downsj 408:
409: return (rc);
410:
411: case CMD_RESET:
1.48 mjc 412: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 413: return (0);
414:
1.18 deraadt 415: rc = ioctl(fd, CDIOCRESET);
1.1 downsj 416: if (rc < 0)
417: return rc;
418: close(fd);
419: fd = -1;
420: return (0);
421:
422: case CMD_DEBUG:
1.48 mjc 423: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 424: return (0);
425:
1.18 deraadt 426: if (! strcasecmp(arg, "on"))
427: return ioctl(fd, CDIOCSETDEBUG);
1.1 downsj 428:
1.18 deraadt 429: if (! strcasecmp(arg, "off"))
430: return ioctl(fd, CDIOCCLRDEBUG);
1.1 downsj 431:
1.18 deraadt 432: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 433:
434: return (0);
435:
1.9 millert 436: case CMD_DEVICE:
437: /* close old device */
438: if (fd > -1) {
1.18 deraadt 439: (void) ioctl(fd, CDIOCALLOW);
1.9 millert 440: close(fd);
441: fd = -1;
1.38 alek 442: }
443:
444: if (strlen(arg) == 0) {
445: printf("%s: Invalid parameter\n", __progname);
446: return (0);
1.9 millert 447: }
448:
449: /* open new device */
1.48 mjc 450: if (! open_cd(arg, 0))
1.9 millert 451: return (0);
1.16 lebel 452: (void) strlcpy(newcdname, arg, sizeof(newcdname));
1.9 millert 453: cdname = newcdname;
454: return (1);
455:
1.1 downsj 456: case CMD_EJECT:
1.48 mjc 457: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 458: return (0);
459:
1.18 deraadt 460: (void) ioctl(fd, CDIOCALLOW);
461: rc = ioctl(fd, CDIOCEJECT);
1.1 downsj 462: if (rc < 0)
463: return (rc);
464: #if defined(__OpenBSD__)
465: close(fd);
466: fd = -1;
467: #endif
1.24 espie 468: if (track_names)
469: free_names(track_names);
470: track_names = NULL;
1.1 downsj 471: return (0);
472:
473: case CMD_CLOSE:
474: #if defined(CDIOCCLOSE)
1.48 mjc 475: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 476: return (0);
477:
1.18 deraadt 478: (void) ioctl(fd, CDIOCALLOW);
479: rc = ioctl(fd, CDIOCCLOSE);
1.1 downsj 480: if (rc < 0)
481: return (rc);
482: close(fd);
483: fd = -1;
484: return (0);
485: #else
1.18 deraadt 486: printf("%s: Command not yet supported\n", __progname);
1.1 downsj 487: return (0);
488: #endif
489:
490: case CMD_PLAY:
1.48 mjc 491: if (fd < 0 && ! open_cd(cdname, 0))
1.1 downsj 492: return (0);
493:
1.18 deraadt 494: while (isspace(*arg))
1.1 downsj 495: arg++;
496:
1.18 deraadt 497: return play(arg);
1.1 downsj 498:
499: case CMD_SET:
1.18 deraadt 500: if (!strcasecmp(arg, "msf"))
1.1 downsj 501: msf = 1;
1.18 deraadt 502: else if (!strcasecmp(arg, "lba"))
1.1 downsj 503: msf = 0;
504: else
1.18 deraadt 505: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 506: return (0);
507:
508: case CMD_VOLUME:
1.48 mjc 509: if (fd < 0 && !open_cd(cdname, 0))
1.1 downsj 510: return (0);
511:
1.18 deraadt 512: if (!strncasecmp(arg, "left", strlen(arg)))
513: return ioctl(fd, CDIOCSETLEFT);
1.1 downsj 514:
1.18 deraadt 515: if (!strncasecmp(arg, "right", strlen(arg)))
516: return ioctl(fd, CDIOCSETRIGHT);
1.1 downsj 517:
1.18 deraadt 518: if (!strncasecmp(arg, "mono", strlen(arg)))
519: return ioctl(fd, CDIOCSETMONO);
1.1 downsj 520:
1.18 deraadt 521: if (!strncasecmp(arg, "stereo", strlen(arg)))
522: return ioctl(fd, CDIOCSETSTEREO);
1.1 downsj 523:
1.18 deraadt 524: if (!strncasecmp(arg, "mute", strlen(arg)))
525: return ioctl(fd, CDIOCSETMUTE);
1.1 downsj 526:
1.47 krw 527: if (2 != sscanf(arg, "%d%d", &l, &r)) {
1.18 deraadt 528: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 529: return (0);
530: }
531:
1.18 deraadt 532: return setvol(l, r);
1.1 downsj 533:
1.18 deraadt 534: case CMD_NEXT:
1.48 mjc 535: if (fd < 0 && ! open_cd(cdname, 0))
1.18 deraadt 536: return (0);
1.5 angelos 537:
1.18 deraadt 538: return play_next(arg);
1.5 angelos 539:
1.18 deraadt 540: case CMD_PREV:
1.48 mjc 541: if (fd < 0 && ! open_cd(cdname, 0))
1.18 deraadt 542: return (0);
1.5 angelos 543:
1.18 deraadt 544: return play_prev(arg);
1.5 angelos 545:
1.6 angelos 546: case CMD_REPLAY:
1.48 mjc 547: if (fd < 0 && ! open_cd(cdname, 0))
1.6 angelos 548: return 0;
549:
1.18 deraadt 550: return play_same(arg);
1.48 mjc 551: case CMD_BLANK:
552: if (fd < 0 && ! open_cd(cdname, 1))
553: return 0;
554:
555: return blank();
1.1 downsj 556: default:
557: case CMD_HELP:
1.18 deraadt 558: help();
1.1 downsj 559: return (0);
560:
561: }
562: }
563:
1.18 deraadt 564: int
1.24 espie 565: play(char *arg)
1.1 downsj 566: {
567: struct ioc_toc_header h;
1.47 krw 568: unsigned char tm, ts, tf;
569: unsigned int tr1, tr2, m1, m2, s1, s2, f1, f2, i1, i2;
570: unsigned int blk, len, n;
571: char c;
572: int rc;
1.1 downsj 573:
1.18 deraadt 574: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 575:
576: if (rc < 0)
577: return (rc);
578:
1.47 krw 579: if (h.starting_track > h.ending_track) {
580: printf("TOC starting_track > TOC ending_track\n");
581: return (0);
582: }
583:
1.1 downsj 584: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 585: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 586:
587: if (rc < 0)
588: return (rc);
589:
1.47 krw 590: /*
591: * Truncate trailing white space. Then by adding %c to the end of the
592: * sscanf() formats we catch any errant trailing characters.
593: */
594: rc = strlen(arg) - 1;
595: while (rc >= 0 && isspace(arg[rc])) {
596: arg[rc] = '\0';
597: rc--;
598: }
599:
1.1 downsj 600: if (! arg || ! *arg) {
601: /* Play the whole disc */
1.47 krw 602: return (play_track(h.starting_track, 1, h.ending_track, 1));
1.1 downsj 603: }
604:
1.18 deraadt 605: if (strchr(arg, '#')) {
1.1 downsj 606: /* Play block #blk [ len ] */
1.47 krw 607: if (2 != sscanf(arg, "#%u%u%c", &blk, &len, &c) &&
608: 1 != sscanf(arg, "#%u%c", &blk, &c)) {
609: printf("%s: Invalid command arguments\n", __progname);
610: return (0);
611: }
1.1 downsj 612:
613: if (len == 0) {
614: if (msf)
1.18 deraadt 615: len = msf2lba(toc_buffer[n].addr.msf.minute,
616: toc_buffer[n].addr.msf.second,
617: toc_buffer[n].addr.msf.frame) - blk;
1.1 downsj 618: else
1.41 krw 619: len = toc_buffer[n].addr.lba - blk;
1.1 downsj 620: }
1.18 deraadt 621: return play_blocks(blk, len);
1.1 downsj 622: }
623:
1.47 krw 624: if (strchr(arg, ':') == NULL) {
1.1 downsj 625: /*
1.47 krw 626: * Play track tr1[.i1] [tr2[.i2]]
1.1 downsj 627: */
1.47 krw 628: if (4 == sscanf(arg, "%u.%u%u.%u%c", &tr1, &i1, &tr2, &i2, &c))
629: goto play_track;
630:
631: i2 = 1;
632: if (3 == sscanf(arg, "%u.%u%u%c", &tr1, &i1, &tr2, &c))
633: goto play_track;
634:
635: i1 = 1;
636: if (3 == sscanf(arg, "%u%u.%u%c", &tr1, &tr2, &i2, &c))
637: goto play_track;
638:
639: tr2 = 0;
640: i2 = 1;
641: if (2 == sscanf(arg, "%u.%u%c", &tr1, &i1, &c))
642: goto play_track;
643:
644: i1 = i2 = 1;
645: if (2 == sscanf(arg, "%u%u%c", &tr1, &tr2, &c))
646: goto play_track;
647:
648: i1 = i2 = 1;
649: tr2 = 0;
650: if (1 == sscanf(arg, "%u%c", &tr1, &c))
651: goto play_track;
652:
653: printf("%s: Invalid command arguments\n", __progname);
654: return (0);
655:
656: play_track:
657: if (tr1 > n || tr2 > n) {
658: printf("Track number must be between 0 and %u\n", n);
1.45 krw 659: return (0);
1.47 krw 660: } else if (tr2 == 0)
661: tr2 = h.ending_track;
662:
663: if (tr1 > tr2) {
664: printf("starting_track > ending_track\n");
1.45 krw 665: return (0);
666: }
667:
1.47 krw 668: return (play_track(tr1, i1, tr2, i2));
669: }
670:
671: /*
672: * Play MSF [tr1] m1:s1[.f1] [tr2] [m2:s2[.f2]]
673: *
674: * Start Time End Time
675: * ---------- --------
676: * tr1 m1:s1.f1 tr2 m2:s2.f2
677: * tr1 m1:s1 tr2 m2:s2.f2
678: * tr1 m1:s1.f1 tr2 m2:s2
679: * tr1 m1:s1 tr2 m2:s2
680: * m1:s1.f1 tr2 m2:s2.f2
681: * m1:s1 tr2 m2:s2.f2
682: * m1:s1.f1 tr2 m2:s2
683: * m1:s1 tr2 m2:s2
684: * tr1 m1:s1.f1 m2:s2.f2
685: * tr1 m1:s1 m2:s2.f2
686: * tr1 m1:s1.f1 m2:s2
687: * tr1 m1:s1 m2:s2
688: * m1:s1.f1 m2:s2.f2
689: * m1:s1 m2:s2.f2
690: * m1:s1.f1 m2:s2
691: * m1:s1 m2:s2
692: * tr1 m1:s1.f1 tr2
693: * tr1 m1:s1 tr2
694: * m1:s1.f1 tr2
695: * m1:s1 tr2
696: * tr1 m1:s1.f1 <end of disc>
697: * tr1 m1:s1 <end of disc>
698: * m1:s1.f1 <end of disc>
699: * m1:s1 <end of disc>
700: */
701:
702: /* tr1 m1:s1.f1 tr2 m2:s2.f2 */
703: if (8 == sscanf(arg, "%u%u:%u.%u%u%u:%u.%u%c",
704: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2, &c))
705: goto play_msf;
706:
707: /* tr1 m1:s1 tr2 m2:s2.f2 */
708: f1 = 0;
709: if (7 == sscanf(arg, "%u%u:%u%u%u:%u.%u%c",
710: &tr1, &m1, &s1, &tr2, &m2, &s2, &f2, &c))
711: goto play_msf;
712:
713: /* tr1 m1:s1.f1 tr2 m2:s2 */
714: f2 =0;
715: if (7 == sscanf(arg, "%u%u:%u.%u%u%u:%u%c",
716: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &c))
717: goto play_msf;
718:
719: /* m1:s1.f1 tr2 m2:s2.f2 */
720: tr1 = 0;
721: if (7 == sscanf(arg, "%u:%u.%u%u%u:%u.%u%c",
722: &m1, &s1, &f1, &tr2, &m2, &s2, &f2, &c))
723: goto play_msf;
724:
725: /* tr1 m1:s1.f1 m2:s2.f2 */
726: tr2 = 0;
727: if (7 == sscanf(arg, "%u%u:%u.%u%u:%u.%u%c",
728: &tr1, &m1, &s1, &f1, &m2, &s2, &f2, &c))
729: goto play_msf;
730:
731: /* m1:s1 tr2 m2:s2.f2 */
732: tr1 = f1 = 0;
733: if (6 == sscanf(arg, "%u:%u%u%u:%u.%u%c",
734: &m1, &s1, &tr2, &m2, &s2, &f2, &c))
735: goto play_msf;
736:
737: /* m1:s1.f1 tr2 m2:s2 */
738: tr1 = f2 = 0;
739: if (6 == sscanf(arg, "%u:%u.%u%u%u:%u%c",
740: &m1, &s1, &f1, &tr2, &m2, &s2, &c))
741: goto play_msf;
742:
743: /* m1:s1.f1 m2:s2.f2 */
744: tr1 = tr2 = 0;
745: if (6 == sscanf(arg, "%u:%u.%u%u:%u.%u%c",
746: &m1, &s1, &f1, &m2, &s2, &f2, &c))
747: goto play_msf;
748:
749: /* tr1 m1:s1.f1 m2:s2 */
750: tr2 = f2 = 0;
751: if (6 == sscanf(arg, "%u%u:%u.%u%u:%u%c",
752: &tr1, &m1, &s1, &f1, &m2, &s2, &c))
753: goto play_msf;
754:
755: /* tr1 m1:s1 m2:s2.f2 */
756: tr2 = f1 = 0;
757: if (6 == sscanf(arg, "%u%u:%u%u:%u.%u%c",
758: &tr1, &m1, &s1, &m2, &s2, &f2, &c))
759: goto play_msf;
760:
761: /* tr1 m1:s1 tr2 m2:s2 */
762: f1 = f2 = 0;
763: if (6 == sscanf(arg, "%u%u:%u%u%u:%u%c",
764: &tr1, &m1, &s1, &tr2, &m2, &s2, &c))
765: goto play_msf;
766:
767: /* m1:s1 tr2 m2:s2 */
768: tr1 = f1 = f2 = 0;
769: if (5 == sscanf(arg, "%u:%u%u%u:%u%c", &m1, &s1, &tr2, &m2, &s2, &c))
770: goto play_msf;
771:
772: /* tr1 m1:s1 m2:s2 */
773: f1 = tr2 = f2 = 0;
774: if (5 == sscanf(arg, "%u%u:%u%u:%u%c", &tr1, &m1, &s1, &m2, &s2, &c))
775: goto play_msf;
776:
777: /* m1:s1 m2:s2.f2 */
778: tr1 = f1 = tr2 = 0;
779: if (5 == sscanf(arg, "%u:%u%u:%u.%u%c", &m1, &s1, &m2, &s2, &f2, &c))
780: goto play_msf;
781:
782: /* m1:s1.f1 m2:s2 */
783: tr1 = tr2 = f2 = 0;
784: if (5 == sscanf(arg, "%u:%u.%u%u:%u%c", &m1, &s1, &f1, &m2, &s2, &c))
785: goto play_msf;
786:
787: /* tr1 m1:s1.f1 tr2 */
788: m2 = s2 = f2 = 0;
789: if (5 == sscanf(arg, "%u%u:%u.%u%u%c", &tr1, &m1, &s1, &f1, &tr2, &c))
790: goto play_msf;
791:
792: /* m1:s1 m2:s2 */
793: tr1 = f1 = tr2 = f2 = 0;
794: if (4 == sscanf(arg, "%u:%u%u:%u%c", &m1, &s1, &m2, &s2, &c))
795: goto play_msf;
796:
797: /* tr1 m1:s1.f1 <end of disc> */
798: tr2 = m2 = s2 = f2 = 0;
799: if (4 == sscanf(arg, "%u%u:%u.%u%c", &tr1, &m1, &s1, &f1, &c))
800: goto play_msf;
801:
802: /* tr1 m1:s1 tr2 */
803: f1 = m2 = s2 = f2 = 0;
804: if (4 == sscanf(arg, "%u%u:%u%u%c", &tr1, &m1, &s1, &tr2, &c))
805: goto play_msf;
806:
807: /* m1:s1.f1 tr2 */
808: tr1 = m2 = s2 = f2 = 0;
809: if (4 == sscanf(arg, "%u%u:%u%u%c", &m1, &s1, &f1, &tr2, &c))
810: goto play_msf;
811:
812: /* m1:s1.f1 <end of disc> */
813: tr1 = tr2 = m2 = s2 = f2 = 0;
814: if (3 == sscanf(arg, "%u:%u.%u%c", &m1, &s1, &f1, &c))
815: goto play_msf;
816:
817: /* tr1 m1:s1 <end of disc> */
818: f1 = tr2 = m2 = s2 = f2 = 0;
819: if (3 == sscanf(arg, "%u%u:%u%c", &tr1, &m1, &s1, &c))
820: goto play_msf;
821:
822: /* m1:s1 tr2 */
823: tr1 = f1 = m2 = s2 = f2 = 0;
824: if (3 == sscanf(arg, "%u:%u%u%c", &m1, &s1, &tr2, &c))
825: goto play_msf;
826:
827: /* m1:s1 <end of disc> */
828: tr1 = f1 = tr2 = m2 = s2 = f2 = 0;
829: if (2 == sscanf(arg, "%u:%u%c", &m1, &s1, &c))
830: goto play_msf;
831:
832: printf("%s: Invalid command arguments\n", __progname);
833: return (0);
834:
835: play_msf:
836: if (tr1 > n || tr2 > n) {
837: printf("Track number must be between 0 and %u\n", n);
838: return (0);
839: } else if (m1 > 99 || m2 > 99) {
840: printf("Minutes must be between 0 and 99\n");
841: return (0);
842: } else if (s1 > 59 || s2 > 59) {
843: printf("Seconds must be between 0 and 59\n");
844: return (0);
845: } if (f1 > 74 || f2 > 74) {
846: printf("Frames number must be between 0 and 74\n");
847: return (0);
848: }
849:
850: if (tr1 > 0) {
851: /*
852: * Start time is relative to tr1, Add start time of tr1
853: * to (m1,s1,f1) to yield absolute start time.
854: */
1.45 krw 855: toc2msf(tr1, &tm, &ts, &tf);
856: addmsf(&m1, &s1, &f1, tm, ts, tf);
1.1 downsj 857:
1.45 krw 858: /* Compare (m1,s1,f1) to start time of next track. */
1.43 krw 859: toc2msf(tr1+1, &tm, &ts, &tf);
1.44 krw 860: if (cmpmsf(m1, s1, f1, tm, ts, tf) == 1) {
1.47 krw 861: printf("Track %u is not that long.\n", tr1);
1.1 downsj 862: return (0);
863: }
1.47 krw 864: }
865:
866: toc2msf(n+1, &tm, &ts, &tf);
867: if (cmpmsf(m1, s1, f1, tm, ts, tf) == 1) {
868: printf("Start time is after end of disc.\n");
869: return (0);
870: }
1.1 downsj 871:
1.47 krw 872: if (tr2 > 0) {
873: /*
874: * End time is relative to tr2, Add start time of tr2
875: * to (m2,s2,f2) to yield absolute end time.
876: */
877: toc2msf(tr2, &tm, &ts, &tf);
878: addmsf(&m2, &s2, &f2, tm, ts, tf);
879:
880: /* Compare (m2,s2,f2) to start time of next track. */
881: toc2msf(tr2+1, &tm, &ts, &tf);
882: if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) {
883: printf("Track %u is not that long.\n", tr2);
884: return (0);
1.1 downsj 885: }
1.47 krw 886: }
887:
888: toc2msf(n+1, &tm, &ts, &tf);
1.43 krw 889:
1.47 krw 890: if (!(tr2 || m2 || s2 || f2)) {
891: /* Play to end of disc. */
892: m2 = tm;
893: s2 = ts;
894: f2 = tf;
895: } else if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) {
896: printf("End time is after end of disc.\n");
897: return (0);
1.1 downsj 898: }
899:
1.47 krw 900: if (cmpmsf(m1, s1, f1, m2, s2, f2) == 1) {
901: printf("Start time is after end time.\n");
902: return (0);
903: }
1.1 downsj 904:
1.47 krw 905: return play_msf(m1, s1, f1, m2, s2, f2);
1.5 angelos 906: }
907:
1.35 deraadt 908: /* ARGSUSED */
1.18 deraadt 909: int
1.24 espie 910: play_prev(char *arg)
1.5 angelos 911: {
1.18 deraadt 912: int trk, min, sec, frm, rc;
913: struct ioc_toc_header h;
1.5 angelos 914:
1.18 deraadt 915: if (status(&trk, &min, &sec, &frm) >= 0) {
916: trk--;
1.5 angelos 917:
1.18 deraadt 918: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
919: if (rc < 0) {
920: warn("getting toc header");
921: return (rc);
922: }
1.5 angelos 923:
1.18 deraadt 924: if (trk < h.starting_track)
925: return play_track(h.starting_track, 1,
926: h.ending_track + 1, 1);
927: return play_track(trk, 1, h.ending_track, 1);
928: }
1.6 angelos 929:
1.18 deraadt 930: return (0);
1.6 angelos 931: }
932:
1.35 deraadt 933: /* ARGSUSED */
1.18 deraadt 934: int
1.24 espie 935: play_same(char *arg)
1.6 angelos 936: {
1.18 deraadt 937: int trk, min, sec, frm, rc;
938: struct ioc_toc_header h;
1.6 angelos 939:
1.18 deraadt 940: if (status (&trk, &min, &sec, &frm) >= 0) {
941: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
942: if (rc < 0) {
943: warn("getting toc header");
944: return (rc);
945: }
1.5 angelos 946:
1.18 deraadt 947: return play_track(trk, 1, h.ending_track, 1);
948: }
1.5 angelos 949:
1.18 deraadt 950: return (0);
1.5 angelos 951: }
952:
1.35 deraadt 953: /* ARGSUSED */
1.18 deraadt 954: int
1.24 espie 955: play_next(char *arg)
1.5 angelos 956: {
957: int trk, min, sec, frm, rc;
958: struct ioc_toc_header h;
959:
1.18 deraadt 960: if (status(&trk, &min, &sec, &frm) >= 0) {
1.5 angelos 961: trk++;
1.18 deraadt 962: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
963: if (rc < 0) {
964: warn("getting toc header");
1.5 angelos 965: return (rc);
966: }
967:
1.18 deraadt 968: if (trk > h.ending_track) {
1.5 angelos 969: printf("%s: end of CD\n", __progname);
970:
1.18 deraadt 971: rc = ioctl(fd, CDIOCSTOP);
1.5 angelos 972:
1.18 deraadt 973: (void) ioctl(fd, CDIOCALLOW);
1.5 angelos 974:
975: return (rc);
976: }
977:
1.18 deraadt 978: return play_track(trk, 1, h.ending_track, 1);
1.5 angelos 979: }
980:
1.1 downsj 981: return (0);
982: }
983:
1.18 deraadt 984: char *
1.24 espie 985: strstatus(int sts)
1.1 downsj 986: {
987: switch (sts) {
1.18 deraadt 988: case ASTS_INVALID:
989: return ("invalid");
990: case ASTS_PLAYING:
991: return ("playing");
992: case ASTS_PAUSED:
993: return ("paused");
994: case ASTS_COMPLETED:
995: return ("completed");
996: case ASTS_ERROR:
997: return ("error");
998: case ASTS_VOID:
999: return ("void");
1000: default:
1001: return ("??");
1.1 downsj 1002: }
1003: }
1004:
1.35 deraadt 1005: /* ARGSUSED */
1.18 deraadt 1006: int
1.24 espie 1007: pstatus(char *arg)
1.1 downsj 1008: {
1009: struct ioc_vol v;
1010: struct ioc_read_subchannel ss;
1011: struct cd_sub_channel_info data;
1012: int rc, trk, m, s, f;
1.17 espie 1013: char vis_catalog[1 + 4 * 15];
1.1 downsj 1014:
1.18 deraadt 1015: rc = status(&trk, &m, &s, &f);
1.9 millert 1016: if (rc >= 0) {
1.24 espie 1017: if (verbose) {
1018: if (track_names)
1019: printf("Audio status = %d<%s>, "
1020: "current track = %d (%s)\n"
1021: "\tcurrent position = %d:%02d.%02d\n",
1022: rc, strstatus(rc), trk,
1023: trk ? track_names[trk-1] : "", m, s, f);
1024: else
1025: printf("Audio status = %d<%s>, "
1026: "current track = %d, "
1027: "current position = %d:%02d.%02d\n",
1028: rc, strstatus(rc), trk, m, s, f);
1029: } else
1.18 deraadt 1030: printf("%d %d %d:%02d.%02d\n", rc, trk, m, s, f);
1.9 millert 1031: } else
1.18 deraadt 1032: printf("No current status info available\n");
1.1 downsj 1033:
1.18 deraadt 1034: bzero(&ss, sizeof (ss));
1.1 downsj 1035: ss.data = &data;
1036: ss.data_len = sizeof (data);
1037: ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1038: ss.data_format = CD_MEDIA_CATALOG;
1.18 deraadt 1039: rc = ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &ss);
1.1 downsj 1040: if (rc >= 0) {
1041: printf("Media catalog is %sactive",
1042: ss.data->what.media_catalog.mc_valid ? "": "in");
1043: if (ss.data->what.media_catalog.mc_valid &&
1.17 espie 1044: ss.data->what.media_catalog.mc_number[0]) {
1045: strvisx(vis_catalog,
1.35 deraadt 1046: (char *)ss.data->what.media_catalog.mc_number,
1.17 espie 1047: 15, VIS_SAFE);
1048: printf(", number \"%.15s\"", vis_catalog);
1049: }
1.1 downsj 1050: putchar('\n');
1051: } else
1052: printf("No media catalog info available\n");
1053:
1.18 deraadt 1054: rc = ioctl(fd, CDIOCGETVOL, &v);
1.9 millert 1055: if (rc >= 0) {
1.1 downsj 1056: if (verbose)
1.18 deraadt 1057: printf("Left volume = %d, right volume = %d\n",
1.1 downsj 1058: v.vol[0], v.vol[1]);
1059: else
1.18 deraadt 1060: printf("%d %d\n", v.vol[0], v.vol[1]);
1.9 millert 1061: } else
1.18 deraadt 1062: printf("No volume level info available\n");
1.1 downsj 1063: return(0);
1.25 espie 1064: }
1065:
1066: int
1.30 deraadt 1067: cdid(void)
1.25 espie 1068: {
1069: unsigned long id;
1070: struct ioc_toc_header h;
1071: int rc, n;
1072:
1073: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1074: if (rc == -1) {
1075: warn("getting toc header");
1076: return (rc);
1077: }
1078:
1079: n = h.ending_track - h.starting_track + 1;
1080: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1081: if (rc < 0)
1082: return (rc);
1083:
1084: id = cddb_discid(n, toc_buffer);
1085: if (id) {
1086: if (verbose)
1087: printf("CDID=");
1088: printf("%08lx\n", id);
1089: }
1090: return id ? 0 : 1;
1.1 downsj 1091: }
1092:
1.35 deraadt 1093: /* ARGSUSED */
1.18 deraadt 1094: int
1.24 espie 1095: info(char *arg)
1.1 downsj 1096: {
1097: struct ioc_toc_header h;
1098: int rc, i, n;
1099:
1.18 deraadt 1100: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 1101: if (rc >= 0) {
1102: if (verbose)
1.18 deraadt 1103: printf("Starting track = %d, ending track = %d, TOC size = %d bytes\n",
1104: h.starting_track, h.ending_track, h.len);
1.1 downsj 1105: else
1.18 deraadt 1106: printf("%d %d %d\n", h.starting_track,
1107: h.ending_track, h.len);
1.1 downsj 1108: } else {
1.18 deraadt 1109: warn("getting toc header");
1.1 downsj 1110: return (rc);
1111: }
1112:
1113: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 1114: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 1115: if (rc < 0)
1116: return (rc);
1117:
1118: if (verbose) {
1.18 deraadt 1119: printf("track start duration block length type\n");
1120: printf("-------------------------------------------------\n");
1.1 downsj 1121: }
1122:
1123: for (i = 0; i < n; i++) {
1.18 deraadt 1124: printf("%5d ", toc_buffer[i].track);
1.24 espie 1125: prtrack(toc_buffer + i, 0, NULL);
1126: }
1127: printf("%5d ", toc_buffer[n].track);
1128: prtrack(toc_buffer + n, 1, NULL);
1129: return (0);
1130: }
1131:
1132: int
1133: cddbinfo(char *arg)
1134: {
1135: struct ioc_toc_header h;
1136: int rc, i, n;
1137:
1138: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1139: if (rc == -1) {
1140: warn("getting toc header");
1141: return (rc);
1142: }
1143:
1144: n = h.ending_track - h.starting_track + 1;
1145: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1146: if (rc < 0)
1147: return (rc);
1148:
1149: if (track_names)
1150: free_names(track_names);
1151: track_names = NULL;
1152:
1153: track_names = cddb(cddb_host, n, toc_buffer, arg);
1154: if (!track_names)
1155: return(0);
1156:
1157: printf("-------------------------------------------------\n");
1158:
1159: for (i = 0; i < n; i++) {
1160: printf("%5d ", toc_buffer[i].track);
1161: prtrack(toc_buffer + i, 0, track_names[i]);
1.1 downsj 1162: }
1.18 deraadt 1163: printf("%5d ", toc_buffer[n].track);
1.24 espie 1164: prtrack(toc_buffer + n, 1, "");
1.1 downsj 1165: return (0);
1166: }
1167:
1.18 deraadt 1168: void
1.24 espie 1169: lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f)
1.1 downsj 1170: {
1.18 deraadt 1171: lba += 150; /* block start offset */
1172: lba &= 0xffffff; /* negative lbas use only 24 bits */
1.1 downsj 1173: *m = lba / (60 * 75);
1174: lba %= (60 * 75);
1175: *s = lba / 75;
1176: *f = lba % 75;
1177: }
1178:
1.18 deraadt 1179: unsigned int
1.23 espie 1180: msf2lba(u_char m, u_char s, u_char f)
1.1 downsj 1181: {
1182: return (((m * 60) + s) * 75 + f) - 150;
1183: }
1184:
1.24 espie 1185: unsigned long
1186: entry2time(struct cd_toc_entry *e)
1187: {
1188: int block;
1189: u_char m, s, f;
1190:
1191: if (msf) {
1192: return (e->addr.msf.minute * 60 + e->addr.msf.second);
1193: } else {
1.41 krw 1194: block = e->addr.lba;
1.24 espie 1195: lba2msf(block, &m, &s, &f);
1196: return (m*60+s);
1197: }
1198: }
1199:
1200: unsigned long
1201: entry2frames(struct cd_toc_entry *e)
1202: {
1203: int block;
1204: unsigned char m, s, f;
1205:
1206: if (msf) {
1207: return e->addr.msf.frame + e->addr.msf.second * 75 +
1208: e->addr.msf.minute * 60 * 75;
1209: } else {
1.41 krw 1210: block = e->addr.lba;
1.24 espie 1211: lba2msf(block, &m, &s, &f);
1212: return f + s * 75 + m * 60 * 75;
1213: }
1214: }
1215:
1.18 deraadt 1216: void
1.24 espie 1217: prtrack(struct cd_toc_entry *e, int lastflag, char *name)
1.1 downsj 1218: {
1219: int block, next, len;
1220: u_char m, s, f;
1221:
1222: if (msf) {
1.24 espie 1223: if (!name || lastflag)
1224: /* Print track start */
1225: printf("%2d:%02d.%02d ", e->addr.msf.minute,
1226: e->addr.msf.second, e->addr.msf.frame);
1.1 downsj 1227:
1.18 deraadt 1228: block = msf2lba(e->addr.msf.minute, e->addr.msf.second,
1.1 downsj 1229: e->addr.msf.frame);
1230: } else {
1.41 krw 1231: block = e->addr.lba;
1.24 espie 1232: if (!name || lastflag) {
1233: lba2msf(block, &m, &s, &f);
1234: /* Print track start */
1235: printf("%2d:%02d.%02d ", m, s, f);
1.46 krw 1236: }
1.1 downsj 1237: }
1238: if (lastflag) {
1.24 espie 1239: if (!name)
1240: /* Last track -- print block */
1241: printf(" - %6d - -\n", block);
1242: else
1243: printf("\n");
1.1 downsj 1244: return;
1245: }
1246:
1247: if (msf)
1.18 deraadt 1248: next = msf2lba(e[1].addr.msf.minute, e[1].addr.msf.second,
1.1 downsj 1249: e[1].addr.msf.frame);
1250: else
1.41 krw 1251: next = e[1].addr.lba;
1.1 downsj 1252: len = next - block;
1.18 deraadt 1253: lba2msf(len, &m, &s, &f);
1.1 downsj 1254:
1.24 espie 1255: if (name)
1256: printf("%2d:%02d.%02d %s\n", m, s, f, name);
1.1 downsj 1257: /* Print duration, block, length, type */
1.24 espie 1258: else
1259: printf("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len,
1260: (e->control & 4) ? "data" : "audio");
1.1 downsj 1261: }
1262:
1.18 deraadt 1263: int
1.24 espie 1264: play_track(int tstart, int istart, int tend, int iend)
1.1 downsj 1265: {
1266: struct ioc_play_track t;
1267:
1268: t.start_track = tstart;
1269: t.start_index = istart;
1270: t.end_track = tend;
1271: t.end_index = iend;
1272:
1.18 deraadt 1273: return ioctl(fd, CDIOCPLAYTRACKS, &t);
1.1 downsj 1274: }
1275:
1.18 deraadt 1276: int
1.24 espie 1277: play_blocks(int blk, int len)
1.1 downsj 1278: {
1279: struct ioc_play_blocks t;
1280:
1281: t.blk = blk;
1282: t.len = len;
1283:
1.18 deraadt 1284: return ioctl(fd, CDIOCPLAYBLOCKS, &t);
1.1 downsj 1285: }
1286:
1.18 deraadt 1287: int
1.24 espie 1288: setvol(int left, int right)
1.1 downsj 1289: {
1290: struct ioc_vol v;
1291:
1292: v.vol[0] = left;
1293: v.vol[1] = right;
1294: v.vol[2] = 0;
1295: v.vol[3] = 0;
1296:
1.18 deraadt 1297: return ioctl(fd, CDIOCSETVOL, &v);
1.1 downsj 1298: }
1299:
1.18 deraadt 1300: int
1.24 espie 1301: read_toc_entrys(int len)
1.1 downsj 1302: {
1303: struct ioc_read_toc_entry t;
1.11 csapuntz 1304:
1305: if (toc_buffer) {
1.18 deraadt 1306: free(toc_buffer);
1307: toc_buffer = 0;
1.11 csapuntz 1308: }
1309:
1.18 deraadt 1310: toc_buffer = malloc(len);
1.11 csapuntz 1311:
1312: if (!toc_buffer) {
1.18 deraadt 1313: errno = ENOMEM;
1314: return (-1);
1.11 csapuntz 1315: }
1.1 downsj 1316:
1317: t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1318: t.starting_track = 0;
1319: t.data_len = len;
1320: t.data = toc_buffer;
1321:
1.18 deraadt 1322: return (ioctl(fd, CDIOREADTOCENTRYS, (char *) &t));
1.1 downsj 1323: }
1324:
1.18 deraadt 1325: int
1.24 espie 1326: play_msf(int start_m, int start_s, int start_f, int end_m, int end_s, int end_f)
1.1 downsj 1327: {
1.18 deraadt 1328: struct ioc_play_msf a;
1.1 downsj 1329:
1330: a.start_m = start_m;
1331: a.start_s = start_s;
1332: a.start_f = start_f;
1333: a.end_m = end_m;
1334: a.end_s = end_s;
1335: a.end_f = end_f;
1336:
1.18 deraadt 1337: return ioctl(fd, CDIOCPLAYMSF, (char *) &a);
1.1 downsj 1338: }
1339:
1.21 espie 1340: int
1.24 espie 1341: status(int *trk, int *min, int *sec, int *frame)
1.1 downsj 1342: {
1343: struct ioc_read_subchannel s;
1344: struct cd_sub_channel_info data;
1345: u_char mm, ss, ff;
1346:
1.18 deraadt 1347: bzero(&s, sizeof (s));
1.1 downsj 1348: s.data = &data;
1349: s.data_len = sizeof (data);
1350: s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1351: s.data_format = CD_CURRENT_POSITION;
1352:
1.18 deraadt 1353: if (ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0)
1.1 downsj 1354: return -1;
1355:
1356: *trk = s.data->what.position.track_number;
1357: if (msf) {
1358: *min = s.data->what.position.reladdr.msf.minute;
1359: *sec = s.data->what.position.reladdr.msf.second;
1360: *frame = s.data->what.position.reladdr.msf.frame;
1361: } else {
1.41 krw 1362: /*
1363: * NOTE: CDIOCREADSUBCHANNEL does not put the lba info into
1364: * host order like CDIOREADTOCENTRYS does.
1365: */
1366: lba2msf(betoh32(s.data->what.position.reladdr.lba), &mm, &ss,
1367: &ff);
1.1 downsj 1368: *min = mm;
1369: *sec = ss;
1370: *frame = ff;
1371: }
1372:
1373: return s.data->header.audio_status;
1374: }
1375:
1.18 deraadt 1376: char *
1.24 espie 1377: input(int *cmd)
1.1 downsj 1378: {
1.27 fgsch 1379: char *buf;
1380: int siz = 0;
1.1 downsj 1381: char *p;
1.31 otto 1382: HistEvent hev;
1.1 downsj 1383:
1384: do {
1.27 fgsch 1385: if ((buf = (char *) el_gets(el, &siz)) == NULL || !siz) {
1.1 downsj 1386: *cmd = CMD_QUIT;
1.18 deraadt 1387: fprintf(stderr, "\r\n");
1.1 downsj 1388: return (0);
1389: }
1.27 fgsch 1390: if (strlen(buf) > 1)
1.31 otto 1391: history(hist, &hev, H_ENTER, buf);
1.18 deraadt 1392: p = parse(buf, cmd);
1393: } while (!p);
1.1 downsj 1394: return (p);
1395: }
1396:
1.18 deraadt 1397: char *
1.24 espie 1398: parse(char *buf, int *cmd)
1.1 downsj 1399: {
1400: struct cmdtab *c;
1401: char *p;
1402: int len;
1403:
1.18 deraadt 1404: for (p=buf; isspace(*p); p++)
1.1 downsj 1405: continue;
1406:
1.18 deraadt 1407: if (isdigit(*p) || (p[0] == '#' && isdigit(p[1]))) {
1.1 downsj 1408: *cmd = CMD_PLAY;
1409: return (p);
1410: }
1411:
1.18 deraadt 1412: for (buf = p; *p && ! isspace(*p); p++)
1.1 downsj 1413: continue;
1.46 krw 1414:
1.1 downsj 1415: len = p - buf;
1416: if (! len)
1417: return (0);
1418:
1.18 deraadt 1419: if (*p) { /* It must be a spacing character! */
1.1 downsj 1420: char *q;
1421:
1422: *p++ = 0;
1423: for (q=p; *q && *q != '\n' && *q != '\r'; q++)
1424: continue;
1425: *q = 0;
1426: }
1427:
1428: *cmd = -1;
1429: for (c=cmdtab; c->name; ++c) {
1430: /* Is it an exact match? */
1.18 deraadt 1431: if (! strcasecmp(buf, c->name)) {
1.1 downsj 1432: *cmd = c->command;
1433: break;
1.46 krw 1434: }
1.1 downsj 1435:
1436: /* Try short hand forms then... */
1.18 deraadt 1437: if (len >= c->min && ! strncasecmp(buf, c->name, len)) {
1.1 downsj 1438: if (*cmd != -1 && *cmd != c->command) {
1.18 deraadt 1439: fprintf(stderr, "Ambiguous command\n");
1.1 downsj 1440: return (0);
1441: }
1442: *cmd = c->command;
1.46 krw 1443: }
1.1 downsj 1444: }
1445:
1446: if (*cmd == -1) {
1.18 deraadt 1447: fprintf(stderr, "%s: Invalid command, enter ``help'' for commands.\n",
1448: __progname);
1.1 downsj 1449: return (0);
1450: }
1451:
1.18 deraadt 1452: while (isspace(*p))
1.1 downsj 1453: p++;
1454: return p;
1455: }
1456:
1.18 deraadt 1457: int
1.48 mjc 1458: open_cd(char *dev, int needwrite)
1.1 downsj 1459: {
1.9 millert 1460: char *realdev;
1.12 millert 1461: int tries;
1.1 downsj 1462:
1463: if (fd > -1)
1464: return (1);
1465:
1.12 millert 1466: for (tries = 0; fd < 0 && tries < 10; tries++) {
1.48 mjc 1467: if (needwrite)
1468: fd = opendev(dev, O_RDWR, OPENDEV_PART, &realdev);
1469: else
1470: fd = opendev(dev, O_RDONLY, OPENDEV_PART, &realdev);
1.12 millert 1471: if (fd < 0) {
1472: if (errno == ENXIO) {
1473: /* ENXIO has an overloaded meaning here.
1474: * The original "Device not configured" should
1475: * be interpreted as "No disc in drive %s". */
1.18 deraadt 1476: warnx("No disc in drive %s.", realdev);
1.12 millert 1477: return (0);
1478: } else if (errno != EIO) {
1479: /* EIO may simply mean the device is not ready
1480: * yet which is common with CD changers. */
1.18 deraadt 1481: warn("Can't open %s", realdev);
1.12 millert 1482: return (0);
1483: }
1484: }
1.18 deraadt 1485: sleep(1);
1.12 millert 1486: }
1.1 downsj 1487: if (fd < 0) {
1.18 deraadt 1488: warn("Can't open %s", realdev);
1.9 millert 1489: return (0);
1.1 downsj 1490: }
1491: return (1);
1.27 fgsch 1492: }
1493:
1494: char *
1495: prompt(void)
1496: {
1497: return (verbose ? "cdio> " : "");
1498: }
1499:
1500: void
1501: switch_el(void)
1502: {
1.31 otto 1503: HistEvent hev;
1504:
1.27 fgsch 1505: if (el == NULL && hist == NULL) {
1.31 otto 1506: el = el_init(__progname, stdin, stdout, stderr);
1.27 fgsch 1507: hist = history_init();
1.31 otto 1508: history(hist, &hev, H_SETSIZE, 100);
1.27 fgsch 1509: el_set(el, EL_HIST, history, hist);
1510: el_set(el, EL_EDITOR, "emacs");
1511: el_set(el, EL_PROMPT, prompt);
1512: el_set(el, EL_SIGNAL, 1);
1513: el_source(el, NULL);
1514:
1515: } else {
1516: if (hist != NULL) {
1517: history_end(hist);
1518: hist = NULL;
1519: }
1520: if (el != NULL) {
1521: el_end(el);
1522: el = NULL;
1523: }
1524: }
1.42 krw 1525: }
1526:
1527: void
1528: addmsf(u_int *m, u_int *s, u_int *f, u_char m_inc, u_char s_inc, u_char f_inc)
1529: {
1530: *f += f_inc;
1531: if (*f > 75) {
1532: *s += *f / 75;
1533: *f %= 75;
1534: }
1535:
1536: *s += s_inc;
1537: if (*s > 60) {
1538: *m += *s / 60;
1539: *s %= 60;
1540: }
1541:
1542: *m += m_inc;
1.44 krw 1543: }
1544:
1545: int
1546: cmpmsf(u_char m1, u_char s1, u_char f1, u_char m2, u_char s2, u_char f2)
1547: {
1548: if (m1 > m2)
1549: return (1);
1550: else if (m1 < m2)
1551: return (-1);
1552:
1553: if (s1 > s2)
1554: return (1);
1555: else if (s1 < s2)
1556: return (-1);
1557:
1558: if (f1 > f2)
1559: return (1);
1560: else if (f1 < f2)
1561: return (-1);
1562:
1563: return (0);
1.43 krw 1564: }
1565:
1566: void
1567: toc2msf(u_int track, u_char *m, u_char *s, u_char *f)
1568: {
1569: struct cd_toc_entry *ctep;
1570:
1571: ctep = &toc_buffer[track - 1];
1572:
1573: if (msf) {
1574: *m = ctep->addr.msf.minute;
1575: *s = ctep->addr.msf.second;
1576: *f = ctep->addr.msf.frame;
1577: } else
1578: lba2msf(ctep->addr.lba, m, s, f);
1.1 downsj 1579: }