Annotation of src/usr.bin/cdio/cdio.c, Revision 1.21
1.21 ! espie 1: /* $OpenBSD: cdio.c,v 1.20 2002/02/17 19:42:30 millert Exp $ */
1.1 downsj 2: /*
3: * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>.
4: * Based on the non-X based CD player by Jean-Marc Zucconi and
5: * Andrey A. Chernov.
6: *
7: * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>.
8: *
9: * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
10: * A couple of further fixes to my own earlier "fixes".
11: *
12: * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
13: * Added an ability to specify addresses relative to the
14: * beginning of a track. This is in fact a variation of
15: * doing the simple play_msf() call.
16: *
17: * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru>
18: * New eject algorithm.
19: * Some code style reformatting.
20: *
21: * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $
22: */
23:
24: #include <ctype.h>
1.17 espie 25: #include <err.h>
26: #include <errno.h>
1.1 downsj 27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <unistd.h>
31: #include <util.h>
1.17 espie 32: #include <vis.h>
1.9 millert 33: #include <sys/param.h>
1.1 downsj 34: #include <sys/file.h>
35: #include <sys/cdio.h>
36: #include <sys/ioctl.h>
37:
38: #define VERSION "2.0"
39:
40: #define ASTS_INVALID 0x00 /* Audio status byte not valid */
41: #define ASTS_PLAYING 0x11 /* Audio play operation in progress */
42: #define ASTS_PAUSED 0x12 /* Audio play operation paused */
43: #define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */
44: #define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */
45: #define ASTS_VOID 0x15 /* No current audio status to return */
46:
47: #ifndef DEFAULT_CD_DRIVE
1.3 deraadt 48: # define DEFAULT_CD_DRIVE "cd0"
1.1 downsj 49: #endif
50:
51: #define CMD_DEBUG 1
1.9 millert 52: #define CMD_DEVICE 2
53: #define CMD_EJECT 3
54: #define CMD_HELP 4
55: #define CMD_INFO 5
56: #define CMD_PAUSE 6
57: #define CMD_PLAY 7
58: #define CMD_QUIT 8
59: #define CMD_RESUME 9
60: #define CMD_STOP 10
61: #define CMD_VOLUME 11
62: #define CMD_CLOSE 12
63: #define CMD_RESET 13
64: #define CMD_SET 14
65: #define CMD_STATUS 15
66: #define CMD_NEXT 16
67: #define CMD_PREV 17
68: #define CMD_REPLAY 18
1.1 downsj 69:
70: struct cmdtab {
71: int command;
72: char *name;
73: unsigned min;
74: char *args;
75: } cmdtab[] = {
76: { CMD_CLOSE, "close", 1, "" },
77: { CMD_DEBUG, "debug", 1, "on | off" },
1.9 millert 78: { CMD_DEVICE, "device", 1, "devname" },
1.1 downsj 79: { CMD_EJECT, "eject", 1, "" },
80: { CMD_HELP, "?", 1, 0 },
81: { CMD_HELP, "help", 1, "" },
82: { CMD_INFO, "info", 1, "" },
1.5 angelos 83: { CMD_NEXT, "next", 1, "" },
1.1 downsj 84: { CMD_PAUSE, "pause", 2, "" },
85: { CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" },
86: { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" },
87: { CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" },
88: { CMD_PLAY, "play", 1, "[#block [len]]" },
1.5 angelos 89: { CMD_PREV, "previous", 2, "" },
1.1 downsj 90: { CMD_QUIT, "quit", 1, "" },
91: { CMD_RESET, "reset", 4, "" },
92: { CMD_RESUME, "resume", 1, "" },
1.6 angelos 93: { CMD_REPLAY, "replay", 3, "" },
1.1 downsj 94: { CMD_SET, "set", 2, "msf | lba" },
95: { CMD_STATUS, "status", 1, "" },
96: { CMD_STOP, "stop", 3, "" },
97: { CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" },
98: { 0, }
99: };
100:
1.11 csapuntz 101: struct cd_toc_entry *toc_buffer;
1.1 downsj 102:
103: char *cdname;
104: int fd = -1;
105: int verbose = 1;
106: int msf = 1;
107:
108: extern char *__progname;
109:
1.19 millert 110: int setvol(int, int);
111: int read_toc_entrys(int);
112: int play_msf(int, int, int, int, int, int);
113: int play_track(int, int, int, int);
114: int get_vol(int *, int *);
115: int status(int *, int *, int *, int *);
116: int open_cd(char *);
117: int play(char *arg);
118: int info(char *arg);
119: int pstatus(char *arg);
120: int play_next(char *arg);
121: int play_prev(char *arg);
122: int play_same(char *arg);
123: char *input(int *);
124: void prtrack(struct cd_toc_entry *e, int lastflag);
1.20 millert 125: void lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f);
1.19 millert 126: unsigned int msf2lba(u_char m, u_char s, u_char f);
127: int play_blocks(int blk, int len);
128: int run(int cmd, char *arg);
129: char *parse(char *buf, int *cmd);
1.1 downsj 130:
1.18 deraadt 131: void
132: help()
1.1 downsj 133: {
134: struct cmdtab *c;
135: char *s, n;
136: int i;
137:
138: for (c=cmdtab; c->name; ++c) {
139: if (! c->args)
140: continue;
141: printf("\t");
142: for (i = c->min, s = c->name; *s; s++, i--) {
143: if (i > 0)
144: n = toupper(*s);
145: else
146: n = *s;
147: putchar(n);
148: }
149: if (*c->args)
1.18 deraadt 150: printf(" %s", c->args);
151: printf("\n");
1.1 downsj 152: }
1.18 deraadt 153: printf("\n\tThe word \"play\" is not required for the play commands.\n");
154: printf("\tThe plain target address is taken as a synonym for play.\n");
1.1 downsj 155: }
156:
1.18 deraadt 157: void
158: usage()
1.1 downsj 159: {
1.18 deraadt 160: fprintf(stderr, "usage: %s [-sv] [-f device] [command args ...]\n",
161: __progname);
162: exit(1);
1.1 downsj 163: }
164:
1.18 deraadt 165: int
166: main(argc, argv)
1.1 downsj 167: int argc;
168: char **argv;
169: {
170: int cmd;
171: char *arg;
172:
1.18 deraadt 173: cdname = getenv("DISC");
1.1 downsj 174: if (! cdname)
1.18 deraadt 175: cdname = getenv("CDROM");
1.1 downsj 176:
177: for (;;) {
1.18 deraadt 178: switch (getopt(argc, argv, "svf:")) {
1.1 downsj 179: case EOF:
180: break;
181: case 's':
182: verbose = 0;
183: continue;
184: case 'v':
185: verbose = 2;
186: continue;
187: case 'f':
188: cdname = optarg;
189: continue;
190: default:
1.18 deraadt 191: usage();
1.1 downsj 192: }
193: break;
194: }
195: argc -= optind;
196: argv += optind;
197:
1.18 deraadt 198: if (argc > 0 && ! strcasecmp(*argv, "help"))
199: usage();
1.1 downsj 200:
201: if (! cdname) {
202: cdname = DEFAULT_CD_DRIVE;
1.18 deraadt 203: fprintf(stderr,
204: "No CD device name specified. Defaulting to %s.\n", cdname);
1.1 downsj 205: }
206:
207: if (argc > 0) {
208: char buf[80], *p;
209: int len;
210:
211: for (p=buf; argc-->0; ++argv) {
1.18 deraadt 212: len = strlen(*argv);
1.1 downsj 213:
214: if (p + len >= buf + sizeof (buf) - 1)
1.18 deraadt 215: usage();
1.1 downsj 216:
217: if (p > buf)
218: *p++ = ' ';
219:
1.18 deraadt 220: strcpy(p, *argv); /* ok */
1.1 downsj 221: p += len;
222: }
223: *p = 0;
1.18 deraadt 224: arg = parse(buf, &cmd);
225: return (run(cmd, arg));
1.1 downsj 226: }
227:
228: if (verbose == 1)
1.18 deraadt 229: verbose = isatty(0);
1.1 downsj 230:
231: if (verbose) {
1.18 deraadt 232: printf("Compact Disc Control utility, version %s\n", VERSION);
233: printf("Type `?' for command list\n\n");
1.1 downsj 234: }
235:
236: for (;;) {
1.18 deraadt 237: arg = input(&cmd);
238: if (run(cmd, arg) < 0) {
1.1 downsj 239: if (verbose)
1.18 deraadt 240: warn(NULL);
241: close(fd);
1.1 downsj 242: fd = -1;
243: }
1.18 deraadt 244: fflush(stdout);
1.1 downsj 245: }
246: }
247:
1.18 deraadt 248: int
249: run(cmd, arg)
1.1 downsj 250: int cmd;
251: char *arg;
252: {
253: int l, r, rc;
1.9 millert 254: static char newcdname[MAXPATHLEN];
1.1 downsj 255:
256: switch (cmd) {
257:
258: case CMD_QUIT:
1.18 deraadt 259: exit(0);
1.1 downsj 260:
261: case CMD_INFO:
1.18 deraadt 262: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 263: return (0);
264:
1.18 deraadt 265: return info(arg);
1.1 downsj 266:
267: case CMD_STATUS:
1.18 deraadt 268: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 269: return (0);
270:
1.18 deraadt 271: return pstatus(arg);
1.1 downsj 272:
273: case CMD_PAUSE:
1.18 deraadt 274: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 275: return (0);
276:
1.18 deraadt 277: return ioctl(fd, CDIOCPAUSE);
1.1 downsj 278:
279: case CMD_RESUME:
1.18 deraadt 280: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 281: return (0);
282:
1.18 deraadt 283: return ioctl(fd, CDIOCRESUME);
1.1 downsj 284:
285: case CMD_STOP:
1.18 deraadt 286: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 287: return (0);
288:
1.18 deraadt 289: rc = ioctl(fd, CDIOCSTOP);
1.1 downsj 290:
1.18 deraadt 291: (void) ioctl(fd, CDIOCALLOW);
1.1 downsj 292:
293: return (rc);
294:
295: case CMD_RESET:
1.18 deraadt 296: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 297: return (0);
298:
1.18 deraadt 299: rc = ioctl(fd, CDIOCRESET);
1.1 downsj 300: if (rc < 0)
301: return rc;
302: close(fd);
303: fd = -1;
304: return (0);
305:
306: case CMD_DEBUG:
1.18 deraadt 307: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 308: return (0);
309:
1.18 deraadt 310: if (! strcasecmp(arg, "on"))
311: return ioctl(fd, CDIOCSETDEBUG);
1.1 downsj 312:
1.18 deraadt 313: if (! strcasecmp(arg, "off"))
314: return ioctl(fd, CDIOCCLRDEBUG);
1.1 downsj 315:
1.18 deraadt 316: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 317:
318: return (0);
319:
1.9 millert 320: case CMD_DEVICE:
321: /* close old device */
322: if (fd > -1) {
1.18 deraadt 323: (void) ioctl(fd, CDIOCALLOW);
1.9 millert 324: close(fd);
325: fd = -1;
326: }
327:
328: /* open new device */
1.18 deraadt 329: if (!open_cd(arg))
1.9 millert 330: return (0);
1.16 lebel 331: (void) strlcpy(newcdname, arg, sizeof(newcdname));
1.9 millert 332: cdname = newcdname;
333: return (1);
334:
1.1 downsj 335: case CMD_EJECT:
1.18 deraadt 336: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 337: return (0);
338:
1.18 deraadt 339: (void) ioctl(fd, CDIOCALLOW);
340: rc = ioctl(fd, CDIOCEJECT);
1.1 downsj 341: if (rc < 0)
342: return (rc);
343: #if defined(__OpenBSD__)
344: close(fd);
345: fd = -1;
346: #endif
347: return (0);
348:
349: case CMD_CLOSE:
350: #if defined(CDIOCCLOSE)
1.18 deraadt 351: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 352: return (0);
353:
1.18 deraadt 354: (void) ioctl(fd, CDIOCALLOW);
355: rc = ioctl(fd, CDIOCCLOSE);
1.1 downsj 356: if (rc < 0)
357: return (rc);
358: close(fd);
359: fd = -1;
360: return (0);
361: #else
1.18 deraadt 362: printf("%s: Command not yet supported\n", __progname);
1.1 downsj 363: return (0);
364: #endif
365:
366: case CMD_PLAY:
1.18 deraadt 367: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 368: return (0);
369:
1.18 deraadt 370: while (isspace(*arg))
1.1 downsj 371: arg++;
372:
1.18 deraadt 373: return play(arg);
1.1 downsj 374:
375: case CMD_SET:
1.18 deraadt 376: if (!strcasecmp(arg, "msf"))
1.1 downsj 377: msf = 1;
1.18 deraadt 378: else if (!strcasecmp(arg, "lba"))
1.1 downsj 379: msf = 0;
380: else
1.18 deraadt 381: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 382: return (0);
383:
384: case CMD_VOLUME:
1.18 deraadt 385: if (fd < 0 && !open_cd(cdname))
1.1 downsj 386: return (0);
387:
1.18 deraadt 388: if (!strncasecmp(arg, "left", strlen(arg)))
389: return ioctl(fd, CDIOCSETLEFT);
1.1 downsj 390:
1.18 deraadt 391: if (!strncasecmp(arg, "right", strlen(arg)))
392: return ioctl(fd, CDIOCSETRIGHT);
1.1 downsj 393:
1.18 deraadt 394: if (!strncasecmp(arg, "mono", strlen(arg)))
395: return ioctl(fd, CDIOCSETMONO);
1.1 downsj 396:
1.18 deraadt 397: if (!strncasecmp(arg, "stereo", strlen(arg)))
398: return ioctl(fd, CDIOCSETSTEREO);
1.1 downsj 399:
1.18 deraadt 400: if (!strncasecmp(arg, "mute", strlen(arg)))
401: return ioctl(fd, CDIOCSETMUTE);
1.1 downsj 402:
1.18 deraadt 403: if (2 != sscanf(arg, "%d %d", &l, &r)) {
404: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 405: return (0);
406: }
407:
1.18 deraadt 408: return setvol(l, r);
1.1 downsj 409:
1.18 deraadt 410: case CMD_NEXT:
411: if (fd < 0 && ! open_cd(cdname))
412: return (0);
1.5 angelos 413:
1.18 deraadt 414: return play_next(arg);
1.5 angelos 415:
1.18 deraadt 416: case CMD_PREV:
417: if (fd < 0 && ! open_cd(cdname))
418: return (0);
1.5 angelos 419:
1.18 deraadt 420: return play_prev(arg);
1.5 angelos 421:
1.6 angelos 422: case CMD_REPLAY:
1.18 deraadt 423: if (fd < 0 && ! open_cd(cdname))
1.6 angelos 424: return 0;
425:
1.18 deraadt 426: return play_same(arg);
1.1 downsj 427: default:
428: case CMD_HELP:
1.18 deraadt 429: help();
1.1 downsj 430: return (0);
431:
432: }
433: }
434:
1.18 deraadt 435: int
436: play(arg)
1.1 downsj 437: char *arg;
438: {
439: struct ioc_toc_header h;
440: int rc, n, start, end = 0, istart = 1, iend = 1;
441:
1.18 deraadt 442: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 443:
444: if (rc < 0)
445: return (rc);
446:
447: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 448: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 449:
450: if (rc < 0)
451: return (rc);
452:
453: if (! arg || ! *arg) {
454: /* Play the whole disc */
1.18 deraadt 455:
1.10 csapuntz 456: return (play_track(h.starting_track, 1,
1.18 deraadt 457: h.ending_track, 1));
1.1 downsj 458: }
459:
1.18 deraadt 460: if (strchr(arg, '#')) {
1.1 downsj 461: /* Play block #blk [ len ] */
462: int blk, len = 0;
463:
1.18 deraadt 464: if (2 != sscanf(arg, "#%d%d", &blk, &len) &&
465: 1 != sscanf(arg, "#%d", &blk))
1.1 downsj 466: goto Clean_up;
467:
468: if (len == 0) {
469: if (msf)
1.18 deraadt 470: len = msf2lba(toc_buffer[n].addr.msf.minute,
471: toc_buffer[n].addr.msf.second,
472: toc_buffer[n].addr.msf.frame) - blk;
1.1 downsj 473: else
474: len = ntohl(toc_buffer[n].addr.lba) - blk;
475: }
1.18 deraadt 476: return play_blocks(blk, len);
1.1 downsj 477: }
478:
1.18 deraadt 479: if (strchr(arg, ':')) {
1.1 downsj 480: /*
481: * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ]
482: *
483: * Will now also undestand timed addresses relative
484: * to the beginning of a track in the form...
485: *
486: * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]
487: */
488: unsigned tr1, tr2;
489: unsigned m1, m2, s1, s2, f1, f2;
490: unsigned char tm, ts, tf;
491:
492: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 493: if (8 == sscanf(arg, "%d %d:%d.%d %d %d:%d.%d",
1.1 downsj 494: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2))
495: goto Play_Relative_Addresses;
496:
497: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 498: if (7 == sscanf(arg, "%d %d:%d %d %d:%d.%d",
1.1 downsj 499: &tr1, &m1, &s1, &tr2, &m2, &s2, &f2))
500: goto Play_Relative_Addresses;
501:
502: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 503: if (7 == sscanf(arg, "%d %d:%d.%d %d %d:%d",
1.1 downsj 504: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2))
505: goto Play_Relative_Addresses;
506:
507: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 508: if (7 == sscanf(arg, "%d %d:%d.%d %d:%d.%d",
1.1 downsj 509: &tr1, &m1, &s1, &f1, &m2, &s2, &f2))
510: goto Play_Relative_Addresses;
511:
512: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 513: if (6 == sscanf(arg, "%d %d:%d.%d %d:%d",
1.1 downsj 514: &tr1, &m1, &s1, &f1, &m2, &s2))
515: goto Play_Relative_Addresses;
516:
517: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 518: if (6 == sscanf(arg, "%d %d:%d %d:%d.%d",
1.1 downsj 519: &tr1, &m1, &s1, &m2, &s2, &f2))
520: goto Play_Relative_Addresses;
521:
522: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 523: if (6 == sscanf(arg, "%d %d:%d.%d %d %d",
1.1 downsj 524: &tr1, &m1, &s1, &f1, &tr2, &m2))
525: goto Play_Relative_Addresses;
526:
527: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 528: if (5 == sscanf(arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2))
1.1 downsj 529: goto Play_Relative_Addresses;
530:
531: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 532: if (5 == sscanf(arg, "%d %d:%d %d %d",
1.1 downsj 533: &tr1, &m1, &s1, &tr2, &m2))
534: goto Play_Relative_Addresses;
535:
536: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 537: if (5 == sscanf(arg, "%d %d:%d.%d %d",
1.1 downsj 538: &tr1, &m1, &s1, &f1, &tr2))
539: goto Play_Relative_Addresses;
540:
541: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 542: if (4 == sscanf(arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2))
1.1 downsj 543: goto Play_Relative_Addresses;
544:
545: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 546: if (4 == sscanf(arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1))
1.1 downsj 547: goto Play_Relative_Addresses;
548:
549: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 550: if (3 == sscanf(arg, "%d %d:%d", &tr1, &m1, &s1))
1.1 downsj 551: goto Play_Relative_Addresses;
552:
553: tr2 = m2 = s2 = f2 = f1 = 0;
554: goto Try_Absolute_Timed_Addresses;
555:
556: Play_Relative_Addresses:
557: if (! tr1)
558: tr1 = 1;
559: else if (tr1 > n)
560: tr1 = n;
561:
562: if (msf) {
563: tm = toc_buffer[tr1].addr.msf.minute;
564: ts = toc_buffer[tr1].addr.msf.second;
565: tf = toc_buffer[tr1].addr.msf.frame;
566: } else
567: lba2msf(ntohl(toc_buffer[tr1].addr.lba),
568: &tm, &ts, &tf);
569: if ((m1 > tm)
570: || ((m1 == tm)
571: && ((s1 > ts)
572: || ((s1 == ts)
573: && (f1 > tf))))) {
1.18 deraadt 574: printf("Track %d is not that long.\n", tr1);
1.1 downsj 575: return (0);
576: }
577:
578: tr1--;
579:
580: f1 += tf;
581: if (f1 >= 75) {
582: s1 += f1 / 75;
583: f1 %= 75;
584: }
585:
586: s1 += ts;
587: if (s1 >= 60) {
588: m1 += s1 / 60;
589: s1 %= 60;
590: }
591:
592: m1 += tm;
593:
594: if (! tr2) {
595: if (m2 || s2 || f2) {
596: tr2 = tr1;
597: f2 += f1;
598: if (f2 >= 75) {
599: s2 += f2 / 75;
600: f2 %= 75;
601: }
602:
603: s2 += s1;
604: if (s2 > 60) {
605: m2 += s2 / 60;
606: s2 %= 60;
607: }
608:
609: m2 += m1;
610: } else {
611: tr2 = n;
612: if (msf) {
613: m2 = toc_buffer[n].addr.msf.minute;
614: s2 = toc_buffer[n].addr.msf.second;
615: f2 = toc_buffer[n].addr.msf.frame;
616: } else {
617: lba2msf(ntohl(toc_buffer[n].addr.lba),
618: &tm, &ts, &tf);
619: m2 = tm;
620: s2 = ts;
621: f2 = tf;
622: }
623: }
624: } else if (tr2 > n) {
625: tr2 = n;
626: m2 = s2 = f2 = 0;
627: } else {
628: if (m2 || s2 || f2)
629: tr2--;
630: if (msf) {
631: tm = toc_buffer[tr2].addr.msf.minute;
632: ts = toc_buffer[tr2].addr.msf.second;
633: tf = toc_buffer[tr2].addr.msf.frame;
634: } else
635: lba2msf(ntohl(toc_buffer[tr2].addr.lba),
636: &tm, &ts, &tf);
637: f2 += tf;
638: if (f2 >= 75) {
639: s2 += f2 / 75;
640: f2 %= 75;
641: }
642:
643: s2 += ts;
644: if (s2 > 60) {
645: m2 += s2 / 60;
646: s2 %= 60;
647: }
648:
649: m2 += tm;
650: }
651:
652: if (msf) {
653: tm = toc_buffer[n].addr.msf.minute;
654: ts = toc_buffer[n].addr.msf.second;
655: tf = toc_buffer[n].addr.msf.frame;
656: } else
657: lba2msf(ntohl(toc_buffer[n].addr.lba),
658: &tm, &ts, &tf);
659: if ((tr2 < n)
660: && ((m2 > tm)
661: || ((m2 == tm)
662: && ((s2 > ts)
663: || ((s2 == ts)
664: && (f2 > tf)))))) {
1.18 deraadt 665: printf("The playing time of the disc is not that long.\n");
1.1 downsj 666: return (0);
667: }
1.18 deraadt 668: return (play_msf(m1, s1, f1, m2, s2, f2));
1.1 downsj 669:
670: Try_Absolute_Timed_Addresses:
1.18 deraadt 671: if (6 != sscanf(arg, "%d:%d.%d%d:%d.%d",
672: &m1, &s1, &f1, &m2, &s2, &f2) &&
673: 5 != sscanf(arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) &&
674: 5 != sscanf(arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) &&
675: 3 != sscanf(arg, "%d:%d.%d", &m1, &s1, &f1) &&
676: 4 != sscanf(arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) &&
677: 2 != sscanf(arg, "%d:%d", &m1, &s1))
1.1 downsj 678: goto Clean_up;
679:
680: if (m2 == 0) {
681: if (msf) {
682: m2 = toc_buffer[n].addr.msf.minute;
683: s2 = toc_buffer[n].addr.msf.second;
684: f2 = toc_buffer[n].addr.msf.frame;
685: } else {
686: lba2msf(ntohl(toc_buffer[n].addr.lba),
687: &tm, &ts, &tf);
688: m2 = tm;
689: s2 = ts;
690: f2 = tf;
691: }
692: }
1.18 deraadt 693: return play_msf(m1, s1, f1, m2, s2, f2);
1.1 downsj 694: }
695:
696: /*
697: * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ]
698: */
1.18 deraadt 699: if (4 != sscanf(arg, "%d.%d%d.%d", &start, &istart, &end, &iend) &&
700: 3 != sscanf(arg, "%d.%d%d", &start, &istart, &end) &&
701: 3 != sscanf(arg, "%d%d.%d", &start, &end, &iend) &&
702: 2 != sscanf(arg, "%d.%d", &start, &istart) &&
703: 2 != sscanf(arg, "%d%d", &start, &end) &&
704: 1 != sscanf(arg, "%d", &start))
1.1 downsj 705: goto Clean_up;
706:
707: if (end == 0)
1.10 csapuntz 708: end = h.ending_track;
1.18 deraadt 709: return (play_track(start, istart, end, iend));
1.1 downsj 710:
711: Clean_up:
1.18 deraadt 712: printf("%s: Invalid command arguments\n", __progname);
1.5 angelos 713: return (0);
714: }
715:
1.18 deraadt 716: int
717: play_prev(arg)
718: char *arg;
1.5 angelos 719: {
1.18 deraadt 720: int trk, min, sec, frm, rc;
721: struct ioc_toc_header h;
1.5 angelos 722:
1.18 deraadt 723: if (status(&trk, &min, &sec, &frm) >= 0) {
724: trk--;
1.5 angelos 725:
1.18 deraadt 726: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
727: if (rc < 0) {
728: warn("getting toc header");
729: return (rc);
730: }
1.5 angelos 731:
1.18 deraadt 732: if (trk < h.starting_track)
733: return play_track(h.starting_track, 1,
734: h.ending_track + 1, 1);
735: return play_track(trk, 1, h.ending_track, 1);
736: }
1.6 angelos 737:
1.18 deraadt 738: return (0);
1.6 angelos 739: }
740:
1.18 deraadt 741: int
742: play_same(arg)
1.6 angelos 743: char *arg;
744: {
1.18 deraadt 745: int trk, min, sec, frm, rc;
746: struct ioc_toc_header h;
1.6 angelos 747:
1.18 deraadt 748: if (status (&trk, &min, &sec, &frm) >= 0) {
749: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
750: if (rc < 0) {
751: warn("getting toc header");
752: return (rc);
753: }
1.5 angelos 754:
1.18 deraadt 755: return play_track(trk, 1, h.ending_track, 1);
756: }
1.5 angelos 757:
1.18 deraadt 758: return (0);
1.5 angelos 759: }
760:
1.18 deraadt 761: int
762: play_next(arg)
1.5 angelos 763: char *arg;
764: {
765: int trk, min, sec, frm, rc;
766: struct ioc_toc_header h;
767:
1.18 deraadt 768: if (status(&trk, &min, &sec, &frm) >= 0) {
1.5 angelos 769: trk++;
1.18 deraadt 770: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
771: if (rc < 0) {
772: warn("getting toc header");
1.5 angelos 773: return (rc);
774: }
775:
1.18 deraadt 776: if (trk > h.ending_track) {
1.5 angelos 777: printf("%s: end of CD\n", __progname);
778:
1.18 deraadt 779: rc = ioctl(fd, CDIOCSTOP);
1.5 angelos 780:
1.18 deraadt 781: (void) ioctl(fd, CDIOCALLOW);
1.5 angelos 782:
783: return (rc);
784: }
785:
1.18 deraadt 786: return play_track(trk, 1, h.ending_track, 1);
1.5 angelos 787: }
788:
1.1 downsj 789: return (0);
790: }
791:
1.18 deraadt 792: char *
793: strstatus(sts)
1.1 downsj 794: int sts;
795: {
796: switch (sts) {
1.18 deraadt 797: case ASTS_INVALID:
798: return ("invalid");
799: case ASTS_PLAYING:
800: return ("playing");
801: case ASTS_PAUSED:
802: return ("paused");
803: case ASTS_COMPLETED:
804: return ("completed");
805: case ASTS_ERROR:
806: return ("error");
807: case ASTS_VOID:
808: return ("void");
809: default:
810: return ("??");
1.1 downsj 811: }
812: }
813:
1.18 deraadt 814: int
815: pstatus(arg)
1.1 downsj 816: char *arg;
817: {
818: struct ioc_vol v;
819: struct ioc_read_subchannel ss;
820: struct cd_sub_channel_info data;
821: int rc, trk, m, s, f;
1.17 espie 822: char vis_catalog[1 + 4 * 15];
1.1 downsj 823:
1.18 deraadt 824: rc = status(&trk, &m, &s, &f);
1.9 millert 825: if (rc >= 0) {
1.1 downsj 826: if (verbose)
1.18 deraadt 827: printf("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n",
828: rc, strstatus(rc), trk, m, s, f);
1.1 downsj 829: else
1.18 deraadt 830: printf("%d %d %d:%02d.%02d\n", rc, trk, m, s, f);
1.9 millert 831: } else
1.18 deraadt 832: printf("No current status info available\n");
1.1 downsj 833:
1.18 deraadt 834: bzero(&ss, sizeof (ss));
1.1 downsj 835: ss.data = &data;
836: ss.data_len = sizeof (data);
837: ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
838: ss.data_format = CD_MEDIA_CATALOG;
1.18 deraadt 839: rc = ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &ss);
1.1 downsj 840: if (rc >= 0) {
841: printf("Media catalog is %sactive",
842: ss.data->what.media_catalog.mc_valid ? "": "in");
843: if (ss.data->what.media_catalog.mc_valid &&
1.17 espie 844: ss.data->what.media_catalog.mc_number[0]) {
845: strvisx(vis_catalog,
846: ss.data->what.media_catalog.mc_number,
847: 15, VIS_SAFE);
848: printf(", number \"%.15s\"", vis_catalog);
849: }
1.1 downsj 850: putchar('\n');
851: } else
852: printf("No media catalog info available\n");
853:
1.18 deraadt 854: rc = ioctl(fd, CDIOCGETVOL, &v);
1.9 millert 855: if (rc >= 0) {
1.1 downsj 856: if (verbose)
1.18 deraadt 857: printf("Left volume = %d, right volume = %d\n",
1.1 downsj 858: v.vol[0], v.vol[1]);
859: else
1.18 deraadt 860: printf("%d %d\n", v.vol[0], v.vol[1]);
1.9 millert 861: } else
1.18 deraadt 862: printf("No volume level info available\n");
1.1 downsj 863: return(0);
864: }
865:
1.18 deraadt 866: int
867: info(arg)
1.1 downsj 868: char *arg;
869: {
870: struct ioc_toc_header h;
871: int rc, i, n;
872:
1.18 deraadt 873: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 874: if (rc >= 0) {
875: if (verbose)
1.18 deraadt 876: printf("Starting track = %d, ending track = %d, TOC size = %d bytes\n",
877: h.starting_track, h.ending_track, h.len);
1.1 downsj 878: else
1.18 deraadt 879: printf("%d %d %d\n", h.starting_track,
880: h.ending_track, h.len);
1.1 downsj 881: } else {
1.18 deraadt 882: warn("getting toc header");
1.1 downsj 883: return (rc);
884: }
885:
886: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 887: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 888: if (rc < 0)
889: return (rc);
890:
891: if (verbose) {
1.18 deraadt 892: printf("track start duration block length type\n");
893: printf("-------------------------------------------------\n");
1.1 downsj 894: }
895:
896: for (i = 0; i < n; i++) {
1.18 deraadt 897: printf("%5d ", toc_buffer[i].track);
898: prtrack(toc_buffer + i, 0);
1.1 downsj 899: }
1.18 deraadt 900: printf("%5d ", toc_buffer[n].track);
901: prtrack(toc_buffer + n, 1);
1.1 downsj 902: return (0);
903: }
904:
1.18 deraadt 905: void
906: lba2msf(lba, m, s, f)
1.1 downsj 907: unsigned long lba;
908: u_char *m;
909: u_char *s;
910: u_char *f;
911: {
1.18 deraadt 912: lba += 150; /* block start offset */
913: lba &= 0xffffff; /* negative lbas use only 24 bits */
1.1 downsj 914: *m = lba / (60 * 75);
915: lba %= (60 * 75);
916: *s = lba / 75;
917: *f = lba % 75;
918: }
919:
1.18 deraadt 920: unsigned int
921: msf2lba(m, s, f)
1.1 downsj 922: u_char m;
923: u_char s;
924: u_char f;
925: {
926: return (((m * 60) + s) * 75 + f) - 150;
927: }
928:
1.18 deraadt 929: void
930: prtrack(e, lastflag)
1.1 downsj 931: struct cd_toc_entry *e;
932: int lastflag;
933: {
934: int block, next, len;
935: u_char m, s, f;
936:
937: if (msf) {
938: /* Print track start */
1.18 deraadt 939: printf("%2d:%02d.%02d ", e->addr.msf.minute,
1.1 downsj 940: e->addr.msf.second, e->addr.msf.frame);
941:
1.18 deraadt 942: block = msf2lba(e->addr.msf.minute, e->addr.msf.second,
1.1 downsj 943: e->addr.msf.frame);
944: } else {
945: block = ntohl(e->addr.lba);
946: lba2msf(block, &m, &s, &f);
947: /* Print track start */
1.18 deraadt 948: printf("%2d:%02d.%02d ", m, s, f);
1.1 downsj 949: }
950: if (lastflag) {
951: /* Last track -- print block */
1.18 deraadt 952: printf(" - %6d - -\n", block);
1.1 downsj 953: return;
954: }
955:
956: if (msf)
1.18 deraadt 957: next = msf2lba(e[1].addr.msf.minute, e[1].addr.msf.second,
1.1 downsj 958: e[1].addr.msf.frame);
959: else
960: next = ntohl(e[1].addr.lba);
961: len = next - block;
1.18 deraadt 962: lba2msf(len, &m, &s, &f);
1.1 downsj 963:
964: /* Print duration, block, length, type */
1.18 deraadt 965: printf("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len,
966: (e->control & 4) ? "data" : "audio");
1.1 downsj 967: }
968:
1.18 deraadt 969: int
970: play_track(tstart, istart, tend, iend)
1.1 downsj 971: int tstart;
972: int istart;
973: int tend;
974: int iend;
975: {
976: struct ioc_play_track t;
977:
978: t.start_track = tstart;
979: t.start_index = istart;
980: t.end_track = tend;
981: t.end_index = iend;
982:
1.18 deraadt 983: return ioctl(fd, CDIOCPLAYTRACKS, &t);
1.1 downsj 984: }
985:
1.18 deraadt 986: int
987: play_blocks(blk, len)
1.1 downsj 988: int blk;
989: int len;
990: {
991: struct ioc_play_blocks t;
992:
993: t.blk = blk;
994: t.len = len;
995:
1.18 deraadt 996: return ioctl(fd, CDIOCPLAYBLOCKS, &t);
1.1 downsj 997: }
998:
1.18 deraadt 999: int
1000: setvol(left, right)
1.1 downsj 1001: int left;
1002: int right;
1003: {
1004: struct ioc_vol v;
1005:
1006: v.vol[0] = left;
1007: v.vol[1] = right;
1008: v.vol[2] = 0;
1009: v.vol[3] = 0;
1010:
1.18 deraadt 1011: return ioctl(fd, CDIOCSETVOL, &v);
1.1 downsj 1012: }
1013:
1.18 deraadt 1014: int
1015: read_toc_entrys(len)
1.1 downsj 1016: int len;
1017: {
1018: struct ioc_read_toc_entry t;
1.11 csapuntz 1019:
1020: if (toc_buffer) {
1.18 deraadt 1021: free(toc_buffer);
1022: toc_buffer = 0;
1.11 csapuntz 1023: }
1024:
1.18 deraadt 1025: toc_buffer = malloc(len);
1.11 csapuntz 1026:
1027: if (!toc_buffer) {
1.18 deraadt 1028: errno = ENOMEM;
1029: return (-1);
1.11 csapuntz 1030: }
1.1 downsj 1031:
1032: t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1033: t.starting_track = 0;
1034: t.data_len = len;
1035: t.data = toc_buffer;
1036:
1.18 deraadt 1037: return (ioctl(fd, CDIOREADTOCENTRYS, (char *) &t));
1.1 downsj 1038: }
1039:
1.18 deraadt 1040: int
1041: play_msf(start_m, start_s, start_f, end_m, end_s, end_f)
1.1 downsj 1042: int start_m;
1043: int start_s;
1044: int start_f;
1045: int end_m;
1046: int end_s;
1047: int end_f;
1048: {
1.18 deraadt 1049: struct ioc_play_msf a;
1.1 downsj 1050:
1051: a.start_m = start_m;
1052: a.start_s = start_s;
1053: a.start_f = start_f;
1054: a.end_m = end_m;
1055: a.end_s = end_s;
1056: a.end_f = end_f;
1057:
1.18 deraadt 1058: return ioctl(fd, CDIOCPLAYMSF, (char *) &a);
1.1 downsj 1059: }
1060:
1.21 ! espie 1061: int
! 1062: status(trk, min, sec, frame)
1.1 downsj 1063: int *trk;
1064: int *min;
1065: int *sec;
1066: int *frame;
1067: {
1068: struct ioc_read_subchannel s;
1069: struct cd_sub_channel_info data;
1070: u_char mm, ss, ff;
1071:
1.18 deraadt 1072: bzero(&s, sizeof (s));
1.1 downsj 1073: s.data = &data;
1074: s.data_len = sizeof (data);
1075: s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1076: s.data_format = CD_CURRENT_POSITION;
1077:
1.18 deraadt 1078: if (ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0)
1.1 downsj 1079: return -1;
1080:
1081: *trk = s.data->what.position.track_number;
1082: if (msf) {
1083: *min = s.data->what.position.reladdr.msf.minute;
1084: *sec = s.data->what.position.reladdr.msf.second;
1085: *frame = s.data->what.position.reladdr.msf.frame;
1086: } else {
1087: lba2msf(ntohl(s.data->what.position.reladdr.lba),
1.18 deraadt 1088: &mm, &ss, &ff);
1.1 downsj 1089: *min = mm;
1090: *sec = ss;
1091: *frame = ff;
1092: }
1093:
1094: return s.data->header.audio_status;
1095: }
1096:
1.18 deraadt 1097: char *
1098: input(cmd)
1.1 downsj 1099: int *cmd;
1100: {
1101: static char buf[80];
1102: char *p;
1103:
1104: do {
1105: if (verbose)
1.18 deraadt 1106: fprintf(stderr, "%s> ", __progname);
1107: if (!fgets(buf, sizeof (buf), stdin)) {
1.1 downsj 1108: *cmd = CMD_QUIT;
1.18 deraadt 1109: fprintf(stderr, "\r\n");
1.1 downsj 1110: return (0);
1111: }
1.18 deraadt 1112: p = parse(buf, cmd);
1113: } while (!p);
1.1 downsj 1114: return (p);
1115: }
1116:
1.18 deraadt 1117: char *
1118: parse(buf, cmd)
1.1 downsj 1119: char *buf;
1120: int *cmd;
1121: {
1122: struct cmdtab *c;
1123: char *p;
1124: int len;
1125:
1.18 deraadt 1126: for (p=buf; isspace(*p); p++)
1.1 downsj 1127: continue;
1128:
1.18 deraadt 1129: if (isdigit(*p) || (p[0] == '#' && isdigit(p[1]))) {
1.1 downsj 1130: *cmd = CMD_PLAY;
1131: return (p);
1132: }
1133:
1.18 deraadt 1134: for (buf = p; *p && ! isspace(*p); p++)
1.1 downsj 1135: continue;
1136:
1137: len = p - buf;
1138: if (! len)
1139: return (0);
1140:
1.18 deraadt 1141: if (*p) { /* It must be a spacing character! */
1.1 downsj 1142: char *q;
1143:
1144: *p++ = 0;
1145: for (q=p; *q && *q != '\n' && *q != '\r'; q++)
1146: continue;
1147: *q = 0;
1148: }
1149:
1150: *cmd = -1;
1151: for (c=cmdtab; c->name; ++c) {
1152: /* Is it an exact match? */
1.18 deraadt 1153: if (! strcasecmp(buf, c->name)) {
1.1 downsj 1154: *cmd = c->command;
1155: break;
1156: }
1157:
1158: /* Try short hand forms then... */
1.18 deraadt 1159: if (len >= c->min && ! strncasecmp(buf, c->name, len)) {
1.1 downsj 1160: if (*cmd != -1 && *cmd != c->command) {
1.18 deraadt 1161: fprintf(stderr, "Ambiguous command\n");
1.1 downsj 1162: return (0);
1163: }
1164: *cmd = c->command;
1165: }
1166: }
1167:
1168: if (*cmd == -1) {
1.18 deraadt 1169: fprintf(stderr, "%s: Invalid command, enter ``help'' for commands.\n",
1170: __progname);
1.1 downsj 1171: return (0);
1172: }
1173:
1.18 deraadt 1174: while (isspace(*p))
1.1 downsj 1175: p++;
1176: return p;
1177: }
1178:
1.18 deraadt 1179: int
1180: open_cd(dev)
1.9 millert 1181: char *dev;
1.1 downsj 1182: {
1.9 millert 1183: char *realdev;
1.12 millert 1184: int tries;
1.1 downsj 1185:
1186: if (fd > -1)
1187: return (1);
1188:
1.12 millert 1189: for (tries = 0; fd < 0 && tries < 10; tries++) {
1190: fd = opendev(dev, O_RDONLY, OPENDEV_PART, &realdev);
1191: if (fd < 0) {
1192: if (errno == ENXIO) {
1193: /* ENXIO has an overloaded meaning here.
1194: * The original "Device not configured" should
1195: * be interpreted as "No disc in drive %s". */
1.18 deraadt 1196: warnx("No disc in drive %s.", realdev);
1.12 millert 1197: return (0);
1198: } else if (errno != EIO) {
1199: /* EIO may simply mean the device is not ready
1200: * yet which is common with CD changers. */
1.18 deraadt 1201: warn("Can't open %s", realdev);
1.12 millert 1202: return (0);
1203: }
1204: }
1.18 deraadt 1205: sleep(1);
1.12 millert 1206: }
1.1 downsj 1207: if (fd < 0) {
1.18 deraadt 1208: warn("Can't open %s", realdev);
1.9 millert 1209: return (0);
1.1 downsj 1210: }
1211: return (1);
1212: }