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