cdcontrol.c revision 122855
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. 1910099Sjkh */ 2013985Sache 21114601Sobrien#include <sys/cdefs.h> 22114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/cdcontrol/cdcontrol.c 122855 2003-11-17 14:02:04Z eivind $"); 2329103Scharnier 2477168Skris#include <sys/cdio.h> 2596213Smaxim#include <sys/cdrio.h> 2677168Skris#include <sys/file.h> 2777168Skris#include <sys/ioctl.h> 2877168Skris#include <sys/param.h> 2990868Smike#include <arpa/inet.h> 3013985Sache#include <ctype.h> 3129103Scharnier#include <err.h> 3229103Scharnier#include <errno.h> 3377168Skris#include <histedit.h> 3496213Smaxim#include <limits.h> 3569793Sobrien#include <paths.h> 3610099Sjkh#include <stdio.h> 3710099Sjkh#include <stdlib.h> 3810099Sjkh#include <string.h> 3910099Sjkh#include <unistd.h> 4077168Skris#include <vis.h> 4110099Sjkh 4213884Sache#define VERSION "2.0" 4310099Sjkh 4487573Smikeh#define ASTS_INVALID 0x00 /* Audio status byte not valid */ 4587573Smikeh#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 4687573Smikeh#define ASTS_PAUSED 0x12 /* Audio play operation paused */ 4787573Smikeh#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 4887573Smikeh#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 4987573Smikeh#define ASTS_VOID 0x15 /* No current audio status to return */ 5010099Sjkh 51122855Seivind#ifdef DEFAULT_CD_DRIVE 52122855Seivind# error "Setting DEFAULT_CD_DRIVE is no longer supported" 5313985Sache#endif 5413985Sache 5587573Smikeh#define CMD_DEBUG 1 5687573Smikeh#define CMD_EJECT 2 5787573Smikeh#define CMD_HELP 3 5887573Smikeh#define CMD_INFO 4 5987573Smikeh#define CMD_PAUSE 5 6087573Smikeh#define CMD_PLAY 6 6187573Smikeh#define CMD_QUIT 7 6287573Smikeh#define CMD_RESUME 8 6387573Smikeh#define CMD_STOP 9 6487573Smikeh#define CMD_VOLUME 10 6587573Smikeh#define CMD_CLOSE 11 6687573Smikeh#define CMD_RESET 12 6787573Smikeh#define CMD_SET 13 6887573Smikeh#define CMD_STATUS 14 6987573Smikeh#define CMD_CDID 15 7087573Smikeh#define CMD_NEXT 16 7187573Smikeh#define CMD_PREVIOUS 17 7296213Smaxim#define CMD_SPEED 18 7387573Smikeh#define STATUS_AUDIO 0x1 7487573Smikeh#define STATUS_MEDIA 0x2 7587573Smikeh#define STATUS_VOLUME 0x4 7613985Sache 7710099Sjkhstruct cmdtab { 7810099Sjkh int command; 7987568Smikeh const char *name; 8087568Smikeh unsigned min; 8187568Smikeh const char *args; 8210099Sjkh} cmdtab[] = { 8387573Smikeh{ CMD_CLOSE, "close", 1, "" }, 8487573Smikeh{ CMD_DEBUG, "debug", 1, "on | off" }, 8587573Smikeh{ CMD_EJECT, "eject", 1, "" }, 8687573Smikeh{ CMD_HELP, "?", 1, 0 }, 8787573Smikeh{ CMD_HELP, "help", 1, "" }, 8887573Smikeh{ CMD_INFO, "info", 1, "" }, 8987573Smikeh{ CMD_NEXT, "next", 1, "" }, 9087573Smikeh{ CMD_PAUSE, "pause", 2, "" }, 9187573Smikeh{ CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 9287573Smikeh{ CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 9387573Smikeh{ CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 9487573Smikeh{ CMD_PLAY, "play", 1, "[#block [len]]" }, 9587573Smikeh{ CMD_PREVIOUS, "previous", 2, "" }, 9687573Smikeh{ CMD_QUIT, "quit", 1, "" }, 9787573Smikeh{ CMD_RESET, "reset", 4, "" }, 9887573Smikeh{ CMD_RESUME, "resume", 1, "" }, 9987573Smikeh{ CMD_SET, "set", 2, "msf | lba" }, 10087573Smikeh{ CMD_STATUS, "status", 1, "[audio | media | volume]" }, 10187573Smikeh{ CMD_STOP, "stop", 3, "" }, 10287573Smikeh{ CMD_VOLUME, "volume", 1, 10387573Smikeh "<l> <r> | left | right | mute | mono | stereo" }, 10487573Smikeh{ CMD_CDID, "cdid", 2, "" }, 10596213Smaxim{ CMD_SPEED, "speed", 2, "speed" }, 10687573Smikeh{ 0, NULL, 0, NULL } 10710099Sjkh}; 10810099Sjkh 10987573Smikehstruct cd_toc_entry toc_buffer[100]; 11010099Sjkh 11187573Smikehconst char *cdname; 11287573Smikehint fd = -1; 11387573Smikehint verbose = 1; 11487573Smikehint msf = 1; 11510099Sjkh 11699800Salfredint setvol(int, int); 11799800Salfredint read_toc_entrys(int); 11899800Salfredint play_msf(int, int, int, int, int, int); 11999800Salfredint play_track(int, int, int, int); 12099800Salfredint get_vol(int *, int *); 12199800Salfredint status(int *, int *, int *, int *); 12299800Salfredint open_cd(void); 12399800Salfredint next_prev(char *arg, int); 12499800Salfredint play(char *arg); 12599800Salfredint info(char *arg); 12699800Salfredint cdid(void); 12799800Salfredint pstatus(char *arg); 12899800Salfredchar *input(int *); 12999800Salfredvoid prtrack(struct cd_toc_entry *e, int lastflag); 13099800Salfredvoid lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f); 13199800Salfredunsigned int msf2lba(u_char m, u_char s, u_char f); 13299800Salfredint play_blocks(int blk, int len); 13399800Salfredint run(int cmd, char *arg); 13499800Salfredchar *parse(char *buf, int *cmd); 13599800Salfredvoid help(void); 13699800Salfredvoid usage(void); 13799800Salfredchar *use_cdrom_instead(const char *); 13899800Salfred__const char *strstatus(int); 13999800Salfredstatic u_int dbprog_discid(void); 14099800Salfred__const char *cdcontrol_prompt(void); 14110099Sjkh 14210099Sjkhvoid help () 14310099Sjkh{ 14410099Sjkh struct cmdtab *c; 14587568Smikeh const char *s; 14687568Smikeh char n; 14713985Sache int i; 14810099Sjkh 14910099Sjkh for (c=cmdtab; c->name; ++c) { 15010099Sjkh if (! c->args) 15110099Sjkh continue; 15213985Sache printf("\t"); 15313985Sache for (i = c->min, s = c->name; *s; s++, i--) { 15413985Sache if (i > 0) 15513985Sache n = toupper(*s); 15613985Sache else 15713985Sache n = *s; 15813985Sache putchar(n); 15913985Sache } 16010099Sjkh if (*c->args) 16110099Sjkh printf (" %s", c->args); 16210099Sjkh printf ("\n"); 16310099Sjkh } 16413985Sache printf ("\n\tThe word \"play\" is not required for the play commands.\n"); 16513985Sache printf ("\tThe plain target address is taken as a synonym for play.\n"); 16610099Sjkh} 16710099Sjkh 16810099Sjkhvoid usage () 16910099Sjkh{ 17043479Sbillf fprintf (stderr, "usage: cdcontrol [-sv] [-f device] [command ...]\n"); 17110099Sjkh exit (1); 17210099Sjkh} 17310099Sjkh 17487568Smikehchar *use_cdrom_instead(const char *old_envvar) 17571122Sjoe{ 17671122Sjoe char *device; 17771122Sjoe 17871122Sjoe device = getenv(old_envvar); 17971122Sjoe if (device) 18071122Sjoe warnx("%s environment variable deprecated, " 18171122Sjoe "please use CDROM in the future.", old_envvar); 18271122Sjoe return device; 18371122Sjoe} 18471122Sjoe 18571122Sjoe 18610099Sjkhint main (int argc, char **argv) 18710099Sjkh{ 18810099Sjkh int cmd; 18910099Sjkh char *arg; 19010099Sjkh 19110099Sjkh for (;;) { 19210099Sjkh switch (getopt (argc, argv, "svhf:")) { 19310099Sjkh case EOF: 19410099Sjkh break; 19510099Sjkh case 's': 19610099Sjkh verbose = 0; 19710099Sjkh continue; 19810099Sjkh case 'v': 19910099Sjkh verbose = 2; 20010099Sjkh continue; 20110099Sjkh case 'f': 20210099Sjkh cdname = optarg; 20310099Sjkh continue; 20410099Sjkh case 'h': 20510099Sjkh default: 20610099Sjkh usage (); 20710099Sjkh } 20810099Sjkh break; 20910099Sjkh } 21010099Sjkh argc -= optind; 21110099Sjkh argv += optind; 21210099Sjkh 21313985Sache if (argc > 0 && ! strcasecmp (*argv, "help")) 21410099Sjkh usage (); 21510099Sjkh 21610099Sjkh if (! cdname) { 21770149Sdes cdname = getenv("CDROM"); 21870149Sdes } 21970149Sdes 22075324Sjoe if (! cdname) 22175324Sjoe cdname = use_cdrom_instead("MUSIC_CD"); 22275324Sjoe if (! cdname) 22375324Sjoe cdname = use_cdrom_instead("CD_DRIVE"); 22475324Sjoe if (! cdname) 22575324Sjoe cdname = use_cdrom_instead("DISC"); 22675324Sjoe if (! cdname) 22775324Sjoe cdname = use_cdrom_instead("CDPLAY"); 22875324Sjoe 22910099Sjkh if (argc > 0) { 23010099Sjkh char buf[80], *p; 23110099Sjkh int len; 23210099Sjkh 23313985Sache for (p=buf; argc-->0; ++argv) { 23410099Sjkh len = strlen (*argv); 23513985Sache 23610099Sjkh if (p + len >= buf + sizeof (buf) - 1) 23710099Sjkh usage (); 23813985Sache 23910099Sjkh if (p > buf) 24010099Sjkh *p++ = ' '; 24113985Sache 24210099Sjkh strcpy (p, *argv); 24310099Sjkh p += len; 24410099Sjkh } 24510099Sjkh *p = 0; 24610099Sjkh arg = parse (buf, &cmd); 24713985Sache return (run (cmd, arg)); 24810099Sjkh } 24910099Sjkh 25010099Sjkh if (verbose == 1) 25110099Sjkh verbose = isatty (0); 25213985Sache 25310099Sjkh if (verbose) { 25413985Sache printf ("Compact Disc Control utility, version %s\n", VERSION); 25510099Sjkh printf ("Type `?' for command list\n\n"); 25610099Sjkh } 25710099Sjkh 25810099Sjkh for (;;) { 25910099Sjkh arg = input (&cmd); 26010099Sjkh if (run (cmd, arg) < 0) { 26110099Sjkh if (verbose) 26229103Scharnier warn(NULL); 26310099Sjkh close (fd); 26410099Sjkh fd = -1; 26510099Sjkh } 26610099Sjkh fflush (stdout); 26710099Sjkh } 26810099Sjkh} 26910099Sjkh 27010099Sjkhint run (int cmd, char *arg) 27110099Sjkh{ 27296213Smaxim long speed; 27310099Sjkh int l, r, rc; 27410099Sjkh 27510099Sjkh switch (cmd) { 27613985Sache 27710099Sjkh case CMD_QUIT: 27810099Sjkh exit (0); 27910099Sjkh 28013985Sache case CMD_INFO: 28113985Sache if (fd < 0 && ! open_cd ()) 28213985Sache return (0); 28310099Sjkh 28410099Sjkh return info (arg); 28510099Sjkh 28663091Sjoe case CMD_CDID: 28763091Sjoe if (fd < 0 && ! open_cd ()) 28863091Sjoe return (0); 28963091Sjoe 29063091Sjoe return cdid (); 29163091Sjoe 29213884Sache case CMD_STATUS: 29313985Sache if (fd < 0 && ! open_cd ()) 29413985Sache return (0); 29513985Sache 29613884Sache return pstatus (arg); 29713884Sache 29877168Skris case CMD_NEXT: 29977168Skris case CMD_PREVIOUS: 30077168Skris if (fd < 0 && ! open_cd ()) 30177168Skris return (0); 30277168Skris 30377168Skris while (isspace (*arg)) 30477168Skris arg++; 30577168Skris 30677168Skris return next_prev (arg, cmd); 30777168Skris 30810099Sjkh case CMD_PAUSE: 30913985Sache if (fd < 0 && ! open_cd ()) 31013985Sache return (0); 31113985Sache 31210099Sjkh return ioctl (fd, CDIOCPAUSE); 31310099Sjkh 31410099Sjkh case CMD_RESUME: 31513985Sache if (fd < 0 && ! open_cd ()) 31613985Sache return (0); 31713985Sache 31810099Sjkh return ioctl (fd, CDIOCRESUME); 31910099Sjkh 32010099Sjkh case CMD_STOP: 32113985Sache if (fd < 0 && ! open_cd ()) 32213985Sache return (0); 32310099Sjkh 32413985Sache rc = ioctl (fd, CDIOCSTOP); 32513985Sache 32613985Sache (void) ioctl (fd, CDIOCALLOW); 32713985Sache 32813985Sache return (rc); 32913985Sache 33013884Sache case CMD_RESET: 33113985Sache if (fd < 0 && ! open_cd ()) 33213985Sache return (0); 33313985Sache 33413884Sache rc = ioctl (fd, CDIOCRESET); 33513884Sache if (rc < 0) 33613884Sache return rc; 33713884Sache close(fd); 33813884Sache fd = -1; 33913884Sache return (0); 34013884Sache 34110099Sjkh case CMD_DEBUG: 34213985Sache if (fd < 0 && ! open_cd ()) 34313985Sache return (0); 34413985Sache 34513985Sache if (! strcasecmp (arg, "on")) 34610099Sjkh return ioctl (fd, CDIOCSETDEBUG); 34713985Sache 34813985Sache if (! strcasecmp (arg, "off")) 34910099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 35013985Sache 35129103Scharnier warnx("invalid command arguments"); 35213985Sache 35310099Sjkh return (0); 35410099Sjkh 35510099Sjkh case CMD_EJECT: 35613985Sache if (fd < 0 && ! open_cd ()) 35713985Sache return (0); 35813985Sache 35910099Sjkh (void) ioctl (fd, CDIOCALLOW); 36010099Sjkh rc = ioctl (fd, CDIOCEJECT); 36110099Sjkh if (rc < 0) 36210099Sjkh return (rc); 36313865Sache return (0); 36413865Sache 36513985Sache case CMD_CLOSE: 36613985Sache if (fd < 0 && ! open_cd ()) 36713985Sache return (0); 36813985Sache 36913985Sache (void) ioctl (fd, CDIOCALLOW); 37013865Sache rc = ioctl (fd, CDIOCCLOSE); 37113865Sache if (rc < 0) 37213865Sache return (rc); 37313865Sache close(fd); 37410099Sjkh fd = -1; 37510099Sjkh return (0); 37610099Sjkh 37710099Sjkh case CMD_PLAY: 37813985Sache if (fd < 0 && ! open_cd ()) 37913985Sache return (0); 38013985Sache 38113985Sache while (isspace (*arg)) 38213985Sache arg++; 38313985Sache 38410099Sjkh return play (arg); 38510099Sjkh 38613884Sache case CMD_SET: 38713985Sache if (! strcasecmp (arg, "msf")) 38813884Sache msf = 1; 38913985Sache else if (! strcasecmp (arg, "lba")) 39013884Sache msf = 0; 39113884Sache else 39229103Scharnier warnx("invalid command arguments"); 39313884Sache return (0); 39413884Sache 39510099Sjkh case CMD_VOLUME: 39613985Sache if (fd < 0 && !open_cd ()) 39713985Sache return (0); 39810099Sjkh 39913985Sache if (! strncasecmp (arg, "left", strlen(arg))) 40010099Sjkh return ioctl (fd, CDIOCSETLEFT); 40113985Sache 40213985Sache if (! strncasecmp (arg, "right", strlen(arg))) 40310099Sjkh return ioctl (fd, CDIOCSETRIGHT); 40413985Sache 40513985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 40610099Sjkh return ioctl (fd, CDIOCSETMONO); 40713985Sache 40813985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 40910099Sjkh return ioctl (fd, CDIOCSETSTERIO); 41010099Sjkh 41113985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 41213985Sache return ioctl (fd, CDIOCSETMUTE); 41313985Sache 41410099Sjkh if (2 != sscanf (arg, "%d %d", &l, &r)) { 41529103Scharnier warnx("invalid command arguments"); 41610099Sjkh return (0); 41710099Sjkh } 41813985Sache 41910099Sjkh return setvol (l, r); 42013985Sache 42196213Smaxim case CMD_SPEED: 42296213Smaxim if (fd < 0 && ! open_cd ()) 42396213Smaxim return (0); 42496213Smaxim 42596213Smaxim errno = 0; 426105421Snjl if (strcasecmp("max", arg) == 0) 427105421Snjl speed = CDR_MAX_SPEED; 428105421Snjl else 429105421Snjl speed = strtol(arg, NULL, 10) * 177; 430105421Snjl if (speed <= 0 || speed > INT_MAX) { 43196213Smaxim warnx("invalid command arguments %s", arg); 43296213Smaxim return (0); 43396213Smaxim } 43496213Smaxim return ioctl(fd, CDRIOCREADSPEED, &speed); 43596213Smaxim 43613985Sache default: 43713985Sache case CMD_HELP: 43813985Sache help (); 43913985Sache return (0); 44013985Sache 44110099Sjkh } 44210099Sjkh} 44310099Sjkh 44410099Sjkhint play (char *arg) 44510099Sjkh{ 44610099Sjkh struct ioc_toc_header h; 44787568Smikeh unsigned int n; 44887568Smikeh int rc, start, end = 0, istart = 1, iend = 1; 44910099Sjkh 45010099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 45113985Sache 45210099Sjkh if (rc < 0) 45310099Sjkh return (rc); 45410099Sjkh 45510099Sjkh n = h.ending_track - h.starting_track + 1; 45610099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 45713985Sache 45810099Sjkh if (rc < 0) 45910099Sjkh return (rc); 46010099Sjkh 46113989Sache if (! arg || ! *arg) { 46213985Sache /* Play the whole disc */ 46313989Sache if (msf) 46413989Sache return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 46513989Sache toc_buffer[n].addr.msf.second, 46613989Sache toc_buffer[n].addr.msf.frame)); 46713989Sache else 46813989Sache return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); 46913989Sache } 47010099Sjkh 47110099Sjkh if (strchr (arg, '#')) { 47213985Sache /* Play block #blk [ len ] */ 47310099Sjkh int blk, len = 0; 47410099Sjkh 47510099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 47613985Sache 1 != sscanf (arg, "#%d", &blk)) 47713985Sache goto Clean_up; 47813985Sache 47913989Sache if (len == 0) { 48013989Sache if (msf) 48113989Sache len = msf2lba (toc_buffer[n].addr.msf.minute, 48213989Sache toc_buffer[n].addr.msf.second, 48313989Sache toc_buffer[n].addr.msf.frame) - blk; 48413989Sache else 48513989Sache len = ntohl(toc_buffer[n].addr.lba) - blk; 48613989Sache } 48710099Sjkh return play_blocks (blk, len); 48810099Sjkh } 48910099Sjkh 49010099Sjkh if (strchr (arg, ':')) { 49110099Sjkh /* 49210099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 49313985Sache * 49413985Sache * Will now also undestand timed addresses relative 49513985Sache * to the beginning of a track in the form... 49613985Sache * 49713985Sache * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 49810099Sjkh */ 49913985Sache unsigned tr1, tr2; 50013985Sache unsigned m1, m2, s1, s2, f1, f2; 50113989Sache unsigned char tm, ts, tf; 50210099Sjkh 50313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 50413985Sache if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", 50513985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) 50613985Sache goto Play_Relative_Addresses; 50713985Sache 50813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 50913985Sache if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d", 51013985Sache &tr1, &m1, &s1, &tr2, &m2, &s2, &f2)) 51113985Sache goto Play_Relative_Addresses; 51213985Sache 51313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51413985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", 51513985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) 51613985Sache goto Play_Relative_Addresses; 51713985Sache 51813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51913985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d", 52013985Sache &tr1, &m1, &s1, &f1, &m2, &s2, &f2)) 52113985Sache goto Play_Relative_Addresses; 52213985Sache 52313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52413985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d:%d", 52513985Sache &tr1, &m1, &s1, &f1, &m2, &s2)) 52613985Sache goto Play_Relative_Addresses; 52713985Sache 52813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52913985Sache if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", 53013985Sache &tr1, &m1, &s1, &m2, &s2, &f2)) 53113985Sache goto Play_Relative_Addresses; 53213985Sache 53313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53413985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d %d", 53513985Sache &tr1, &m1, &s1, &f1, &tr2, &m2)) 53613985Sache goto Play_Relative_Addresses; 53713985Sache 53813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53913985Sache if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) 54013985Sache goto Play_Relative_Addresses; 54113985Sache 54213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54313985Sache if (5 == sscanf (arg, "%d %d:%d %d %d", 54413985Sache &tr1, &m1, &s1, &tr2, &m2)) 54513985Sache goto Play_Relative_Addresses; 54613985Sache 54713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54813985Sache if (5 == sscanf (arg, "%d %d:%d.%d %d", 54913985Sache &tr1, &m1, &s1, &f1, &tr2)) 55013985Sache goto Play_Relative_Addresses; 55113985Sache 55213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55313985Sache if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 55413985Sache goto Play_Relative_Addresses; 55513985Sache 55613985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55713985Sache if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 55813985Sache goto Play_Relative_Addresses; 55913985Sache 56013985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56113985Sache if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) 56213985Sache goto Play_Relative_Addresses; 56313985Sache 56413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56513985Sache goto Try_Absolute_Timed_Addresses; 56613985Sache 56713985SachePlay_Relative_Addresses: 56813985Sache if (! tr1) 56913985Sache tr1 = 1; 57013985Sache else if (tr1 > n) 57113985Sache tr1 = n; 57213985Sache 573112559Seivind tr1--; 574112559Seivind 57513989Sache if (msf) { 57613989Sache tm = toc_buffer[tr1].addr.msf.minute; 57713989Sache ts = toc_buffer[tr1].addr.msf.second; 57813989Sache tf = toc_buffer[tr1].addr.msf.frame; 57913989Sache } else 58013989Sache lba2msf(ntohl(toc_buffer[tr1].addr.lba), 58113989Sache &tm, &ts, &tf); 58213989Sache if ((m1 > tm) 58313989Sache || ((m1 == tm) 58413989Sache && ((s1 > ts) 58513989Sache || ((s1 == ts) 58613989Sache && (f1 > tf))))) { 58713985Sache printf ("Track %d is not that long.\n", tr1); 58813985Sache return (0); 58913985Sache } 59013985Sache 59113989Sache f1 += tf; 59213985Sache if (f1 >= 75) { 59313985Sache s1 += f1 / 75; 59413985Sache f1 %= 75; 59513985Sache } 59613985Sache 59713989Sache s1 += ts; 59813985Sache if (s1 >= 60) { 59913985Sache m1 += s1 / 60; 60013985Sache s1 %= 60; 60113985Sache } 60213985Sache 60313989Sache m1 += tm; 60413985Sache 60513985Sache if (! tr2) { 60613985Sache if (m2 || s2 || f2) { 60713985Sache tr2 = tr1; 60813985Sache f2 += f1; 60913985Sache if (f2 >= 75) { 61013985Sache s2 += f2 / 75; 61113985Sache f2 %= 75; 61213985Sache } 61313985Sache 61413985Sache s2 += s1; 61513985Sache if (s2 > 60) { 61613985Sache m2 += s2 / 60; 61713985Sache s2 %= 60; 61813985Sache } 61913985Sache 62013985Sache m2 += m1; 62113985Sache } else { 62213985Sache tr2 = n; 62313989Sache if (msf) { 62413989Sache m2 = toc_buffer[n].addr.msf.minute; 62513989Sache s2 = toc_buffer[n].addr.msf.second; 62613989Sache f2 = toc_buffer[n].addr.msf.frame; 62713989Sache } else { 62813989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 62913989Sache &tm, &ts, &tf); 63013989Sache m2 = tm; 63113989Sache s2 = ts; 63213989Sache f2 = tf; 63313989Sache } 63413985Sache } 63513985Sache } else if (tr2 > n) { 63613985Sache tr2 = n; 63713985Sache m2 = s2 = f2 = 0; 63813985Sache } else { 63913985Sache if (m2 || s2 || f2) 64013985Sache tr2--; 64113989Sache if (msf) { 64213989Sache tm = toc_buffer[tr2].addr.msf.minute; 64313989Sache ts = toc_buffer[tr2].addr.msf.second; 64413989Sache tf = toc_buffer[tr2].addr.msf.frame; 64513989Sache } else 64613989Sache lba2msf(ntohl(toc_buffer[tr2].addr.lba), 64713989Sache &tm, &ts, &tf); 64813989Sache f2 += tf; 64913985Sache if (f2 >= 75) { 65013985Sache s2 += f2 / 75; 65113985Sache f2 %= 75; 65213985Sache } 65313985Sache 65413989Sache s2 += ts; 65513985Sache if (s2 > 60) { 65613985Sache m2 += s2 / 60; 65713985Sache s2 %= 60; 65813985Sache } 65913985Sache 66013989Sache m2 += tm; 66113985Sache } 66213985Sache 66313989Sache if (msf) { 66413989Sache tm = toc_buffer[n].addr.msf.minute; 66513989Sache ts = toc_buffer[n].addr.msf.second; 66613989Sache tf = toc_buffer[n].addr.msf.frame; 66713989Sache } else 66813989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 66913989Sache &tm, &ts, &tf); 67013985Sache if ((tr2 < n) 67113989Sache && ((m2 > tm) 67213989Sache || ((m2 == tm) 67313989Sache && ((s2 > ts) 67413989Sache || ((s2 == ts) 67513989Sache && (f2 > tf)))))) { 67613985Sache printf ("The playing time of the disc is not that long.\n"); 67713985Sache return (0); 67813985Sache } 67913985Sache return (play_msf (m1, s1, f1, m2, s2, f2)); 68013985Sache 68113985SacheTry_Absolute_Timed_Addresses: 68213985Sache if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", 68313985Sache &m1, &s1, &f1, &m2, &s2, &f2) && 68410099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 68510099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 68610099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 68710099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 68810099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 68913985Sache goto Clean_up; 69013985Sache 69110099Sjkh if (m2 == 0) { 69213989Sache if (msf) { 69313989Sache m2 = toc_buffer[n].addr.msf.minute; 69413989Sache s2 = toc_buffer[n].addr.msf.second; 69513989Sache f2 = toc_buffer[n].addr.msf.frame; 69613989Sache } else { 69713989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 69813989Sache &tm, &ts, &tf); 69913989Sache m2 = tm; 70013989Sache s2 = ts; 70113989Sache f2 = tf; 70213989Sache } 70310099Sjkh } 70410099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 70510099Sjkh } 70610099Sjkh 70710099Sjkh /* 70810099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 70910099Sjkh */ 71010099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 71110099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 71210099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 71310099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 71410099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 71510099Sjkh 1 != sscanf (arg, "%d", &start)) 71613985Sache goto Clean_up; 71713985Sache 71810099Sjkh if (end == 0) 71910099Sjkh end = n; 72013985Sache return (play_track (start, istart, end, iend)); 72113985Sache 72213985SacheClean_up: 72329103Scharnier warnx("invalid command arguments"); 72413985Sache return (0); 72510099Sjkh} 72610099Sjkh 72777168Skrisint next_prev (char *arg, int cmd) 72877168Skris{ 72977168Skris struct ioc_toc_header h; 73077168Skris int dir, junk, n, off, rc, trk; 73177168Skris 73277168Skris dir = (cmd == CMD_NEXT) ? 1 : -1; 73377168Skris rc = ioctl (fd, CDIOREADTOCHEADER, &h); 73477168Skris if (rc < 0) 73577168Skris return (rc); 73677168Skris 73777168Skris n = h.ending_track - h.starting_track + 1; 73877168Skris rc = status (&trk, &junk, &junk, &junk); 73977168Skris if (rc < 0) 74077168Skris return (-1); 74177168Skris 74277168Skris if (arg && *arg) { 74377168Skris if (sscanf (arg, "%u", &off) != 1) { 74477168Skris warnx("invalid command argument"); 74577168Skris return (0); 74677168Skris } else 74777168Skris trk += off * dir; 74877168Skris } else 74977168Skris trk += dir; 75077168Skris 75177168Skris if (trk > h.ending_track) 75277168Skris trk = 1; 75377168Skris 75477168Skris return (play_track (trk, 1, n, 1)); 75577168Skris} 75677168Skris 75787568Smikehconst char *strstatus (int sts) 75810099Sjkh{ 75910099Sjkh switch (sts) { 76087573Smikeh case ASTS_INVALID: return ("invalid"); 76187573Smikeh case ASTS_PLAYING: return ("playing"); 76287573Smikeh case ASTS_PAUSED: return ("paused"); 76387573Smikeh case ASTS_COMPLETED: return ("completed"); 76487573Smikeh case ASTS_ERROR: return ("error"); 76587573Smikeh case ASTS_VOID: return ("void"); 76687573Smikeh default: return ("??"); 76710099Sjkh } 76810099Sjkh} 76910099Sjkh 77013884Sacheint pstatus (char *arg) 77110099Sjkh{ 77210099Sjkh struct ioc_vol v; 77313888Sache struct ioc_read_subchannel ss; 77413888Sache struct cd_sub_channel_info data; 77513884Sache int rc, trk, m, s, f; 77632782Sjmz int what = 0; 77777168Skris char *p, vmcn[(4 * 15) + 1]; 77810099Sjkh 77932782Sjmz while ((p = strtok(arg, " \t"))) { 78032782Sjmz arg = 0; 78132782Sjmz if (!strncasecmp(p, "audio", strlen(p))) 78232782Sjmz what |= STATUS_AUDIO; 78332782Sjmz else if (!strncasecmp(p, "media", strlen(p))) 78432782Sjmz what |= STATUS_MEDIA; 78532782Sjmz else if (!strncasecmp(p, "volume", strlen(p))) 78632782Sjmz what |= STATUS_VOLUME; 78732782Sjmz else { 78832782Sjmz warnx("invalid command arguments"); 78932782Sjmz return 0; 79032782Sjmz } 79132782Sjmz } 79232782Sjmz if (!what) 79332782Sjmz what = STATUS_AUDIO|STATUS_MEDIA|STATUS_VOLUME; 79432782Sjmz if (what & STATUS_AUDIO) { 79532782Sjmz rc = status (&trk, &m, &s, &f); 79632782Sjmz if (rc >= 0) 79710099Sjkh if (verbose) 79832782Sjmz printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 79932782Sjmz rc, strstatus (rc), trk, m, s, f); 80010099Sjkh else 80132782Sjmz printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 80232782Sjmz else 80313888Sache printf ("No current status info available\n"); 80432782Sjmz } 80532782Sjmz if (what & STATUS_MEDIA) { 80632782Sjmz bzero (&ss, sizeof (ss)); 80732782Sjmz ss.data = &data; 80832782Sjmz ss.data_len = sizeof (data); 80932782Sjmz ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 81032782Sjmz ss.data_format = CD_MEDIA_CATALOG; 81132782Sjmz rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); 81232782Sjmz if (rc >= 0) { 81313889Sache printf("Media catalog is %sactive", 81487573Smikeh ss.data->what.media_catalog.mc_valid ? "": "in"); 81516736Sache if (ss.data->what.media_catalog.mc_valid && 81616736Sache ss.data->what.media_catalog.mc_number[0]) 81777168Skris { 81877168Skris strvisx (vmcn, ss.data->what.media_catalog.mc_number, 81977168Skris (sizeof (vmcn) - 1) / 4, VIS_OCTAL | VIS_NL); 82077168Skris printf(", number \"%.*s\"", (int)sizeof (vmcn), vmcn); 82177168Skris } 82213889Sache putchar('\n'); 82332782Sjmz } else 82413888Sache printf("No media catalog info available\n"); 82532782Sjmz } 82632782Sjmz if (what & STATUS_VOLUME) { 82732782Sjmz rc = ioctl (fd, CDIOCGETVOL, &v); 82832782Sjmz if (rc >= 0) 82910099Sjkh if (verbose) 83032782Sjmz printf ("Left volume = %d, right volume = %d\n", 83132782Sjmz v.vol[0], v.vol[1]); 83210099Sjkh else 83332782Sjmz printf ("%d %d\n", v.vol[0], v.vol[1]); 83432782Sjmz else 83513888Sache printf ("No volume level info available\n"); 83632782Sjmz } 83713884Sache return(0); 83813884Sache} 83910099Sjkh 84063091Sjoe/* 84163091Sjoe * dbprog_sum 84263091Sjoe * Convert an integer to its text string representation, and 84363091Sjoe * compute its checksum. Used by dbprog_discid to derive the 84463091Sjoe * disc ID. 84563091Sjoe * 84663091Sjoe * Args: 84763091Sjoe * n - The integer value. 84863091Sjoe * 84963091Sjoe * Return: 85063091Sjoe * The integer checksum. 85163091Sjoe */ 85263091Sjoestatic int 85363091Sjoedbprog_sum(int n) 85463091Sjoe{ 85563091Sjoe char buf[12], 85663091Sjoe *p; 85763091Sjoe int ret = 0; 85863091Sjoe 85963091Sjoe /* For backward compatibility this algorithm must not change */ 86063091Sjoe sprintf(buf, "%u", n); 86163091Sjoe for (p = buf; *p != '\0'; p++) 86263091Sjoe ret += (*p - '0'); 86363091Sjoe 86463091Sjoe return(ret); 86563091Sjoe} 86663091Sjoe 86763091Sjoe 86863091Sjoe/* 86963091Sjoe * dbprog_discid 87063091Sjoe * Compute a magic disc ID based on the number of tracks, 87163091Sjoe * the length of each track, and a checksum of the string 87263091Sjoe * that represents the offset of each track. 87363091Sjoe * 87463091Sjoe * Args: 87563091Sjoe * s - Pointer to the curstat_t structure. 87663091Sjoe * 87763091Sjoe * Return: 87863091Sjoe * The integer disc ID. 87963091Sjoe */ 88063091Sjoestatic u_int 88163091Sjoedbprog_discid() 88263091Sjoe{ 88363091Sjoe struct ioc_toc_header h; 88463091Sjoe int rc; 88563091Sjoe int i, ntr, 88663091Sjoe t = 0, 88763091Sjoe n = 0; 88863091Sjoe 88963091Sjoe rc = ioctl (fd, CDIOREADTOCHEADER, &h); 89063091Sjoe if (rc < 0) 89163091Sjoe return 0; 89263091Sjoe ntr = h.ending_track - h.starting_track + 1; 89363091Sjoe i = msf; 89463091Sjoe msf = 1; 89563091Sjoe rc = read_toc_entrys ((ntr + 1) * sizeof (struct cd_toc_entry)); 89663091Sjoe msf = i; 89763091Sjoe if (rc < 0) 89863091Sjoe return 0; 89963091Sjoe /* For backward compatibility this algorithm must not change */ 90063091Sjoe for (i = 0; i < ntr; i++) { 90163091Sjoe#define TC_MM(a) toc_buffer[a].addr.msf.minute 90263091Sjoe#define TC_SS(a) toc_buffer[a].addr.msf.second 90363091Sjoe n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i)); 90463091Sjoe 90563091Sjoe t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - 90687573Smikeh ((TC_MM(i) * 60) + TC_SS(i)); 90763091Sjoe } 90863091Sjoe 90963091Sjoe return((n % 0xff) << 24 | t << 8 | ntr); 91063091Sjoe} 91163091Sjoe 91263091Sjoeint cdid () 91363091Sjoe{ 91463091Sjoe u_int id; 91563091Sjoe 91663091Sjoe id = dbprog_discid(); 91763091Sjoe if (id) 91863091Sjoe { 91963091Sjoe if (verbose) 92063091Sjoe printf ("CDID="); 92163091Sjoe printf ("%08x\n",id); 92263091Sjoe } 92363091Sjoe return id ? 0 : 1; 92463091Sjoe} 92563091Sjoe 92687568Smikehint info (char *arg __unused) 92713884Sache{ 92813884Sache struct ioc_toc_header h; 92913884Sache int rc, i, n; 93013884Sache 93110099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 93213888Sache if (rc >= 0) { 93310099Sjkh if (verbose) 93410099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 93510099Sjkh h.starting_track, h.ending_track, h.len); 93610099Sjkh else 93710099Sjkh printf ("%d %d %d\n", h.starting_track, 93810099Sjkh h.ending_track, h.len); 93913888Sache } else { 94029103Scharnier warn("getting toc header"); 94110099Sjkh return (rc); 94210099Sjkh } 94310099Sjkh 94410099Sjkh n = h.ending_track - h.starting_track + 1; 94510099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 94610099Sjkh if (rc < 0) 94710099Sjkh return (rc); 94813985Sache 94910099Sjkh if (verbose) { 95010099Sjkh printf ("track start duration block length type\n"); 95110099Sjkh printf ("-------------------------------------------------\n"); 95210099Sjkh } 95313985Sache 95410099Sjkh for (i = 0; i < n; i++) { 95510099Sjkh printf ("%5d ", toc_buffer[i].track); 95610099Sjkh prtrack (toc_buffer + i, 0); 95710099Sjkh } 95813867Sache printf ("%5d ", toc_buffer[n].track); 95910099Sjkh prtrack (toc_buffer + n, 1); 96010099Sjkh return (0); 96110099Sjkh} 96210099Sjkh 96313985Sachevoid lba2msf (unsigned long lba, u_char *m, u_char *s, u_char *f) 96410099Sjkh{ 96587573Smikeh lba += 150; /* block start offset */ 96687573Smikeh lba &= 0xffffff; /* negative lbas use only 24 bits */ 96710099Sjkh *m = lba / (60 * 75); 96810099Sjkh lba %= (60 * 75); 96910099Sjkh *s = lba / 75; 97010099Sjkh *f = lba % 75; 97110099Sjkh} 97210099Sjkh 97313985Sacheunsigned int msf2lba (u_char m, u_char s, u_char f) 97410099Sjkh{ 97510099Sjkh return (((m * 60) + s) * 75 + f) - 150; 97610099Sjkh} 97710099Sjkh 97810099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag) 97910099Sjkh{ 98010099Sjkh int block, next, len; 98110099Sjkh u_char m, s, f; 98210099Sjkh 98313884Sache if (msf) { 98413884Sache /* Print track start */ 98513884Sache printf ("%2d:%02d.%02d ", e->addr.msf.minute, 98613884Sache e->addr.msf.second, e->addr.msf.frame); 98710099Sjkh 98813884Sache block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 98913884Sache e->addr.msf.frame); 99013884Sache } else { 99113884Sache block = ntohl(e->addr.lba); 99213884Sache lba2msf(block, &m, &s, &f); 99313884Sache /* Print track start */ 99413884Sache printf ("%2d:%02d.%02d ", m, s, f); 99513884Sache } 99610099Sjkh if (lastflag) { 99710099Sjkh /* Last track -- print block */ 99810099Sjkh printf (" - %6d - -\n", block); 99910099Sjkh return; 100010099Sjkh } 100110099Sjkh 100213884Sache if (msf) 100313884Sache next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 100413884Sache e[1].addr.msf.frame); 100513884Sache else 100613884Sache next = ntohl(e[1].addr.lba); 100710099Sjkh len = next - block; 1008103861Smaxim /* Take into account a start offset time. */ 1009103861Smaxim lba2msf (len - 150, &m, &s, &f); 101010099Sjkh 101110099Sjkh /* Print duration, block, length, type */ 101210099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 101313985Sache (e->control & 4) ? "data" : "audio"); 101410099Sjkh} 101510099Sjkh 101610099Sjkhint play_track (int tstart, int istart, int tend, int iend) 101710099Sjkh{ 101810099Sjkh struct ioc_play_track t; 101910099Sjkh 102010099Sjkh t.start_track = tstart; 102110099Sjkh t.start_index = istart; 102210099Sjkh t.end_track = tend; 102310099Sjkh t.end_index = iend; 102413985Sache 102510099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 102610099Sjkh} 102710099Sjkh 102810099Sjkhint play_blocks (int blk, int len) 102910099Sjkh{ 103013985Sache struct ioc_play_blocks t; 103110099Sjkh 103210099Sjkh t.blk = blk; 103310099Sjkh t.len = len; 103413985Sache 103510099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 103610099Sjkh} 103710099Sjkh 103813985Sacheint setvol (int left, int right) 103910099Sjkh{ 104013985Sache struct ioc_vol v; 104110099Sjkh 104213985Sache v.vol[0] = left; 104313985Sache v.vol[1] = right; 104410099Sjkh v.vol[2] = 0; 104510099Sjkh v.vol[3] = 0; 104613985Sache 104710099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 104810099Sjkh} 104910099Sjkh 105010099Sjkhint read_toc_entrys (int len) 105110099Sjkh{ 105210099Sjkh struct ioc_read_toc_entry t; 105310099Sjkh 105413884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 105513737Sache t.starting_track = 0; 105610099Sjkh t.data_len = len; 105710099Sjkh t.data = toc_buffer; 105813985Sache 105913985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 106010099Sjkh} 106110099Sjkh 106210099Sjkhint play_msf (int start_m, int start_s, int start_f, 106313985Sache int end_m, int end_s, int end_f) 106410099Sjkh{ 106587573Smikeh struct ioc_play_msf a; 106610099Sjkh 106710099Sjkh a.start_m = start_m; 106810099Sjkh a.start_s = start_s; 106910099Sjkh a.start_f = start_f; 107010099Sjkh a.end_m = end_m; 107110099Sjkh a.end_s = end_s; 107210099Sjkh a.end_f = end_f; 107313985Sache 107410099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 107510099Sjkh} 107610099Sjkh 107710099Sjkhint status (int *trk, int *min, int *sec, int *frame) 107810099Sjkh{ 107910099Sjkh struct ioc_read_subchannel s; 108010099Sjkh struct cd_sub_channel_info data; 108113884Sache u_char mm, ss, ff; 108210099Sjkh 108310099Sjkh bzero (&s, sizeof (s)); 108410099Sjkh s.data = &data; 108510099Sjkh s.data_len = sizeof (data); 108613884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 108710099Sjkh s.data_format = CD_CURRENT_POSITION; 108813985Sache 108910099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 109010099Sjkh return -1; 109113985Sache 109210099Sjkh *trk = s.data->what.position.track_number; 109313884Sache if (msf) { 109413884Sache *min = s.data->what.position.reladdr.msf.minute; 109513884Sache *sec = s.data->what.position.reladdr.msf.second; 109613884Sache *frame = s.data->what.position.reladdr.msf.frame; 109713884Sache } else { 109813884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 109913884Sache &mm, &ss, &ff); 110013884Sache *min = mm; 110113884Sache *sec = ss; 110213884Sache *frame = ff; 110313884Sache } 110413985Sache 110510099Sjkh return s.data->header.audio_status; 110610099Sjkh} 110710099Sjkh 110850039Smdoddconst char * 110950039Smdoddcdcontrol_prompt() 111010099Sjkh{ 111150039Smdodd return ("cdcontrol> "); 111250039Smdodd} 111350039Smdodd 111450039Smdoddchar * 111550039Smdoddinput (int *cmd) 111650039Smdodd{ 111750039Smdodd#define MAXLINE 80 111850039Smdodd static EditLine *el = NULL; 111950039Smdodd static History *hist = NULL; 112084261Sobrien HistEvent he; 112150039Smdodd static char buf[MAXLINE]; 112250039Smdodd int num = 0; 112350071Smdodd int len; 112450039Smdodd const char *bp = NULL; 112510099Sjkh char *p; 112610099Sjkh 112710099Sjkh do { 112850039Smdodd if (verbose) { 112950039Smdodd if (!el) { 113084261Sobrien el = el_init("cdcontrol", stdin, stdout, 113184261Sobrien stderr); 113250039Smdodd hist = history_init(); 113384261Sobrien history(hist, &he, H_EVENT, 100); 113450039Smdodd el_set(el, EL_HIST, history, hist); 113550039Smdodd el_set(el, EL_EDITOR, "emacs"); 113650039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 113750039Smdodd el_set(el, EL_SIGNAL, 1); 113850042Smdodd el_source(el, NULL); 113950039Smdodd } 114063070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 114163070Smckay *cmd = CMD_QUIT; 114263070Smckay fprintf (stderr, "\r\n"); 114350039Smdodd return (0); 114463070Smckay } 114550039Smdodd 114650071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 114750071Smdodd memcpy(buf, bp, len); 114850071Smdodd buf[len] = 0; 114984261Sobrien history(hist, &he, H_ENTER, bp); 115050039Smdodd#undef MAXLINE 115150039Smdodd 115250039Smdodd } else { 115350039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 115450039Smdodd *cmd = CMD_QUIT; 115550039Smdodd fprintf (stderr, "\r\n"); 115650039Smdodd return (0); 115750039Smdodd } 115810099Sjkh } 115910099Sjkh p = parse (buf, cmd); 116010099Sjkh } while (! p); 116110099Sjkh return (p); 116210099Sjkh} 116310099Sjkh 116410099Sjkhchar *parse (char *buf, int *cmd) 116510099Sjkh{ 116610099Sjkh struct cmdtab *c; 116710099Sjkh char *p; 116887568Smikeh unsigned int len; 116910099Sjkh 117013985Sache for (p=buf; isspace (*p); p++) 117113985Sache continue; 117210099Sjkh 117313985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 117413985Sache *cmd = CMD_PLAY; 117513985Sache return (p); 117677168Skris } else if (*p == '+') { 117777168Skris *cmd = CMD_NEXT; 117877168Skris return (p + 1); 117977168Skris } else if (*p == '-') { 118077168Skris *cmd = CMD_PREVIOUS; 118177168Skris return (p + 1); 118213985Sache } 118310099Sjkh 118413985Sache for (buf = p; *p && ! isspace (*p); p++) 118513985Sache continue; 118696214Smaxim 118713985Sache len = p - buf; 118810099Sjkh if (! len) 118910099Sjkh return (0); 119013985Sache 119187573Smikeh if (*p) { /* It must be a spacing character! */ 119213985Sache char *q; 119313985Sache 119413985Sache *p++ = 0; 119513985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 119613985Sache continue; 119713985Sache *q = 0; 119813985Sache } 119913985Sache 120010099Sjkh *cmd = -1; 120110099Sjkh for (c=cmdtab; c->name; ++c) { 120213985Sache /* Is it an exact match? */ 120313985Sache if (! strcasecmp (buf, c->name)) { 120413985Sache *cmd = c->command; 120513985Sache break; 120613985Sache } 120713985Sache 120813985Sache /* Try short hand forms then... */ 120913985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 121013985Sache if (*cmd != -1 && *cmd != c->command) { 121129103Scharnier warnx("ambiguous command"); 121213985Sache return (0); 121313985Sache } 121410099Sjkh *cmd = c->command; 121513985Sache } 121613985Sache } 121710099Sjkh 121810099Sjkh if (*cmd == -1) { 121929103Scharnier warnx("invalid command, enter ``help'' for commands"); 122010099Sjkh return (0); 122110099Sjkh } 122213985Sache 122313985Sache while (isspace (*p)) 122413985Sache p++; 122510099Sjkh return p; 122610099Sjkh} 122710099Sjkh 122810099Sjkhint open_cd () 122910099Sjkh{ 123054164Sjoe char devbuf[MAXPATHLEN]; 123110099Sjkh 123210099Sjkh if (fd > -1) 123310099Sjkh return (1); 123413985Sache 1235122855Seivind if (cdname) { 1236122855Seivind if (*cdname == '/') { 1237122855Seivind snprintf (devbuf, MAXPATHLEN, "%s", cdname); 1238122855Seivind } else { 1239122855Seivind snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 1240122855Seivind } 1241122855Seivind fd = open (devbuf, O_RDONLY); 124261105Smsmith } else { 1243122855Seivind fd = open("/dev/cdrom", O_RDONLY); 1244122855Seivind if (fd < 0 && errno == ENOENT) 1245122855Seivind fd = open("/dev/cd0", O_RDONLY); 1246122855Seivind if (fd < 0 && errno == ENOENT) 1247122855Seivind fd = open("/dev/acd0", O_RDONLY); 124854164Sjoe } 124913985Sache 125010099Sjkh if (fd < 0) { 125113985Sache if (errno == ENXIO) { 125213985Sache /* ENXIO has an overloaded meaning here. 125313985Sache * The original "Device not configured" should 125413985Sache * be interpreted as "No disc in drive %s". */ 125529103Scharnier warnx("no disc in drive %s", devbuf); 125613985Sache return (0); 125710099Sjkh } 125829103Scharnier err(1, "%s", devbuf); 125910099Sjkh } 126010099Sjkh return (1); 126110099Sjkh} 1262