1*5b133f3fSguenther /* $OpenBSD: cdio.c,v 1.86 2023/03/08 04:43:10 guenther Exp $ */
2de23af84Sjmc
3de23af84Sjmc /* Copyright (c) 1995 Serge V. Vakulenko
4de23af84Sjmc * All rights reserved.
5de23af84Sjmc *
6de23af84Sjmc * Redistribution and use in source and binary forms, with or without
7de23af84Sjmc * modification, are permitted provided that the following conditions
8de23af84Sjmc * are met:
9de23af84Sjmc *
10de23af84Sjmc * 1. Redistributions of source code must retain the above copyright
11de23af84Sjmc * notice, this list of conditions and the following disclaimer.
12de23af84Sjmc * 2. Redistributions in binary form must reproduce the above copyright
13de23af84Sjmc * notice, this list of conditions and the following disclaimer in the
14de23af84Sjmc * documentation and/or other materials provided with the distribution.
15de23af84Sjmc * 3. All advertising materials mentioning features or use of this software
16de23af84Sjmc * must display the following acknowledgement:
17de23af84Sjmc * This product includes software developed by Serge V. Vakulenko.
18de23af84Sjmc * 4. The name of the author may not be used to endorse or promote products
19de23af84Sjmc * derived from this software without specific prior written permission.
20de23af84Sjmc *
21de23af84Sjmc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22de23af84Sjmc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23de23af84Sjmc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24de23af84Sjmc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25de23af84Sjmc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26de23af84Sjmc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27de23af84Sjmc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28de23af84Sjmc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29de23af84Sjmc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30de23af84Sjmc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31de23af84Sjmc */
32de23af84Sjmc
33c92011ceSdownsj /*
34c92011ceSdownsj * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>.
35c92011ceSdownsj * Based on the non-X based CD player by Jean-Marc Zucconi and
36c92011ceSdownsj * Andrey A. Chernov.
37c92011ceSdownsj *
38c92011ceSdownsj * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>.
39c92011ceSdownsj *
40c92011ceSdownsj * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
41c92011ceSdownsj * A couple of further fixes to my own earlier "fixes".
42c92011ceSdownsj *
43c92011ceSdownsj * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
44c92011ceSdownsj * Added an ability to specify addresses relative to the
45c92011ceSdownsj * beginning of a track. This is in fact a variation of
46c92011ceSdownsj * doing the simple play_msf() call.
47c92011ceSdownsj *
48c92011ceSdownsj * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru>
49c92011ceSdownsj * New eject algorithm.
50c92011ceSdownsj * Some code style reformatting.
51c92011ceSdownsj *
52c92011ceSdownsj * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $
53c92011ceSdownsj */
54c92011ceSdownsj
551a0afcdeSderaadt #include <sys/types.h>
56ec6762c7Sfgsch #include <sys/cdio.h>
57ec6762c7Sfgsch #include <sys/ioctl.h>
58cf22b6b5Smjc #include <sys/queue.h>
597993cdedSmjc #include <sys/scsiio.h>
60cf22b6b5Smjc #include <sys/stat.h>
61ec6762c7Sfgsch
62c92011ceSdownsj #include <ctype.h>
63dfcdb41bSespie #include <err.h>
64dfcdb41bSespie #include <errno.h>
65f4147939Sguenther #include <fcntl.h>
66a93de8edSschwarze #include <signal.h>
67c92011ceSdownsj #include <stdio.h>
68c92011ceSdownsj #include <stdlib.h>
69c92011ceSdownsj #include <string.h>
70c92011ceSdownsj #include <unistd.h>
71b9fc9a72Sderaadt #include <limits.h>
72ec6762c7Sfgsch #include <histedit.h>
73c92011ceSdownsj #include <util.h>
74dfcdb41bSespie #include <vis.h>
75c92011ceSdownsj
76ec6762c7Sfgsch #include "extern.h"
77c92011ceSdownsj
78c92011ceSdownsj #define ASTS_INVALID 0x00 /* Audio status byte not valid */
79c92011ceSdownsj #define ASTS_PLAYING 0x11 /* Audio play operation in progress */
80c92011ceSdownsj #define ASTS_PAUSED 0x12 /* Audio play operation paused */
81c92011ceSdownsj #define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */
82c92011ceSdownsj #define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */
83c92011ceSdownsj #define ASTS_VOID 0x15 /* No current audio status to return */
84c92011ceSdownsj
85c92011ceSdownsj #ifndef DEFAULT_CD_DRIVE
8633d336edSderaadt # define DEFAULT_CD_DRIVE "cd0"
87c92011ceSdownsj #endif
88c92011ceSdownsj
89c92011ceSdownsj #define CMD_DEBUG 1
90f87f2499Smillert #define CMD_DEVICE 2
91f87f2499Smillert #define CMD_EJECT 3
92f87f2499Smillert #define CMD_HELP 4
93f87f2499Smillert #define CMD_INFO 5
94f87f2499Smillert #define CMD_PAUSE 6
95f87f2499Smillert #define CMD_PLAY 7
96f87f2499Smillert #define CMD_QUIT 8
97f87f2499Smillert #define CMD_RESUME 9
98f87f2499Smillert #define CMD_STOP 10
99f87f2499Smillert #define CMD_VOLUME 11
100f87f2499Smillert #define CMD_CLOSE 12
101f87f2499Smillert #define CMD_RESET 13
102f87f2499Smillert #define CMD_SET 14
103f87f2499Smillert #define CMD_STATUS 15
104f87f2499Smillert #define CMD_NEXT 16
105f87f2499Smillert #define CMD_PREV 17
106f87f2499Smillert #define CMD_REPLAY 18
1079ed7639aSespie #define CMD_CDDB 19
108ae359c1cSespie #define CMD_CDID 20
1097993cdedSmjc #define CMD_BLANK 21
110a076f0c4Smjc #define CMD_CDRIP 22
111a076f0c4Smjc #define CMD_CDPLAY 23
112c92011ceSdownsj
113c92011ceSdownsj struct cmdtab {
114c92011ceSdownsj int command;
115c92011ceSdownsj char *name;
116a248831fSnaddy int min;
117c92011ceSdownsj char *args;
118c92011ceSdownsj } cmdtab[] = {
119c4c97271Snaddy { CMD_BLANK, "blank", 1, "" },
120c4c97271Snaddy { CMD_CDDB, "cddbinfo", 2, "[n]" },
121c4c97271Snaddy { CMD_CDID, "cdid", 3, "" },
122c4c97271Snaddy { CMD_CDPLAY, "cdplay", 3, "[track1-trackN ...]" },
123c4c97271Snaddy { CMD_CDRIP, "cdrip", 3, "[track1-trackN ...]" },
124c92011ceSdownsj { CMD_CLOSE, "close", 1, "" },
125c934c333Salek { CMD_DEBUG, "debug", 3, "on | off" },
126f87f2499Smillert { CMD_DEVICE, "device", 1, "devname" },
127c92011ceSdownsj { CMD_EJECT, "eject", 1, "" },
128c4c97271Snaddy { CMD_QUIT, "exit", 2, "" },
129c92011ceSdownsj { CMD_HELP, "?", 1, 0 },
130c92011ceSdownsj { CMD_HELP, "help", 1, "" },
131c92011ceSdownsj { CMD_INFO, "info", 1, "" },
1323301428eSangelos { CMD_NEXT, "next", 1, "" },
133c92011ceSdownsj { CMD_PAUSE, "pause", 2, "" },
13474fdbf9dSjmc { CMD_PLAY, "play", 1, "[track1[.index1] [track2[.index2]]]" },
13574fdbf9dSjmc { CMD_PLAY, "play", 1, "[[tr1] m1:s1[.f1] [tr2] [m2:s2[.f2]]]" },
136c92011ceSdownsj { CMD_PLAY, "play", 1, "[#block [len]]" },
1373301428eSangelos { CMD_PREV, "previous", 2, "" },
138c92011ceSdownsj { CMD_QUIT, "quit", 1, "" },
139c4c97271Snaddy { CMD_REPLAY, "replay", 3, "" },
140c92011ceSdownsj { CMD_RESET, "reset", 4, "" },
141c92011ceSdownsj { CMD_RESUME, "resume", 1, "" },
142c4c97271Snaddy { CMD_SET, "set", 2, "lba | msf" },
143c92011ceSdownsj { CMD_STATUS, "status", 1, "" },
144c92011ceSdownsj { CMD_STOP, "stop", 3, "" },
145c4c97271Snaddy { CMD_VOLUME, "volume", 1, "left_channel right_channel" },
146c4c97271Snaddy { CMD_VOLUME, "volume", 1, "left | right | mono | stereo | mute" },
1479ed7639aSespie { 0, 0, 0, 0}
148c92011ceSdownsj };
149c92011ceSdownsj
1503a87bfaeScsapuntz struct cd_toc_entry *toc_buffer;
151c92011ceSdownsj
152c52ec6b0Smortimer struct track_head tracks;
153c52ec6b0Smortimer
154c92011ceSdownsj char *cdname;
155c92011ceSdownsj int fd = -1;
156c7ed6047Sav int writeperm = 0;
157dc4cd921Skrw u_int8_t mediacap[MMC_FEATURE_MAX / NBBY];
158c92011ceSdownsj int verbose = 1;
159c92011ceSdownsj int msf = 1;
1609ed7639aSespie const char *cddb_host;
1619ed7639aSespie char **track_names;
162a93de8edSschwarze volatile sig_atomic_t signo;
163c92011ceSdownsj
164ec6762c7Sfgsch EditLine *el = NULL; /* line-editing structure */
165ec6762c7Sfgsch History *hist = NULL; /* line-editing history */
166ec6762c7Sfgsch void switch_el(void);
167ec6762c7Sfgsch
168c92011ceSdownsj extern char *__progname;
169c92011ceSdownsj
170c72b5b24Smillert int setvol(int, int);
171c72b5b24Smillert int read_toc_entrys(int);
172c72b5b24Smillert int play_msf(int, int, int, int, int, int);
173c72b5b24Smillert int play_track(int, int, int, int);
174c72b5b24Smillert int status(int *, int *, int *, int *);
1757b34dc5fSav int is_wave(int);
1769dfd8015Sav __dead void tao(int argc, char **argv);
177c72b5b24Smillert int play(char *arg);
178c72b5b24Smillert int info(char *arg);
1799ed7639aSespie int cddbinfo(char *arg);
180c72b5b24Smillert int pstatus(char *arg);
181c72b5b24Smillert int play_next(char *arg);
182c72b5b24Smillert int play_prev(char *arg);
183c72b5b24Smillert int play_same(char *arg);
184a93de8edSschwarze void sigint_handler(int);
185c72b5b24Smillert char *input(int *);
186ec6762c7Sfgsch char *prompt(void);
1879ed7639aSespie void prtrack(struct cd_toc_entry *e, int lastflag, char *name);
188f3c3a9c6Smillert void lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f);
189c72b5b24Smillert unsigned int msf2lba(u_char m, u_char s, u_char f);
190c72b5b24Smillert int play_blocks(int blk, int len);
191c72b5b24Smillert int run(int cmd, char *arg);
192c72b5b24Smillert char *parse(char *buf, int *cmd);
193da50f41aSespie void help(void);
194da50f41aSespie void usage(void);
195da50f41aSespie char *strstatus(int);
196ae359c1cSespie int cdid(void);
1978dcc8943Skrw void addmsf(u_int *, u_int *, u_int *, u_char, u_char, u_char);
198b8a783aeSkrw int cmpmsf(u_char, u_char, u_char, u_char, u_char, u_char);
1993438b82bSkrw void toc2msf(u_int, u_char *, u_char *, u_char *);
200c92011ceSdownsj
201f18d0a50Sderaadt void
help(void)2021837a5caSderaadt help(void)
203c92011ceSdownsj {
204c92011ceSdownsj struct cmdtab *c;
205c92011ceSdownsj char *s, n;
206a248831fSnaddy int i;
207c92011ceSdownsj
208c92011ceSdownsj for (c = cmdtab; c->name; ++c) {
209c92011ceSdownsj if (!c->args)
210c92011ceSdownsj continue;
211c92011ceSdownsj printf("\t");
212c92011ceSdownsj for (i = c->min, s = c->name; *s; s++, i--) {
213c92011ceSdownsj if (i > 0)
21420ae3208Sderaadt n = toupper((unsigned char)*s);
215c92011ceSdownsj else
216c92011ceSdownsj n = *s;
217c92011ceSdownsj putchar(n);
218c92011ceSdownsj }
219c92011ceSdownsj if (*c->args)
220c92011ceSdownsj printf(" %s", c->args);
221c92011ceSdownsj printf("\n");
222c92011ceSdownsj }
223c92011ceSdownsj printf("\n\tThe word \"play\" is not required for the play commands.\n");
224c92011ceSdownsj printf("\tThe plain target address is taken as a synonym for play.\n");
225c92011ceSdownsj }
226c92011ceSdownsj
227f18d0a50Sderaadt void
usage(void)2281837a5caSderaadt usage(void)
229c92011ceSdownsj {
230881f6c5fSkn fprintf(stderr, "usage: %s [-sv] [-d host:port] [-f device] "
231881f6c5fSkn "[command [arg ...]]\n",
232f18d0a50Sderaadt __progname);
233c92011ceSdownsj exit(1);
234c92011ceSdownsj }
235c92011ceSdownsj
236f18d0a50Sderaadt int
main(int argc,char ** argv)2379ed7639aSespie main(int argc, char **argv)
238c92011ceSdownsj {
239c283657cSmiod int ch, cmd;
240c92011ceSdownsj char *arg;
241c92011ceSdownsj
242c92011ceSdownsj cdname = getenv("DISC");
243c92011ceSdownsj if (!cdname)
244c92011ceSdownsj cdname = getenv("CDROM");
245c92011ceSdownsj
2469ed7639aSespie cddb_host = getenv("CDDB");
2479ed7639aSespie if (!cddb_host)
248143054faSnaddy cddb_host = "gnudb.gnudb.org";
2499ed7639aSespie
250c283657cSmiod while ((ch = getopt(argc, argv, "svd:f:")) != -1)
251c283657cSmiod switch (ch) {
252c92011ceSdownsj case 's':
253c92011ceSdownsj verbose = 0;
254c283657cSmiod break;
255c92011ceSdownsj case 'v':
256dc4cd921Skrw verbose++;
257c283657cSmiod break;
258c92011ceSdownsj case 'f':
259c92011ceSdownsj cdname = optarg;
260c283657cSmiod break;
2619ed7639aSespie case 'd':
2629ed7639aSespie cddb_host = optarg;
263c283657cSmiod break;
264c92011ceSdownsj default:
265c92011ceSdownsj usage();
266c92011ceSdownsj }
267c283657cSmiod
268c92011ceSdownsj argc -= optind;
269c92011ceSdownsj argv += optind;
270c92011ceSdownsj
271c92011ceSdownsj if (argc > 0 && ! strcasecmp(*argv, "help"))
272c92011ceSdownsj usage();
273c92011ceSdownsj
274c92011ceSdownsj if (!cdname) {
275c92011ceSdownsj cdname = DEFAULT_CD_DRIVE;
276dc4cd921Skrw if (verbose > 1)
277c92011ceSdownsj fprintf(stderr,
27880cdf6b4Sderaadt "No CD device name specified. Defaulting to %s.\n",
27980cdf6b4Sderaadt cdname);
280c92011ceSdownsj }
281c92011ceSdownsj
2827993cdedSmjc if (argc > 0 && !strcasecmp(*argv, "tao")) {
2839dfd8015Sav tao(argc, argv);
2849dfd8015Sav /* NOTREACHED */
2857993cdedSmjc }
286c92011ceSdownsj if (argc > 0) {
287c92011ceSdownsj char buf[80], *p;
288c92011ceSdownsj int len;
289c92011ceSdownsj
290c92011ceSdownsj for (p=buf; argc-->0; ++argv) {
2910144018cSkrw len = snprintf(p, buf + sizeof buf - p,
2920144018cSkrw "%s%s", (p > buf) ? " " : "", *argv);
293c92011ceSdownsj
294515e489cSderaadt if (len < 0 || len >= buf + sizeof buf - p)
2950144018cSkrw errx(1, "argument list too long.");
296c92011ceSdownsj
297c92011ceSdownsj p += len;
298c92011ceSdownsj }
299c92011ceSdownsj arg = parse(buf, &cmd);
300c92011ceSdownsj return (run(cmd, arg));
301c92011ceSdownsj }
302c92011ceSdownsj
303c92011ceSdownsj if (verbose == 1)
304c92011ceSdownsj verbose = isatty(0);
305c92011ceSdownsj
306c92011ceSdownsj if (verbose) {
307c92011ceSdownsj printf("Compact Disc Control utility, version %s\n", VERSION);
308c92011ceSdownsj printf("Type `?' for command list\n\n");
309c92011ceSdownsj }
310c92011ceSdownsj
311ec6762c7Sfgsch switch_el();
312ec6762c7Sfgsch
313c92011ceSdownsj for (;;) {
314c92011ceSdownsj arg = input(&cmd);
315c92011ceSdownsj if (run(cmd, arg) < 0) {
316c92011ceSdownsj if (verbose)
317f87f2499Smillert warn(NULL);
318c92011ceSdownsj close(fd);
319c92011ceSdownsj fd = -1;
320c92011ceSdownsj }
321c92011ceSdownsj fflush(stdout);
322c92011ceSdownsj }
323c92011ceSdownsj }
324c92011ceSdownsj
325f18d0a50Sderaadt int
run(int cmd,char * arg)3269ed7639aSespie run(int cmd, char *arg)
327c92011ceSdownsj {
3287b34dc5fSav int l, r, rc;
329b9fc9a72Sderaadt static char newcdname[PATH_MAX];
330c92011ceSdownsj
331c92011ceSdownsj switch (cmd) {
332c92011ceSdownsj
333c92011ceSdownsj case CMD_QUIT:
334ec6762c7Sfgsch switch_el();
335c92011ceSdownsj exit(0);
336c92011ceSdownsj
337c92011ceSdownsj case CMD_INFO:
338c7ed6047Sav if (!open_cd(cdname, 0))
339c92011ceSdownsj return (0);
340c92011ceSdownsj
341c92011ceSdownsj return info(arg);
342c92011ceSdownsj
3439ed7639aSespie case CMD_CDDB:
344c7ed6047Sav if (!open_cd(cdname, 0))
3459ed7639aSespie return (0);
3469ed7639aSespie
3479ed7639aSespie return cddbinfo(arg);
3489ed7639aSespie
349ae359c1cSespie case CMD_CDID:
350c7ed6047Sav if (!open_cd(cdname, 0))
351ae359c1cSespie return (0);
352ae359c1cSespie return cdid();
353ae359c1cSespie
354c92011ceSdownsj case CMD_STATUS:
355c7ed6047Sav if (!open_cd(cdname, 0))
356c92011ceSdownsj return (0);
357c92011ceSdownsj
358c92011ceSdownsj return pstatus(arg);
359c92011ceSdownsj
360c92011ceSdownsj case CMD_PAUSE:
361c7ed6047Sav if (!open_cd(cdname, 0))
362c92011ceSdownsj return (0);
363c92011ceSdownsj
364c92011ceSdownsj return ioctl(fd, CDIOCPAUSE);
365c92011ceSdownsj
366c92011ceSdownsj case CMD_RESUME:
367c7ed6047Sav if (!open_cd(cdname, 0))
368c92011ceSdownsj return (0);
369c92011ceSdownsj
370c92011ceSdownsj return ioctl(fd, CDIOCRESUME);
371c92011ceSdownsj
372c92011ceSdownsj case CMD_STOP:
373c7ed6047Sav if (!open_cd(cdname, 0))
374c92011ceSdownsj return (0);
375c92011ceSdownsj
376c92011ceSdownsj rc = ioctl(fd, CDIOCSTOP);
377c92011ceSdownsj
378c92011ceSdownsj (void) ioctl(fd, CDIOCALLOW);
379c92011ceSdownsj
380c92011ceSdownsj return (rc);
381c92011ceSdownsj
382c92011ceSdownsj case CMD_RESET:
383c7ed6047Sav if (!open_cd(cdname, 0))
384c92011ceSdownsj return (0);
385c92011ceSdownsj
386c92011ceSdownsj rc = ioctl(fd, CDIOCRESET);
3873aaa63ebSderaadt if (rc == -1)
388c92011ceSdownsj return rc;
389c92011ceSdownsj close(fd);
390c92011ceSdownsj fd = -1;
391c92011ceSdownsj return (0);
392c92011ceSdownsj
393c92011ceSdownsj case CMD_DEBUG:
394c7ed6047Sav if (!open_cd(cdname, 0))
395c92011ceSdownsj return (0);
396c92011ceSdownsj
397c92011ceSdownsj if (!strcasecmp(arg, "on"))
398c92011ceSdownsj return ioctl(fd, CDIOCSETDEBUG);
399c92011ceSdownsj
400c92011ceSdownsj if (!strcasecmp(arg, "off"))
401c92011ceSdownsj return ioctl(fd, CDIOCCLRDEBUG);
402c92011ceSdownsj
403c92011ceSdownsj printf("%s: Invalid command arguments\n", __progname);
404c92011ceSdownsj
405c92011ceSdownsj return (0);
406c92011ceSdownsj
407f87f2499Smillert case CMD_DEVICE:
408f87f2499Smillert /* close old device */
409f87f2499Smillert if (fd > -1) {
410f87f2499Smillert (void) ioctl(fd, CDIOCALLOW);
411f87f2499Smillert close(fd);
412f87f2499Smillert fd = -1;
413f87f2499Smillert }
414f87f2499Smillert
415d8a9cdc1Salek if (strlen(arg) == 0) {
416d8a9cdc1Salek printf("%s: Invalid parameter\n", __progname);
417d8a9cdc1Salek return (0);
418d8a9cdc1Salek }
419d8a9cdc1Salek
420f87f2499Smillert /* open new device */
4217993cdedSmjc if (!open_cd(arg, 0))
422f87f2499Smillert return (0);
4233cbec610Slebel (void) strlcpy(newcdname, arg, sizeof(newcdname));
424f87f2499Smillert cdname = newcdname;
425f87f2499Smillert return (1);
426f87f2499Smillert
427c92011ceSdownsj case CMD_EJECT:
428c7ed6047Sav if (!open_cd(cdname, 0))
429c92011ceSdownsj return (0);
430c92011ceSdownsj
431c92011ceSdownsj (void) ioctl(fd, CDIOCALLOW);
432c92011ceSdownsj rc = ioctl(fd, CDIOCEJECT);
4333aaa63ebSderaadt if (rc == -1)
434c92011ceSdownsj return (rc);
435c92011ceSdownsj close(fd);
436c92011ceSdownsj fd = -1;
4379ed7639aSespie if (track_names)
4389ed7639aSespie free_names(track_names);
4399ed7639aSespie track_names = NULL;
440c92011ceSdownsj return (0);
441c92011ceSdownsj
442c92011ceSdownsj case CMD_CLOSE:
443c7ed6047Sav if (!open_cd(cdname, 0))
444c92011ceSdownsj return (0);
445c92011ceSdownsj
446c92011ceSdownsj (void) ioctl(fd, CDIOCALLOW);
447c92011ceSdownsj rc = ioctl(fd, CDIOCCLOSE);
4483aaa63ebSderaadt if (rc == -1)
449c92011ceSdownsj return (rc);
450c92011ceSdownsj close(fd);
451c92011ceSdownsj fd = -1;
452c92011ceSdownsj return (0);
453c92011ceSdownsj
454c92011ceSdownsj case CMD_PLAY:
455c7ed6047Sav if (!open_cd(cdname, 0))
456c92011ceSdownsj return (0);
457c92011ceSdownsj
45820ae3208Sderaadt while (isspace((unsigned char)*arg))
459c92011ceSdownsj arg++;
460c92011ceSdownsj
461c92011ceSdownsj return play(arg);
462c92011ceSdownsj
463c92011ceSdownsj case CMD_SET:
464c92011ceSdownsj if (!strcasecmp(arg, "msf"))
465c92011ceSdownsj msf = 1;
466c92011ceSdownsj else if (!strcasecmp(arg, "lba"))
467c92011ceSdownsj msf = 0;
468c92011ceSdownsj else
469c92011ceSdownsj printf("%s: Invalid command arguments\n", __progname);
470c92011ceSdownsj return (0);
471c92011ceSdownsj
472c92011ceSdownsj case CMD_VOLUME:
473c7ed6047Sav if (!open_cd(cdname, 0))
474c92011ceSdownsj return (0);
475c92011ceSdownsj
476c92011ceSdownsj if (!strncasecmp(arg, "left", strlen(arg)))
477c92011ceSdownsj return ioctl(fd, CDIOCSETLEFT);
478c92011ceSdownsj
479c92011ceSdownsj if (!strncasecmp(arg, "right", strlen(arg)))
480c92011ceSdownsj return ioctl(fd, CDIOCSETRIGHT);
481c92011ceSdownsj
482c92011ceSdownsj if (!strncasecmp(arg, "mono", strlen(arg)))
483c92011ceSdownsj return ioctl(fd, CDIOCSETMONO);
484c92011ceSdownsj
485c92011ceSdownsj if (!strncasecmp(arg, "stereo", strlen(arg)))
486ac9e9f6dSdownsj return ioctl(fd, CDIOCSETSTEREO);
487c92011ceSdownsj
488c92011ceSdownsj if (!strncasecmp(arg, "mute", strlen(arg)))
489c92011ceSdownsj return ioctl(fd, CDIOCSETMUTE);
490c92011ceSdownsj
491c92011ceSdownsj if (2 != sscanf(arg, "%d%d", &l, &r)) {
492c92011ceSdownsj printf("%s: Invalid command arguments\n", __progname);
493c92011ceSdownsj return (0);
494c92011ceSdownsj }
495c92011ceSdownsj
496c92011ceSdownsj return setvol(l, r);
497c92011ceSdownsj
4983301428eSangelos case CMD_NEXT:
499c7ed6047Sav if (!open_cd(cdname, 0))
5003301428eSangelos return (0);
5013301428eSangelos
5023301428eSangelos return play_next(arg);
5033301428eSangelos
5043301428eSangelos case CMD_PREV:
505c7ed6047Sav if (!open_cd(cdname, 0))
5063301428eSangelos return (0);
5073301428eSangelos
5083301428eSangelos return play_prev(arg);
5093301428eSangelos
5104efcb1a6Sangelos case CMD_REPLAY:
511c7ed6047Sav if (!open_cd(cdname, 0))
5124efcb1a6Sangelos return 0;
5134efcb1a6Sangelos
5144efcb1a6Sangelos return play_same(arg);
5157993cdedSmjc case CMD_BLANK:
516c7ed6047Sav if (!open_cd(cdname, 1))
5177993cdedSmjc return 0;
5187993cdedSmjc
5197299f7a2Sfgsch if (get_media_capabilities(mediacap, 1) == -1) {
5205c0dfce9Sav warnx("Can't determine media type");
5215c0dfce9Sav return (0);
5225c0dfce9Sav }
5231a0afcdeSderaadt if (cdio_isset(mediacap, MMC_FEATURE_CDRW_WRITE) == 0 &&
524f560e737Sav get_media_type() != MEDIATYPE_CDRW) {
5255c0dfce9Sav warnx("The media doesn't support blanking");
5265c0dfce9Sav return (0);
5275c0dfce9Sav }
5285c0dfce9Sav
5297993cdedSmjc return blank();
530a076f0c4Smjc case CMD_CDRIP:
531c7ed6047Sav if (!open_cd(cdname, 0))
532a076f0c4Smjc return (0);
533a076f0c4Smjc
53420ae3208Sderaadt while (isspace((unsigned char)*arg))
535a076f0c4Smjc arg++;
536a076f0c4Smjc
537a076f0c4Smjc return cdrip(arg);
538a076f0c4Smjc case CMD_CDPLAY:
539c7ed6047Sav if (!open_cd(cdname, 0))
540a076f0c4Smjc return (0);
541a076f0c4Smjc
54220ae3208Sderaadt while (isspace((unsigned char)*arg))
543a076f0c4Smjc arg++;
544a076f0c4Smjc
545a076f0c4Smjc return cdplay(arg);
546c92011ceSdownsj default:
547c92011ceSdownsj case CMD_HELP:
548c92011ceSdownsj help();
549c92011ceSdownsj return (0);
550c92011ceSdownsj
551c92011ceSdownsj }
552c92011ceSdownsj }
553c92011ceSdownsj
554f7dfecd4Sav /*
555f7dfecd4Sav * Check if audio file has RIFF WAVE format. If not, we assume it's just PCM.
556f7dfecd4Sav */
557f7dfecd4Sav int
is_wave(int fd)558f7dfecd4Sav is_wave(int fd)
559f7dfecd4Sav {
560f7dfecd4Sav char buf[WAVHDRLEN];
561f7dfecd4Sav int rv;
562f7dfecd4Sav
563f7dfecd4Sav rv = 0;
564f7dfecd4Sav if (read(fd, buf, sizeof(buf)) == sizeof(buf)) {
565f7dfecd4Sav if (memcmp(buf, "RIFF", 4) == 0 &&
566f7dfecd4Sav memcmp(buf + 8, "WAVE", 4) == 0)
567f7dfecd4Sav rv = 1;
568f7dfecd4Sav }
569f7dfecd4Sav
570f7dfecd4Sav return (rv);
571f7dfecd4Sav }
572f7dfecd4Sav
5739dfd8015Sav __dead void
tao(int argc,char ** argv)5749dfd8015Sav tao(int argc, char **argv)
5759dfd8015Sav {
5769dfd8015Sav struct stat sb;
5779dfd8015Sav struct track_info *cur_track;
5789dfd8015Sav struct track_info *tr;
5799dfd8015Sav off_t availblk, needblk = 0;
5809dfd8015Sav u_int blklen;
5819dfd8015Sav u_int ntracks = 0;
5829dfd8015Sav char type;
5837b34dc5fSav int ch, speed;
5847b34dc5fSav const char *errstr;
5859dfd8015Sav
5869dfd8015Sav if (argc == 1)
5879dfd8015Sav usage();
5889dfd8015Sav
5899dfd8015Sav SLIST_INIT(&tracks);
5909dfd8015Sav type = 'd';
5917b34dc5fSav speed = DRIVE_SPEED_OPTIMAL;
5929dfd8015Sav blklen = 2048;
5939dfd8015Sav while (argc > 1) {
5949dfd8015Sav tr = malloc(sizeof(struct track_info));
5959dfd8015Sav if (tr == NULL)
5969dfd8015Sav err(1, "tao");
5979dfd8015Sav
5989dfd8015Sav optreset = 1;
5999dfd8015Sav optind = 1;
6007b34dc5fSav while ((ch = getopt(argc, argv, "ads:")) != -1) {
6019dfd8015Sav switch (ch) {
6029dfd8015Sav case 'a':
6039dfd8015Sav type = 'a';
6049dfd8015Sav blklen = 2352;
6059dfd8015Sav break;
6069dfd8015Sav case 'd':
6079dfd8015Sav type = 'd';
6089dfd8015Sav blklen = 2048;
6099dfd8015Sav break;
6107b34dc5fSav case 's':
6117b34dc5fSav if (strcmp(optarg, "auto") == 0) {
6127b34dc5fSav speed = DRIVE_SPEED_OPTIMAL;
6137b34dc5fSav } else if (strcmp(optarg, "max") == 0) {
6147b34dc5fSav speed = DRIVE_SPEED_MAX;
6157b34dc5fSav } else {
6167b34dc5fSav speed = (int)strtonum(optarg, 1,
6177b34dc5fSav CD_MAX_SPEED, &errstr);
6187b34dc5fSav if (errstr != NULL) {
6197b34dc5fSav errx(1,
6207b34dc5fSav "incorrect speed value");
6217b34dc5fSav }
6227b34dc5fSav }
6237b34dc5fSav break;
6249dfd8015Sav default:
6259dfd8015Sav usage();
6269dfd8015Sav /* NOTREACHED */
6279dfd8015Sav }
6289dfd8015Sav }
6299dfd8015Sav
6307b34dc5fSav if (speed != DRIVE_SPEED_OPTIMAL && speed != DRIVE_SPEED_MAX)
6317b34dc5fSav tr->speed = CD_SPEED_TO_KBPS(speed, blklen);
6327b34dc5fSav else
6337b34dc5fSav tr->speed = speed;
6347b34dc5fSav
6359dfd8015Sav tr->type = type;
6369dfd8015Sav tr->blklen = blklen;
6379dfd8015Sav argc -= optind;
6389dfd8015Sav argv += optind;
6399dfd8015Sav if (argv[0] == NULL)
6409dfd8015Sav usage();
6419dfd8015Sav tr->file = argv[0];
642b7041c07Sderaadt tr->fd = open(tr->file, O_RDONLY);
6439dfd8015Sav if (tr->fd == -1)
6449dfd8015Sav err(1, "cannot open file %s", tr->file);
6459dfd8015Sav if (fstat(tr->fd, &sb) == -1)
6469dfd8015Sav err(1, "cannot stat file %s", tr->file);
6479dfd8015Sav tr->sz = sb.st_size;
648f7dfecd4Sav tr->off = 0;
649f7dfecd4Sav if (tr->type == 'a') {
650f7dfecd4Sav if (is_wave(tr->fd)) {
6519dfd8015Sav tr->sz -= WAVHDRLEN;
652f7dfecd4Sav tr->off = WAVHDRLEN;
653f7dfecd4Sav }
654f7dfecd4Sav }
6559dfd8015Sav if (SLIST_EMPTY(&tracks))
6569dfd8015Sav SLIST_INSERT_HEAD(&tracks, tr, track_list);
6579dfd8015Sav else
6589dfd8015Sav SLIST_INSERT_AFTER(cur_track, tr, track_list);
6599dfd8015Sav cur_track = tr;
6609dfd8015Sav }
6619dfd8015Sav
6629dfd8015Sav if (!open_cd(cdname, 1))
6639dfd8015Sav exit(1);
6647299f7a2Sfgsch if (get_media_capabilities(mediacap, 1) == -1)
6659dfd8015Sav errx(1, "Can't determine media type");
6661a0afcdeSderaadt if (cdio_isset(mediacap, MMC_FEATURE_CD_TAO) == 0)
6679dfd8015Sav errx(1, "The media can't be written in TAO mode");
6689dfd8015Sav
6699dfd8015Sav get_disc_size(&availblk);
6709dfd8015Sav SLIST_FOREACH(tr, &tracks, track_list) {
6719dfd8015Sav needblk += tr->sz/tr->blklen;
6729dfd8015Sav ntracks++;
6739dfd8015Sav }
6749dfd8015Sav needblk += (ntracks - 1) * 150; /* transition area between tracks */
6759dfd8015Sav if (needblk > availblk)
6769dfd8015Sav errx(1, "Only %llu of the required %llu blocks available",
6779dfd8015Sav availblk, needblk);
6789dfd8015Sav if (writetao(&tracks) != 0)
6799dfd8015Sav exit(1);
6809dfd8015Sav else
6819dfd8015Sav exit(0);
6829dfd8015Sav }
6839dfd8015Sav
684f18d0a50Sderaadt int
play(char * arg)6859ed7639aSespie play(char *arg)
686c92011ceSdownsj {
687c92011ceSdownsj struct ioc_toc_header h;
6888bdf91ceSkrw unsigned char tm, ts, tf;
6898bdf91ceSkrw unsigned int tr1, tr2, m1, m2, s1, s2, f1, f2, i1, i2;
6908bdf91ceSkrw unsigned int blk, len, n;
6918bdf91ceSkrw char c;
6928bdf91ceSkrw int rc;
693c92011ceSdownsj
694c92011ceSdownsj rc = ioctl(fd, CDIOREADTOCHEADER, &h);
695c92011ceSdownsj
6963aaa63ebSderaadt if (rc == -1)
697c92011ceSdownsj return (rc);
698c92011ceSdownsj
6998bdf91ceSkrw if (h.starting_track > h.ending_track) {
7008bdf91ceSkrw printf("TOC starting_track > TOC ending_track\n");
7018bdf91ceSkrw return (0);
7028bdf91ceSkrw }
7038bdf91ceSkrw
704c92011ceSdownsj n = h.ending_track - h.starting_track + 1;
705c92011ceSdownsj rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
706c92011ceSdownsj
707c92011ceSdownsj if (rc < 0)
708c92011ceSdownsj return (rc);
709c92011ceSdownsj
7108bdf91ceSkrw /*
7118bdf91ceSkrw * Truncate trailing white space. Then by adding %c to the end of the
7128bdf91ceSkrw * sscanf() formats we catch any errant trailing characters.
7138bdf91ceSkrw */
7148bdf91ceSkrw rc = strlen(arg) - 1;
71520ae3208Sderaadt while (rc >= 0 && isspace((unsigned char)arg[rc])) {
7168bdf91ceSkrw arg[rc] = '\0';
7178bdf91ceSkrw rc--;
7188bdf91ceSkrw }
7198bdf91ceSkrw
720c92011ceSdownsj if (!arg || ! *arg) {
721c92011ceSdownsj /* Play the whole disc */
7228bdf91ceSkrw return (play_track(h.starting_track, 1, h.ending_track, 1));
723c92011ceSdownsj }
724c92011ceSdownsj
725c92011ceSdownsj if (strchr(arg, '#')) {
726c92011ceSdownsj /* Play block #blk [ len ] */
7278bdf91ceSkrw if (2 != sscanf(arg, "#%u%u%c", &blk, &len, &c) &&
7288bdf91ceSkrw 1 != sscanf(arg, "#%u%c", &blk, &c)) {
7298bdf91ceSkrw printf("%s: Invalid command arguments\n", __progname);
7308bdf91ceSkrw return (0);
7318bdf91ceSkrw }
732c92011ceSdownsj
733c92011ceSdownsj if (len == 0) {
734c92011ceSdownsj if (msf)
735c92011ceSdownsj len = msf2lba(toc_buffer[n].addr.msf.minute,
736c92011ceSdownsj toc_buffer[n].addr.msf.second,
737c92011ceSdownsj toc_buffer[n].addr.msf.frame) - blk;
738c92011ceSdownsj else
73943844f6cSkrw len = toc_buffer[n].addr.lba - blk;
740c92011ceSdownsj }
741c92011ceSdownsj return play_blocks(blk, len);
742c92011ceSdownsj }
743c92011ceSdownsj
7448bdf91ceSkrw if (strchr(arg, ':') == NULL) {
745c92011ceSdownsj /*
7468bdf91ceSkrw * Play track tr1[.i1] [tr2[.i2]]
747c92011ceSdownsj */
7488bdf91ceSkrw if (4 == sscanf(arg, "%u.%u%u.%u%c", &tr1, &i1, &tr2, &i2, &c))
7498bdf91ceSkrw goto play_track;
750c92011ceSdownsj
7518bdf91ceSkrw i2 = 1;
7528bdf91ceSkrw if (3 == sscanf(arg, "%u.%u%u%c", &tr1, &i1, &tr2, &c))
7538bdf91ceSkrw goto play_track;
754c92011ceSdownsj
7558bdf91ceSkrw i1 = 1;
7568bdf91ceSkrw if (3 == sscanf(arg, "%u%u.%u%c", &tr1, &tr2, &i2, &c))
7578bdf91ceSkrw goto play_track;
758c92011ceSdownsj
7598bdf91ceSkrw tr2 = 0;
7608bdf91ceSkrw i2 = 1;
7618bdf91ceSkrw if (2 == sscanf(arg, "%u.%u%c", &tr1, &i1, &c))
7628bdf91ceSkrw goto play_track;
763c92011ceSdownsj
7648bdf91ceSkrw i1 = i2 = 1;
7658bdf91ceSkrw if (2 == sscanf(arg, "%u%u%c", &tr1, &tr2, &c))
7668bdf91ceSkrw goto play_track;
767c92011ceSdownsj
7688bdf91ceSkrw i1 = i2 = 1;
7698bdf91ceSkrw tr2 = 0;
7708bdf91ceSkrw if (1 == sscanf(arg, "%u%c", &tr1, &c))
7718bdf91ceSkrw goto play_track;
772c92011ceSdownsj
7738bdf91ceSkrw printf("%s: Invalid command arguments\n", __progname);
7747a498d98Skrw return (0);
7758bdf91ceSkrw
7768bdf91ceSkrw play_track:
7778bdf91ceSkrw if (tr1 > n || tr2 > n) {
7788bdf91ceSkrw printf("Track number must be between 0 and %u\n", n);
7798bdf91ceSkrw return (0);
7808bdf91ceSkrw } else if (tr2 == 0)
7818bdf91ceSkrw tr2 = h.ending_track;
7828bdf91ceSkrw
7838bdf91ceSkrw if (tr1 > tr2) {
7848bdf91ceSkrw printf("starting_track > ending_track\n");
7857a498d98Skrw return (0);
7867a498d98Skrw }
787c92011ceSdownsj
7888bdf91ceSkrw return (play_track(tr1, i1, tr2, i2));
7898bdf91ceSkrw }
7908bdf91ceSkrw
7918bdf91ceSkrw /*
7928bdf91ceSkrw * Play MSF [tr1] m1:s1[.f1] [tr2] [m2:s2[.f2]]
7938bdf91ceSkrw *
7948bdf91ceSkrw * Start Time End Time
7958bdf91ceSkrw * ---------- --------
7968bdf91ceSkrw * tr1 m1:s1.f1 tr2 m2:s2.f2
7978bdf91ceSkrw * tr1 m1:s1 tr2 m2:s2.f2
7988bdf91ceSkrw * tr1 m1:s1.f1 tr2 m2:s2
7998bdf91ceSkrw * tr1 m1:s1 tr2 m2:s2
8008bdf91ceSkrw * m1:s1.f1 tr2 m2:s2.f2
8018bdf91ceSkrw * m1:s1 tr2 m2:s2.f2
8028bdf91ceSkrw * m1:s1.f1 tr2 m2:s2
8038bdf91ceSkrw * m1:s1 tr2 m2:s2
8048bdf91ceSkrw * tr1 m1:s1.f1 m2:s2.f2
8058bdf91ceSkrw * tr1 m1:s1 m2:s2.f2
8068bdf91ceSkrw * tr1 m1:s1.f1 m2:s2
8078bdf91ceSkrw * tr1 m1:s1 m2:s2
8088bdf91ceSkrw * m1:s1.f1 m2:s2.f2
8098bdf91ceSkrw * m1:s1 m2:s2.f2
8108bdf91ceSkrw * m1:s1.f1 m2:s2
8118bdf91ceSkrw * m1:s1 m2:s2
8128bdf91ceSkrw * tr1 m1:s1.f1 tr2
8138bdf91ceSkrw * tr1 m1:s1 tr2
8148bdf91ceSkrw * m1:s1.f1 tr2
8158bdf91ceSkrw * m1:s1 tr2
8168bdf91ceSkrw * tr1 m1:s1.f1 <end of disc>
8178bdf91ceSkrw * tr1 m1:s1 <end of disc>
8188bdf91ceSkrw * m1:s1.f1 <end of disc>
8198bdf91ceSkrw * m1:s1 <end of disc>
8208bdf91ceSkrw */
8218bdf91ceSkrw
8228bdf91ceSkrw /* tr1 m1:s1.f1 tr2 m2:s2.f2 */
8238bdf91ceSkrw if (8 == sscanf(arg, "%u%u:%u.%u%u%u:%u.%u%c",
8248bdf91ceSkrw &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2, &c))
8258bdf91ceSkrw goto play_msf;
8268bdf91ceSkrw
8278bdf91ceSkrw /* tr1 m1:s1 tr2 m2:s2.f2 */
8288bdf91ceSkrw f1 = 0;
8298bdf91ceSkrw if (7 == sscanf(arg, "%u%u:%u%u%u:%u.%u%c",
8308bdf91ceSkrw &tr1, &m1, &s1, &tr2, &m2, &s2, &f2, &c))
8318bdf91ceSkrw goto play_msf;
8328bdf91ceSkrw
8338bdf91ceSkrw /* tr1 m1:s1.f1 tr2 m2:s2 */
8348bdf91ceSkrw f2 =0;
8358bdf91ceSkrw if (7 == sscanf(arg, "%u%u:%u.%u%u%u:%u%c",
8368bdf91ceSkrw &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &c))
8378bdf91ceSkrw goto play_msf;
8388bdf91ceSkrw
8398bdf91ceSkrw /* m1:s1.f1 tr2 m2:s2.f2 */
8408bdf91ceSkrw tr1 = 0;
8418bdf91ceSkrw if (7 == sscanf(arg, "%u:%u.%u%u%u:%u.%u%c",
8428bdf91ceSkrw &m1, &s1, &f1, &tr2, &m2, &s2, &f2, &c))
8438bdf91ceSkrw goto play_msf;
8448bdf91ceSkrw
8458bdf91ceSkrw /* tr1 m1:s1.f1 m2:s2.f2 */
8468bdf91ceSkrw tr2 = 0;
8478bdf91ceSkrw if (7 == sscanf(arg, "%u%u:%u.%u%u:%u.%u%c",
8488bdf91ceSkrw &tr1, &m1, &s1, &f1, &m2, &s2, &f2, &c))
8498bdf91ceSkrw goto play_msf;
8508bdf91ceSkrw
8518bdf91ceSkrw /* m1:s1 tr2 m2:s2.f2 */
8528bdf91ceSkrw tr1 = f1 = 0;
8538bdf91ceSkrw if (6 == sscanf(arg, "%u:%u%u%u:%u.%u%c",
8548bdf91ceSkrw &m1, &s1, &tr2, &m2, &s2, &f2, &c))
8558bdf91ceSkrw goto play_msf;
8568bdf91ceSkrw
8578bdf91ceSkrw /* m1:s1.f1 tr2 m2:s2 */
8588bdf91ceSkrw tr1 = f2 = 0;
8598bdf91ceSkrw if (6 == sscanf(arg, "%u:%u.%u%u%u:%u%c",
8608bdf91ceSkrw &m1, &s1, &f1, &tr2, &m2, &s2, &c))
8618bdf91ceSkrw goto play_msf;
8628bdf91ceSkrw
8638bdf91ceSkrw /* m1:s1.f1 m2:s2.f2 */
8648bdf91ceSkrw tr1 = tr2 = 0;
8658bdf91ceSkrw if (6 == sscanf(arg, "%u:%u.%u%u:%u.%u%c",
8668bdf91ceSkrw &m1, &s1, &f1, &m2, &s2, &f2, &c))
8678bdf91ceSkrw goto play_msf;
8688bdf91ceSkrw
8698bdf91ceSkrw /* tr1 m1:s1.f1 m2:s2 */
8708bdf91ceSkrw tr2 = f2 = 0;
8718bdf91ceSkrw if (6 == sscanf(arg, "%u%u:%u.%u%u:%u%c",
8728bdf91ceSkrw &tr1, &m1, &s1, &f1, &m2, &s2, &c))
8738bdf91ceSkrw goto play_msf;
8748bdf91ceSkrw
8758bdf91ceSkrw /* tr1 m1:s1 m2:s2.f2 */
8768bdf91ceSkrw tr2 = f1 = 0;
8778bdf91ceSkrw if (6 == sscanf(arg, "%u%u:%u%u:%u.%u%c",
8788bdf91ceSkrw &tr1, &m1, &s1, &m2, &s2, &f2, &c))
8798bdf91ceSkrw goto play_msf;
8808bdf91ceSkrw
8818bdf91ceSkrw /* tr1 m1:s1 tr2 m2:s2 */
8828bdf91ceSkrw f1 = f2 = 0;
8838bdf91ceSkrw if (6 == sscanf(arg, "%u%u:%u%u%u:%u%c",
8848bdf91ceSkrw &tr1, &m1, &s1, &tr2, &m2, &s2, &c))
8858bdf91ceSkrw goto play_msf;
8868bdf91ceSkrw
8878bdf91ceSkrw /* m1:s1 tr2 m2:s2 */
8888bdf91ceSkrw tr1 = f1 = f2 = 0;
8898bdf91ceSkrw if (5 == sscanf(arg, "%u:%u%u%u:%u%c", &m1, &s1, &tr2, &m2, &s2, &c))
8908bdf91ceSkrw goto play_msf;
8918bdf91ceSkrw
8928bdf91ceSkrw /* tr1 m1:s1 m2:s2 */
8938bdf91ceSkrw f1 = tr2 = f2 = 0;
8948bdf91ceSkrw if (5 == sscanf(arg, "%u%u:%u%u:%u%c", &tr1, &m1, &s1, &m2, &s2, &c))
8958bdf91ceSkrw goto play_msf;
8968bdf91ceSkrw
8978bdf91ceSkrw /* m1:s1 m2:s2.f2 */
8988bdf91ceSkrw tr1 = f1 = tr2 = 0;
8998bdf91ceSkrw if (5 == sscanf(arg, "%u:%u%u:%u.%u%c", &m1, &s1, &m2, &s2, &f2, &c))
9008bdf91ceSkrw goto play_msf;
9018bdf91ceSkrw
9028bdf91ceSkrw /* m1:s1.f1 m2:s2 */
9038bdf91ceSkrw tr1 = tr2 = f2 = 0;
9048bdf91ceSkrw if (5 == sscanf(arg, "%u:%u.%u%u:%u%c", &m1, &s1, &f1, &m2, &s2, &c))
9058bdf91ceSkrw goto play_msf;
9068bdf91ceSkrw
9078bdf91ceSkrw /* tr1 m1:s1.f1 tr2 */
9088bdf91ceSkrw m2 = s2 = f2 = 0;
9098bdf91ceSkrw if (5 == sscanf(arg, "%u%u:%u.%u%u%c", &tr1, &m1, &s1, &f1, &tr2, &c))
9108bdf91ceSkrw goto play_msf;
9118bdf91ceSkrw
9128bdf91ceSkrw /* m1:s1 m2:s2 */
9138bdf91ceSkrw tr1 = f1 = tr2 = f2 = 0;
9148bdf91ceSkrw if (4 == sscanf(arg, "%u:%u%u:%u%c", &m1, &s1, &m2, &s2, &c))
9158bdf91ceSkrw goto play_msf;
9168bdf91ceSkrw
9178bdf91ceSkrw /* tr1 m1:s1.f1 <end of disc> */
9188bdf91ceSkrw tr2 = m2 = s2 = f2 = 0;
9198bdf91ceSkrw if (4 == sscanf(arg, "%u%u:%u.%u%c", &tr1, &m1, &s1, &f1, &c))
9208bdf91ceSkrw goto play_msf;
9218bdf91ceSkrw
9228bdf91ceSkrw /* tr1 m1:s1 tr2 */
9238bdf91ceSkrw f1 = m2 = s2 = f2 = 0;
9248bdf91ceSkrw if (4 == sscanf(arg, "%u%u:%u%u%c", &tr1, &m1, &s1, &tr2, &c))
9258bdf91ceSkrw goto play_msf;
9268bdf91ceSkrw
9278bdf91ceSkrw /* m1:s1.f1 tr2 */
9288bdf91ceSkrw tr1 = m2 = s2 = f2 = 0;
9298bdf91ceSkrw if (4 == sscanf(arg, "%u%u:%u%u%c", &m1, &s1, &f1, &tr2, &c))
9308bdf91ceSkrw goto play_msf;
9318bdf91ceSkrw
9328bdf91ceSkrw /* m1:s1.f1 <end of disc> */
9338bdf91ceSkrw tr1 = tr2 = m2 = s2 = f2 = 0;
9348bdf91ceSkrw if (3 == sscanf(arg, "%u:%u.%u%c", &m1, &s1, &f1, &c))
9358bdf91ceSkrw goto play_msf;
9368bdf91ceSkrw
9378bdf91ceSkrw /* tr1 m1:s1 <end of disc> */
9388bdf91ceSkrw f1 = tr2 = m2 = s2 = f2 = 0;
9398bdf91ceSkrw if (3 == sscanf(arg, "%u%u:%u%c", &tr1, &m1, &s1, &c))
9408bdf91ceSkrw goto play_msf;
9418bdf91ceSkrw
9428bdf91ceSkrw /* m1:s1 tr2 */
9438bdf91ceSkrw tr1 = f1 = m2 = s2 = f2 = 0;
9448bdf91ceSkrw if (3 == sscanf(arg, "%u:%u%u%c", &m1, &s1, &tr2, &c))
9458bdf91ceSkrw goto play_msf;
9468bdf91ceSkrw
9478bdf91ceSkrw /* m1:s1 <end of disc> */
9488bdf91ceSkrw tr1 = f1 = tr2 = m2 = s2 = f2 = 0;
9498bdf91ceSkrw if (2 == sscanf(arg, "%u:%u%c", &m1, &s1, &c))
9508bdf91ceSkrw goto play_msf;
9518bdf91ceSkrw
9528bdf91ceSkrw printf("%s: Invalid command arguments\n", __progname);
9538bdf91ceSkrw return (0);
9548bdf91ceSkrw
9558bdf91ceSkrw play_msf:
9568bdf91ceSkrw if (tr1 > n || tr2 > n) {
9578bdf91ceSkrw printf("Track number must be between 0 and %u\n", n);
9588bdf91ceSkrw return (0);
9598bdf91ceSkrw } else if (m1 > 99 || m2 > 99) {
9608bdf91ceSkrw printf("Minutes must be between 0 and 99\n");
9618bdf91ceSkrw return (0);
9628bdf91ceSkrw } else if (s1 > 59 || s2 > 59) {
9638bdf91ceSkrw printf("Seconds must be between 0 and 59\n");
9648bdf91ceSkrw return (0);
9652ccade87Snaddy } else if (f1 > 74 || f2 > 74) {
9668bdf91ceSkrw printf("Frames number must be between 0 and 74\n");
9678bdf91ceSkrw return (0);
9688bdf91ceSkrw }
9698bdf91ceSkrw
9708bdf91ceSkrw if (tr1 > 0) {
9718bdf91ceSkrw /*
9728bdf91ceSkrw * Start time is relative to tr1, Add start time of tr1
9738bdf91ceSkrw * to (m1,s1,f1) to yield absolute start time.
9748bdf91ceSkrw */
9757a498d98Skrw toc2msf(tr1, &tm, &ts, &tf);
9767a498d98Skrw addmsf(&m1, &s1, &f1, tm, ts, tf);
9777a498d98Skrw
9787a498d98Skrw /* Compare (m1,s1,f1) to start time of next track. */
9793438b82bSkrw toc2msf(tr1+1, &tm, &ts, &tf);
980b8a783aeSkrw if (cmpmsf(m1, s1, f1, tm, ts, tf) == 1) {
9818bdf91ceSkrw printf("Track %u is not that long.\n", tr1);
9828bdf91ceSkrw return (0);
9838bdf91ceSkrw }
9848bdf91ceSkrw }
9858bdf91ceSkrw
9868bdf91ceSkrw toc2msf(n+1, &tm, &ts, &tf);
9878bdf91ceSkrw if (cmpmsf(m1, s1, f1, tm, ts, tf) == 1) {
9888bdf91ceSkrw printf("Start time is after end of disc.\n");
989c92011ceSdownsj return (0);
990c92011ceSdownsj }
991c92011ceSdownsj
9928bdf91ceSkrw if (tr2 > 0) {
9937a498d98Skrw /*
9948bdf91ceSkrw * End time is relative to tr2, Add start time of tr2
9958bdf91ceSkrw * to (m2,s2,f2) to yield absolute end time.
9967a498d98Skrw */
9977a498d98Skrw toc2msf(tr2, &tm, &ts, &tf);
9988dcc8943Skrw addmsf(&m2, &s2, &f2, tm, ts, tf);
9998bdf91ceSkrw
10007a498d98Skrw /* Compare (m2,s2,f2) to start time of next track. */
10017a498d98Skrw toc2msf(tr2+1, &tm, &ts, &tf);
10027a498d98Skrw if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) {
10038bdf91ceSkrw printf("Track %u is not that long.\n", tr2);
10047a498d98Skrw return (0);
10057a498d98Skrw }
10067a498d98Skrw }
10077a498d98Skrw
10083438b82bSkrw toc2msf(n+1, &tm, &ts, &tf);
10098bdf91ceSkrw
10108bdf91ceSkrw if (!(tr2 || m2 || s2 || f2)) {
10118bdf91ceSkrw /* Play to end of disc. */
1012c92011ceSdownsj m2 = tm;
1013c92011ceSdownsj s2 = ts;
1014c92011ceSdownsj f2 = tf;
10158bdf91ceSkrw } else if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) {
10168bdf91ceSkrw printf("End time is after end of disc.\n");
10178bdf91ceSkrw return (0);
10188bdf91ceSkrw }
10198bdf91ceSkrw
10208bdf91ceSkrw if (cmpmsf(m1, s1, f1, m2, s2, f2) == 1) {
10218bdf91ceSkrw printf("Start time is after end time.\n");
10228bdf91ceSkrw return (0);
1023c92011ceSdownsj }
10243438b82bSkrw
1025c92011ceSdownsj return play_msf(m1, s1, f1, m2, s2, f2);
1026c92011ceSdownsj }
1027c92011ceSdownsj
1028f18d0a50Sderaadt int
play_prev(char * arg)10299ed7639aSespie play_prev(char *arg)
10303301428eSangelos {
10313301428eSangelos int trk, min, sec, frm, rc;
10323301428eSangelos struct ioc_toc_header h;
10333301428eSangelos
1034f18d0a50Sderaadt if (status(&trk, &min, &sec, &frm) >= 0) {
10353301428eSangelos trk--;
10363301428eSangelos
10373301428eSangelos rc = ioctl(fd, CDIOREADTOCHEADER, &h);
10383aaa63ebSderaadt if (rc == -1) {
1039f87f2499Smillert warn("getting toc header");
10403301428eSangelos return (rc);
10413301428eSangelos }
10423301428eSangelos
10433301428eSangelos if (trk < h.starting_track)
10443301428eSangelos return play_track(h.starting_track, 1,
1045ada687dbSangelos h.ending_track + 1, 1);
1046ada687dbSangelos return play_track(trk, 1, h.ending_track, 1);
10473301428eSangelos }
10483301428eSangelos
10493301428eSangelos return (0);
10503301428eSangelos }
10513301428eSangelos
1052f18d0a50Sderaadt int
play_same(char * arg)10539ed7639aSespie play_same(char *arg)
10544efcb1a6Sangelos {
10554efcb1a6Sangelos int trk, min, sec, frm, rc;
10564efcb1a6Sangelos struct ioc_toc_header h;
10574efcb1a6Sangelos
1058f18d0a50Sderaadt if (status (&trk, &min, &sec, &frm) >= 0) {
10594efcb1a6Sangelos rc = ioctl(fd, CDIOREADTOCHEADER, &h);
10603aaa63ebSderaadt if (rc == -1) {
1061f87f2499Smillert warn("getting toc header");
10624efcb1a6Sangelos return (rc);
10634efcb1a6Sangelos }
10644efcb1a6Sangelos
1065ada687dbSangelos return play_track(trk, 1, h.ending_track, 1);
10664efcb1a6Sangelos }
10674efcb1a6Sangelos
10684efcb1a6Sangelos return (0);
10694efcb1a6Sangelos }
10704efcb1a6Sangelos
1071f18d0a50Sderaadt int
play_next(char * arg)10729ed7639aSespie play_next(char *arg)
10733301428eSangelos {
10743301428eSangelos int trk, min, sec, frm, rc;
10753301428eSangelos struct ioc_toc_header h;
10763301428eSangelos
1077f18d0a50Sderaadt if (status(&trk, &min, &sec, &frm) >= 0) {
10783301428eSangelos trk++;
10793301428eSangelos rc = ioctl(fd, CDIOREADTOCHEADER, &h);
10803aaa63ebSderaadt if (rc == -1) {
1081f87f2499Smillert warn("getting toc header");
10823301428eSangelos return (rc);
10833301428eSangelos }
10843301428eSangelos
1085f18d0a50Sderaadt if (trk > h.ending_track) {
10863301428eSangelos printf("%s: end of CD\n", __progname);
10873301428eSangelos
10883301428eSangelos rc = ioctl(fd, CDIOCSTOP);
10893301428eSangelos
10903301428eSangelos (void) ioctl(fd, CDIOCALLOW);
10913301428eSangelos
10923301428eSangelos return (rc);
10933301428eSangelos }
10943301428eSangelos
1095ada687dbSangelos return play_track(trk, 1, h.ending_track, 1);
10963301428eSangelos }
10973301428eSangelos
10983301428eSangelos return (0);
10993301428eSangelos }
11003301428eSangelos
1101f18d0a50Sderaadt char *
strstatus(int sts)11029ed7639aSespie strstatus(int sts)
1103c92011ceSdownsj {
1104c92011ceSdownsj switch (sts) {
1105f18d0a50Sderaadt case ASTS_INVALID:
1106f18d0a50Sderaadt return ("invalid");
1107f18d0a50Sderaadt case ASTS_PLAYING:
1108f18d0a50Sderaadt return ("playing");
1109f18d0a50Sderaadt case ASTS_PAUSED:
1110f18d0a50Sderaadt return ("paused");
1111f18d0a50Sderaadt case ASTS_COMPLETED:
1112f18d0a50Sderaadt return ("completed");
1113f18d0a50Sderaadt case ASTS_ERROR:
1114f18d0a50Sderaadt return ("error");
1115f18d0a50Sderaadt case ASTS_VOID:
1116f18d0a50Sderaadt return ("void");
1117f18d0a50Sderaadt default:
1118f18d0a50Sderaadt return ("??");
1119c92011ceSdownsj }
1120c92011ceSdownsj }
1121c92011ceSdownsj
1122f18d0a50Sderaadt int
pstatus(char * arg)11239ed7639aSespie pstatus(char *arg)
1124c92011ceSdownsj {
1125c92011ceSdownsj struct ioc_vol v;
1126c92011ceSdownsj struct ioc_read_subchannel ss;
1127c92011ceSdownsj struct cd_sub_channel_info data;
1128c92011ceSdownsj int rc, trk, m, s, f;
1129dfcdb41bSespie char vis_catalog[1 + 4 * 15];
1130c92011ceSdownsj
1131c92011ceSdownsj rc = status(&trk, &m, &s, &f);
1132f87f2499Smillert if (rc >= 0) {
11339ed7639aSespie if (verbose) {
11349ed7639aSespie if (track_names)
11359ed7639aSespie printf("Audio status = %d<%s>, "
11369ed7639aSespie "current track = %d (%s)\n"
11379ed7639aSespie "\tcurrent position = %d:%02d.%02d\n",
11389ed7639aSespie rc, strstatus(rc), trk,
11399ed7639aSespie trk ? track_names[trk-1] : "", m, s, f);
1140c92011ceSdownsj else
11419ed7639aSespie printf("Audio status = %d<%s>, "
11429ed7639aSespie "current track = %d, "
11439ed7639aSespie "current position = %d:%02d.%02d\n",
11449ed7639aSespie rc, strstatus(rc), trk, m, s, f);
11459ed7639aSespie } else
1146c92011ceSdownsj printf("%d %d %d:%02d.%02d\n", rc, trk, m, s, f);
1147f87f2499Smillert } else
1148c92011ceSdownsj printf("No current status info available\n");
1149c92011ceSdownsj
1150c92011ceSdownsj bzero(&ss, sizeof (ss));
1151c92011ceSdownsj ss.data = &data;
1152c92011ceSdownsj ss.data_len = sizeof (data);
1153c92011ceSdownsj ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1154c92011ceSdownsj ss.data_format = CD_MEDIA_CATALOG;
1155c92011ceSdownsj rc = ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &ss);
1156c92011ceSdownsj if (rc >= 0) {
1157c92011ceSdownsj printf("Media catalog is %sactive",
1158c92011ceSdownsj ss.data->what.media_catalog.mc_valid ? "": "in");
1159c92011ceSdownsj if (ss.data->what.media_catalog.mc_valid &&
1160dfcdb41bSespie ss.data->what.media_catalog.mc_number[0]) {
1161dfcdb41bSespie strvisx(vis_catalog,
1162c2a796bdSderaadt (char *)ss.data->what.media_catalog.mc_number,
1163dfcdb41bSespie 15, VIS_SAFE);
1164dfcdb41bSespie printf(", number \"%.15s\"", vis_catalog);
1165dfcdb41bSespie }
1166c92011ceSdownsj putchar('\n');
1167c92011ceSdownsj } else
1168c92011ceSdownsj printf("No media catalog info available\n");
1169c92011ceSdownsj
1170c92011ceSdownsj rc = ioctl(fd, CDIOCGETVOL, &v);
1171f87f2499Smillert if (rc >= 0) {
1172c92011ceSdownsj if (verbose)
1173c92011ceSdownsj printf("Left volume = %d, right volume = %d\n",
1174c92011ceSdownsj v.vol[0], v.vol[1]);
1175c92011ceSdownsj else
1176c92011ceSdownsj printf("%d %d\n", v.vol[0], v.vol[1]);
1177f87f2499Smillert } else
1178c92011ceSdownsj printf("No volume level info available\n");
1179c92011ceSdownsj return(0);
1180c92011ceSdownsj }
1181c92011ceSdownsj
1182f18d0a50Sderaadt int
cdid(void)11831837a5caSderaadt cdid(void)
1184ae359c1cSespie {
1185ae359c1cSespie unsigned long id;
1186ae359c1cSespie struct ioc_toc_header h;
1187ae359c1cSespie int rc, n;
1188ae359c1cSespie
1189ae359c1cSespie rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1190ae359c1cSespie if (rc == -1) {
1191ae359c1cSespie warn("getting toc header");
1192ae359c1cSespie return (rc);
1193ae359c1cSespie }
1194ae359c1cSespie
1195ae359c1cSespie n = h.ending_track - h.starting_track + 1;
1196ae359c1cSespie rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1197ae359c1cSespie if (rc < 0)
1198ae359c1cSespie return (rc);
1199ae359c1cSespie
1200ae359c1cSespie id = cddb_discid(n, toc_buffer);
1201ae359c1cSespie if (id) {
1202ae359c1cSespie if (verbose)
1203ae359c1cSespie printf("CDID=");
1204ae359c1cSespie printf("%08lx\n", id);
1205ae359c1cSespie }
1206ae359c1cSespie return id ? 0 : 1;
1207ae359c1cSespie }
1208ae359c1cSespie
1209ae359c1cSespie int
info(char * arg)12109ed7639aSespie info(char *arg)
1211c92011ceSdownsj {
1212c92011ceSdownsj struct ioc_toc_header h;
1213c92011ceSdownsj int rc, i, n;
1214c92011ceSdownsj
1215dc4cd921Skrw if (get_media_capabilities(mediacap, 1) == -1)
1216dc4cd921Skrw errx(1, "Can't determine media type");
1217dc4cd921Skrw
1218c92011ceSdownsj rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1219c92011ceSdownsj if (rc >= 0) {
1220c92011ceSdownsj if (verbose)
1221c92011ceSdownsj printf("Starting track = %d, ending track = %d, TOC size = %d bytes\n",
1222c92011ceSdownsj h.starting_track, h.ending_track, h.len);
1223c92011ceSdownsj else
1224c92011ceSdownsj printf("%d %d %d\n", h.starting_track,
1225c92011ceSdownsj h.ending_track, h.len);
1226c92011ceSdownsj } else {
1227f87f2499Smillert warn("getting toc header");
1228c92011ceSdownsj return (rc);
1229c92011ceSdownsj }
1230c92011ceSdownsj
1231c92011ceSdownsj n = h.ending_track - h.starting_track + 1;
1232c92011ceSdownsj rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1233c92011ceSdownsj if (rc < 0)
1234c92011ceSdownsj return (rc);
1235c92011ceSdownsj
1236c92011ceSdownsj if (verbose) {
1237c92011ceSdownsj printf("track start duration block length type\n");
1238c92011ceSdownsj printf("-------------------------------------------------\n");
1239c92011ceSdownsj }
1240c92011ceSdownsj
1241c92011ceSdownsj for (i = 0; i < n; i++) {
1242c92011ceSdownsj printf("%5d ", toc_buffer[i].track);
12439ed7639aSespie prtrack(toc_buffer + i, 0, NULL);
1244c92011ceSdownsj }
1245c92011ceSdownsj printf("%5d ", toc_buffer[n].track);
12469ed7639aSespie prtrack(toc_buffer + n, 1, NULL);
12479ed7639aSespie return (0);
12489ed7639aSespie }
12499ed7639aSespie
12509ed7639aSespie int
cddbinfo(char * arg)12519ed7639aSespie cddbinfo(char *arg)
12529ed7639aSespie {
12539ed7639aSespie struct ioc_toc_header h;
12549ed7639aSespie int rc, i, n;
12559ed7639aSespie
12569ed7639aSespie rc = ioctl(fd, CDIOREADTOCHEADER, &h);
12579ed7639aSespie if (rc == -1) {
12589ed7639aSespie warn("getting toc header");
12599ed7639aSespie return (rc);
12609ed7639aSespie }
12619ed7639aSespie
12629ed7639aSespie n = h.ending_track - h.starting_track + 1;
12639ed7639aSespie rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
12649ed7639aSespie if (rc < 0)
12659ed7639aSespie return (rc);
12669ed7639aSespie
12679ed7639aSespie if (track_names)
12689ed7639aSespie free_names(track_names);
12699ed7639aSespie track_names = NULL;
12709ed7639aSespie
12719ed7639aSespie track_names = cddb(cddb_host, n, toc_buffer, arg);
12729ed7639aSespie if (!track_names)
12739ed7639aSespie return(0);
12749ed7639aSespie
12759ed7639aSespie printf("-------------------------------------------------\n");
12769ed7639aSespie
12779ed7639aSespie for (i = 0; i < n; i++) {
12789ed7639aSespie printf("%5d ", toc_buffer[i].track);
12799ed7639aSespie prtrack(toc_buffer + i, 0, track_names[i]);
12809ed7639aSespie }
12819ed7639aSespie printf("%5d ", toc_buffer[n].track);
12829ed7639aSespie prtrack(toc_buffer + n, 1, "");
1283c92011ceSdownsj return (0);
1284c92011ceSdownsj }
1285c92011ceSdownsj
1286f18d0a50Sderaadt void
lba2msf(unsigned long lba,u_char * m,u_char * s,u_char * f)12879ed7639aSespie lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f)
1288c92011ceSdownsj {
1289c92011ceSdownsj lba += 150; /* block start offset */
1290c92011ceSdownsj lba &= 0xffffff; /* negative lbas use only 24 bits */
1291c92011ceSdownsj *m = lba / (60 * 75);
1292c92011ceSdownsj lba %= (60 * 75);
1293c92011ceSdownsj *s = lba / 75;
1294c92011ceSdownsj *f = lba % 75;
1295c92011ceSdownsj }
1296c92011ceSdownsj
1297f18d0a50Sderaadt unsigned int
msf2lba(u_char m,u_char s,u_char f)1298da50f41aSespie msf2lba(u_char m, u_char s, u_char f)
1299c92011ceSdownsj {
1300c92011ceSdownsj return (((m * 60) + s) * 75 + f) - 150;
1301c92011ceSdownsj }
1302c92011ceSdownsj
13039ed7639aSespie unsigned long
entry2time(struct cd_toc_entry * e)13049ed7639aSespie entry2time(struct cd_toc_entry *e)
13059ed7639aSespie {
13069ed7639aSespie int block;
13079ed7639aSespie u_char m, s, f;
13089ed7639aSespie
13099ed7639aSespie if (msf) {
13109ed7639aSespie return (e->addr.msf.minute * 60 + e->addr.msf.second);
13119ed7639aSespie } else {
131243844f6cSkrw block = e->addr.lba;
13139ed7639aSespie lba2msf(block, &m, &s, &f);
13149ed7639aSespie return (m*60+s);
13159ed7639aSespie }
13169ed7639aSespie }
13179ed7639aSespie
13189ed7639aSespie unsigned long
entry2frames(struct cd_toc_entry * e)13199ed7639aSespie entry2frames(struct cd_toc_entry *e)
13209ed7639aSespie {
13219ed7639aSespie int block;
13229ed7639aSespie unsigned char m, s, f;
13239ed7639aSespie
13249ed7639aSespie if (msf) {
13259ed7639aSespie return e->addr.msf.frame + e->addr.msf.second * 75 +
13269ed7639aSespie e->addr.msf.minute * 60 * 75;
13279ed7639aSespie } else {
132843844f6cSkrw block = e->addr.lba;
13299ed7639aSespie lba2msf(block, &m, &s, &f);
13309ed7639aSespie return f + s * 75 + m * 60 * 75;
13319ed7639aSespie }
13329ed7639aSespie }
13339ed7639aSespie
1334f18d0a50Sderaadt void
prtrack(struct cd_toc_entry * e,int lastflag,char * name)13359ed7639aSespie prtrack(struct cd_toc_entry *e, int lastflag, char *name)
1336c92011ceSdownsj {
1337c92011ceSdownsj int block, next, len;
1338c92011ceSdownsj u_char m, s, f;
1339c92011ceSdownsj
1340c92011ceSdownsj if (msf) {
13419ed7639aSespie if (!name || lastflag)
1342c92011ceSdownsj /* Print track start */
1343c92011ceSdownsj printf("%2d:%02d.%02d ", e->addr.msf.minute,
1344c92011ceSdownsj e->addr.msf.second, e->addr.msf.frame);
1345c92011ceSdownsj
1346c92011ceSdownsj block = msf2lba(e->addr.msf.minute, e->addr.msf.second,
1347c92011ceSdownsj e->addr.msf.frame);
1348c92011ceSdownsj } else {
134943844f6cSkrw block = e->addr.lba;
13509ed7639aSespie if (!name || lastflag) {
1351c92011ceSdownsj lba2msf(block, &m, &s, &f);
1352c92011ceSdownsj /* Print track start */
1353c92011ceSdownsj printf("%2d:%02d.%02d ", m, s, f);
1354c92011ceSdownsj }
13559ed7639aSespie }
1356c92011ceSdownsj if (lastflag) {
13579ed7639aSespie if (!name)
1358c92011ceSdownsj /* Last track -- print block */
1359c92011ceSdownsj printf(" - %6d - -\n", block);
13609ed7639aSespie else
13619ed7639aSespie printf("\n");
1362c92011ceSdownsj return;
1363c92011ceSdownsj }
1364c92011ceSdownsj
1365c92011ceSdownsj if (msf)
1366c92011ceSdownsj next = msf2lba(e[1].addr.msf.minute, e[1].addr.msf.second,
1367c92011ceSdownsj e[1].addr.msf.frame);
1368c92011ceSdownsj else
136943844f6cSkrw next = e[1].addr.lba;
1370c92011ceSdownsj len = next - block;
1371fbd1c299Sfgsch lba2msf(len - 150, &m, &s, &f);
1372c92011ceSdownsj
13739ed7639aSespie if (name)
13749ed7639aSespie printf("%2d:%02d.%02d %s\n", m, s, f, name);
1375c92011ceSdownsj /* Print duration, block, length, type */
13769ed7639aSespie else
1377c92011ceSdownsj printf("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len,
1378c92011ceSdownsj (e->control & 4) ? "data" : "audio");
1379c92011ceSdownsj }
1380c92011ceSdownsj
1381f18d0a50Sderaadt int
play_track(int tstart,int istart,int tend,int iend)13829ed7639aSespie play_track(int tstart, int istart, int tend, int iend)
1383c92011ceSdownsj {
1384c92011ceSdownsj struct ioc_play_track t;
1385c92011ceSdownsj
1386c92011ceSdownsj t.start_track = tstart;
1387c92011ceSdownsj t.start_index = istart;
1388c92011ceSdownsj t.end_track = tend;
1389c92011ceSdownsj t.end_index = iend;
1390c92011ceSdownsj
1391c92011ceSdownsj return ioctl(fd, CDIOCPLAYTRACKS, &t);
1392c92011ceSdownsj }
1393c92011ceSdownsj
1394f18d0a50Sderaadt int
play_blocks(int blk,int len)13959ed7639aSespie play_blocks(int blk, int len)
1396c92011ceSdownsj {
1397c92011ceSdownsj struct ioc_play_blocks t;
1398c92011ceSdownsj
1399c92011ceSdownsj t.blk = blk;
1400c92011ceSdownsj t.len = len;
1401c92011ceSdownsj
1402c92011ceSdownsj return ioctl(fd, CDIOCPLAYBLOCKS, &t);
1403c92011ceSdownsj }
1404c92011ceSdownsj
1405f18d0a50Sderaadt int
setvol(int left,int right)14069ed7639aSespie setvol(int left, int right)
1407c92011ceSdownsj {
1408c92011ceSdownsj struct ioc_vol v;
1409c92011ceSdownsj
1410c92011ceSdownsj v.vol[0] = left;
1411c92011ceSdownsj v.vol[1] = right;
1412c92011ceSdownsj v.vol[2] = 0;
1413c92011ceSdownsj v.vol[3] = 0;
1414c92011ceSdownsj
1415c92011ceSdownsj return ioctl(fd, CDIOCSETVOL, &v);
1416c92011ceSdownsj }
1417c92011ceSdownsj
1418f18d0a50Sderaadt int
read_toc_entrys(int len)14199ed7639aSespie read_toc_entrys(int len)
1420c92011ceSdownsj {
1421c92011ceSdownsj struct ioc_read_toc_entry t;
1422c92011ceSdownsj
14233a87bfaeScsapuntz if (toc_buffer) {
14243a87bfaeScsapuntz free(toc_buffer);
14253a87bfaeScsapuntz toc_buffer = 0;
14263a87bfaeScsapuntz }
14273a87bfaeScsapuntz
14283a87bfaeScsapuntz toc_buffer = malloc(len);
14293a87bfaeScsapuntz
14303a87bfaeScsapuntz if (!toc_buffer) {
14313a87bfaeScsapuntz errno = ENOMEM;
14323a87bfaeScsapuntz return (-1);
14333a87bfaeScsapuntz }
14343a87bfaeScsapuntz
1435c92011ceSdownsj t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1436c92011ceSdownsj t.starting_track = 0;
1437c92011ceSdownsj t.data_len = len;
1438c92011ceSdownsj t.data = toc_buffer;
1439c92011ceSdownsj
1440c92011ceSdownsj return (ioctl(fd, CDIOREADTOCENTRYS, (char *) &t));
1441c92011ceSdownsj }
1442c92011ceSdownsj
1443f18d0a50Sderaadt int
play_msf(int start_m,int start_s,int start_f,int end_m,int end_s,int end_f)14449ed7639aSespie play_msf(int start_m, int start_s, int start_f, int end_m, int end_s, int end_f)
1445c92011ceSdownsj {
1446c92011ceSdownsj struct ioc_play_msf a;
1447c92011ceSdownsj
1448c92011ceSdownsj a.start_m = start_m;
1449c92011ceSdownsj a.start_s = start_s;
1450c92011ceSdownsj a.start_f = start_f;
1451c92011ceSdownsj a.end_m = end_m;
1452c92011ceSdownsj a.end_s = end_s;
1453c92011ceSdownsj a.end_f = end_f;
1454c92011ceSdownsj
1455c92011ceSdownsj return ioctl(fd, CDIOCPLAYMSF, (char *) &a);
1456c92011ceSdownsj }
1457c92011ceSdownsj
145867831131Sespie int
status(int * trk,int * min,int * sec,int * frame)14599ed7639aSespie status(int *trk, int *min, int *sec, int *frame)
1460c92011ceSdownsj {
1461c92011ceSdownsj struct ioc_read_subchannel s;
1462c92011ceSdownsj struct cd_sub_channel_info data;
1463c92011ceSdownsj u_char mm, ss, ff;
1464c92011ceSdownsj
1465c92011ceSdownsj bzero(&s, sizeof (s));
1466c92011ceSdownsj s.data = &data;
1467c92011ceSdownsj s.data_len = sizeof (data);
1468c92011ceSdownsj s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1469c92011ceSdownsj s.data_format = CD_CURRENT_POSITION;
1470c92011ceSdownsj
14713aaa63ebSderaadt if (ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &s) == -1)
1472c92011ceSdownsj return -1;
1473c92011ceSdownsj
1474c92011ceSdownsj *trk = s.data->what.position.track_number;
1475c92011ceSdownsj if (msf) {
1476c92011ceSdownsj *min = s.data->what.position.reladdr.msf.minute;
1477c92011ceSdownsj *sec = s.data->what.position.reladdr.msf.second;
1478c92011ceSdownsj *frame = s.data->what.position.reladdr.msf.frame;
1479c92011ceSdownsj } else {
148043844f6cSkrw /*
148143844f6cSkrw * NOTE: CDIOCREADSUBCHANNEL does not put the lba info into
148243844f6cSkrw * host order like CDIOREADTOCENTRYS does.
148343844f6cSkrw */
148443844f6cSkrw lba2msf(betoh32(s.data->what.position.reladdr.lba), &mm, &ss,
148543844f6cSkrw &ff);
1486c92011ceSdownsj *min = mm;
1487c92011ceSdownsj *sec = ss;
1488c92011ceSdownsj *frame = ff;
1489c92011ceSdownsj }
1490c92011ceSdownsj
1491c92011ceSdownsj return s.data->header.audio_status;
1492c92011ceSdownsj }
1493c92011ceSdownsj
1494a93de8edSschwarze void
sigint_handler(int signo_arg)1495a93de8edSschwarze sigint_handler(int signo_arg)
1496a93de8edSschwarze {
1497a93de8edSschwarze signo = signo_arg;
1498a93de8edSschwarze }
1499a93de8edSschwarze
1500f18d0a50Sderaadt char *
input(int * cmd)15019ed7639aSespie input(int *cmd)
1502c92011ceSdownsj {
1503a93de8edSschwarze struct sigaction sa;
1504ec6762c7Sfgsch char *buf;
1505ec6762c7Sfgsch int siz = 0;
1506c92011ceSdownsj char *p;
15078b59c5f0Sotto HistEvent hev;
1508c92011ceSdownsj
1509a93de8edSschwarze memset(&sa, 0, sizeof(sa));
1510c92011ceSdownsj do {
1511a93de8edSschwarze signo = 0;
1512a93de8edSschwarze sa.sa_handler = sigint_handler;
1513a93de8edSschwarze if (sigaction(SIGINT, &sa, NULL) == -1)
1514a93de8edSschwarze err(1, "sigaction");
1515a93de8edSschwarze buf = (char *)el_gets(el, &siz);
1516a93de8edSschwarze sa.sa_handler = SIG_DFL;
1517a93de8edSschwarze if (sigaction(SIGINT, &sa, NULL) == -1)
1518a93de8edSschwarze err(1, "sigaction");
1519a93de8edSschwarze if (buf == NULL || siz <= 0) {
1520c92011ceSdownsj fprintf(stderr, "\r\n");
1521a93de8edSschwarze if (siz < 0 && errno == EINTR && signo == SIGINT)
1522a93de8edSschwarze continue;
1523a93de8edSschwarze *cmd = CMD_QUIT;
1524c92011ceSdownsj return (0);
1525c92011ceSdownsj }
1526ec6762c7Sfgsch if (strlen(buf) > 1)
15278b59c5f0Sotto history(hist, &hev, H_ENTER, buf);
1528c92011ceSdownsj p = parse(buf, cmd);
1529c92011ceSdownsj } while (!p);
1530c92011ceSdownsj return (p);
1531c92011ceSdownsj }
1532c92011ceSdownsj
1533f18d0a50Sderaadt char *
parse(char * buf,int * cmd)15349ed7639aSespie parse(char *buf, int *cmd)
1535c92011ceSdownsj {
1536c92011ceSdownsj struct cmdtab *c;
1537c92011ceSdownsj char *p;
1538fa3e22b8Sav size_t len;
1539c92011ceSdownsj
154020ae3208Sderaadt for (p=buf; isspace((unsigned char)*p); p++)
1541c92011ceSdownsj continue;
1542c92011ceSdownsj
154320ae3208Sderaadt if (isdigit((unsigned char)*p) ||
154420ae3208Sderaadt (p[0] == '#' && isdigit((unsigned char)p[1]))) {
1545c92011ceSdownsj *cmd = CMD_PLAY;
1546c92011ceSdownsj return (p);
1547c92011ceSdownsj }
1548c92011ceSdownsj
154920ae3208Sderaadt for (buf = p; *p && ! isspace((unsigned char)*p); p++)
1550c92011ceSdownsj continue;
1551c92011ceSdownsj
1552c92011ceSdownsj len = p - buf;
1553c92011ceSdownsj if (!len)
1554c92011ceSdownsj return (0);
1555c92011ceSdownsj
1556c92011ceSdownsj if (*p) { /* It must be a spacing character! */
1557c92011ceSdownsj char *q;
1558c92011ceSdownsj
1559c92011ceSdownsj *p++ = 0;
1560c92011ceSdownsj for (q=p; *q && *q != '\n' && *q != '\r'; q++)
1561c92011ceSdownsj continue;
1562c92011ceSdownsj *q = 0;
1563c92011ceSdownsj }
1564c92011ceSdownsj
1565c92011ceSdownsj *cmd = -1;
1566c92011ceSdownsj for (c=cmdtab; c->name; ++c) {
1567c92011ceSdownsj /* Is it an exact match? */
1568c92011ceSdownsj if (!strcasecmp(buf, c->name)) {
1569c92011ceSdownsj *cmd = c->command;
1570c92011ceSdownsj break;
1571c92011ceSdownsj }
1572c92011ceSdownsj
1573c92011ceSdownsj /* Try short hand forms then... */
1574c92011ceSdownsj if (len >= c->min && ! strncasecmp(buf, c->name, len)) {
1575c92011ceSdownsj if (*cmd != -1 && *cmd != c->command) {
1576c92011ceSdownsj fprintf(stderr, "Ambiguous command\n");
1577c92011ceSdownsj return (0);
1578c92011ceSdownsj }
1579c92011ceSdownsj *cmd = c->command;
1580c92011ceSdownsj }
1581c92011ceSdownsj }
1582c92011ceSdownsj
1583c92011ceSdownsj if (*cmd == -1) {
1584c92011ceSdownsj fprintf(stderr, "%s: Invalid command, enter ``help'' for commands.\n",
1585c92011ceSdownsj __progname);
1586c92011ceSdownsj return (0);
1587c92011ceSdownsj }
1588c92011ceSdownsj
158920ae3208Sderaadt while (isspace((unsigned char)*p))
1590c92011ceSdownsj p++;
1591c92011ceSdownsj return p;
1592c92011ceSdownsj }
1593c92011ceSdownsj
1594f18d0a50Sderaadt int
open_cd(char * dev,int needwrite)15957993cdedSmjc open_cd(char *dev, int needwrite)
1596f87f2499Smillert {
1597f87f2499Smillert char *realdev;
159895cc45e3Smillert int tries;
1599c92011ceSdownsj
1600c7ed6047Sav if (fd > -1) {
1601c7ed6047Sav if (needwrite && !writeperm) {
1602c7ed6047Sav close(fd);
1603c7ed6047Sav fd = -1;
1604c7ed6047Sav } else
1605c92011ceSdownsj return (1);
1606c7ed6047Sav }
1607c92011ceSdownsj
160895cc45e3Smillert for (tries = 0; fd < 0 && tries < 10; tries++) {
16097993cdedSmjc if (needwrite)
16107993cdedSmjc fd = opendev(dev, O_RDWR, OPENDEV_PART, &realdev);
16117993cdedSmjc else
1612f87f2499Smillert fd = opendev(dev, O_RDONLY, OPENDEV_PART, &realdev);
16133aaa63ebSderaadt if (fd == -1) {
161495cc45e3Smillert if (errno == ENXIO) {
1615c92011ceSdownsj /* ENXIO has an overloaded meaning here.
1616c92011ceSdownsj * The original "Device not configured" should
1617c92011ceSdownsj * be interpreted as "No disc in drive %s". */
1618f87f2499Smillert warnx("No disc in drive %s.", realdev);
1619c92011ceSdownsj return (0);
162095cc45e3Smillert } else if (errno != EIO) {
162195cc45e3Smillert /* EIO may simply mean the device is not ready
162295cc45e3Smillert * yet which is common with CD changers. */
162395cc45e3Smillert warn("Can't open %s", realdev);
162495cc45e3Smillert return (0);
1625c92011ceSdownsj }
162695cc45e3Smillert }
162795cc45e3Smillert sleep(1);
162895cc45e3Smillert }
16293aaa63ebSderaadt if (fd == -1) {
1630f87f2499Smillert warn("Can't open %s", realdev);
1631f87f2499Smillert return (0);
1632c92011ceSdownsj }
1633c7ed6047Sav writeperm = needwrite;
1634c92011ceSdownsj return (1);
1635c92011ceSdownsj }
1636ec6762c7Sfgsch
1637ec6762c7Sfgsch char *
prompt(void)1638ec6762c7Sfgsch prompt(void)
1639ec6762c7Sfgsch {
1640ec6762c7Sfgsch return (verbose ? "cdio> " : "");
1641ec6762c7Sfgsch }
1642ec6762c7Sfgsch
1643ec6762c7Sfgsch void
switch_el(void)1644ec6762c7Sfgsch switch_el(void)
1645ec6762c7Sfgsch {
16468b59c5f0Sotto HistEvent hev;
16478b59c5f0Sotto
1648ec6762c7Sfgsch if (el == NULL && hist == NULL) {
16498b59c5f0Sotto el = el_init(__progname, stdin, stdout, stderr);
1650ec6762c7Sfgsch hist = history_init();
16518b59c5f0Sotto history(hist, &hev, H_SETSIZE, 100);
1652ec6762c7Sfgsch el_set(el, EL_HIST, history, hist);
1653ec6762c7Sfgsch el_set(el, EL_EDITOR, "emacs");
1654ec6762c7Sfgsch el_set(el, EL_PROMPT, prompt);
1655ec6762c7Sfgsch el_set(el, EL_SIGNAL, 1);
1656ec6762c7Sfgsch el_source(el, NULL);
1657ec6762c7Sfgsch
1658ec6762c7Sfgsch } else {
1659ec6762c7Sfgsch if (hist != NULL) {
1660ec6762c7Sfgsch history_end(hist);
1661ec6762c7Sfgsch hist = NULL;
1662ec6762c7Sfgsch }
1663ec6762c7Sfgsch if (el != NULL) {
1664ec6762c7Sfgsch el_end(el);
1665ec6762c7Sfgsch el = NULL;
1666ec6762c7Sfgsch }
1667ec6762c7Sfgsch }
1668ec6762c7Sfgsch }
16698dcc8943Skrw
16708dcc8943Skrw void
addmsf(u_int * m,u_int * s,u_int * f,u_char m_inc,u_char s_inc,u_char f_inc)16718dcc8943Skrw addmsf(u_int *m, u_int *s, u_int *f, u_char m_inc, u_char s_inc, u_char f_inc)
16728dcc8943Skrw {
16738dcc8943Skrw *f += f_inc;
16748dcc8943Skrw if (*f > 75) {
16758dcc8943Skrw *s += *f / 75;
16768dcc8943Skrw *f %= 75;
16778dcc8943Skrw }
16788dcc8943Skrw
16798dcc8943Skrw *s += s_inc;
16808dcc8943Skrw if (*s > 60) {
16818dcc8943Skrw *m += *s / 60;
16828dcc8943Skrw *s %= 60;
16838dcc8943Skrw }
16848dcc8943Skrw
16858dcc8943Skrw *m += m_inc;
16868dcc8943Skrw }
16873438b82bSkrw
1688b8a783aeSkrw int
cmpmsf(u_char m1,u_char s1,u_char f1,u_char m2,u_char s2,u_char f2)1689b8a783aeSkrw cmpmsf(u_char m1, u_char s1, u_char f1, u_char m2, u_char s2, u_char f2)
1690b8a783aeSkrw {
1691b8a783aeSkrw if (m1 > m2)
1692b8a783aeSkrw return (1);
1693b8a783aeSkrw else if (m1 < m2)
1694b8a783aeSkrw return (-1);
1695b8a783aeSkrw
1696b8a783aeSkrw if (s1 > s2)
1697b8a783aeSkrw return (1);
1698b8a783aeSkrw else if (s1 < s2)
1699b8a783aeSkrw return (-1);
1700b8a783aeSkrw
1701b8a783aeSkrw if (f1 > f2)
1702b8a783aeSkrw return (1);
1703b8a783aeSkrw else if (f1 < f2)
1704b8a783aeSkrw return (-1);
1705b8a783aeSkrw
1706b8a783aeSkrw return (0);
1707b8a783aeSkrw }
1708b8a783aeSkrw
17093438b82bSkrw void
toc2msf(u_int track,u_char * m,u_char * s,u_char * f)17103438b82bSkrw toc2msf(u_int track, u_char *m, u_char *s, u_char *f)
17113438b82bSkrw {
17123438b82bSkrw struct cd_toc_entry *ctep;
17133438b82bSkrw
17143438b82bSkrw ctep = &toc_buffer[track - 1];
17153438b82bSkrw
17163438b82bSkrw if (msf) {
17173438b82bSkrw *m = ctep->addr.msf.minute;
17183438b82bSkrw *s = ctep->addr.msf.second;
17193438b82bSkrw *f = ctep->addr.msf.frame;
17203438b82bSkrw } else
17213438b82bSkrw lba2msf(ctep->addr.lba, m, s, f);
17223438b82bSkrw }
1723