Annotation of src/usr.bin/cdio/cdio.c, Revision 1.23
1.23 ! espie 1: /* $OpenBSD: cdio.c,v 1.22 2002/03/21 17:43:48 espie 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.23 ! espie 130: void help(void);
! 131: void usage(void);
! 132: char *strstatus(int);
1.1 downsj 133:
1.18 deraadt 134: void
135: help()
1.1 downsj 136: {
137: struct cmdtab *c;
138: char *s, n;
139: int i;
140:
141: for (c=cmdtab; c->name; ++c) {
142: if (! c->args)
143: continue;
144: printf("\t");
145: for (i = c->min, s = c->name; *s; s++, i--) {
146: if (i > 0)
147: n = toupper(*s);
148: else
149: n = *s;
150: putchar(n);
151: }
152: if (*c->args)
1.18 deraadt 153: printf(" %s", c->args);
154: printf("\n");
1.1 downsj 155: }
1.18 deraadt 156: printf("\n\tThe word \"play\" is not required for the play commands.\n");
157: printf("\tThe plain target address is taken as a synonym for play.\n");
1.1 downsj 158: }
159:
1.18 deraadt 160: void
161: usage()
1.1 downsj 162: {
1.18 deraadt 163: fprintf(stderr, "usage: %s [-sv] [-f device] [command args ...]\n",
164: __progname);
165: exit(1);
1.1 downsj 166: }
167:
1.18 deraadt 168: int
169: main(argc, argv)
1.1 downsj 170: int argc;
171: char **argv;
172: {
173: int cmd;
174: char *arg;
175:
1.18 deraadt 176: cdname = getenv("DISC");
1.1 downsj 177: if (! cdname)
1.18 deraadt 178: cdname = getenv("CDROM");
1.1 downsj 179:
180: for (;;) {
1.18 deraadt 181: switch (getopt(argc, argv, "svf:")) {
1.22 espie 182: case -1:
1.1 downsj 183: break;
184: case 's':
185: verbose = 0;
186: continue;
187: case 'v':
188: verbose = 2;
189: continue;
190: case 'f':
191: cdname = optarg;
192: continue;
193: default:
1.18 deraadt 194: usage();
1.1 downsj 195: }
196: break;
197: }
198: argc -= optind;
199: argv += optind;
200:
1.18 deraadt 201: if (argc > 0 && ! strcasecmp(*argv, "help"))
202: usage();
1.1 downsj 203:
204: if (! cdname) {
205: cdname = DEFAULT_CD_DRIVE;
1.18 deraadt 206: fprintf(stderr,
207: "No CD device name specified. Defaulting to %s.\n", cdname);
1.1 downsj 208: }
209:
210: if (argc > 0) {
211: char buf[80], *p;
212: int len;
213:
214: for (p=buf; argc-->0; ++argv) {
1.18 deraadt 215: len = strlen(*argv);
1.1 downsj 216:
217: if (p + len >= buf + sizeof (buf) - 1)
1.18 deraadt 218: usage();
1.1 downsj 219:
220: if (p > buf)
221: *p++ = ' ';
222:
1.18 deraadt 223: strcpy(p, *argv); /* ok */
1.1 downsj 224: p += len;
225: }
226: *p = 0;
1.18 deraadt 227: arg = parse(buf, &cmd);
228: return (run(cmd, arg));
1.1 downsj 229: }
230:
231: if (verbose == 1)
1.18 deraadt 232: verbose = isatty(0);
1.1 downsj 233:
234: if (verbose) {
1.18 deraadt 235: printf("Compact Disc Control utility, version %s\n", VERSION);
236: printf("Type `?' for command list\n\n");
1.1 downsj 237: }
238:
239: for (;;) {
1.18 deraadt 240: arg = input(&cmd);
241: if (run(cmd, arg) < 0) {
1.1 downsj 242: if (verbose)
1.18 deraadt 243: warn(NULL);
244: close(fd);
1.1 downsj 245: fd = -1;
246: }
1.18 deraadt 247: fflush(stdout);
1.1 downsj 248: }
249: }
250:
1.18 deraadt 251: int
252: run(cmd, arg)
1.1 downsj 253: int cmd;
254: char *arg;
255: {
256: int l, r, rc;
1.9 millert 257: static char newcdname[MAXPATHLEN];
1.1 downsj 258:
259: switch (cmd) {
260:
261: case CMD_QUIT:
1.18 deraadt 262: exit(0);
1.1 downsj 263:
264: case CMD_INFO:
1.18 deraadt 265: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 266: return (0);
267:
1.18 deraadt 268: return info(arg);
1.1 downsj 269:
270: case CMD_STATUS:
1.18 deraadt 271: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 272: return (0);
273:
1.18 deraadt 274: return pstatus(arg);
1.1 downsj 275:
276: case CMD_PAUSE:
1.18 deraadt 277: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 278: return (0);
279:
1.18 deraadt 280: return ioctl(fd, CDIOCPAUSE);
1.1 downsj 281:
282: case CMD_RESUME:
1.18 deraadt 283: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 284: return (0);
285:
1.18 deraadt 286: return ioctl(fd, CDIOCRESUME);
1.1 downsj 287:
288: case CMD_STOP:
1.18 deraadt 289: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 290: return (0);
291:
1.18 deraadt 292: rc = ioctl(fd, CDIOCSTOP);
1.1 downsj 293:
1.18 deraadt 294: (void) ioctl(fd, CDIOCALLOW);
1.1 downsj 295:
296: return (rc);
297:
298: case CMD_RESET:
1.18 deraadt 299: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 300: return (0);
301:
1.18 deraadt 302: rc = ioctl(fd, CDIOCRESET);
1.1 downsj 303: if (rc < 0)
304: return rc;
305: close(fd);
306: fd = -1;
307: return (0);
308:
309: case CMD_DEBUG:
1.18 deraadt 310: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 311: return (0);
312:
1.18 deraadt 313: if (! strcasecmp(arg, "on"))
314: return ioctl(fd, CDIOCSETDEBUG);
1.1 downsj 315:
1.18 deraadt 316: if (! strcasecmp(arg, "off"))
317: return ioctl(fd, CDIOCCLRDEBUG);
1.1 downsj 318:
1.18 deraadt 319: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 320:
321: return (0);
322:
1.9 millert 323: case CMD_DEVICE:
324: /* close old device */
325: if (fd > -1) {
1.18 deraadt 326: (void) ioctl(fd, CDIOCALLOW);
1.9 millert 327: close(fd);
328: fd = -1;
329: }
330:
331: /* open new device */
1.18 deraadt 332: if (!open_cd(arg))
1.9 millert 333: return (0);
1.16 lebel 334: (void) strlcpy(newcdname, arg, sizeof(newcdname));
1.9 millert 335: cdname = newcdname;
336: return (1);
337:
1.1 downsj 338: case CMD_EJECT:
1.18 deraadt 339: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 340: return (0);
341:
1.18 deraadt 342: (void) ioctl(fd, CDIOCALLOW);
343: rc = ioctl(fd, CDIOCEJECT);
1.1 downsj 344: if (rc < 0)
345: return (rc);
346: #if defined(__OpenBSD__)
347: close(fd);
348: fd = -1;
349: #endif
350: return (0);
351:
352: case CMD_CLOSE:
353: #if defined(CDIOCCLOSE)
1.18 deraadt 354: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 355: return (0);
356:
1.18 deraadt 357: (void) ioctl(fd, CDIOCALLOW);
358: rc = ioctl(fd, CDIOCCLOSE);
1.1 downsj 359: if (rc < 0)
360: return (rc);
361: close(fd);
362: fd = -1;
363: return (0);
364: #else
1.18 deraadt 365: printf("%s: Command not yet supported\n", __progname);
1.1 downsj 366: return (0);
367: #endif
368:
369: case CMD_PLAY:
1.18 deraadt 370: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 371: return (0);
372:
1.18 deraadt 373: while (isspace(*arg))
1.1 downsj 374: arg++;
375:
1.18 deraadt 376: return play(arg);
1.1 downsj 377:
378: case CMD_SET:
1.18 deraadt 379: if (!strcasecmp(arg, "msf"))
1.1 downsj 380: msf = 1;
1.18 deraadt 381: else if (!strcasecmp(arg, "lba"))
1.1 downsj 382: msf = 0;
383: else
1.18 deraadt 384: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 385: return (0);
386:
387: case CMD_VOLUME:
1.18 deraadt 388: if (fd < 0 && !open_cd(cdname))
1.1 downsj 389: return (0);
390:
1.18 deraadt 391: if (!strncasecmp(arg, "left", strlen(arg)))
392: return ioctl(fd, CDIOCSETLEFT);
1.1 downsj 393:
1.18 deraadt 394: if (!strncasecmp(arg, "right", strlen(arg)))
395: return ioctl(fd, CDIOCSETRIGHT);
1.1 downsj 396:
1.18 deraadt 397: if (!strncasecmp(arg, "mono", strlen(arg)))
398: return ioctl(fd, CDIOCSETMONO);
1.1 downsj 399:
1.18 deraadt 400: if (!strncasecmp(arg, "stereo", strlen(arg)))
401: return ioctl(fd, CDIOCSETSTEREO);
1.1 downsj 402:
1.18 deraadt 403: if (!strncasecmp(arg, "mute", strlen(arg)))
404: return ioctl(fd, CDIOCSETMUTE);
1.1 downsj 405:
1.18 deraadt 406: if (2 != sscanf(arg, "%d %d", &l, &r)) {
407: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 408: return (0);
409: }
410:
1.18 deraadt 411: return setvol(l, r);
1.1 downsj 412:
1.18 deraadt 413: case CMD_NEXT:
414: if (fd < 0 && ! open_cd(cdname))
415: return (0);
1.5 angelos 416:
1.18 deraadt 417: return play_next(arg);
1.5 angelos 418:
1.18 deraadt 419: case CMD_PREV:
420: if (fd < 0 && ! open_cd(cdname))
421: return (0);
1.5 angelos 422:
1.18 deraadt 423: return play_prev(arg);
1.5 angelos 424:
1.6 angelos 425: case CMD_REPLAY:
1.18 deraadt 426: if (fd < 0 && ! open_cd(cdname))
1.6 angelos 427: return 0;
428:
1.18 deraadt 429: return play_same(arg);
1.1 downsj 430: default:
431: case CMD_HELP:
1.18 deraadt 432: help();
1.1 downsj 433: return (0);
434:
435: }
436: }
437:
1.18 deraadt 438: int
439: play(arg)
1.1 downsj 440: char *arg;
441: {
442: struct ioc_toc_header h;
443: int rc, n, start, end = 0, istart = 1, iend = 1;
444:
1.18 deraadt 445: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 446:
447: if (rc < 0)
448: return (rc);
449:
450: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 451: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 452:
453: if (rc < 0)
454: return (rc);
455:
456: if (! arg || ! *arg) {
457: /* Play the whole disc */
1.18 deraadt 458:
1.10 csapuntz 459: return (play_track(h.starting_track, 1,
1.18 deraadt 460: h.ending_track, 1));
1.1 downsj 461: }
462:
1.18 deraadt 463: if (strchr(arg, '#')) {
1.1 downsj 464: /* Play block #blk [ len ] */
465: int blk, len = 0;
466:
1.18 deraadt 467: if (2 != sscanf(arg, "#%d%d", &blk, &len) &&
468: 1 != sscanf(arg, "#%d", &blk))
1.1 downsj 469: goto Clean_up;
470:
471: if (len == 0) {
472: if (msf)
1.18 deraadt 473: len = msf2lba(toc_buffer[n].addr.msf.minute,
474: toc_buffer[n].addr.msf.second,
475: toc_buffer[n].addr.msf.frame) - blk;
1.1 downsj 476: else
477: len = ntohl(toc_buffer[n].addr.lba) - blk;
478: }
1.18 deraadt 479: return play_blocks(blk, len);
1.1 downsj 480: }
481:
1.18 deraadt 482: if (strchr(arg, ':')) {
1.1 downsj 483: /*
484: * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ]
485: *
486: * Will now also undestand timed addresses relative
487: * to the beginning of a track in the form...
488: *
489: * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]
490: */
491: unsigned tr1, tr2;
492: unsigned m1, m2, s1, s2, f1, f2;
493: unsigned char tm, ts, tf;
494:
495: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 496: if (8 == sscanf(arg, "%d %d:%d.%d %d %d:%d.%d",
1.1 downsj 497: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2))
498: goto Play_Relative_Addresses;
499:
500: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 501: if (7 == sscanf(arg, "%d %d:%d %d %d:%d.%d",
1.1 downsj 502: &tr1, &m1, &s1, &tr2, &m2, &s2, &f2))
503: goto Play_Relative_Addresses;
504:
505: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 506: if (7 == sscanf(arg, "%d %d:%d.%d %d %d:%d",
1.1 downsj 507: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2))
508: goto Play_Relative_Addresses;
509:
510: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 511: if (7 == sscanf(arg, "%d %d:%d.%d %d:%d.%d",
1.1 downsj 512: &tr1, &m1, &s1, &f1, &m2, &s2, &f2))
513: goto Play_Relative_Addresses;
514:
515: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 516: if (6 == sscanf(arg, "%d %d:%d.%d %d:%d",
1.1 downsj 517: &tr1, &m1, &s1, &f1, &m2, &s2))
518: goto Play_Relative_Addresses;
519:
520: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 521: if (6 == sscanf(arg, "%d %d:%d %d:%d.%d",
1.1 downsj 522: &tr1, &m1, &s1, &m2, &s2, &f2))
523: goto Play_Relative_Addresses;
524:
525: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 526: if (6 == sscanf(arg, "%d %d:%d.%d %d %d",
1.1 downsj 527: &tr1, &m1, &s1, &f1, &tr2, &m2))
528: goto Play_Relative_Addresses;
529:
530: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 531: if (5 == sscanf(arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2))
1.1 downsj 532: goto Play_Relative_Addresses;
533:
534: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 535: if (5 == sscanf(arg, "%d %d:%d %d %d",
1.1 downsj 536: &tr1, &m1, &s1, &tr2, &m2))
537: goto Play_Relative_Addresses;
538:
539: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 540: if (5 == sscanf(arg, "%d %d:%d.%d %d",
1.1 downsj 541: &tr1, &m1, &s1, &f1, &tr2))
542: goto Play_Relative_Addresses;
543:
544: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 545: if (4 == sscanf(arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2))
1.1 downsj 546: goto Play_Relative_Addresses;
547:
548: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 549: if (4 == sscanf(arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1))
1.1 downsj 550: goto Play_Relative_Addresses;
551:
552: tr2 = m2 = s2 = f2 = f1 = 0;
1.18 deraadt 553: if (3 == sscanf(arg, "%d %d:%d", &tr1, &m1, &s1))
1.1 downsj 554: goto Play_Relative_Addresses;
555:
556: tr2 = m2 = s2 = f2 = f1 = 0;
557: goto Try_Absolute_Timed_Addresses;
558:
559: Play_Relative_Addresses:
560: if (! tr1)
561: tr1 = 1;
562: else if (tr1 > n)
563: tr1 = n;
564:
565: if (msf) {
566: tm = toc_buffer[tr1].addr.msf.minute;
567: ts = toc_buffer[tr1].addr.msf.second;
568: tf = toc_buffer[tr1].addr.msf.frame;
569: } else
570: lba2msf(ntohl(toc_buffer[tr1].addr.lba),
571: &tm, &ts, &tf);
572: if ((m1 > tm)
573: || ((m1 == tm)
574: && ((s1 > ts)
575: || ((s1 == ts)
576: && (f1 > tf))))) {
1.18 deraadt 577: printf("Track %d is not that long.\n", tr1);
1.1 downsj 578: return (0);
579: }
580:
581: tr1--;
582:
583: f1 += tf;
584: if (f1 >= 75) {
585: s1 += f1 / 75;
586: f1 %= 75;
587: }
588:
589: s1 += ts;
590: if (s1 >= 60) {
591: m1 += s1 / 60;
592: s1 %= 60;
593: }
594:
595: m1 += tm;
596:
597: if (! tr2) {
598: if (m2 || s2 || f2) {
599: tr2 = tr1;
600: f2 += f1;
601: if (f2 >= 75) {
602: s2 += f2 / 75;
603: f2 %= 75;
604: }
605:
606: s2 += s1;
607: if (s2 > 60) {
608: m2 += s2 / 60;
609: s2 %= 60;
610: }
611:
612: m2 += m1;
613: } else {
614: tr2 = n;
615: if (msf) {
616: m2 = toc_buffer[n].addr.msf.minute;
617: s2 = toc_buffer[n].addr.msf.second;
618: f2 = toc_buffer[n].addr.msf.frame;
619: } else {
620: lba2msf(ntohl(toc_buffer[n].addr.lba),
621: &tm, &ts, &tf);
622: m2 = tm;
623: s2 = ts;
624: f2 = tf;
625: }
626: }
627: } else if (tr2 > n) {
628: tr2 = n;
629: m2 = s2 = f2 = 0;
630: } else {
631: if (m2 || s2 || f2)
632: tr2--;
633: if (msf) {
634: tm = toc_buffer[tr2].addr.msf.minute;
635: ts = toc_buffer[tr2].addr.msf.second;
636: tf = toc_buffer[tr2].addr.msf.frame;
637: } else
638: lba2msf(ntohl(toc_buffer[tr2].addr.lba),
639: &tm, &ts, &tf);
640: f2 += tf;
641: if (f2 >= 75) {
642: s2 += f2 / 75;
643: f2 %= 75;
644: }
645:
646: s2 += ts;
647: if (s2 > 60) {
648: m2 += s2 / 60;
649: s2 %= 60;
650: }
651:
652: m2 += tm;
653: }
654:
655: if (msf) {
656: tm = toc_buffer[n].addr.msf.minute;
657: ts = toc_buffer[n].addr.msf.second;
658: tf = toc_buffer[n].addr.msf.frame;
659: } else
660: lba2msf(ntohl(toc_buffer[n].addr.lba),
661: &tm, &ts, &tf);
662: if ((tr2 < n)
663: && ((m2 > tm)
664: || ((m2 == tm)
665: && ((s2 > ts)
666: || ((s2 == ts)
667: && (f2 > tf)))))) {
1.18 deraadt 668: printf("The playing time of the disc is not that long.\n");
1.1 downsj 669: return (0);
670: }
1.18 deraadt 671: return (play_msf(m1, s1, f1, m2, s2, f2));
1.1 downsj 672:
673: Try_Absolute_Timed_Addresses:
1.18 deraadt 674: if (6 != sscanf(arg, "%d:%d.%d%d:%d.%d",
675: &m1, &s1, &f1, &m2, &s2, &f2) &&
676: 5 != sscanf(arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) &&
677: 5 != sscanf(arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) &&
678: 3 != sscanf(arg, "%d:%d.%d", &m1, &s1, &f1) &&
679: 4 != sscanf(arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) &&
680: 2 != sscanf(arg, "%d:%d", &m1, &s1))
1.1 downsj 681: goto Clean_up;
682:
683: if (m2 == 0) {
684: if (msf) {
685: m2 = toc_buffer[n].addr.msf.minute;
686: s2 = toc_buffer[n].addr.msf.second;
687: f2 = toc_buffer[n].addr.msf.frame;
688: } else {
689: lba2msf(ntohl(toc_buffer[n].addr.lba),
690: &tm, &ts, &tf);
691: m2 = tm;
692: s2 = ts;
693: f2 = tf;
694: }
695: }
1.18 deraadt 696: return play_msf(m1, s1, f1, m2, s2, f2);
1.1 downsj 697: }
698:
699: /*
700: * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ]
701: */
1.18 deraadt 702: if (4 != sscanf(arg, "%d.%d%d.%d", &start, &istart, &end, &iend) &&
703: 3 != sscanf(arg, "%d.%d%d", &start, &istart, &end) &&
704: 3 != sscanf(arg, "%d%d.%d", &start, &end, &iend) &&
705: 2 != sscanf(arg, "%d.%d", &start, &istart) &&
706: 2 != sscanf(arg, "%d%d", &start, &end) &&
707: 1 != sscanf(arg, "%d", &start))
1.1 downsj 708: goto Clean_up;
709:
710: if (end == 0)
1.10 csapuntz 711: end = h.ending_track;
1.18 deraadt 712: return (play_track(start, istart, end, iend));
1.1 downsj 713:
714: Clean_up:
1.18 deraadt 715: printf("%s: Invalid command arguments\n", __progname);
1.5 angelos 716: return (0);
717: }
718:
1.18 deraadt 719: int
720: play_prev(arg)
721: char *arg;
1.5 angelos 722: {
1.18 deraadt 723: int trk, min, sec, frm, rc;
724: struct ioc_toc_header h;
1.5 angelos 725:
1.18 deraadt 726: if (status(&trk, &min, &sec, &frm) >= 0) {
727: trk--;
1.5 angelos 728:
1.18 deraadt 729: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
730: if (rc < 0) {
731: warn("getting toc header");
732: return (rc);
733: }
1.5 angelos 734:
1.18 deraadt 735: if (trk < h.starting_track)
736: return play_track(h.starting_track, 1,
737: h.ending_track + 1, 1);
738: return play_track(trk, 1, h.ending_track, 1);
739: }
1.6 angelos 740:
1.18 deraadt 741: return (0);
1.6 angelos 742: }
743:
1.18 deraadt 744: int
745: play_same(arg)
1.6 angelos 746: char *arg;
747: {
1.18 deraadt 748: int trk, min, sec, frm, rc;
749: struct ioc_toc_header h;
1.6 angelos 750:
1.18 deraadt 751: if (status (&trk, &min, &sec, &frm) >= 0) {
752: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
753: if (rc < 0) {
754: warn("getting toc header");
755: return (rc);
756: }
1.5 angelos 757:
1.18 deraadt 758: return play_track(trk, 1, h.ending_track, 1);
759: }
1.5 angelos 760:
1.18 deraadt 761: return (0);
1.5 angelos 762: }
763:
1.18 deraadt 764: int
765: play_next(arg)
1.5 angelos 766: char *arg;
767: {
768: int trk, min, sec, frm, rc;
769: struct ioc_toc_header h;
770:
1.18 deraadt 771: if (status(&trk, &min, &sec, &frm) >= 0) {
1.5 angelos 772: trk++;
1.18 deraadt 773: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
774: if (rc < 0) {
775: warn("getting toc header");
1.5 angelos 776: return (rc);
777: }
778:
1.18 deraadt 779: if (trk > h.ending_track) {
1.5 angelos 780: printf("%s: end of CD\n", __progname);
781:
1.18 deraadt 782: rc = ioctl(fd, CDIOCSTOP);
1.5 angelos 783:
1.18 deraadt 784: (void) ioctl(fd, CDIOCALLOW);
1.5 angelos 785:
786: return (rc);
787: }
788:
1.18 deraadt 789: return play_track(trk, 1, h.ending_track, 1);
1.5 angelos 790: }
791:
1.1 downsj 792: return (0);
793: }
794:
1.18 deraadt 795: char *
796: strstatus(sts)
1.1 downsj 797: int sts;
798: {
799: switch (sts) {
1.18 deraadt 800: case ASTS_INVALID:
801: return ("invalid");
802: case ASTS_PLAYING:
803: return ("playing");
804: case ASTS_PAUSED:
805: return ("paused");
806: case ASTS_COMPLETED:
807: return ("completed");
808: case ASTS_ERROR:
809: return ("error");
810: case ASTS_VOID:
811: return ("void");
812: default:
813: return ("??");
1.1 downsj 814: }
815: }
816:
1.18 deraadt 817: int
818: pstatus(arg)
1.1 downsj 819: char *arg;
820: {
821: struct ioc_vol v;
822: struct ioc_read_subchannel ss;
823: struct cd_sub_channel_info data;
824: int rc, trk, m, s, f;
1.17 espie 825: char vis_catalog[1 + 4 * 15];
1.1 downsj 826:
1.18 deraadt 827: rc = status(&trk, &m, &s, &f);
1.9 millert 828: if (rc >= 0) {
1.1 downsj 829: if (verbose)
1.18 deraadt 830: printf("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n",
831: rc, strstatus(rc), trk, m, s, f);
1.1 downsj 832: else
1.18 deraadt 833: printf("%d %d %d:%02d.%02d\n", rc, trk, m, s, f);
1.9 millert 834: } else
1.18 deraadt 835: printf("No current status info available\n");
1.1 downsj 836:
1.18 deraadt 837: bzero(&ss, sizeof (ss));
1.1 downsj 838: ss.data = &data;
839: ss.data_len = sizeof (data);
840: ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
841: ss.data_format = CD_MEDIA_CATALOG;
1.18 deraadt 842: rc = ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &ss);
1.1 downsj 843: if (rc >= 0) {
844: printf("Media catalog is %sactive",
845: ss.data->what.media_catalog.mc_valid ? "": "in");
846: if (ss.data->what.media_catalog.mc_valid &&
1.17 espie 847: ss.data->what.media_catalog.mc_number[0]) {
848: strvisx(vis_catalog,
849: ss.data->what.media_catalog.mc_number,
850: 15, VIS_SAFE);
851: printf(", number \"%.15s\"", vis_catalog);
852: }
1.1 downsj 853: putchar('\n');
854: } else
855: printf("No media catalog info available\n");
856:
1.18 deraadt 857: rc = ioctl(fd, CDIOCGETVOL, &v);
1.9 millert 858: if (rc >= 0) {
1.1 downsj 859: if (verbose)
1.18 deraadt 860: printf("Left volume = %d, right volume = %d\n",
1.1 downsj 861: v.vol[0], v.vol[1]);
862: else
1.18 deraadt 863: printf("%d %d\n", v.vol[0], v.vol[1]);
1.9 millert 864: } else
1.18 deraadt 865: printf("No volume level info available\n");
1.1 downsj 866: return(0);
867: }
868:
1.18 deraadt 869: int
870: info(arg)
1.1 downsj 871: char *arg;
872: {
873: struct ioc_toc_header h;
874: int rc, i, n;
875:
1.18 deraadt 876: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 877: if (rc >= 0) {
878: if (verbose)
1.18 deraadt 879: printf("Starting track = %d, ending track = %d, TOC size = %d bytes\n",
880: h.starting_track, h.ending_track, h.len);
1.1 downsj 881: else
1.18 deraadt 882: printf("%d %d %d\n", h.starting_track,
883: h.ending_track, h.len);
1.1 downsj 884: } else {
1.18 deraadt 885: warn("getting toc header");
1.1 downsj 886: return (rc);
887: }
888:
889: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 890: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 891: if (rc < 0)
892: return (rc);
893:
894: if (verbose) {
1.18 deraadt 895: printf("track start duration block length type\n");
896: printf("-------------------------------------------------\n");
1.1 downsj 897: }
898:
899: for (i = 0; i < n; i++) {
1.18 deraadt 900: printf("%5d ", toc_buffer[i].track);
901: prtrack(toc_buffer + i, 0);
1.1 downsj 902: }
1.18 deraadt 903: printf("%5d ", toc_buffer[n].track);
904: prtrack(toc_buffer + n, 1);
1.1 downsj 905: return (0);
906: }
907:
1.18 deraadt 908: void
909: lba2msf(lba, m, s, f)
1.1 downsj 910: unsigned long lba;
911: u_char *m;
912: u_char *s;
913: u_char *f;
914: {
1.18 deraadt 915: lba += 150; /* block start offset */
916: lba &= 0xffffff; /* negative lbas use only 24 bits */
1.1 downsj 917: *m = lba / (60 * 75);
918: lba %= (60 * 75);
919: *s = lba / 75;
920: *f = lba % 75;
921: }
922:
1.18 deraadt 923: unsigned int
1.23 ! espie 924: msf2lba(u_char m, u_char s, u_char f)
1.1 downsj 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: }