cdcontrol.c revision 105421
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 2129103Scharnier#ifndef lint 2229103Scharnierstatic const char rcsid[] = 2350479Speter "$FreeBSD: head/usr.sbin/cdcontrol/cdcontrol.c 105421 2002-10-18 22:03:39Z njl $"; 2429103Scharnier#endif /* not lint */ 2529103Scharnier 2677168Skris#include <sys/cdio.h> 2796213Smaxim#include <sys/cdrio.h> 2877168Skris#include <sys/file.h> 2977168Skris#include <sys/ioctl.h> 3077168Skris#include <sys/param.h> 3190868Smike#include <arpa/inet.h> 3213985Sache#include <ctype.h> 3329103Scharnier#include <err.h> 3429103Scharnier#include <errno.h> 3577168Skris#include <histedit.h> 3696213Smaxim#include <limits.h> 3769793Sobrien#include <paths.h> 3810099Sjkh#include <stdio.h> 3910099Sjkh#include <stdlib.h> 4010099Sjkh#include <string.h> 4110099Sjkh#include <unistd.h> 4277168Skris#include <vis.h> 4310099Sjkh 4413884Sache#define VERSION "2.0" 4510099Sjkh 4687573Smikeh#define ASTS_INVALID 0x00 /* Audio status byte not valid */ 4787573Smikeh#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 4887573Smikeh#define ASTS_PAUSED 0x12 /* Audio play operation paused */ 4987573Smikeh#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 5087573Smikeh#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 5187573Smikeh#define ASTS_VOID 0x15 /* No current audio status to return */ 5210099Sjkh 5313985Sache#ifndef DEFAULT_CD_DRIVE 5413985Sache# define DEFAULT_CD_DRIVE "/dev/cd0c" 5513985Sache#endif 5613985Sache 5713985Sache#ifndef DEFAULT_CD_PARTITION 5813985Sache# define DEFAULT_CD_PARTITION "c" 5913985Sache#endif 6013985Sache 6187573Smikeh#define CMD_DEBUG 1 6287573Smikeh#define CMD_EJECT 2 6387573Smikeh#define CMD_HELP 3 6487573Smikeh#define CMD_INFO 4 6587573Smikeh#define CMD_PAUSE 5 6687573Smikeh#define CMD_PLAY 6 6787573Smikeh#define CMD_QUIT 7 6887573Smikeh#define CMD_RESUME 8 6987573Smikeh#define CMD_STOP 9 7087573Smikeh#define CMD_VOLUME 10 7187573Smikeh#define CMD_CLOSE 11 7287573Smikeh#define CMD_RESET 12 7387573Smikeh#define CMD_SET 13 7487573Smikeh#define CMD_STATUS 14 7587573Smikeh#define CMD_CDID 15 7687573Smikeh#define CMD_NEXT 16 7787573Smikeh#define CMD_PREVIOUS 17 7896213Smaxim#define CMD_SPEED 18 7987573Smikeh#define STATUS_AUDIO 0x1 8087573Smikeh#define STATUS_MEDIA 0x2 8187573Smikeh#define STATUS_VOLUME 0x4 8213985Sache 8310099Sjkhstruct cmdtab { 8410099Sjkh int command; 8587568Smikeh const char *name; 8687568Smikeh unsigned min; 8787568Smikeh const char *args; 8810099Sjkh} cmdtab[] = { 8987573Smikeh{ CMD_CLOSE, "close", 1, "" }, 9087573Smikeh{ CMD_DEBUG, "debug", 1, "on | off" }, 9187573Smikeh{ CMD_EJECT, "eject", 1, "" }, 9287573Smikeh{ CMD_HELP, "?", 1, 0 }, 9387573Smikeh{ CMD_HELP, "help", 1, "" }, 9487573Smikeh{ CMD_INFO, "info", 1, "" }, 9587573Smikeh{ CMD_NEXT, "next", 1, "" }, 9687573Smikeh{ CMD_PAUSE, "pause", 2, "" }, 9787573Smikeh{ CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 9887573Smikeh{ CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 9987573Smikeh{ CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 10087573Smikeh{ CMD_PLAY, "play", 1, "[#block [len]]" }, 10187573Smikeh{ CMD_PREVIOUS, "previous", 2, "" }, 10287573Smikeh{ CMD_QUIT, "quit", 1, "" }, 10387573Smikeh{ CMD_RESET, "reset", 4, "" }, 10487573Smikeh{ CMD_RESUME, "resume", 1, "" }, 10587573Smikeh{ CMD_SET, "set", 2, "msf | lba" }, 10687573Smikeh{ CMD_STATUS, "status", 1, "[audio | media | volume]" }, 10787573Smikeh{ CMD_STOP, "stop", 3, "" }, 10887573Smikeh{ CMD_VOLUME, "volume", 1, 10987573Smikeh "<l> <r> | left | right | mute | mono | stereo" }, 11087573Smikeh{ CMD_CDID, "cdid", 2, "" }, 11196213Smaxim{ CMD_SPEED, "speed", 2, "speed" }, 11287573Smikeh{ 0, NULL, 0, NULL } 11310099Sjkh}; 11410099Sjkh 11587573Smikehstruct cd_toc_entry toc_buffer[100]; 11610099Sjkh 11787573Smikehconst char *cdname; 11887573Smikehint fd = -1; 11987573Smikehint verbose = 1; 12087573Smikehint msf = 1; 12110099Sjkh 12299800Salfredint setvol(int, int); 12399800Salfredint read_toc_entrys(int); 12499800Salfredint play_msf(int, int, int, int, int, int); 12599800Salfredint play_track(int, int, int, int); 12699800Salfredint get_vol(int *, int *); 12799800Salfredint status(int *, int *, int *, int *); 12899800Salfredint open_cd(void); 12999800Salfredint next_prev(char *arg, int); 13099800Salfredint play(char *arg); 13199800Salfredint info(char *arg); 13299800Salfredint cdid(void); 13399800Salfredint pstatus(char *arg); 13499800Salfredchar *input(int *); 13599800Salfredvoid prtrack(struct cd_toc_entry *e, int lastflag); 13699800Salfredvoid lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f); 13799800Salfredunsigned int msf2lba(u_char m, u_char s, u_char f); 13899800Salfredint play_blocks(int blk, int len); 13999800Salfredint run(int cmd, char *arg); 14099800Salfredchar *parse(char *buf, int *cmd); 14199800Salfredvoid help(void); 14299800Salfredvoid usage(void); 14399800Salfredchar *use_cdrom_instead(const char *); 14499800Salfred__const char *strstatus(int); 14599800Salfredstatic u_int dbprog_discid(void); 14699800Salfred__const char *cdcontrol_prompt(void); 14710099Sjkh 14810099Sjkhvoid help () 14910099Sjkh{ 15010099Sjkh struct cmdtab *c; 15187568Smikeh const char *s; 15287568Smikeh char n; 15313985Sache int i; 15410099Sjkh 15510099Sjkh for (c=cmdtab; c->name; ++c) { 15610099Sjkh if (! c->args) 15710099Sjkh continue; 15813985Sache printf("\t"); 15913985Sache for (i = c->min, s = c->name; *s; s++, i--) { 16013985Sache if (i > 0) 16113985Sache n = toupper(*s); 16213985Sache else 16313985Sache n = *s; 16413985Sache putchar(n); 16513985Sache } 16610099Sjkh if (*c->args) 16710099Sjkh printf (" %s", c->args); 16810099Sjkh printf ("\n"); 16910099Sjkh } 17013985Sache printf ("\n\tThe word \"play\" is not required for the play commands.\n"); 17113985Sache printf ("\tThe plain target address is taken as a synonym for play.\n"); 17210099Sjkh} 17310099Sjkh 17410099Sjkhvoid usage () 17510099Sjkh{ 17643479Sbillf fprintf (stderr, "usage: cdcontrol [-sv] [-f device] [command ...]\n"); 17710099Sjkh exit (1); 17810099Sjkh} 17910099Sjkh 18087568Smikehchar *use_cdrom_instead(const char *old_envvar) 18171122Sjoe{ 18271122Sjoe char *device; 18371122Sjoe 18471122Sjoe device = getenv(old_envvar); 18571122Sjoe if (device) 18671122Sjoe warnx("%s environment variable deprecated, " 18771122Sjoe "please use CDROM in the future.", old_envvar); 18871122Sjoe return device; 18971122Sjoe} 19071122Sjoe 19171122Sjoe 19210099Sjkhint main (int argc, char **argv) 19310099Sjkh{ 19410099Sjkh int cmd; 19510099Sjkh char *arg; 19610099Sjkh 19710099Sjkh for (;;) { 19810099Sjkh switch (getopt (argc, argv, "svhf:")) { 19910099Sjkh case EOF: 20010099Sjkh break; 20110099Sjkh case 's': 20210099Sjkh verbose = 0; 20310099Sjkh continue; 20410099Sjkh case 'v': 20510099Sjkh verbose = 2; 20610099Sjkh continue; 20710099Sjkh case 'f': 20810099Sjkh cdname = optarg; 20910099Sjkh continue; 21010099Sjkh case 'h': 21110099Sjkh default: 21210099Sjkh usage (); 21310099Sjkh } 21410099Sjkh break; 21510099Sjkh } 21610099Sjkh argc -= optind; 21710099Sjkh argv += optind; 21810099Sjkh 21913985Sache if (argc > 0 && ! strcasecmp (*argv, "help")) 22010099Sjkh usage (); 22110099Sjkh 22210099Sjkh if (! cdname) { 22370149Sdes cdname = getenv("CDROM"); 22470149Sdes } 22570149Sdes 22675324Sjoe if (! cdname) 22775324Sjoe cdname = use_cdrom_instead("MUSIC_CD"); 22875324Sjoe if (! cdname) 22975324Sjoe cdname = use_cdrom_instead("CD_DRIVE"); 23075324Sjoe if (! cdname) 23175324Sjoe cdname = use_cdrom_instead("DISC"); 23275324Sjoe if (! cdname) 23375324Sjoe cdname = use_cdrom_instead("CDPLAY"); 23475324Sjoe 23570149Sdes if (! cdname) { 23613985Sache cdname = DEFAULT_CD_DRIVE; 23729103Scharnier warnx("no CD device name specified, defaulting to %s", cdname); 23810099Sjkh } 23910099Sjkh 24010099Sjkh if (argc > 0) { 24110099Sjkh char buf[80], *p; 24210099Sjkh int len; 24310099Sjkh 24413985Sache for (p=buf; argc-->0; ++argv) { 24510099Sjkh len = strlen (*argv); 24613985Sache 24710099Sjkh if (p + len >= buf + sizeof (buf) - 1) 24810099Sjkh usage (); 24913985Sache 25010099Sjkh if (p > buf) 25110099Sjkh *p++ = ' '; 25213985Sache 25310099Sjkh strcpy (p, *argv); 25410099Sjkh p += len; 25510099Sjkh } 25610099Sjkh *p = 0; 25710099Sjkh arg = parse (buf, &cmd); 25813985Sache return (run (cmd, arg)); 25910099Sjkh } 26010099Sjkh 26110099Sjkh if (verbose == 1) 26210099Sjkh verbose = isatty (0); 26313985Sache 26410099Sjkh if (verbose) { 26513985Sache printf ("Compact Disc Control utility, version %s\n", VERSION); 26610099Sjkh printf ("Type `?' for command list\n\n"); 26710099Sjkh } 26810099Sjkh 26910099Sjkh for (;;) { 27010099Sjkh arg = input (&cmd); 27110099Sjkh if (run (cmd, arg) < 0) { 27210099Sjkh if (verbose) 27329103Scharnier warn(NULL); 27410099Sjkh close (fd); 27510099Sjkh fd = -1; 27610099Sjkh } 27710099Sjkh fflush (stdout); 27810099Sjkh } 27910099Sjkh} 28010099Sjkh 28110099Sjkhint run (int cmd, char *arg) 28210099Sjkh{ 28396213Smaxim long speed; 28410099Sjkh int l, r, rc; 28510099Sjkh 28610099Sjkh switch (cmd) { 28713985Sache 28810099Sjkh case CMD_QUIT: 28910099Sjkh exit (0); 29010099Sjkh 29113985Sache case CMD_INFO: 29213985Sache if (fd < 0 && ! open_cd ()) 29313985Sache return (0); 29410099Sjkh 29510099Sjkh return info (arg); 29610099Sjkh 29763091Sjoe case CMD_CDID: 29863091Sjoe if (fd < 0 && ! open_cd ()) 29963091Sjoe return (0); 30063091Sjoe 30163091Sjoe return cdid (); 30263091Sjoe 30313884Sache case CMD_STATUS: 30413985Sache if (fd < 0 && ! open_cd ()) 30513985Sache return (0); 30613985Sache 30713884Sache return pstatus (arg); 30813884Sache 30977168Skris case CMD_NEXT: 31077168Skris case CMD_PREVIOUS: 31177168Skris if (fd < 0 && ! open_cd ()) 31277168Skris return (0); 31377168Skris 31477168Skris while (isspace (*arg)) 31577168Skris arg++; 31677168Skris 31777168Skris return next_prev (arg, cmd); 31877168Skris 31910099Sjkh case CMD_PAUSE: 32013985Sache if (fd < 0 && ! open_cd ()) 32113985Sache return (0); 32213985Sache 32310099Sjkh return ioctl (fd, CDIOCPAUSE); 32410099Sjkh 32510099Sjkh case CMD_RESUME: 32613985Sache if (fd < 0 && ! open_cd ()) 32713985Sache return (0); 32813985Sache 32910099Sjkh return ioctl (fd, CDIOCRESUME); 33010099Sjkh 33110099Sjkh case CMD_STOP: 33213985Sache if (fd < 0 && ! open_cd ()) 33313985Sache return (0); 33410099Sjkh 33513985Sache rc = ioctl (fd, CDIOCSTOP); 33613985Sache 33713985Sache (void) ioctl (fd, CDIOCALLOW); 33813985Sache 33913985Sache return (rc); 34013985Sache 34113884Sache case CMD_RESET: 34213985Sache if (fd < 0 && ! open_cd ()) 34313985Sache return (0); 34413985Sache 34513884Sache rc = ioctl (fd, CDIOCRESET); 34613884Sache if (rc < 0) 34713884Sache return rc; 34813884Sache close(fd); 34913884Sache fd = -1; 35013884Sache return (0); 35113884Sache 35210099Sjkh case CMD_DEBUG: 35313985Sache if (fd < 0 && ! open_cd ()) 35413985Sache return (0); 35513985Sache 35613985Sache if (! strcasecmp (arg, "on")) 35710099Sjkh return ioctl (fd, CDIOCSETDEBUG); 35813985Sache 35913985Sache if (! strcasecmp (arg, "off")) 36010099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 36113985Sache 36229103Scharnier warnx("invalid command arguments"); 36313985Sache 36410099Sjkh return (0); 36510099Sjkh 36610099Sjkh case CMD_EJECT: 36713985Sache if (fd < 0 && ! open_cd ()) 36813985Sache return (0); 36913985Sache 37010099Sjkh (void) ioctl (fd, CDIOCALLOW); 37110099Sjkh rc = ioctl (fd, CDIOCEJECT); 37210099Sjkh if (rc < 0) 37310099Sjkh return (rc); 37413865Sache return (0); 37513865Sache 37613985Sache case CMD_CLOSE: 37713985Sache if (fd < 0 && ! open_cd ()) 37813985Sache return (0); 37913985Sache 38013985Sache (void) ioctl (fd, CDIOCALLOW); 38113865Sache rc = ioctl (fd, CDIOCCLOSE); 38213865Sache if (rc < 0) 38313865Sache return (rc); 38413865Sache close(fd); 38510099Sjkh fd = -1; 38610099Sjkh return (0); 38710099Sjkh 38810099Sjkh case CMD_PLAY: 38913985Sache if (fd < 0 && ! open_cd ()) 39013985Sache return (0); 39113985Sache 39213985Sache while (isspace (*arg)) 39313985Sache arg++; 39413985Sache 39510099Sjkh return play (arg); 39610099Sjkh 39713884Sache case CMD_SET: 39813985Sache if (! strcasecmp (arg, "msf")) 39913884Sache msf = 1; 40013985Sache else if (! strcasecmp (arg, "lba")) 40113884Sache msf = 0; 40213884Sache else 40329103Scharnier warnx("invalid command arguments"); 40413884Sache return (0); 40513884Sache 40610099Sjkh case CMD_VOLUME: 40713985Sache if (fd < 0 && !open_cd ()) 40813985Sache return (0); 40910099Sjkh 41013985Sache if (! strncasecmp (arg, "left", strlen(arg))) 41110099Sjkh return ioctl (fd, CDIOCSETLEFT); 41213985Sache 41313985Sache if (! strncasecmp (arg, "right", strlen(arg))) 41410099Sjkh return ioctl (fd, CDIOCSETRIGHT); 41513985Sache 41613985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 41710099Sjkh return ioctl (fd, CDIOCSETMONO); 41813985Sache 41913985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 42010099Sjkh return ioctl (fd, CDIOCSETSTERIO); 42110099Sjkh 42213985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 42313985Sache return ioctl (fd, CDIOCSETMUTE); 42413985Sache 42510099Sjkh if (2 != sscanf (arg, "%d %d", &l, &r)) { 42629103Scharnier warnx("invalid command arguments"); 42710099Sjkh return (0); 42810099Sjkh } 42913985Sache 43010099Sjkh return setvol (l, r); 43113985Sache 43296213Smaxim case CMD_SPEED: 43396213Smaxim if (fd < 0 && ! open_cd ()) 43496213Smaxim return (0); 43596213Smaxim 43696213Smaxim errno = 0; 437105421Snjl if (strcasecmp("max", arg) == 0) 438105421Snjl speed = CDR_MAX_SPEED; 439105421Snjl else 440105421Snjl speed = strtol(arg, NULL, 10) * 177; 441105421Snjl if (speed <= 0 || speed > INT_MAX) { 44296213Smaxim warnx("invalid command arguments %s", arg); 44396213Smaxim return (0); 44496213Smaxim } 44596213Smaxim return ioctl(fd, CDRIOCREADSPEED, &speed); 44696213Smaxim 44713985Sache default: 44813985Sache case CMD_HELP: 44913985Sache help (); 45013985Sache return (0); 45113985Sache 45210099Sjkh } 45310099Sjkh} 45410099Sjkh 45510099Sjkhint play (char *arg) 45610099Sjkh{ 45710099Sjkh struct ioc_toc_header h; 45887568Smikeh unsigned int n; 45987568Smikeh int rc, start, end = 0, istart = 1, iend = 1; 46010099Sjkh 46110099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 46213985Sache 46310099Sjkh if (rc < 0) 46410099Sjkh return (rc); 46510099Sjkh 46610099Sjkh n = h.ending_track - h.starting_track + 1; 46710099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 46813985Sache 46910099Sjkh if (rc < 0) 47010099Sjkh return (rc); 47110099Sjkh 47213989Sache if (! arg || ! *arg) { 47313985Sache /* Play the whole disc */ 47413989Sache if (msf) 47513989Sache return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 47613989Sache toc_buffer[n].addr.msf.second, 47713989Sache toc_buffer[n].addr.msf.frame)); 47813989Sache else 47913989Sache return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); 48013989Sache } 48110099Sjkh 48210099Sjkh if (strchr (arg, '#')) { 48313985Sache /* Play block #blk [ len ] */ 48410099Sjkh int blk, len = 0; 48510099Sjkh 48610099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 48713985Sache 1 != sscanf (arg, "#%d", &blk)) 48813985Sache goto Clean_up; 48913985Sache 49013989Sache if (len == 0) { 49113989Sache if (msf) 49213989Sache len = msf2lba (toc_buffer[n].addr.msf.minute, 49313989Sache toc_buffer[n].addr.msf.second, 49413989Sache toc_buffer[n].addr.msf.frame) - blk; 49513989Sache else 49613989Sache len = ntohl(toc_buffer[n].addr.lba) - blk; 49713989Sache } 49810099Sjkh return play_blocks (blk, len); 49910099Sjkh } 50010099Sjkh 50110099Sjkh if (strchr (arg, ':')) { 50210099Sjkh /* 50310099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 50413985Sache * 50513985Sache * Will now also undestand timed addresses relative 50613985Sache * to the beginning of a track in the form... 50713985Sache * 50813985Sache * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 50910099Sjkh */ 51013985Sache unsigned tr1, tr2; 51113985Sache unsigned m1, m2, s1, s2, f1, f2; 51213989Sache unsigned char tm, ts, tf; 51310099Sjkh 51413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51513985Sache if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", 51613985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) 51713985Sache goto Play_Relative_Addresses; 51813985Sache 51913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52013985Sache if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d", 52113985Sache &tr1, &m1, &s1, &tr2, &m2, &s2, &f2)) 52213985Sache goto Play_Relative_Addresses; 52313985Sache 52413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52513985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", 52613985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) 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, &f1, &m2, &s2, &f2)) 53213985Sache goto Play_Relative_Addresses; 53313985Sache 53413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53513985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d:%d", 53613985Sache &tr1, &m1, &s1, &f1, &m2, &s2)) 53713985Sache goto Play_Relative_Addresses; 53813985Sache 53913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54013985Sache if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", 54113985Sache &tr1, &m1, &s1, &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, &tr2, &m2)) 54713985Sache goto Play_Relative_Addresses; 54813985Sache 54913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55013985Sache if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) 55113985Sache goto Play_Relative_Addresses; 55213985Sache 55313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55413985Sache if (5 == sscanf (arg, "%d %d:%d %d %d", 55513985Sache &tr1, &m1, &s1, &tr2, &m2)) 55613985Sache goto Play_Relative_Addresses; 55713985Sache 55813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55913985Sache if (5 == sscanf (arg, "%d %d:%d.%d %d", 56013985Sache &tr1, &m1, &s1, &f1, &tr2)) 56113985Sache goto Play_Relative_Addresses; 56213985Sache 56313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56413985Sache if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 56513985Sache goto Play_Relative_Addresses; 56613985Sache 56713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56813985Sache if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 56913985Sache goto Play_Relative_Addresses; 57013985Sache 57113985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57213985Sache if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) 57313985Sache goto Play_Relative_Addresses; 57413985Sache 57513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57613985Sache goto Try_Absolute_Timed_Addresses; 57713985Sache 57813985SachePlay_Relative_Addresses: 57913985Sache if (! tr1) 58013985Sache tr1 = 1; 58113985Sache else if (tr1 > n) 58213985Sache tr1 = n; 58313985Sache 58413989Sache if (msf) { 58513989Sache tm = toc_buffer[tr1].addr.msf.minute; 58613989Sache ts = toc_buffer[tr1].addr.msf.second; 58713989Sache tf = toc_buffer[tr1].addr.msf.frame; 58813989Sache } else 58913989Sache lba2msf(ntohl(toc_buffer[tr1].addr.lba), 59013989Sache &tm, &ts, &tf); 59113989Sache if ((m1 > tm) 59213989Sache || ((m1 == tm) 59313989Sache && ((s1 > ts) 59413989Sache || ((s1 == ts) 59513989Sache && (f1 > tf))))) { 59613985Sache printf ("Track %d is not that long.\n", tr1); 59713985Sache return (0); 59813985Sache } 59913985Sache 60013985Sache tr1--; 60113985Sache 60213989Sache f1 += tf; 60313985Sache if (f1 >= 75) { 60413985Sache s1 += f1 / 75; 60513985Sache f1 %= 75; 60613985Sache } 60713985Sache 60813989Sache s1 += ts; 60913985Sache if (s1 >= 60) { 61013985Sache m1 += s1 / 60; 61113985Sache s1 %= 60; 61213985Sache } 61313985Sache 61413989Sache m1 += tm; 61513985Sache 61613985Sache if (! tr2) { 61713985Sache if (m2 || s2 || f2) { 61813985Sache tr2 = tr1; 61913985Sache f2 += f1; 62013985Sache if (f2 >= 75) { 62113985Sache s2 += f2 / 75; 62213985Sache f2 %= 75; 62313985Sache } 62413985Sache 62513985Sache s2 += s1; 62613985Sache if (s2 > 60) { 62713985Sache m2 += s2 / 60; 62813985Sache s2 %= 60; 62913985Sache } 63013985Sache 63113985Sache m2 += m1; 63213985Sache } else { 63313985Sache tr2 = n; 63413989Sache if (msf) { 63513989Sache m2 = toc_buffer[n].addr.msf.minute; 63613989Sache s2 = toc_buffer[n].addr.msf.second; 63713989Sache f2 = toc_buffer[n].addr.msf.frame; 63813989Sache } else { 63913989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 64013989Sache &tm, &ts, &tf); 64113989Sache m2 = tm; 64213989Sache s2 = ts; 64313989Sache f2 = tf; 64413989Sache } 64513985Sache } 64613985Sache } else if (tr2 > n) { 64713985Sache tr2 = n; 64813985Sache m2 = s2 = f2 = 0; 64913985Sache } else { 65013985Sache if (m2 || s2 || f2) 65113985Sache tr2--; 65213989Sache if (msf) { 65313989Sache tm = toc_buffer[tr2].addr.msf.minute; 65413989Sache ts = toc_buffer[tr2].addr.msf.second; 65513989Sache tf = toc_buffer[tr2].addr.msf.frame; 65613989Sache } else 65713989Sache lba2msf(ntohl(toc_buffer[tr2].addr.lba), 65813989Sache &tm, &ts, &tf); 65913989Sache f2 += tf; 66013985Sache if (f2 >= 75) { 66113985Sache s2 += f2 / 75; 66213985Sache f2 %= 75; 66313985Sache } 66413985Sache 66513989Sache s2 += ts; 66613985Sache if (s2 > 60) { 66713985Sache m2 += s2 / 60; 66813985Sache s2 %= 60; 66913985Sache } 67013985Sache 67113989Sache m2 += tm; 67213985Sache } 67313985Sache 67413989Sache if (msf) { 67513989Sache tm = toc_buffer[n].addr.msf.minute; 67613989Sache ts = toc_buffer[n].addr.msf.second; 67713989Sache tf = toc_buffer[n].addr.msf.frame; 67813989Sache } else 67913989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 68013989Sache &tm, &ts, &tf); 68113985Sache if ((tr2 < n) 68213989Sache && ((m2 > tm) 68313989Sache || ((m2 == tm) 68413989Sache && ((s2 > ts) 68513989Sache || ((s2 == ts) 68613989Sache && (f2 > tf)))))) { 68713985Sache printf ("The playing time of the disc is not that long.\n"); 68813985Sache return (0); 68913985Sache } 69013985Sache return (play_msf (m1, s1, f1, m2, s2, f2)); 69113985Sache 69213985SacheTry_Absolute_Timed_Addresses: 69313985Sache if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", 69413985Sache &m1, &s1, &f1, &m2, &s2, &f2) && 69510099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 69610099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 69710099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 69810099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 69910099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 70013985Sache goto Clean_up; 70113985Sache 70210099Sjkh if (m2 == 0) { 70313989Sache if (msf) { 70413989Sache m2 = toc_buffer[n].addr.msf.minute; 70513989Sache s2 = toc_buffer[n].addr.msf.second; 70613989Sache f2 = toc_buffer[n].addr.msf.frame; 70713989Sache } else { 70813989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 70913989Sache &tm, &ts, &tf); 71013989Sache m2 = tm; 71113989Sache s2 = ts; 71213989Sache f2 = tf; 71313989Sache } 71410099Sjkh } 71510099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 71610099Sjkh } 71710099Sjkh 71810099Sjkh /* 71910099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 72010099Sjkh */ 72110099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 72210099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 72310099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 72410099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 72510099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 72610099Sjkh 1 != sscanf (arg, "%d", &start)) 72713985Sache goto Clean_up; 72813985Sache 72910099Sjkh if (end == 0) 73010099Sjkh end = n; 73113985Sache return (play_track (start, istart, end, iend)); 73213985Sache 73313985SacheClean_up: 73429103Scharnier warnx("invalid command arguments"); 73513985Sache return (0); 73610099Sjkh} 73710099Sjkh 73877168Skrisint next_prev (char *arg, int cmd) 73977168Skris{ 74077168Skris struct ioc_toc_header h; 74177168Skris int dir, junk, n, off, rc, trk; 74277168Skris 74377168Skris dir = (cmd == CMD_NEXT) ? 1 : -1; 74477168Skris rc = ioctl (fd, CDIOREADTOCHEADER, &h); 74577168Skris if (rc < 0) 74677168Skris return (rc); 74777168Skris 74877168Skris n = h.ending_track - h.starting_track + 1; 74977168Skris rc = status (&trk, &junk, &junk, &junk); 75077168Skris if (rc < 0) 75177168Skris return (-1); 75277168Skris 75377168Skris if (arg && *arg) { 75477168Skris if (sscanf (arg, "%u", &off) != 1) { 75577168Skris warnx("invalid command argument"); 75677168Skris return (0); 75777168Skris } else 75877168Skris trk += off * dir; 75977168Skris } else 76077168Skris trk += dir; 76177168Skris 76277168Skris if (trk > h.ending_track) 76377168Skris trk = 1; 76477168Skris 76577168Skris return (play_track (trk, 1, n, 1)); 76677168Skris} 76777168Skris 76887568Smikehconst char *strstatus (int sts) 76910099Sjkh{ 77010099Sjkh switch (sts) { 77187573Smikeh case ASTS_INVALID: return ("invalid"); 77287573Smikeh case ASTS_PLAYING: return ("playing"); 77387573Smikeh case ASTS_PAUSED: return ("paused"); 77487573Smikeh case ASTS_COMPLETED: return ("completed"); 77587573Smikeh case ASTS_ERROR: return ("error"); 77687573Smikeh case ASTS_VOID: return ("void"); 77787573Smikeh default: return ("??"); 77810099Sjkh } 77910099Sjkh} 78010099Sjkh 78113884Sacheint pstatus (char *arg) 78210099Sjkh{ 78310099Sjkh struct ioc_vol v; 78413888Sache struct ioc_read_subchannel ss; 78513888Sache struct cd_sub_channel_info data; 78613884Sache int rc, trk, m, s, f; 78732782Sjmz int what = 0; 78877168Skris char *p, vmcn[(4 * 15) + 1]; 78910099Sjkh 79032782Sjmz while ((p = strtok(arg, " \t"))) { 79132782Sjmz arg = 0; 79232782Sjmz if (!strncasecmp(p, "audio", strlen(p))) 79332782Sjmz what |= STATUS_AUDIO; 79432782Sjmz else if (!strncasecmp(p, "media", strlen(p))) 79532782Sjmz what |= STATUS_MEDIA; 79632782Sjmz else if (!strncasecmp(p, "volume", strlen(p))) 79732782Sjmz what |= STATUS_VOLUME; 79832782Sjmz else { 79932782Sjmz warnx("invalid command arguments"); 80032782Sjmz return 0; 80132782Sjmz } 80232782Sjmz } 80332782Sjmz if (!what) 80432782Sjmz what = STATUS_AUDIO|STATUS_MEDIA|STATUS_VOLUME; 80532782Sjmz if (what & STATUS_AUDIO) { 80632782Sjmz rc = status (&trk, &m, &s, &f); 80732782Sjmz if (rc >= 0) 80810099Sjkh if (verbose) 80932782Sjmz printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 81032782Sjmz rc, strstatus (rc), trk, m, s, f); 81110099Sjkh else 81232782Sjmz printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 81332782Sjmz else 81413888Sache printf ("No current status info available\n"); 81532782Sjmz } 81632782Sjmz if (what & STATUS_MEDIA) { 81732782Sjmz bzero (&ss, sizeof (ss)); 81832782Sjmz ss.data = &data; 81932782Sjmz ss.data_len = sizeof (data); 82032782Sjmz ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 82132782Sjmz ss.data_format = CD_MEDIA_CATALOG; 82232782Sjmz rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); 82332782Sjmz if (rc >= 0) { 82413889Sache printf("Media catalog is %sactive", 82587573Smikeh ss.data->what.media_catalog.mc_valid ? "": "in"); 82616736Sache if (ss.data->what.media_catalog.mc_valid && 82716736Sache ss.data->what.media_catalog.mc_number[0]) 82877168Skris { 82977168Skris strvisx (vmcn, ss.data->what.media_catalog.mc_number, 83077168Skris (sizeof (vmcn) - 1) / 4, VIS_OCTAL | VIS_NL); 83177168Skris printf(", number \"%.*s\"", (int)sizeof (vmcn), vmcn); 83277168Skris } 83313889Sache putchar('\n'); 83432782Sjmz } else 83513888Sache printf("No media catalog info available\n"); 83632782Sjmz } 83732782Sjmz if (what & STATUS_VOLUME) { 83832782Sjmz rc = ioctl (fd, CDIOCGETVOL, &v); 83932782Sjmz if (rc >= 0) 84010099Sjkh if (verbose) 84132782Sjmz printf ("Left volume = %d, right volume = %d\n", 84232782Sjmz v.vol[0], v.vol[1]); 84310099Sjkh else 84432782Sjmz printf ("%d %d\n", v.vol[0], v.vol[1]); 84532782Sjmz else 84613888Sache printf ("No volume level info available\n"); 84732782Sjmz } 84813884Sache return(0); 84913884Sache} 85010099Sjkh 85163091Sjoe/* 85263091Sjoe * dbprog_sum 85363091Sjoe * Convert an integer to its text string representation, and 85463091Sjoe * compute its checksum. Used by dbprog_discid to derive the 85563091Sjoe * disc ID. 85663091Sjoe * 85763091Sjoe * Args: 85863091Sjoe * n - The integer value. 85963091Sjoe * 86063091Sjoe * Return: 86163091Sjoe * The integer checksum. 86263091Sjoe */ 86363091Sjoestatic int 86463091Sjoedbprog_sum(int n) 86563091Sjoe{ 86663091Sjoe char buf[12], 86763091Sjoe *p; 86863091Sjoe int ret = 0; 86963091Sjoe 87063091Sjoe /* For backward compatibility this algorithm must not change */ 87163091Sjoe sprintf(buf, "%u", n); 87263091Sjoe for (p = buf; *p != '\0'; p++) 87363091Sjoe ret += (*p - '0'); 87463091Sjoe 87563091Sjoe return(ret); 87663091Sjoe} 87763091Sjoe 87863091Sjoe 87963091Sjoe/* 88063091Sjoe * dbprog_discid 88163091Sjoe * Compute a magic disc ID based on the number of tracks, 88263091Sjoe * the length of each track, and a checksum of the string 88363091Sjoe * that represents the offset of each track. 88463091Sjoe * 88563091Sjoe * Args: 88663091Sjoe * s - Pointer to the curstat_t structure. 88763091Sjoe * 88863091Sjoe * Return: 88963091Sjoe * The integer disc ID. 89063091Sjoe */ 89163091Sjoestatic u_int 89263091Sjoedbprog_discid() 89363091Sjoe{ 89463091Sjoe struct ioc_toc_header h; 89563091Sjoe int rc; 89663091Sjoe int i, ntr, 89763091Sjoe t = 0, 89863091Sjoe n = 0; 89963091Sjoe 90063091Sjoe rc = ioctl (fd, CDIOREADTOCHEADER, &h); 90163091Sjoe if (rc < 0) 90263091Sjoe return 0; 90363091Sjoe ntr = h.ending_track - h.starting_track + 1; 90463091Sjoe i = msf; 90563091Sjoe msf = 1; 90663091Sjoe rc = read_toc_entrys ((ntr + 1) * sizeof (struct cd_toc_entry)); 90763091Sjoe msf = i; 90863091Sjoe if (rc < 0) 90963091Sjoe return 0; 91063091Sjoe /* For backward compatibility this algorithm must not change */ 91163091Sjoe for (i = 0; i < ntr; i++) { 91263091Sjoe#define TC_MM(a) toc_buffer[a].addr.msf.minute 91363091Sjoe#define TC_SS(a) toc_buffer[a].addr.msf.second 91463091Sjoe n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i)); 91563091Sjoe 91663091Sjoe t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - 91787573Smikeh ((TC_MM(i) * 60) + TC_SS(i)); 91863091Sjoe } 91963091Sjoe 92063091Sjoe return((n % 0xff) << 24 | t << 8 | ntr); 92163091Sjoe} 92263091Sjoe 92363091Sjoeint cdid () 92463091Sjoe{ 92563091Sjoe u_int id; 92663091Sjoe 92763091Sjoe id = dbprog_discid(); 92863091Sjoe if (id) 92963091Sjoe { 93063091Sjoe if (verbose) 93163091Sjoe printf ("CDID="); 93263091Sjoe printf ("%08x\n",id); 93363091Sjoe } 93463091Sjoe return id ? 0 : 1; 93563091Sjoe} 93663091Sjoe 93787568Smikehint info (char *arg __unused) 93813884Sache{ 93913884Sache struct ioc_toc_header h; 94013884Sache int rc, i, n; 94113884Sache 94210099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 94313888Sache if (rc >= 0) { 94410099Sjkh if (verbose) 94510099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 94610099Sjkh h.starting_track, h.ending_track, h.len); 94710099Sjkh else 94810099Sjkh printf ("%d %d %d\n", h.starting_track, 94910099Sjkh h.ending_track, h.len); 95013888Sache } else { 95129103Scharnier warn("getting toc header"); 95210099Sjkh return (rc); 95310099Sjkh } 95410099Sjkh 95510099Sjkh n = h.ending_track - h.starting_track + 1; 95610099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 95710099Sjkh if (rc < 0) 95810099Sjkh return (rc); 95913985Sache 96010099Sjkh if (verbose) { 96110099Sjkh printf ("track start duration block length type\n"); 96210099Sjkh printf ("-------------------------------------------------\n"); 96310099Sjkh } 96413985Sache 96510099Sjkh for (i = 0; i < n; i++) { 96610099Sjkh printf ("%5d ", toc_buffer[i].track); 96710099Sjkh prtrack (toc_buffer + i, 0); 96810099Sjkh } 96913867Sache printf ("%5d ", toc_buffer[n].track); 97010099Sjkh prtrack (toc_buffer + n, 1); 97110099Sjkh return (0); 97210099Sjkh} 97310099Sjkh 97413985Sachevoid lba2msf (unsigned long lba, u_char *m, u_char *s, u_char *f) 97510099Sjkh{ 97687573Smikeh lba += 150; /* block start offset */ 97787573Smikeh lba &= 0xffffff; /* negative lbas use only 24 bits */ 97810099Sjkh *m = lba / (60 * 75); 97910099Sjkh lba %= (60 * 75); 98010099Sjkh *s = lba / 75; 98110099Sjkh *f = lba % 75; 98210099Sjkh} 98310099Sjkh 98413985Sacheunsigned int msf2lba (u_char m, u_char s, u_char f) 98510099Sjkh{ 98610099Sjkh return (((m * 60) + s) * 75 + f) - 150; 98710099Sjkh} 98810099Sjkh 98910099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag) 99010099Sjkh{ 99110099Sjkh int block, next, len; 99210099Sjkh u_char m, s, f; 99310099Sjkh 99413884Sache if (msf) { 99513884Sache /* Print track start */ 99613884Sache printf ("%2d:%02d.%02d ", e->addr.msf.minute, 99713884Sache e->addr.msf.second, e->addr.msf.frame); 99810099Sjkh 99913884Sache block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 100013884Sache e->addr.msf.frame); 100113884Sache } else { 100213884Sache block = ntohl(e->addr.lba); 100313884Sache lba2msf(block, &m, &s, &f); 100413884Sache /* Print track start */ 100513884Sache printf ("%2d:%02d.%02d ", m, s, f); 100613884Sache } 100710099Sjkh if (lastflag) { 100810099Sjkh /* Last track -- print block */ 100910099Sjkh printf (" - %6d - -\n", block); 101010099Sjkh return; 101110099Sjkh } 101210099Sjkh 101313884Sache if (msf) 101413884Sache next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 101513884Sache e[1].addr.msf.frame); 101613884Sache else 101713884Sache next = ntohl(e[1].addr.lba); 101810099Sjkh len = next - block; 1019103861Smaxim /* Take into account a start offset time. */ 1020103861Smaxim lba2msf (len - 150, &m, &s, &f); 102110099Sjkh 102210099Sjkh /* Print duration, block, length, type */ 102310099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 102413985Sache (e->control & 4) ? "data" : "audio"); 102510099Sjkh} 102610099Sjkh 102710099Sjkhint play_track (int tstart, int istart, int tend, int iend) 102810099Sjkh{ 102910099Sjkh struct ioc_play_track t; 103010099Sjkh 103110099Sjkh t.start_track = tstart; 103210099Sjkh t.start_index = istart; 103310099Sjkh t.end_track = tend; 103410099Sjkh t.end_index = iend; 103513985Sache 103610099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 103710099Sjkh} 103810099Sjkh 103910099Sjkhint play_blocks (int blk, int len) 104010099Sjkh{ 104113985Sache struct ioc_play_blocks t; 104210099Sjkh 104310099Sjkh t.blk = blk; 104410099Sjkh t.len = len; 104513985Sache 104610099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 104710099Sjkh} 104810099Sjkh 104913985Sacheint setvol (int left, int right) 105010099Sjkh{ 105113985Sache struct ioc_vol v; 105210099Sjkh 105313985Sache v.vol[0] = left; 105413985Sache v.vol[1] = right; 105510099Sjkh v.vol[2] = 0; 105610099Sjkh v.vol[3] = 0; 105713985Sache 105810099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 105910099Sjkh} 106010099Sjkh 106110099Sjkhint read_toc_entrys (int len) 106210099Sjkh{ 106310099Sjkh struct ioc_read_toc_entry t; 106410099Sjkh 106513884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 106613737Sache t.starting_track = 0; 106710099Sjkh t.data_len = len; 106810099Sjkh t.data = toc_buffer; 106913985Sache 107013985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 107110099Sjkh} 107210099Sjkh 107310099Sjkhint play_msf (int start_m, int start_s, int start_f, 107413985Sache int end_m, int end_s, int end_f) 107510099Sjkh{ 107687573Smikeh struct ioc_play_msf a; 107710099Sjkh 107810099Sjkh a.start_m = start_m; 107910099Sjkh a.start_s = start_s; 108010099Sjkh a.start_f = start_f; 108110099Sjkh a.end_m = end_m; 108210099Sjkh a.end_s = end_s; 108310099Sjkh a.end_f = end_f; 108413985Sache 108510099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 108610099Sjkh} 108710099Sjkh 108810099Sjkhint status (int *trk, int *min, int *sec, int *frame) 108910099Sjkh{ 109010099Sjkh struct ioc_read_subchannel s; 109110099Sjkh struct cd_sub_channel_info data; 109213884Sache u_char mm, ss, ff; 109310099Sjkh 109410099Sjkh bzero (&s, sizeof (s)); 109510099Sjkh s.data = &data; 109610099Sjkh s.data_len = sizeof (data); 109713884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 109810099Sjkh s.data_format = CD_CURRENT_POSITION; 109913985Sache 110010099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 110110099Sjkh return -1; 110213985Sache 110310099Sjkh *trk = s.data->what.position.track_number; 110413884Sache if (msf) { 110513884Sache *min = s.data->what.position.reladdr.msf.minute; 110613884Sache *sec = s.data->what.position.reladdr.msf.second; 110713884Sache *frame = s.data->what.position.reladdr.msf.frame; 110813884Sache } else { 110913884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 111013884Sache &mm, &ss, &ff); 111113884Sache *min = mm; 111213884Sache *sec = ss; 111313884Sache *frame = ff; 111413884Sache } 111513985Sache 111610099Sjkh return s.data->header.audio_status; 111710099Sjkh} 111810099Sjkh 111950039Smdoddconst char * 112050039Smdoddcdcontrol_prompt() 112110099Sjkh{ 112250039Smdodd return ("cdcontrol> "); 112350039Smdodd} 112450039Smdodd 112550039Smdoddchar * 112650039Smdoddinput (int *cmd) 112750039Smdodd{ 112850039Smdodd#define MAXLINE 80 112950039Smdodd static EditLine *el = NULL; 113050039Smdodd static History *hist = NULL; 113184261Sobrien HistEvent he; 113250039Smdodd static char buf[MAXLINE]; 113350039Smdodd int num = 0; 113450071Smdodd int len; 113550039Smdodd const char *bp = NULL; 113610099Sjkh char *p; 113710099Sjkh 113810099Sjkh do { 113950039Smdodd if (verbose) { 114050039Smdodd if (!el) { 114184261Sobrien el = el_init("cdcontrol", stdin, stdout, 114284261Sobrien stderr); 114350039Smdodd hist = history_init(); 114484261Sobrien history(hist, &he, H_EVENT, 100); 114550039Smdodd el_set(el, EL_HIST, history, hist); 114650039Smdodd el_set(el, EL_EDITOR, "emacs"); 114750039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 114850039Smdodd el_set(el, EL_SIGNAL, 1); 114950042Smdodd el_source(el, NULL); 115050039Smdodd } 115163070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 115263070Smckay *cmd = CMD_QUIT; 115363070Smckay fprintf (stderr, "\r\n"); 115450039Smdodd return (0); 115563070Smckay } 115650039Smdodd 115750071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 115850071Smdodd memcpy(buf, bp, len); 115950071Smdodd buf[len] = 0; 116084261Sobrien history(hist, &he, H_ENTER, bp); 116150039Smdodd#undef MAXLINE 116250039Smdodd 116350039Smdodd } else { 116450039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 116550039Smdodd *cmd = CMD_QUIT; 116650039Smdodd fprintf (stderr, "\r\n"); 116750039Smdodd return (0); 116850039Smdodd } 116910099Sjkh } 117010099Sjkh p = parse (buf, cmd); 117110099Sjkh } while (! p); 117210099Sjkh return (p); 117310099Sjkh} 117410099Sjkh 117510099Sjkhchar *parse (char *buf, int *cmd) 117610099Sjkh{ 117710099Sjkh struct cmdtab *c; 117810099Sjkh char *p; 117987568Smikeh unsigned int len; 118010099Sjkh 118113985Sache for (p=buf; isspace (*p); p++) 118213985Sache continue; 118310099Sjkh 118413985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 118513985Sache *cmd = CMD_PLAY; 118613985Sache return (p); 118777168Skris } else if (*p == '+') { 118877168Skris *cmd = CMD_NEXT; 118977168Skris return (p + 1); 119077168Skris } else if (*p == '-') { 119177168Skris *cmd = CMD_PREVIOUS; 119277168Skris return (p + 1); 119313985Sache } 119410099Sjkh 119513985Sache for (buf = p; *p && ! isspace (*p); p++) 119613985Sache continue; 119796214Smaxim 119813985Sache len = p - buf; 119910099Sjkh if (! len) 120010099Sjkh return (0); 120113985Sache 120287573Smikeh if (*p) { /* It must be a spacing character! */ 120313985Sache char *q; 120413985Sache 120513985Sache *p++ = 0; 120613985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 120713985Sache continue; 120813985Sache *q = 0; 120913985Sache } 121013985Sache 121110099Sjkh *cmd = -1; 121210099Sjkh for (c=cmdtab; c->name; ++c) { 121313985Sache /* Is it an exact match? */ 121413985Sache if (! strcasecmp (buf, c->name)) { 121513985Sache *cmd = c->command; 121613985Sache break; 121713985Sache } 121813985Sache 121913985Sache /* Try short hand forms then... */ 122013985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 122113985Sache if (*cmd != -1 && *cmd != c->command) { 122229103Scharnier warnx("ambiguous command"); 122313985Sache return (0); 122413985Sache } 122510099Sjkh *cmd = c->command; 122613985Sache } 122713985Sache } 122810099Sjkh 122910099Sjkh if (*cmd == -1) { 123029103Scharnier warnx("invalid command, enter ``help'' for commands"); 123110099Sjkh return (0); 123210099Sjkh } 123313985Sache 123413985Sache while (isspace (*p)) 123513985Sache p++; 123610099Sjkh return p; 123710099Sjkh} 123810099Sjkh 123910099Sjkhint open_cd () 124010099Sjkh{ 124154164Sjoe char devbuf[MAXPATHLEN]; 124210099Sjkh 124310099Sjkh if (fd > -1) 124410099Sjkh return (1); 124513985Sache 124654164Sjoe if (*cdname == '/') { 124754164Sjoe snprintf (devbuf, MAXPATHLEN, "%s", cdname); 124861105Smsmith } else { 124969793Sobrien snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 125054164Sjoe } 125113985Sache 125210099Sjkh fd = open (devbuf, O_RDONLY); 125313985Sache 125410099Sjkh if (fd < 0 && errno == ENOENT) { 125513985Sache strcat (devbuf, DEFAULT_CD_PARTITION); 125610099Sjkh fd = open (devbuf, O_RDONLY); 125710099Sjkh } 125813985Sache 125910099Sjkh if (fd < 0) { 126013985Sache if (errno == ENXIO) { 126113985Sache /* ENXIO has an overloaded meaning here. 126213985Sache * The original "Device not configured" should 126313985Sache * be interpreted as "No disc in drive %s". */ 126429103Scharnier warnx("no disc in drive %s", devbuf); 126513985Sache return (0); 126610099Sjkh } 126729103Scharnier err(1, "%s", devbuf); 126810099Sjkh } 126910099Sjkh return (1); 127010099Sjkh} 1271