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