cdcontrol.c revision 197833
110099Sjkh/* 213884Sache * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>. 310099Sjkh * Based on the non-X based CD player by Jean-Marc Zucconi and 413832Sache * Andrey A. Chernov. 513884Sache * 613985Sache * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>. 713985Sache * 813985Sache * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 913985Sache * A couple of further fixes to my own earlier "fixes". 1013985Sache * 1113985Sache * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 1213985Sache * Added an ability to specify addresses relative to the 1313985Sache * beginning of a track. This is in fact a variation of 1413985Sache * doing the simple play_msf() call. 1513985Sache * 1613985Sache * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru> 1713985Sache * New eject algorithm. 1813985Sache * Some code style reformatting. 19180507Sgahr * 20180507Sgahr * 13-Dec-1999: Knut A. Syed <kas@kas.no> 21180507Sgahr * Volume-command modified. If used with only one 22180507Sgahr * parameter it now sets both channels. If used without 23180507Sgahr * parameters it will print volume-info. 24180507Sgahr * Version 2.0.1 25180507Sgahr * 26180507Sgahr * 27-Jun-2008 Pietro Cerutti <gahr@FreeBSD.org> 27180507Sgahr * Further enhancement to volume. Values not in range 0-255 28180507Sgahr * are now reduced to be in range. This prevents overflow in 29180507Sgahr * the uchar storing the volume (256 -> 0, -20 -> 236, ...). 30180507Sgahr * Version 2.0.2 31180507Sgahr * 3210099Sjkh */ 3313985Sache 34114601Sobrien#include <sys/cdefs.h> 35114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/cdcontrol/cdcontrol.c 197833 2009-10-07 13:25:22Z jh $"); 3629103Scharnier 3777168Skris#include <sys/cdio.h> 3896213Smaxim#include <sys/cdrio.h> 3977168Skris#include <sys/file.h> 4077168Skris#include <sys/ioctl.h> 4177168Skris#include <sys/param.h> 4290868Smike#include <arpa/inet.h> 4313985Sache#include <ctype.h> 4429103Scharnier#include <err.h> 4529103Scharnier#include <errno.h> 4677168Skris#include <histedit.h> 4796213Smaxim#include <limits.h> 4869793Sobrien#include <paths.h> 4910099Sjkh#include <stdio.h> 5010099Sjkh#include <stdlib.h> 5110099Sjkh#include <string.h> 5210099Sjkh#include <unistd.h> 5377168Skris#include <vis.h> 5410099Sjkh 55180507Sgahr#define VERSION "2.0.2" 5610099Sjkh 5787573Smikeh#define ASTS_INVALID 0x00 /* Audio status byte not valid */ 5887573Smikeh#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 5987573Smikeh#define ASTS_PAUSED 0x12 /* Audio play operation paused */ 6087573Smikeh#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 6187573Smikeh#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 6287573Smikeh#define ASTS_VOID 0x15 /* No current audio status to return */ 6310099Sjkh 64122855Seivind#ifdef DEFAULT_CD_DRIVE 65122855Seivind# error "Setting DEFAULT_CD_DRIVE is no longer supported" 6613985Sache#endif 6713985Sache 6887573Smikeh#define CMD_DEBUG 1 6987573Smikeh#define CMD_EJECT 2 7087573Smikeh#define CMD_HELP 3 7187573Smikeh#define CMD_INFO 4 7287573Smikeh#define CMD_PAUSE 5 7387573Smikeh#define CMD_PLAY 6 7487573Smikeh#define CMD_QUIT 7 7587573Smikeh#define CMD_RESUME 8 7687573Smikeh#define CMD_STOP 9 7787573Smikeh#define CMD_VOLUME 10 7887573Smikeh#define CMD_CLOSE 11 7987573Smikeh#define CMD_RESET 12 8087573Smikeh#define CMD_SET 13 8187573Smikeh#define CMD_STATUS 14 8287573Smikeh#define CMD_CDID 15 8387573Smikeh#define CMD_NEXT 16 8487573Smikeh#define CMD_PREVIOUS 17 8596213Smaxim#define CMD_SPEED 18 8687573Smikeh#define STATUS_AUDIO 0x1 8787573Smikeh#define STATUS_MEDIA 0x2 8887573Smikeh#define STATUS_VOLUME 0x4 8913985Sache 9010099Sjkhstruct cmdtab { 9110099Sjkh int command; 9287568Smikeh const char *name; 9387568Smikeh unsigned min; 9487568Smikeh const char *args; 9510099Sjkh} cmdtab[] = { 9687573Smikeh{ CMD_CLOSE, "close", 1, "" }, 9787573Smikeh{ CMD_DEBUG, "debug", 1, "on | off" }, 9887573Smikeh{ CMD_EJECT, "eject", 1, "" }, 9987573Smikeh{ CMD_HELP, "?", 1, 0 }, 10087573Smikeh{ CMD_HELP, "help", 1, "" }, 10187573Smikeh{ CMD_INFO, "info", 1, "" }, 10287573Smikeh{ CMD_NEXT, "next", 1, "" }, 10387573Smikeh{ CMD_PAUSE, "pause", 2, "" }, 10487573Smikeh{ CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 10587573Smikeh{ CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 10687573Smikeh{ CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 10787573Smikeh{ CMD_PLAY, "play", 1, "[#block [len]]" }, 10887573Smikeh{ CMD_PREVIOUS, "previous", 2, "" }, 10987573Smikeh{ CMD_QUIT, "quit", 1, "" }, 11087573Smikeh{ CMD_RESET, "reset", 4, "" }, 11187573Smikeh{ CMD_RESUME, "resume", 1, "" }, 11287573Smikeh{ CMD_SET, "set", 2, "msf | lba" }, 11387573Smikeh{ CMD_STATUS, "status", 1, "[audio | media | volume]" }, 11487573Smikeh{ CMD_STOP, "stop", 3, "" }, 11587573Smikeh{ CMD_VOLUME, "volume", 1, 116180507Sgahr "<l&r> <l> <r> | left | right | mute | mono | stereo" }, 11787573Smikeh{ CMD_CDID, "cdid", 2, "" }, 11896213Smaxim{ CMD_SPEED, "speed", 2, "speed" }, 11987573Smikeh{ 0, NULL, 0, NULL } 12010099Sjkh}; 12110099Sjkh 12287573Smikehstruct cd_toc_entry toc_buffer[100]; 12310099Sjkh 12487573Smikehconst char *cdname; 12587573Smikehint fd = -1; 12687573Smikehint verbose = 1; 12787573Smikehint msf = 1; 12810099Sjkh 12999800Salfredint setvol(int, int); 13099800Salfredint read_toc_entrys(int); 13199800Salfredint play_msf(int, int, int, int, int, int); 13299800Salfredint play_track(int, int, int, int); 13399800Salfredint get_vol(int *, int *); 13499800Salfredint status(int *, int *, int *, int *); 13599800Salfredint open_cd(void); 13699800Salfredint next_prev(char *arg, int); 13799800Salfredint play(char *arg); 13899800Salfredint info(char *arg); 13999800Salfredint cdid(void); 14099800Salfredint pstatus(char *arg); 14199800Salfredchar *input(int *); 14299800Salfredvoid prtrack(struct cd_toc_entry *e, int lastflag); 14399800Salfredvoid lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f); 14499800Salfredunsigned int msf2lba(u_char m, u_char s, u_char f); 14599800Salfredint play_blocks(int blk, int len); 14699800Salfredint run(int cmd, char *arg); 14799800Salfredchar *parse(char *buf, int *cmd); 14899800Salfredvoid help(void); 14999800Salfredvoid usage(void); 15099800Salfredchar *use_cdrom_instead(const char *); 15199800Salfred__const char *strstatus(int); 15299800Salfredstatic u_int dbprog_discid(void); 15399800Salfred__const char *cdcontrol_prompt(void); 15410099Sjkh 15510099Sjkhvoid help () 15610099Sjkh{ 15710099Sjkh struct cmdtab *c; 15887568Smikeh const char *s; 15987568Smikeh char n; 16013985Sache int i; 16110099Sjkh 16210099Sjkh for (c=cmdtab; c->name; ++c) { 16310099Sjkh if (! c->args) 16410099Sjkh continue; 16513985Sache printf("\t"); 16613985Sache for (i = c->min, s = c->name; *s; s++, i--) { 16713985Sache if (i > 0) 16813985Sache n = toupper(*s); 16913985Sache else 17013985Sache n = *s; 17113985Sache putchar(n); 17213985Sache } 17310099Sjkh if (*c->args) 17410099Sjkh printf (" %s", c->args); 17510099Sjkh printf ("\n"); 17610099Sjkh } 17713985Sache printf ("\n\tThe word \"play\" is not required for the play commands.\n"); 17813985Sache printf ("\tThe plain target address is taken as a synonym for play.\n"); 17910099Sjkh} 18010099Sjkh 18110099Sjkhvoid usage () 18210099Sjkh{ 18343479Sbillf fprintf (stderr, "usage: cdcontrol [-sv] [-f device] [command ...]\n"); 18410099Sjkh exit (1); 18510099Sjkh} 18610099Sjkh 18787568Smikehchar *use_cdrom_instead(const char *old_envvar) 18871122Sjoe{ 18971122Sjoe char *device; 19071122Sjoe 19171122Sjoe device = getenv(old_envvar); 19271122Sjoe if (device) 19371122Sjoe warnx("%s environment variable deprecated, " 19471122Sjoe "please use CDROM in the future.", old_envvar); 19571122Sjoe return device; 19671122Sjoe} 19771122Sjoe 19871122Sjoe 19910099Sjkhint main (int argc, char **argv) 20010099Sjkh{ 20110099Sjkh int cmd; 20210099Sjkh char *arg; 20310099Sjkh 20410099Sjkh for (;;) { 20510099Sjkh switch (getopt (argc, argv, "svhf:")) { 206176407Sru case -1: 20710099Sjkh break; 20810099Sjkh case 's': 20910099Sjkh verbose = 0; 21010099Sjkh continue; 21110099Sjkh case 'v': 21210099Sjkh verbose = 2; 21310099Sjkh continue; 21410099Sjkh case 'f': 21510099Sjkh cdname = optarg; 21610099Sjkh continue; 21710099Sjkh case 'h': 21810099Sjkh default: 21910099Sjkh usage (); 22010099Sjkh } 22110099Sjkh break; 22210099Sjkh } 22310099Sjkh argc -= optind; 22410099Sjkh argv += optind; 22510099Sjkh 22613985Sache if (argc > 0 && ! strcasecmp (*argv, "help")) 22710099Sjkh usage (); 22810099Sjkh 22910099Sjkh if (! cdname) { 23070149Sdes cdname = getenv("CDROM"); 23170149Sdes } 23270149Sdes 23375324Sjoe if (! cdname) 23475324Sjoe cdname = use_cdrom_instead("MUSIC_CD"); 23575324Sjoe if (! cdname) 23675324Sjoe cdname = use_cdrom_instead("CD_DRIVE"); 23775324Sjoe if (! cdname) 23875324Sjoe cdname = use_cdrom_instead("DISC"); 23975324Sjoe if (! cdname) 24075324Sjoe cdname = use_cdrom_instead("CDPLAY"); 24175324Sjoe 24210099Sjkh if (argc > 0) { 24310099Sjkh char buf[80], *p; 244197833Sjh int len, rc; 24510099Sjkh 24613985Sache for (p=buf; argc-->0; ++argv) { 24710099Sjkh len = strlen (*argv); 24813985Sache 24910099Sjkh if (p + len >= buf + sizeof (buf) - 1) 25010099Sjkh usage (); 25113985Sache 25210099Sjkh if (p > buf) 25310099Sjkh *p++ = ' '; 25413985Sache 25510099Sjkh strcpy (p, *argv); 25610099Sjkh p += len; 25710099Sjkh } 25810099Sjkh *p = 0; 25910099Sjkh arg = parse (buf, &cmd); 260197833Sjh rc = run (cmd, arg); 261197833Sjh if (rc < 0 && verbose) 262197833Sjh warn(NULL); 263197833Sjh 264197833Sjh return (rc); 26510099Sjkh } 26610099Sjkh 26710099Sjkh if (verbose == 1) 26810099Sjkh verbose = isatty (0); 26913985Sache 27010099Sjkh if (verbose) { 27113985Sache printf ("Compact Disc Control utility, version %s\n", VERSION); 27210099Sjkh printf ("Type `?' for command list\n\n"); 27310099Sjkh } 27410099Sjkh 27510099Sjkh for (;;) { 27610099Sjkh arg = input (&cmd); 27710099Sjkh if (run (cmd, arg) < 0) { 27810099Sjkh if (verbose) 27929103Scharnier warn(NULL); 28010099Sjkh close (fd); 28110099Sjkh fd = -1; 28210099Sjkh } 28310099Sjkh fflush (stdout); 28410099Sjkh } 28510099Sjkh} 28610099Sjkh 28710099Sjkhint run (int cmd, char *arg) 28810099Sjkh{ 28996213Smaxim long speed; 290180507Sgahr int l, r, rc, count; 29110099Sjkh 29210099Sjkh switch (cmd) { 29313985Sache 29410099Sjkh case CMD_QUIT: 29510099Sjkh exit (0); 29610099Sjkh 29713985Sache case CMD_INFO: 29813985Sache if (fd < 0 && ! open_cd ()) 29913985Sache return (0); 30010099Sjkh 30110099Sjkh return info (arg); 30210099Sjkh 30363091Sjoe case CMD_CDID: 30463091Sjoe if (fd < 0 && ! open_cd ()) 30563091Sjoe return (0); 30663091Sjoe 30763091Sjoe return cdid (); 30863091Sjoe 30913884Sache case CMD_STATUS: 31013985Sache if (fd < 0 && ! open_cd ()) 31113985Sache return (0); 31213985Sache 31313884Sache return pstatus (arg); 31413884Sache 31577168Skris case CMD_NEXT: 31677168Skris case CMD_PREVIOUS: 31777168Skris if (fd < 0 && ! open_cd ()) 31877168Skris return (0); 31977168Skris 32077168Skris while (isspace (*arg)) 32177168Skris arg++; 32277168Skris 32377168Skris return next_prev (arg, cmd); 32477168Skris 32510099Sjkh case CMD_PAUSE: 32613985Sache if (fd < 0 && ! open_cd ()) 32713985Sache return (0); 32813985Sache 32910099Sjkh return ioctl (fd, CDIOCPAUSE); 33010099Sjkh 33110099Sjkh case CMD_RESUME: 33213985Sache if (fd < 0 && ! open_cd ()) 33313985Sache return (0); 33413985Sache 33510099Sjkh return ioctl (fd, CDIOCRESUME); 33610099Sjkh 33710099Sjkh case CMD_STOP: 33813985Sache if (fd < 0 && ! open_cd ()) 33913985Sache return (0); 34010099Sjkh 34113985Sache rc = ioctl (fd, CDIOCSTOP); 34213985Sache 34313985Sache (void) ioctl (fd, CDIOCALLOW); 34413985Sache 34513985Sache return (rc); 34613985Sache 34713884Sache case CMD_RESET: 34813985Sache if (fd < 0 && ! open_cd ()) 34913985Sache return (0); 35013985Sache 35113884Sache rc = ioctl (fd, CDIOCRESET); 35213884Sache if (rc < 0) 35313884Sache return rc; 35413884Sache close(fd); 35513884Sache fd = -1; 35613884Sache return (0); 35713884Sache 35810099Sjkh case CMD_DEBUG: 35913985Sache if (fd < 0 && ! open_cd ()) 36013985Sache return (0); 36113985Sache 36213985Sache if (! strcasecmp (arg, "on")) 36310099Sjkh return ioctl (fd, CDIOCSETDEBUG); 36413985Sache 36513985Sache if (! strcasecmp (arg, "off")) 36610099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 36713985Sache 36829103Scharnier warnx("invalid command arguments"); 36913985Sache 37010099Sjkh return (0); 37110099Sjkh 37210099Sjkh case CMD_EJECT: 37313985Sache if (fd < 0 && ! open_cd ()) 37413985Sache return (0); 37513985Sache 37610099Sjkh (void) ioctl (fd, CDIOCALLOW); 37710099Sjkh rc = ioctl (fd, CDIOCEJECT); 37810099Sjkh if (rc < 0) 37910099Sjkh return (rc); 38013865Sache return (0); 38113865Sache 38213985Sache case CMD_CLOSE: 38313985Sache if (fd < 0 && ! open_cd ()) 38413985Sache return (0); 38513985Sache 38613985Sache (void) ioctl (fd, CDIOCALLOW); 38713865Sache rc = ioctl (fd, CDIOCCLOSE); 38813865Sache if (rc < 0) 38913865Sache return (rc); 39013865Sache close(fd); 39110099Sjkh fd = -1; 39210099Sjkh return (0); 39310099Sjkh 39410099Sjkh case CMD_PLAY: 39513985Sache if (fd < 0 && ! open_cd ()) 39613985Sache return (0); 39713985Sache 39813985Sache while (isspace (*arg)) 39913985Sache arg++; 40013985Sache 40110099Sjkh return play (arg); 40210099Sjkh 40313884Sache case CMD_SET: 40413985Sache if (! strcasecmp (arg, "msf")) 40513884Sache msf = 1; 40613985Sache else if (! strcasecmp (arg, "lba")) 40713884Sache msf = 0; 40813884Sache else 40929103Scharnier warnx("invalid command arguments"); 41013884Sache return (0); 41113884Sache 41210099Sjkh case CMD_VOLUME: 41313985Sache if (fd < 0 && !open_cd ()) 41413985Sache return (0); 41510099Sjkh 416180507Sgahr if (! strlen (arg)) 417180507Sgahr return pstatus ("volume"); 418180507Sgahr 41913985Sache if (! strncasecmp (arg, "left", strlen(arg))) 42010099Sjkh return ioctl (fd, CDIOCSETLEFT); 42113985Sache 42213985Sache if (! strncasecmp (arg, "right", strlen(arg))) 42310099Sjkh return ioctl (fd, CDIOCSETRIGHT); 42413985Sache 42513985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 42610099Sjkh return ioctl (fd, CDIOCSETMONO); 42713985Sache 42813985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 42910099Sjkh return ioctl (fd, CDIOCSETSTERIO); 43010099Sjkh 43113985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 43213985Sache return ioctl (fd, CDIOCSETMUTE); 43313985Sache 434180507Sgahr count = sscanf (arg, "%d %d", &l, &r); 435180507Sgahr if (count == 1) 436180507Sgahr return setvol (l, l); 437180507Sgahr if (count == 2) 438180507Sgahr return setvol (l, r); 439180507Sgahr warnx("invalid command arguments"); 440180507Sgahr return (0); 44113985Sache 44296213Smaxim case CMD_SPEED: 44396213Smaxim if (fd < 0 && ! open_cd ()) 44496213Smaxim return (0); 44596213Smaxim 44696213Smaxim errno = 0; 447105421Snjl if (strcasecmp("max", arg) == 0) 448105421Snjl speed = CDR_MAX_SPEED; 449105421Snjl else 450105421Snjl speed = strtol(arg, NULL, 10) * 177; 451105421Snjl if (speed <= 0 || speed > INT_MAX) { 45296213Smaxim warnx("invalid command arguments %s", arg); 45396213Smaxim return (0); 45496213Smaxim } 45596213Smaxim return ioctl(fd, CDRIOCREADSPEED, &speed); 45696213Smaxim 45713985Sache default: 45813985Sache case CMD_HELP: 45913985Sache help (); 46013985Sache return (0); 46113985Sache 46210099Sjkh } 46310099Sjkh} 46410099Sjkh 46510099Sjkhint play (char *arg) 46610099Sjkh{ 46710099Sjkh struct ioc_toc_header h; 46887568Smikeh unsigned int n; 46987568Smikeh int rc, start, end = 0, istart = 1, iend = 1; 47010099Sjkh 47110099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 47213985Sache 47310099Sjkh if (rc < 0) 47410099Sjkh return (rc); 47510099Sjkh 47610099Sjkh n = h.ending_track - h.starting_track + 1; 47710099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 47813985Sache 47910099Sjkh if (rc < 0) 48010099Sjkh return (rc); 48110099Sjkh 48213989Sache if (! arg || ! *arg) { 48313985Sache /* Play the whole disc */ 48413989Sache if (msf) 48513989Sache return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 48613989Sache toc_buffer[n].addr.msf.second, 48713989Sache toc_buffer[n].addr.msf.frame)); 48813989Sache else 48913989Sache return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); 49013989Sache } 49110099Sjkh 49210099Sjkh if (strchr (arg, '#')) { 49313985Sache /* Play block #blk [ len ] */ 49410099Sjkh int blk, len = 0; 49510099Sjkh 49610099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 49713985Sache 1 != sscanf (arg, "#%d", &blk)) 49813985Sache goto Clean_up; 49913985Sache 50013989Sache if (len == 0) { 50113989Sache if (msf) 50213989Sache len = msf2lba (toc_buffer[n].addr.msf.minute, 50313989Sache toc_buffer[n].addr.msf.second, 50413989Sache toc_buffer[n].addr.msf.frame) - blk; 50513989Sache else 50613989Sache len = ntohl(toc_buffer[n].addr.lba) - blk; 50713989Sache } 50810099Sjkh return play_blocks (blk, len); 50910099Sjkh } 51010099Sjkh 51110099Sjkh if (strchr (arg, ':')) { 51210099Sjkh /* 51310099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 51413985Sache * 51513985Sache * Will now also undestand timed addresses relative 51613985Sache * to the beginning of a track in the form... 51713985Sache * 51813985Sache * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 51910099Sjkh */ 52013985Sache unsigned tr1, tr2; 52113985Sache unsigned m1, m2, s1, s2, f1, f2; 52213989Sache unsigned char tm, ts, tf; 52310099Sjkh 52413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52513985Sache if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", 52613985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) 52713985Sache goto Play_Relative_Addresses; 52813985Sache 52913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53013985Sache if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d", 53113985Sache &tr1, &m1, &s1, &tr2, &m2, &s2, &f2)) 53213985Sache goto Play_Relative_Addresses; 53313985Sache 53413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53513985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", 53613985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) 53713985Sache goto Play_Relative_Addresses; 53813985Sache 53913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54013985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d", 54113985Sache &tr1, &m1, &s1, &f1, &m2, &s2, &f2)) 54213985Sache goto Play_Relative_Addresses; 54313985Sache 54413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54513985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d:%d", 54613985Sache &tr1, &m1, &s1, &f1, &m2, &s2)) 54713985Sache goto Play_Relative_Addresses; 54813985Sache 54913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55013985Sache if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", 55113985Sache &tr1, &m1, &s1, &m2, &s2, &f2)) 55213985Sache goto Play_Relative_Addresses; 55313985Sache 55413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55513985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d %d", 55613985Sache &tr1, &m1, &s1, &f1, &tr2, &m2)) 55713985Sache goto Play_Relative_Addresses; 55813985Sache 55913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56013985Sache if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) 56113985Sache goto Play_Relative_Addresses; 56213985Sache 56313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56413985Sache if (5 == sscanf (arg, "%d %d:%d %d %d", 56513985Sache &tr1, &m1, &s1, &tr2, &m2)) 56613985Sache goto Play_Relative_Addresses; 56713985Sache 56813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56913985Sache if (5 == sscanf (arg, "%d %d:%d.%d %d", 57013985Sache &tr1, &m1, &s1, &f1, &tr2)) 57113985Sache goto Play_Relative_Addresses; 57213985Sache 57313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57413985Sache if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 57513985Sache goto Play_Relative_Addresses; 57613985Sache 57713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57813985Sache if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 57913985Sache goto Play_Relative_Addresses; 58013985Sache 58113985Sache tr2 = m2 = s2 = f2 = f1 = 0; 58213985Sache if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) 58313985Sache goto Play_Relative_Addresses; 58413985Sache 58513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 58613985Sache goto Try_Absolute_Timed_Addresses; 58713985Sache 58813985SachePlay_Relative_Addresses: 58913985Sache if (! tr1) 59013985Sache tr1 = 1; 59113985Sache else if (tr1 > n) 59213985Sache tr1 = n; 59313985Sache 594112559Seivind tr1--; 595112559Seivind 59613989Sache if (msf) { 59713989Sache tm = toc_buffer[tr1].addr.msf.minute; 59813989Sache ts = toc_buffer[tr1].addr.msf.second; 59913989Sache tf = toc_buffer[tr1].addr.msf.frame; 60013989Sache } else 60113989Sache lba2msf(ntohl(toc_buffer[tr1].addr.lba), 60213989Sache &tm, &ts, &tf); 60313989Sache if ((m1 > tm) 60413989Sache || ((m1 == tm) 60513989Sache && ((s1 > ts) 60613989Sache || ((s1 == ts) 60713989Sache && (f1 > tf))))) { 60813985Sache printf ("Track %d is not that long.\n", tr1); 60913985Sache return (0); 61013985Sache } 61113985Sache 61213989Sache f1 += tf; 61313985Sache if (f1 >= 75) { 61413985Sache s1 += f1 / 75; 61513985Sache f1 %= 75; 61613985Sache } 61713985Sache 61813989Sache s1 += ts; 61913985Sache if (s1 >= 60) { 62013985Sache m1 += s1 / 60; 62113985Sache s1 %= 60; 62213985Sache } 62313985Sache 62413989Sache m1 += tm; 62513985Sache 62613985Sache if (! tr2) { 62713985Sache if (m2 || s2 || f2) { 62813985Sache tr2 = tr1; 62913985Sache f2 += f1; 63013985Sache if (f2 >= 75) { 63113985Sache s2 += f2 / 75; 63213985Sache f2 %= 75; 63313985Sache } 63413985Sache 63513985Sache s2 += s1; 63613985Sache if (s2 > 60) { 63713985Sache m2 += s2 / 60; 63813985Sache s2 %= 60; 63913985Sache } 64013985Sache 64113985Sache m2 += m1; 64213985Sache } else { 64313985Sache tr2 = n; 64413989Sache if (msf) { 64513989Sache m2 = toc_buffer[n].addr.msf.minute; 64613989Sache s2 = toc_buffer[n].addr.msf.second; 64713989Sache f2 = toc_buffer[n].addr.msf.frame; 64813989Sache } else { 64913989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 65013989Sache &tm, &ts, &tf); 65113989Sache m2 = tm; 65213989Sache s2 = ts; 65313989Sache f2 = tf; 65413989Sache } 65513985Sache } 65613985Sache } else if (tr2 > n) { 65713985Sache tr2 = n; 65813985Sache m2 = s2 = f2 = 0; 65913985Sache } else { 66013985Sache if (m2 || s2 || f2) 66113985Sache tr2--; 66213989Sache if (msf) { 66313989Sache tm = toc_buffer[tr2].addr.msf.minute; 66413989Sache ts = toc_buffer[tr2].addr.msf.second; 66513989Sache tf = toc_buffer[tr2].addr.msf.frame; 66613989Sache } else 66713989Sache lba2msf(ntohl(toc_buffer[tr2].addr.lba), 66813989Sache &tm, &ts, &tf); 66913989Sache f2 += tf; 67013985Sache if (f2 >= 75) { 67113985Sache s2 += f2 / 75; 67213985Sache f2 %= 75; 67313985Sache } 67413985Sache 67513989Sache s2 += ts; 67613985Sache if (s2 > 60) { 67713985Sache m2 += s2 / 60; 67813985Sache s2 %= 60; 67913985Sache } 68013985Sache 68113989Sache m2 += tm; 68213985Sache } 68313985Sache 68413989Sache if (msf) { 68513989Sache tm = toc_buffer[n].addr.msf.minute; 68613989Sache ts = toc_buffer[n].addr.msf.second; 68713989Sache tf = toc_buffer[n].addr.msf.frame; 68813989Sache } else 68913989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 69013989Sache &tm, &ts, &tf); 69113985Sache if ((tr2 < n) 69213989Sache && ((m2 > tm) 69313989Sache || ((m2 == tm) 69413989Sache && ((s2 > ts) 69513989Sache || ((s2 == ts) 69613989Sache && (f2 > tf)))))) { 69713985Sache printf ("The playing time of the disc is not that long.\n"); 69813985Sache return (0); 69913985Sache } 70013985Sache return (play_msf (m1, s1, f1, m2, s2, f2)); 70113985Sache 70213985SacheTry_Absolute_Timed_Addresses: 70313985Sache if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", 70413985Sache &m1, &s1, &f1, &m2, &s2, &f2) && 70510099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 70610099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 70710099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 70810099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 70910099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 71013985Sache goto Clean_up; 71113985Sache 71210099Sjkh if (m2 == 0) { 71313989Sache if (msf) { 71413989Sache m2 = toc_buffer[n].addr.msf.minute; 71513989Sache s2 = toc_buffer[n].addr.msf.second; 71613989Sache f2 = toc_buffer[n].addr.msf.frame; 71713989Sache } else { 71813989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 71913989Sache &tm, &ts, &tf); 72013989Sache m2 = tm; 72113989Sache s2 = ts; 72213989Sache f2 = tf; 72313989Sache } 72410099Sjkh } 72510099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 72610099Sjkh } 72710099Sjkh 72810099Sjkh /* 72910099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 73010099Sjkh */ 73110099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 73210099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 73310099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 73410099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 73510099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 73610099Sjkh 1 != sscanf (arg, "%d", &start)) 73713985Sache goto Clean_up; 73813985Sache 73910099Sjkh if (end == 0) 74010099Sjkh end = n; 74113985Sache return (play_track (start, istart, end, iend)); 74213985Sache 74313985SacheClean_up: 74429103Scharnier warnx("invalid command arguments"); 74513985Sache return (0); 74610099Sjkh} 74710099Sjkh 74877168Skrisint next_prev (char *arg, int cmd) 74977168Skris{ 75077168Skris struct ioc_toc_header h; 75177168Skris int dir, junk, n, off, rc, trk; 75277168Skris 75377168Skris dir = (cmd == CMD_NEXT) ? 1 : -1; 75477168Skris rc = ioctl (fd, CDIOREADTOCHEADER, &h); 75577168Skris if (rc < 0) 75677168Skris return (rc); 75777168Skris 75877168Skris n = h.ending_track - h.starting_track + 1; 75977168Skris rc = status (&trk, &junk, &junk, &junk); 76077168Skris if (rc < 0) 76177168Skris return (-1); 76277168Skris 76377168Skris if (arg && *arg) { 76477168Skris if (sscanf (arg, "%u", &off) != 1) { 76577168Skris warnx("invalid command argument"); 76677168Skris return (0); 76777168Skris } else 76877168Skris trk += off * dir; 76977168Skris } else 77077168Skris trk += dir; 77177168Skris 77277168Skris if (trk > h.ending_track) 77377168Skris trk = 1; 77477168Skris 77577168Skris return (play_track (trk, 1, n, 1)); 77677168Skris} 77777168Skris 77887568Smikehconst char *strstatus (int sts) 77910099Sjkh{ 78010099Sjkh switch (sts) { 78187573Smikeh case ASTS_INVALID: return ("invalid"); 78287573Smikeh case ASTS_PLAYING: return ("playing"); 78387573Smikeh case ASTS_PAUSED: return ("paused"); 78487573Smikeh case ASTS_COMPLETED: return ("completed"); 78587573Smikeh case ASTS_ERROR: return ("error"); 78687573Smikeh case ASTS_VOID: return ("void"); 78787573Smikeh default: return ("??"); 78810099Sjkh } 78910099Sjkh} 79010099Sjkh 79113884Sacheint pstatus (char *arg) 79210099Sjkh{ 79310099Sjkh struct ioc_vol v; 79413888Sache struct ioc_read_subchannel ss; 79513888Sache struct cd_sub_channel_info data; 79613884Sache int rc, trk, m, s, f; 79732782Sjmz int what = 0; 79877168Skris char *p, vmcn[(4 * 15) + 1]; 79910099Sjkh 80032782Sjmz while ((p = strtok(arg, " \t"))) { 80132782Sjmz arg = 0; 80232782Sjmz if (!strncasecmp(p, "audio", strlen(p))) 80332782Sjmz what |= STATUS_AUDIO; 80432782Sjmz else if (!strncasecmp(p, "media", strlen(p))) 80532782Sjmz what |= STATUS_MEDIA; 80632782Sjmz else if (!strncasecmp(p, "volume", strlen(p))) 80732782Sjmz what |= STATUS_VOLUME; 80832782Sjmz else { 80932782Sjmz warnx("invalid command arguments"); 81032782Sjmz return 0; 81132782Sjmz } 81232782Sjmz } 81332782Sjmz if (!what) 81432782Sjmz what = STATUS_AUDIO|STATUS_MEDIA|STATUS_VOLUME; 81532782Sjmz if (what & STATUS_AUDIO) { 81632782Sjmz rc = status (&trk, &m, &s, &f); 81732782Sjmz if (rc >= 0) 81810099Sjkh if (verbose) 81932782Sjmz printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 82032782Sjmz rc, strstatus (rc), trk, m, s, f); 82110099Sjkh else 82232782Sjmz printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 82332782Sjmz else 82413888Sache printf ("No current status info available\n"); 82532782Sjmz } 82632782Sjmz if (what & STATUS_MEDIA) { 82732782Sjmz bzero (&ss, sizeof (ss)); 82832782Sjmz ss.data = &data; 82932782Sjmz ss.data_len = sizeof (data); 83032782Sjmz ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 83132782Sjmz ss.data_format = CD_MEDIA_CATALOG; 83232782Sjmz rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); 83332782Sjmz if (rc >= 0) { 83413889Sache printf("Media catalog is %sactive", 83587573Smikeh ss.data->what.media_catalog.mc_valid ? "": "in"); 83616736Sache if (ss.data->what.media_catalog.mc_valid && 83716736Sache ss.data->what.media_catalog.mc_number[0]) 83877168Skris { 83977168Skris strvisx (vmcn, ss.data->what.media_catalog.mc_number, 84077168Skris (sizeof (vmcn) - 1) / 4, VIS_OCTAL | VIS_NL); 84177168Skris printf(", number \"%.*s\"", (int)sizeof (vmcn), vmcn); 84277168Skris } 84313889Sache putchar('\n'); 84432782Sjmz } else 84513888Sache printf("No media catalog info available\n"); 84632782Sjmz } 84732782Sjmz if (what & STATUS_VOLUME) { 84832782Sjmz rc = ioctl (fd, CDIOCGETVOL, &v); 84932782Sjmz if (rc >= 0) 85010099Sjkh if (verbose) 85132782Sjmz printf ("Left volume = %d, right volume = %d\n", 85232782Sjmz v.vol[0], v.vol[1]); 85310099Sjkh else 85432782Sjmz printf ("%d %d\n", v.vol[0], v.vol[1]); 85532782Sjmz else 85613888Sache printf ("No volume level info available\n"); 85732782Sjmz } 85813884Sache return(0); 85913884Sache} 86010099Sjkh 86163091Sjoe/* 86263091Sjoe * dbprog_sum 86363091Sjoe * Convert an integer to its text string representation, and 86463091Sjoe * compute its checksum. Used by dbprog_discid to derive the 86563091Sjoe * disc ID. 86663091Sjoe * 86763091Sjoe * Args: 86863091Sjoe * n - The integer value. 86963091Sjoe * 87063091Sjoe * Return: 87163091Sjoe * The integer checksum. 87263091Sjoe */ 87363091Sjoestatic int 87463091Sjoedbprog_sum(int n) 87563091Sjoe{ 87663091Sjoe char buf[12], 87763091Sjoe *p; 87863091Sjoe int ret = 0; 87963091Sjoe 88063091Sjoe /* For backward compatibility this algorithm must not change */ 88163091Sjoe sprintf(buf, "%u", n); 88263091Sjoe for (p = buf; *p != '\0'; p++) 88363091Sjoe ret += (*p - '0'); 88463091Sjoe 88563091Sjoe return(ret); 88663091Sjoe} 88763091Sjoe 88863091Sjoe 88963091Sjoe/* 89063091Sjoe * dbprog_discid 89163091Sjoe * Compute a magic disc ID based on the number of tracks, 89263091Sjoe * the length of each track, and a checksum of the string 89363091Sjoe * that represents the offset of each track. 89463091Sjoe * 89563091Sjoe * Args: 89663091Sjoe * s - Pointer to the curstat_t structure. 89763091Sjoe * 89863091Sjoe * Return: 89963091Sjoe * The integer disc ID. 90063091Sjoe */ 90163091Sjoestatic u_int 90263091Sjoedbprog_discid() 90363091Sjoe{ 90463091Sjoe struct ioc_toc_header h; 90563091Sjoe int rc; 90663091Sjoe int i, ntr, 90763091Sjoe t = 0, 90863091Sjoe n = 0; 90963091Sjoe 91063091Sjoe rc = ioctl (fd, CDIOREADTOCHEADER, &h); 91163091Sjoe if (rc < 0) 91263091Sjoe return 0; 91363091Sjoe ntr = h.ending_track - h.starting_track + 1; 91463091Sjoe i = msf; 91563091Sjoe msf = 1; 91663091Sjoe rc = read_toc_entrys ((ntr + 1) * sizeof (struct cd_toc_entry)); 91763091Sjoe msf = i; 91863091Sjoe if (rc < 0) 91963091Sjoe return 0; 92063091Sjoe /* For backward compatibility this algorithm must not change */ 92163091Sjoe for (i = 0; i < ntr; i++) { 92263091Sjoe#define TC_MM(a) toc_buffer[a].addr.msf.minute 92363091Sjoe#define TC_SS(a) toc_buffer[a].addr.msf.second 92463091Sjoe n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i)); 92563091Sjoe 92663091Sjoe t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - 92787573Smikeh ((TC_MM(i) * 60) + TC_SS(i)); 92863091Sjoe } 92963091Sjoe 93063091Sjoe return((n % 0xff) << 24 | t << 8 | ntr); 93163091Sjoe} 93263091Sjoe 93363091Sjoeint cdid () 93463091Sjoe{ 93563091Sjoe u_int id; 93663091Sjoe 93763091Sjoe id = dbprog_discid(); 93863091Sjoe if (id) 93963091Sjoe { 94063091Sjoe if (verbose) 94163091Sjoe printf ("CDID="); 94263091Sjoe printf ("%08x\n",id); 94363091Sjoe } 94463091Sjoe return id ? 0 : 1; 94563091Sjoe} 94663091Sjoe 94787568Smikehint info (char *arg __unused) 94813884Sache{ 94913884Sache struct ioc_toc_header h; 95013884Sache int rc, i, n; 95113884Sache 95210099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 95313888Sache if (rc >= 0) { 95410099Sjkh if (verbose) 95510099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 95610099Sjkh h.starting_track, h.ending_track, h.len); 95710099Sjkh else 95810099Sjkh printf ("%d %d %d\n", h.starting_track, 95910099Sjkh h.ending_track, h.len); 96013888Sache } else { 96129103Scharnier warn("getting toc header"); 96210099Sjkh return (rc); 96310099Sjkh } 96410099Sjkh 96510099Sjkh n = h.ending_track - h.starting_track + 1; 96610099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 96710099Sjkh if (rc < 0) 96810099Sjkh return (rc); 96913985Sache 97010099Sjkh if (verbose) { 97110099Sjkh printf ("track start duration block length type\n"); 97210099Sjkh printf ("-------------------------------------------------\n"); 97310099Sjkh } 97413985Sache 97510099Sjkh for (i = 0; i < n; i++) { 97610099Sjkh printf ("%5d ", toc_buffer[i].track); 97710099Sjkh prtrack (toc_buffer + i, 0); 97810099Sjkh } 97913867Sache printf ("%5d ", toc_buffer[n].track); 98010099Sjkh prtrack (toc_buffer + n, 1); 98110099Sjkh return (0); 98210099Sjkh} 98310099Sjkh 98413985Sachevoid lba2msf (unsigned long lba, u_char *m, u_char *s, u_char *f) 98510099Sjkh{ 98687573Smikeh lba += 150; /* block start offset */ 98787573Smikeh lba &= 0xffffff; /* negative lbas use only 24 bits */ 98810099Sjkh *m = lba / (60 * 75); 98910099Sjkh lba %= (60 * 75); 99010099Sjkh *s = lba / 75; 99110099Sjkh *f = lba % 75; 99210099Sjkh} 99310099Sjkh 99413985Sacheunsigned int msf2lba (u_char m, u_char s, u_char f) 99510099Sjkh{ 99610099Sjkh return (((m * 60) + s) * 75 + f) - 150; 99710099Sjkh} 99810099Sjkh 99910099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag) 100010099Sjkh{ 100110099Sjkh int block, next, len; 100210099Sjkh u_char m, s, f; 100310099Sjkh 100413884Sache if (msf) { 100513884Sache /* Print track start */ 100613884Sache printf ("%2d:%02d.%02d ", e->addr.msf.minute, 100713884Sache e->addr.msf.second, e->addr.msf.frame); 100810099Sjkh 100913884Sache block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 101013884Sache e->addr.msf.frame); 101113884Sache } else { 101213884Sache block = ntohl(e->addr.lba); 101313884Sache lba2msf(block, &m, &s, &f); 101413884Sache /* Print track start */ 101513884Sache printf ("%2d:%02d.%02d ", m, s, f); 101613884Sache } 101710099Sjkh if (lastflag) { 101810099Sjkh /* Last track -- print block */ 101910099Sjkh printf (" - %6d - -\n", block); 102010099Sjkh return; 102110099Sjkh } 102210099Sjkh 102313884Sache if (msf) 102413884Sache next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 102513884Sache e[1].addr.msf.frame); 102613884Sache else 102713884Sache next = ntohl(e[1].addr.lba); 102810099Sjkh len = next - block; 1029103861Smaxim /* Take into account a start offset time. */ 1030103861Smaxim lba2msf (len - 150, &m, &s, &f); 103110099Sjkh 103210099Sjkh /* Print duration, block, length, type */ 103310099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 103413985Sache (e->control & 4) ? "data" : "audio"); 103510099Sjkh} 103610099Sjkh 103710099Sjkhint play_track (int tstart, int istart, int tend, int iend) 103810099Sjkh{ 103910099Sjkh struct ioc_play_track t; 104010099Sjkh 104110099Sjkh t.start_track = tstart; 104210099Sjkh t.start_index = istart; 104310099Sjkh t.end_track = tend; 104410099Sjkh t.end_index = iend; 104513985Sache 104610099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 104710099Sjkh} 104810099Sjkh 104910099Sjkhint play_blocks (int blk, int len) 105010099Sjkh{ 105113985Sache struct ioc_play_blocks t; 105210099Sjkh 105310099Sjkh t.blk = blk; 105410099Sjkh t.len = len; 105513985Sache 105610099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 105710099Sjkh} 105810099Sjkh 105913985Sacheint setvol (int left, int right) 106010099Sjkh{ 106113985Sache struct ioc_vol v; 106210099Sjkh 1063180507Sgahr left = left < 0 ? 0 : left > 255 ? 255 : left; 1064180507Sgahr right = right < 0 ? 0 : right > 255 ? 255 : right; 1065180507Sgahr 106613985Sache v.vol[0] = left; 106713985Sache v.vol[1] = right; 106810099Sjkh v.vol[2] = 0; 106910099Sjkh v.vol[3] = 0; 107013985Sache 107110099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 107210099Sjkh} 107310099Sjkh 107410099Sjkhint read_toc_entrys (int len) 107510099Sjkh{ 107610099Sjkh struct ioc_read_toc_entry t; 107710099Sjkh 107813884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 107913737Sache t.starting_track = 0; 108010099Sjkh t.data_len = len; 108110099Sjkh t.data = toc_buffer; 108213985Sache 108313985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 108410099Sjkh} 108510099Sjkh 108610099Sjkhint play_msf (int start_m, int start_s, int start_f, 108713985Sache int end_m, int end_s, int end_f) 108810099Sjkh{ 108987573Smikeh struct ioc_play_msf a; 109010099Sjkh 109110099Sjkh a.start_m = start_m; 109210099Sjkh a.start_s = start_s; 109310099Sjkh a.start_f = start_f; 109410099Sjkh a.end_m = end_m; 109510099Sjkh a.end_s = end_s; 109610099Sjkh a.end_f = end_f; 109713985Sache 109810099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 109910099Sjkh} 110010099Sjkh 110110099Sjkhint status (int *trk, int *min, int *sec, int *frame) 110210099Sjkh{ 110310099Sjkh struct ioc_read_subchannel s; 110410099Sjkh struct cd_sub_channel_info data; 110513884Sache u_char mm, ss, ff; 110610099Sjkh 110710099Sjkh bzero (&s, sizeof (s)); 110810099Sjkh s.data = &data; 110910099Sjkh s.data_len = sizeof (data); 111013884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 111110099Sjkh s.data_format = CD_CURRENT_POSITION; 111213985Sache 111310099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 111410099Sjkh return -1; 111513985Sache 111610099Sjkh *trk = s.data->what.position.track_number; 111713884Sache if (msf) { 111813884Sache *min = s.data->what.position.reladdr.msf.minute; 111913884Sache *sec = s.data->what.position.reladdr.msf.second; 112013884Sache *frame = s.data->what.position.reladdr.msf.frame; 112113884Sache } else { 112213884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 112313884Sache &mm, &ss, &ff); 112413884Sache *min = mm; 112513884Sache *sec = ss; 112613884Sache *frame = ff; 112713884Sache } 112813985Sache 112910099Sjkh return s.data->header.audio_status; 113010099Sjkh} 113110099Sjkh 113250039Smdoddconst char * 113350039Smdoddcdcontrol_prompt() 113410099Sjkh{ 113550039Smdodd return ("cdcontrol> "); 113650039Smdodd} 113750039Smdodd 113850039Smdoddchar * 113950039Smdoddinput (int *cmd) 114050039Smdodd{ 114150039Smdodd#define MAXLINE 80 114250039Smdodd static EditLine *el = NULL; 114350039Smdodd static History *hist = NULL; 114484261Sobrien HistEvent he; 114550039Smdodd static char buf[MAXLINE]; 114650039Smdodd int num = 0; 114750071Smdodd int len; 114850039Smdodd const char *bp = NULL; 114910099Sjkh char *p; 115010099Sjkh 115110099Sjkh do { 115250039Smdodd if (verbose) { 115350039Smdodd if (!el) { 115484261Sobrien el = el_init("cdcontrol", stdin, stdout, 115584261Sobrien stderr); 115650039Smdodd hist = history_init(); 1157151471Sstefanf history(hist, &he, H_SETSIZE, 100); 115850039Smdodd el_set(el, EL_HIST, history, hist); 115950039Smdodd el_set(el, EL_EDITOR, "emacs"); 116050039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 116150039Smdodd el_set(el, EL_SIGNAL, 1); 116250042Smdodd el_source(el, NULL); 116350039Smdodd } 116463070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 116563070Smckay *cmd = CMD_QUIT; 116663070Smckay fprintf (stderr, "\r\n"); 116750039Smdodd return (0); 116863070Smckay } 116950039Smdodd 117050071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 117150071Smdodd memcpy(buf, bp, len); 117250071Smdodd buf[len] = 0; 117384261Sobrien history(hist, &he, H_ENTER, bp); 117450039Smdodd#undef MAXLINE 117550039Smdodd 117650039Smdodd } else { 117750039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 117850039Smdodd *cmd = CMD_QUIT; 117950039Smdodd fprintf (stderr, "\r\n"); 118050039Smdodd return (0); 118150039Smdodd } 118210099Sjkh } 118310099Sjkh p = parse (buf, cmd); 118410099Sjkh } while (! p); 118510099Sjkh return (p); 118610099Sjkh} 118710099Sjkh 118810099Sjkhchar *parse (char *buf, int *cmd) 118910099Sjkh{ 119010099Sjkh struct cmdtab *c; 119110099Sjkh char *p; 119287568Smikeh unsigned int len; 119310099Sjkh 119413985Sache for (p=buf; isspace (*p); p++) 119513985Sache continue; 119610099Sjkh 119713985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 119813985Sache *cmd = CMD_PLAY; 119913985Sache return (p); 120077168Skris } else if (*p == '+') { 120177168Skris *cmd = CMD_NEXT; 120277168Skris return (p + 1); 120377168Skris } else if (*p == '-') { 120477168Skris *cmd = CMD_PREVIOUS; 120577168Skris return (p + 1); 120613985Sache } 120710099Sjkh 120813985Sache for (buf = p; *p && ! isspace (*p); p++) 120913985Sache continue; 121096214Smaxim 121113985Sache len = p - buf; 121210099Sjkh if (! len) 121310099Sjkh return (0); 121413985Sache 121587573Smikeh if (*p) { /* It must be a spacing character! */ 121613985Sache char *q; 121713985Sache 121813985Sache *p++ = 0; 121913985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 122013985Sache continue; 122113985Sache *q = 0; 122213985Sache } 122313985Sache 122410099Sjkh *cmd = -1; 122510099Sjkh for (c=cmdtab; c->name; ++c) { 122613985Sache /* Is it an exact match? */ 122713985Sache if (! strcasecmp (buf, c->name)) { 122813985Sache *cmd = c->command; 122913985Sache break; 123013985Sache } 123113985Sache 123213985Sache /* Try short hand forms then... */ 123313985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 123413985Sache if (*cmd != -1 && *cmd != c->command) { 123529103Scharnier warnx("ambiguous command"); 123613985Sache return (0); 123713985Sache } 123810099Sjkh *cmd = c->command; 123913985Sache } 124013985Sache } 124110099Sjkh 124210099Sjkh if (*cmd == -1) { 124329103Scharnier warnx("invalid command, enter ``help'' for commands"); 124410099Sjkh return (0); 124510099Sjkh } 124613985Sache 124713985Sache while (isspace (*p)) 124813985Sache p++; 124910099Sjkh return p; 125010099Sjkh} 125110099Sjkh 125210099Sjkhint open_cd () 125310099Sjkh{ 125454164Sjoe char devbuf[MAXPATHLEN]; 1255127714Sdwmalone const char *dev; 125610099Sjkh 125710099Sjkh if (fd > -1) 125810099Sjkh return (1); 125913985Sache 1260122855Seivind if (cdname) { 1261122855Seivind if (*cdname == '/') { 1262122855Seivind snprintf (devbuf, MAXPATHLEN, "%s", cdname); 1263122855Seivind } else { 1264122855Seivind snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 1265122855Seivind } 1266127714Sdwmalone fd = open (dev = devbuf, O_RDONLY); 126761105Smsmith } else { 1268127714Sdwmalone fd = open(dev = "/dev/cdrom", O_RDONLY); 1269122855Seivind if (fd < 0 && errno == ENOENT) 1270127714Sdwmalone fd = open(dev = "/dev/cd0", O_RDONLY); 1271122855Seivind if (fd < 0 && errno == ENOENT) 1272127714Sdwmalone fd = open(dev = "/dev/acd0", O_RDONLY); 127354164Sjoe } 127413985Sache 127510099Sjkh if (fd < 0) { 127613985Sache if (errno == ENXIO) { 127713985Sache /* ENXIO has an overloaded meaning here. 127813985Sache * The original "Device not configured" should 127913985Sache * be interpreted as "No disc in drive %s". */ 1280127714Sdwmalone warnx("no disc in drive %s", dev); 128113985Sache return (0); 128210099Sjkh } 1283127714Sdwmalone err(1, "%s", dev); 128410099Sjkh } 128510099Sjkh return (1); 128610099Sjkh} 1287