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