cdcontrol.c revision 99800
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 99800 2002-07-11 18:31:16Z alfred $"; 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; 28596213Smaxim char *ep; 28610099Sjkh 28710099Sjkh switch (cmd) { 28813985Sache 28910099Sjkh case CMD_QUIT: 29010099Sjkh exit (0); 29110099Sjkh 29213985Sache case CMD_INFO: 29313985Sache if (fd < 0 && ! open_cd ()) 29413985Sache return (0); 29510099Sjkh 29610099Sjkh return info (arg); 29710099Sjkh 29863091Sjoe case CMD_CDID: 29963091Sjoe if (fd < 0 && ! open_cd ()) 30063091Sjoe return (0); 30163091Sjoe 30263091Sjoe return cdid (); 30363091Sjoe 30413884Sache case CMD_STATUS: 30513985Sache if (fd < 0 && ! open_cd ()) 30613985Sache return (0); 30713985Sache 30813884Sache return pstatus (arg); 30913884Sache 31077168Skris case CMD_NEXT: 31177168Skris case CMD_PREVIOUS: 31277168Skris if (fd < 0 && ! open_cd ()) 31377168Skris return (0); 31477168Skris 31577168Skris while (isspace (*arg)) 31677168Skris arg++; 31777168Skris 31877168Skris return next_prev (arg, cmd); 31977168Skris 32010099Sjkh case CMD_PAUSE: 32113985Sache if (fd < 0 && ! open_cd ()) 32213985Sache return (0); 32313985Sache 32410099Sjkh return ioctl (fd, CDIOCPAUSE); 32510099Sjkh 32610099Sjkh case CMD_RESUME: 32713985Sache if (fd < 0 && ! open_cd ()) 32813985Sache return (0); 32913985Sache 33010099Sjkh return ioctl (fd, CDIOCRESUME); 33110099Sjkh 33210099Sjkh case CMD_STOP: 33313985Sache if (fd < 0 && ! open_cd ()) 33413985Sache return (0); 33510099Sjkh 33613985Sache rc = ioctl (fd, CDIOCSTOP); 33713985Sache 33813985Sache (void) ioctl (fd, CDIOCALLOW); 33913985Sache 34013985Sache return (rc); 34113985Sache 34213884Sache case CMD_RESET: 34313985Sache if (fd < 0 && ! open_cd ()) 34413985Sache return (0); 34513985Sache 34613884Sache rc = ioctl (fd, CDIOCRESET); 34713884Sache if (rc < 0) 34813884Sache return rc; 34913884Sache close(fd); 35013884Sache fd = -1; 35113884Sache return (0); 35213884Sache 35310099Sjkh case CMD_DEBUG: 35413985Sache if (fd < 0 && ! open_cd ()) 35513985Sache return (0); 35613985Sache 35713985Sache if (! strcasecmp (arg, "on")) 35810099Sjkh return ioctl (fd, CDIOCSETDEBUG); 35913985Sache 36013985Sache if (! strcasecmp (arg, "off")) 36110099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 36213985Sache 36329103Scharnier warnx("invalid command arguments"); 36413985Sache 36510099Sjkh return (0); 36610099Sjkh 36710099Sjkh case CMD_EJECT: 36813985Sache if (fd < 0 && ! open_cd ()) 36913985Sache return (0); 37013985Sache 37110099Sjkh (void) ioctl (fd, CDIOCALLOW); 37210099Sjkh rc = ioctl (fd, CDIOCEJECT); 37310099Sjkh if (rc < 0) 37410099Sjkh return (rc); 37513865Sache return (0); 37613865Sache 37713985Sache case CMD_CLOSE: 37813985Sache if (fd < 0 && ! open_cd ()) 37913985Sache return (0); 38013985Sache 38113985Sache (void) ioctl (fd, CDIOCALLOW); 38213865Sache rc = ioctl (fd, CDIOCCLOSE); 38313865Sache if (rc < 0) 38413865Sache return (rc); 38513865Sache close(fd); 38610099Sjkh fd = -1; 38710099Sjkh return (0); 38810099Sjkh 38910099Sjkh case CMD_PLAY: 39013985Sache if (fd < 0 && ! open_cd ()) 39113985Sache return (0); 39213985Sache 39313985Sache while (isspace (*arg)) 39413985Sache arg++; 39513985Sache 39610099Sjkh return play (arg); 39710099Sjkh 39813884Sache case CMD_SET: 39913985Sache if (! strcasecmp (arg, "msf")) 40013884Sache msf = 1; 40113985Sache else if (! strcasecmp (arg, "lba")) 40213884Sache msf = 0; 40313884Sache else 40429103Scharnier warnx("invalid command arguments"); 40513884Sache return (0); 40613884Sache 40710099Sjkh case CMD_VOLUME: 40813985Sache if (fd < 0 && !open_cd ()) 40913985Sache return (0); 41010099Sjkh 41113985Sache if (! strncasecmp (arg, "left", strlen(arg))) 41210099Sjkh return ioctl (fd, CDIOCSETLEFT); 41313985Sache 41413985Sache if (! strncasecmp (arg, "right", strlen(arg))) 41510099Sjkh return ioctl (fd, CDIOCSETRIGHT); 41613985Sache 41713985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 41810099Sjkh return ioctl (fd, CDIOCSETMONO); 41913985Sache 42013985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 42110099Sjkh return ioctl (fd, CDIOCSETSTERIO); 42210099Sjkh 42313985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 42413985Sache return ioctl (fd, CDIOCSETMUTE); 42513985Sache 42610099Sjkh if (2 != sscanf (arg, "%d %d", &l, &r)) { 42729103Scharnier warnx("invalid command arguments"); 42810099Sjkh return (0); 42910099Sjkh } 43013985Sache 43110099Sjkh return setvol (l, r); 43213985Sache 43396213Smaxim case CMD_SPEED: 43496213Smaxim if (fd < 0 && ! open_cd ()) 43596213Smaxim return (0); 43696213Smaxim 43796213Smaxim errno = 0; 43896213Smaxim speed = strtol(arg, &ep, 10); 43996213Smaxim if (*ep || ep == arg || speed <= 0 || speed > INT_MAX || 44096213Smaxim errno != 0) { 44196213Smaxim warnx("invalid command arguments %s", arg); 44296213Smaxim return (0); 44396213Smaxim } 44496213Smaxim return ioctl(fd, CDRIOCREADSPEED, &speed); 44596213Smaxim 44613985Sache default: 44713985Sache case CMD_HELP: 44813985Sache help (); 44913985Sache return (0); 45013985Sache 45110099Sjkh } 45210099Sjkh} 45310099Sjkh 45410099Sjkhint play (char *arg) 45510099Sjkh{ 45610099Sjkh struct ioc_toc_header h; 45787568Smikeh unsigned int n; 45887568Smikeh int rc, start, end = 0, istart = 1, iend = 1; 45910099Sjkh 46010099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 46113985Sache 46210099Sjkh if (rc < 0) 46310099Sjkh return (rc); 46410099Sjkh 46510099Sjkh n = h.ending_track - h.starting_track + 1; 46610099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 46713985Sache 46810099Sjkh if (rc < 0) 46910099Sjkh return (rc); 47010099Sjkh 47113989Sache if (! arg || ! *arg) { 47213985Sache /* Play the whole disc */ 47313989Sache if (msf) 47413989Sache return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 47513989Sache toc_buffer[n].addr.msf.second, 47613989Sache toc_buffer[n].addr.msf.frame)); 47713989Sache else 47813989Sache return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); 47913989Sache } 48010099Sjkh 48110099Sjkh if (strchr (arg, '#')) { 48213985Sache /* Play block #blk [ len ] */ 48310099Sjkh int blk, len = 0; 48410099Sjkh 48510099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 48613985Sache 1 != sscanf (arg, "#%d", &blk)) 48713985Sache goto Clean_up; 48813985Sache 48913989Sache if (len == 0) { 49013989Sache if (msf) 49113989Sache len = msf2lba (toc_buffer[n].addr.msf.minute, 49213989Sache toc_buffer[n].addr.msf.second, 49313989Sache toc_buffer[n].addr.msf.frame) - blk; 49413989Sache else 49513989Sache len = ntohl(toc_buffer[n].addr.lba) - blk; 49613989Sache } 49710099Sjkh return play_blocks (blk, len); 49810099Sjkh } 49910099Sjkh 50010099Sjkh if (strchr (arg, ':')) { 50110099Sjkh /* 50210099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 50313985Sache * 50413985Sache * Will now also undestand timed addresses relative 50513985Sache * to the beginning of a track in the form... 50613985Sache * 50713985Sache * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 50810099Sjkh */ 50913985Sache unsigned tr1, tr2; 51013985Sache unsigned m1, m2, s1, s2, f1, f2; 51113989Sache unsigned char tm, ts, tf; 51210099Sjkh 51313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51413985Sache if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", 51513985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) 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, &tr2, &m2, &s2, &f2)) 52113985Sache goto Play_Relative_Addresses; 52213985Sache 52313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52413985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", 52513985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) 52613985Sache goto Play_Relative_Addresses; 52713985Sache 52813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52913985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d", 53013985Sache &tr1, &m1, &s1, &f1, &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, &m2, &s2)) 53613985Sache goto Play_Relative_Addresses; 53713985Sache 53813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53913985Sache if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", 54013985Sache &tr1, &m1, &s1, &m2, &s2, &f2)) 54113985Sache goto Play_Relative_Addresses; 54213985Sache 54313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54413985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d %d", 54513985Sache &tr1, &m1, &s1, &f1, &tr2, &m2)) 54613985Sache goto Play_Relative_Addresses; 54713985Sache 54813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54913985Sache if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) 55013985Sache goto Play_Relative_Addresses; 55113985Sache 55213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55313985Sache if (5 == sscanf (arg, "%d %d:%d %d %d", 55413985Sache &tr1, &m1, &s1, &tr2, &m2)) 55513985Sache goto Play_Relative_Addresses; 55613985Sache 55713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55813985Sache if (5 == sscanf (arg, "%d %d:%d.%d %d", 55913985Sache &tr1, &m1, &s1, &f1, &tr2)) 56013985Sache goto Play_Relative_Addresses; 56113985Sache 56213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56313985Sache if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 56413985Sache goto Play_Relative_Addresses; 56513985Sache 56613985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56713985Sache if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 56813985Sache goto Play_Relative_Addresses; 56913985Sache 57013985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57113985Sache if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) 57213985Sache goto Play_Relative_Addresses; 57313985Sache 57413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57513985Sache goto Try_Absolute_Timed_Addresses; 57613985Sache 57713985SachePlay_Relative_Addresses: 57813985Sache if (! tr1) 57913985Sache tr1 = 1; 58013985Sache else if (tr1 > n) 58113985Sache tr1 = n; 58213985Sache 58313989Sache if (msf) { 58413989Sache tm = toc_buffer[tr1].addr.msf.minute; 58513989Sache ts = toc_buffer[tr1].addr.msf.second; 58613989Sache tf = toc_buffer[tr1].addr.msf.frame; 58713989Sache } else 58813989Sache lba2msf(ntohl(toc_buffer[tr1].addr.lba), 58913989Sache &tm, &ts, &tf); 59013989Sache if ((m1 > tm) 59113989Sache || ((m1 == tm) 59213989Sache && ((s1 > ts) 59313989Sache || ((s1 == ts) 59413989Sache && (f1 > tf))))) { 59513985Sache printf ("Track %d is not that long.\n", tr1); 59613985Sache return (0); 59713985Sache } 59813985Sache 59913985Sache tr1--; 60013985Sache 60113989Sache f1 += tf; 60213985Sache if (f1 >= 75) { 60313985Sache s1 += f1 / 75; 60413985Sache f1 %= 75; 60513985Sache } 60613985Sache 60713989Sache s1 += ts; 60813985Sache if (s1 >= 60) { 60913985Sache m1 += s1 / 60; 61013985Sache s1 %= 60; 61113985Sache } 61213985Sache 61313989Sache m1 += tm; 61413985Sache 61513985Sache if (! tr2) { 61613985Sache if (m2 || s2 || f2) { 61713985Sache tr2 = tr1; 61813985Sache f2 += f1; 61913985Sache if (f2 >= 75) { 62013985Sache s2 += f2 / 75; 62113985Sache f2 %= 75; 62213985Sache } 62313985Sache 62413985Sache s2 += s1; 62513985Sache if (s2 > 60) { 62613985Sache m2 += s2 / 60; 62713985Sache s2 %= 60; 62813985Sache } 62913985Sache 63013985Sache m2 += m1; 63113985Sache } else { 63213985Sache tr2 = n; 63313989Sache if (msf) { 63413989Sache m2 = toc_buffer[n].addr.msf.minute; 63513989Sache s2 = toc_buffer[n].addr.msf.second; 63613989Sache f2 = toc_buffer[n].addr.msf.frame; 63713989Sache } else { 63813989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 63913989Sache &tm, &ts, &tf); 64013989Sache m2 = tm; 64113989Sache s2 = ts; 64213989Sache f2 = tf; 64313989Sache } 64413985Sache } 64513985Sache } else if (tr2 > n) { 64613985Sache tr2 = n; 64713985Sache m2 = s2 = f2 = 0; 64813985Sache } else { 64913985Sache if (m2 || s2 || f2) 65013985Sache tr2--; 65113989Sache if (msf) { 65213989Sache tm = toc_buffer[tr2].addr.msf.minute; 65313989Sache ts = toc_buffer[tr2].addr.msf.second; 65413989Sache tf = toc_buffer[tr2].addr.msf.frame; 65513989Sache } else 65613989Sache lba2msf(ntohl(toc_buffer[tr2].addr.lba), 65713989Sache &tm, &ts, &tf); 65813989Sache f2 += tf; 65913985Sache if (f2 >= 75) { 66013985Sache s2 += f2 / 75; 66113985Sache f2 %= 75; 66213985Sache } 66313985Sache 66413989Sache s2 += ts; 66513985Sache if (s2 > 60) { 66613985Sache m2 += s2 / 60; 66713985Sache s2 %= 60; 66813985Sache } 66913985Sache 67013989Sache m2 += tm; 67113985Sache } 67213985Sache 67313989Sache if (msf) { 67413989Sache tm = toc_buffer[n].addr.msf.minute; 67513989Sache ts = toc_buffer[n].addr.msf.second; 67613989Sache tf = toc_buffer[n].addr.msf.frame; 67713989Sache } else 67813989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 67913989Sache &tm, &ts, &tf); 68013985Sache if ((tr2 < n) 68113989Sache && ((m2 > tm) 68213989Sache || ((m2 == tm) 68313989Sache && ((s2 > ts) 68413989Sache || ((s2 == ts) 68513989Sache && (f2 > tf)))))) { 68613985Sache printf ("The playing time of the disc is not that long.\n"); 68713985Sache return (0); 68813985Sache } 68913985Sache return (play_msf (m1, s1, f1, m2, s2, f2)); 69013985Sache 69113985SacheTry_Absolute_Timed_Addresses: 69213985Sache if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", 69313985Sache &m1, &s1, &f1, &m2, &s2, &f2) && 69410099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 69510099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 69610099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 69710099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 69810099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 69913985Sache goto Clean_up; 70013985Sache 70110099Sjkh if (m2 == 0) { 70213989Sache if (msf) { 70313989Sache m2 = toc_buffer[n].addr.msf.minute; 70413989Sache s2 = toc_buffer[n].addr.msf.second; 70513989Sache f2 = toc_buffer[n].addr.msf.frame; 70613989Sache } else { 70713989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 70813989Sache &tm, &ts, &tf); 70913989Sache m2 = tm; 71013989Sache s2 = ts; 71113989Sache f2 = tf; 71213989Sache } 71310099Sjkh } 71410099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 71510099Sjkh } 71610099Sjkh 71710099Sjkh /* 71810099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 71910099Sjkh */ 72010099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 72110099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 72210099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 72310099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 72410099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 72510099Sjkh 1 != sscanf (arg, "%d", &start)) 72613985Sache goto Clean_up; 72713985Sache 72810099Sjkh if (end == 0) 72910099Sjkh end = n; 73013985Sache return (play_track (start, istart, end, iend)); 73113985Sache 73213985SacheClean_up: 73329103Scharnier warnx("invalid command arguments"); 73413985Sache return (0); 73510099Sjkh} 73610099Sjkh 73777168Skrisint next_prev (char *arg, int cmd) 73877168Skris{ 73977168Skris struct ioc_toc_header h; 74077168Skris int dir, junk, n, off, rc, trk; 74177168Skris 74277168Skris dir = (cmd == CMD_NEXT) ? 1 : -1; 74377168Skris rc = ioctl (fd, CDIOREADTOCHEADER, &h); 74477168Skris if (rc < 0) 74577168Skris return (rc); 74677168Skris 74777168Skris n = h.ending_track - h.starting_track + 1; 74877168Skris rc = status (&trk, &junk, &junk, &junk); 74977168Skris if (rc < 0) 75077168Skris return (-1); 75177168Skris 75277168Skris if (arg && *arg) { 75377168Skris if (sscanf (arg, "%u", &off) != 1) { 75477168Skris warnx("invalid command argument"); 75577168Skris return (0); 75677168Skris } else 75777168Skris trk += off * dir; 75877168Skris } else 75977168Skris trk += dir; 76077168Skris 76177168Skris if (trk > h.ending_track) 76277168Skris trk = 1; 76377168Skris 76477168Skris return (play_track (trk, 1, n, 1)); 76577168Skris} 76677168Skris 76787568Smikehconst char *strstatus (int sts) 76810099Sjkh{ 76910099Sjkh switch (sts) { 77087573Smikeh case ASTS_INVALID: return ("invalid"); 77187573Smikeh case ASTS_PLAYING: return ("playing"); 77287573Smikeh case ASTS_PAUSED: return ("paused"); 77387573Smikeh case ASTS_COMPLETED: return ("completed"); 77487573Smikeh case ASTS_ERROR: return ("error"); 77587573Smikeh case ASTS_VOID: return ("void"); 77687573Smikeh default: return ("??"); 77710099Sjkh } 77810099Sjkh} 77910099Sjkh 78013884Sacheint pstatus (char *arg) 78110099Sjkh{ 78210099Sjkh struct ioc_vol v; 78313888Sache struct ioc_read_subchannel ss; 78413888Sache struct cd_sub_channel_info data; 78513884Sache int rc, trk, m, s, f; 78632782Sjmz int what = 0; 78777168Skris char *p, vmcn[(4 * 15) + 1]; 78810099Sjkh 78932782Sjmz while ((p = strtok(arg, " \t"))) { 79032782Sjmz arg = 0; 79132782Sjmz if (!strncasecmp(p, "audio", strlen(p))) 79232782Sjmz what |= STATUS_AUDIO; 79332782Sjmz else if (!strncasecmp(p, "media", strlen(p))) 79432782Sjmz what |= STATUS_MEDIA; 79532782Sjmz else if (!strncasecmp(p, "volume", strlen(p))) 79632782Sjmz what |= STATUS_VOLUME; 79732782Sjmz else { 79832782Sjmz warnx("invalid command arguments"); 79932782Sjmz return 0; 80032782Sjmz } 80132782Sjmz } 80232782Sjmz if (!what) 80332782Sjmz what = STATUS_AUDIO|STATUS_MEDIA|STATUS_VOLUME; 80432782Sjmz if (what & STATUS_AUDIO) { 80532782Sjmz rc = status (&trk, &m, &s, &f); 80632782Sjmz if (rc >= 0) 80710099Sjkh if (verbose) 80832782Sjmz printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 80932782Sjmz rc, strstatus (rc), trk, m, s, f); 81010099Sjkh else 81132782Sjmz printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 81232782Sjmz else 81313888Sache printf ("No current status info available\n"); 81432782Sjmz } 81532782Sjmz if (what & STATUS_MEDIA) { 81632782Sjmz bzero (&ss, sizeof (ss)); 81732782Sjmz ss.data = &data; 81832782Sjmz ss.data_len = sizeof (data); 81932782Sjmz ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 82032782Sjmz ss.data_format = CD_MEDIA_CATALOG; 82132782Sjmz rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); 82232782Sjmz if (rc >= 0) { 82313889Sache printf("Media catalog is %sactive", 82487573Smikeh ss.data->what.media_catalog.mc_valid ? "": "in"); 82516736Sache if (ss.data->what.media_catalog.mc_valid && 82616736Sache ss.data->what.media_catalog.mc_number[0]) 82777168Skris { 82877168Skris strvisx (vmcn, ss.data->what.media_catalog.mc_number, 82977168Skris (sizeof (vmcn) - 1) / 4, VIS_OCTAL | VIS_NL); 83077168Skris printf(", number \"%.*s\"", (int)sizeof (vmcn), vmcn); 83177168Skris } 83213889Sache putchar('\n'); 83332782Sjmz } else 83413888Sache printf("No media catalog info available\n"); 83532782Sjmz } 83632782Sjmz if (what & STATUS_VOLUME) { 83732782Sjmz rc = ioctl (fd, CDIOCGETVOL, &v); 83832782Sjmz if (rc >= 0) 83910099Sjkh if (verbose) 84032782Sjmz printf ("Left volume = %d, right volume = %d\n", 84132782Sjmz v.vol[0], v.vol[1]); 84210099Sjkh else 84332782Sjmz printf ("%d %d\n", v.vol[0], v.vol[1]); 84432782Sjmz else 84513888Sache printf ("No volume level info available\n"); 84632782Sjmz } 84713884Sache return(0); 84813884Sache} 84910099Sjkh 85063091Sjoe/* 85163091Sjoe * dbprog_sum 85263091Sjoe * Convert an integer to its text string representation, and 85363091Sjoe * compute its checksum. Used by dbprog_discid to derive the 85463091Sjoe * disc ID. 85563091Sjoe * 85663091Sjoe * Args: 85763091Sjoe * n - The integer value. 85863091Sjoe * 85963091Sjoe * Return: 86063091Sjoe * The integer checksum. 86163091Sjoe */ 86263091Sjoestatic int 86363091Sjoedbprog_sum(int n) 86463091Sjoe{ 86563091Sjoe char buf[12], 86663091Sjoe *p; 86763091Sjoe int ret = 0; 86863091Sjoe 86963091Sjoe /* For backward compatibility this algorithm must not change */ 87063091Sjoe sprintf(buf, "%u", n); 87163091Sjoe for (p = buf; *p != '\0'; p++) 87263091Sjoe ret += (*p - '0'); 87363091Sjoe 87463091Sjoe return(ret); 87563091Sjoe} 87663091Sjoe 87763091Sjoe 87863091Sjoe/* 87963091Sjoe * dbprog_discid 88063091Sjoe * Compute a magic disc ID based on the number of tracks, 88163091Sjoe * the length of each track, and a checksum of the string 88263091Sjoe * that represents the offset of each track. 88363091Sjoe * 88463091Sjoe * Args: 88563091Sjoe * s - Pointer to the curstat_t structure. 88663091Sjoe * 88763091Sjoe * Return: 88863091Sjoe * The integer disc ID. 88963091Sjoe */ 89063091Sjoestatic u_int 89163091Sjoedbprog_discid() 89263091Sjoe{ 89363091Sjoe struct ioc_toc_header h; 89463091Sjoe int rc; 89563091Sjoe int i, ntr, 89663091Sjoe t = 0, 89763091Sjoe n = 0; 89863091Sjoe 89963091Sjoe rc = ioctl (fd, CDIOREADTOCHEADER, &h); 90063091Sjoe if (rc < 0) 90163091Sjoe return 0; 90263091Sjoe ntr = h.ending_track - h.starting_track + 1; 90363091Sjoe i = msf; 90463091Sjoe msf = 1; 90563091Sjoe rc = read_toc_entrys ((ntr + 1) * sizeof (struct cd_toc_entry)); 90663091Sjoe msf = i; 90763091Sjoe if (rc < 0) 90863091Sjoe return 0; 90963091Sjoe /* For backward compatibility this algorithm must not change */ 91063091Sjoe for (i = 0; i < ntr; i++) { 91163091Sjoe#define TC_MM(a) toc_buffer[a].addr.msf.minute 91263091Sjoe#define TC_SS(a) toc_buffer[a].addr.msf.second 91363091Sjoe n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i)); 91463091Sjoe 91563091Sjoe t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - 91687573Smikeh ((TC_MM(i) * 60) + TC_SS(i)); 91763091Sjoe } 91863091Sjoe 91963091Sjoe return((n % 0xff) << 24 | t << 8 | ntr); 92063091Sjoe} 92163091Sjoe 92263091Sjoeint cdid () 92363091Sjoe{ 92463091Sjoe u_int id; 92563091Sjoe 92663091Sjoe id = dbprog_discid(); 92763091Sjoe if (id) 92863091Sjoe { 92963091Sjoe if (verbose) 93063091Sjoe printf ("CDID="); 93163091Sjoe printf ("%08x\n",id); 93263091Sjoe } 93363091Sjoe return id ? 0 : 1; 93463091Sjoe} 93563091Sjoe 93687568Smikehint info (char *arg __unused) 93713884Sache{ 93813884Sache struct ioc_toc_header h; 93913884Sache int rc, i, n; 94013884Sache 94110099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 94213888Sache if (rc >= 0) { 94310099Sjkh if (verbose) 94410099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 94510099Sjkh h.starting_track, h.ending_track, h.len); 94610099Sjkh else 94710099Sjkh printf ("%d %d %d\n", h.starting_track, 94810099Sjkh h.ending_track, h.len); 94913888Sache } else { 95029103Scharnier warn("getting toc header"); 95110099Sjkh return (rc); 95210099Sjkh } 95310099Sjkh 95410099Sjkh n = h.ending_track - h.starting_track + 1; 95510099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 95610099Sjkh if (rc < 0) 95710099Sjkh return (rc); 95813985Sache 95910099Sjkh if (verbose) { 96010099Sjkh printf ("track start duration block length type\n"); 96110099Sjkh printf ("-------------------------------------------------\n"); 96210099Sjkh } 96313985Sache 96410099Sjkh for (i = 0; i < n; i++) { 96510099Sjkh printf ("%5d ", toc_buffer[i].track); 96610099Sjkh prtrack (toc_buffer + i, 0); 96710099Sjkh } 96813867Sache printf ("%5d ", toc_buffer[n].track); 96910099Sjkh prtrack (toc_buffer + n, 1); 97010099Sjkh return (0); 97110099Sjkh} 97210099Sjkh 97313985Sachevoid lba2msf (unsigned long lba, u_char *m, u_char *s, u_char *f) 97410099Sjkh{ 97587573Smikeh lba += 150; /* block start offset */ 97687573Smikeh lba &= 0xffffff; /* negative lbas use only 24 bits */ 97710099Sjkh *m = lba / (60 * 75); 97810099Sjkh lba %= (60 * 75); 97910099Sjkh *s = lba / 75; 98010099Sjkh *f = lba % 75; 98110099Sjkh} 98210099Sjkh 98313985Sacheunsigned int msf2lba (u_char m, u_char s, u_char f) 98410099Sjkh{ 98510099Sjkh return (((m * 60) + s) * 75 + f) - 150; 98610099Sjkh} 98710099Sjkh 98810099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag) 98910099Sjkh{ 99010099Sjkh int block, next, len; 99110099Sjkh u_char m, s, f; 99210099Sjkh 99313884Sache if (msf) { 99413884Sache /* Print track start */ 99513884Sache printf ("%2d:%02d.%02d ", e->addr.msf.minute, 99613884Sache e->addr.msf.second, e->addr.msf.frame); 99710099Sjkh 99813884Sache block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 99913884Sache e->addr.msf.frame); 100013884Sache } else { 100113884Sache block = ntohl(e->addr.lba); 100213884Sache lba2msf(block, &m, &s, &f); 100313884Sache /* Print track start */ 100413884Sache printf ("%2d:%02d.%02d ", m, s, f); 100513884Sache } 100610099Sjkh if (lastflag) { 100710099Sjkh /* Last track -- print block */ 100810099Sjkh printf (" - %6d - -\n", block); 100910099Sjkh return; 101010099Sjkh } 101110099Sjkh 101213884Sache if (msf) 101313884Sache next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 101413884Sache e[1].addr.msf.frame); 101513884Sache else 101613884Sache next = ntohl(e[1].addr.lba); 101710099Sjkh len = next - block; 101810099Sjkh lba2msf (len, &m, &s, &f); 101910099Sjkh 102010099Sjkh /* Print duration, block, length, type */ 102110099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 102213985Sache (e->control & 4) ? "data" : "audio"); 102310099Sjkh} 102410099Sjkh 102510099Sjkhint play_track (int tstart, int istart, int tend, int iend) 102610099Sjkh{ 102710099Sjkh struct ioc_play_track t; 102810099Sjkh 102910099Sjkh t.start_track = tstart; 103010099Sjkh t.start_index = istart; 103110099Sjkh t.end_track = tend; 103210099Sjkh t.end_index = iend; 103313985Sache 103410099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 103510099Sjkh} 103610099Sjkh 103710099Sjkhint play_blocks (int blk, int len) 103810099Sjkh{ 103913985Sache struct ioc_play_blocks t; 104010099Sjkh 104110099Sjkh t.blk = blk; 104210099Sjkh t.len = len; 104313985Sache 104410099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 104510099Sjkh} 104610099Sjkh 104713985Sacheint setvol (int left, int right) 104810099Sjkh{ 104913985Sache struct ioc_vol v; 105010099Sjkh 105113985Sache v.vol[0] = left; 105213985Sache v.vol[1] = right; 105310099Sjkh v.vol[2] = 0; 105410099Sjkh v.vol[3] = 0; 105513985Sache 105610099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 105710099Sjkh} 105810099Sjkh 105910099Sjkhint read_toc_entrys (int len) 106010099Sjkh{ 106110099Sjkh struct ioc_read_toc_entry t; 106210099Sjkh 106313884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 106413737Sache t.starting_track = 0; 106510099Sjkh t.data_len = len; 106610099Sjkh t.data = toc_buffer; 106713985Sache 106813985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 106910099Sjkh} 107010099Sjkh 107110099Sjkhint play_msf (int start_m, int start_s, int start_f, 107213985Sache int end_m, int end_s, int end_f) 107310099Sjkh{ 107487573Smikeh struct ioc_play_msf a; 107510099Sjkh 107610099Sjkh a.start_m = start_m; 107710099Sjkh a.start_s = start_s; 107810099Sjkh a.start_f = start_f; 107910099Sjkh a.end_m = end_m; 108010099Sjkh a.end_s = end_s; 108110099Sjkh a.end_f = end_f; 108213985Sache 108310099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 108410099Sjkh} 108510099Sjkh 108610099Sjkhint status (int *trk, int *min, int *sec, int *frame) 108710099Sjkh{ 108810099Sjkh struct ioc_read_subchannel s; 108910099Sjkh struct cd_sub_channel_info data; 109013884Sache u_char mm, ss, ff; 109110099Sjkh 109210099Sjkh bzero (&s, sizeof (s)); 109310099Sjkh s.data = &data; 109410099Sjkh s.data_len = sizeof (data); 109513884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 109610099Sjkh s.data_format = CD_CURRENT_POSITION; 109713985Sache 109810099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 109910099Sjkh return -1; 110013985Sache 110110099Sjkh *trk = s.data->what.position.track_number; 110213884Sache if (msf) { 110313884Sache *min = s.data->what.position.reladdr.msf.minute; 110413884Sache *sec = s.data->what.position.reladdr.msf.second; 110513884Sache *frame = s.data->what.position.reladdr.msf.frame; 110613884Sache } else { 110713884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 110813884Sache &mm, &ss, &ff); 110913884Sache *min = mm; 111013884Sache *sec = ss; 111113884Sache *frame = ff; 111213884Sache } 111313985Sache 111410099Sjkh return s.data->header.audio_status; 111510099Sjkh} 111610099Sjkh 111750039Smdoddconst char * 111850039Smdoddcdcontrol_prompt() 111910099Sjkh{ 112050039Smdodd return ("cdcontrol> "); 112150039Smdodd} 112250039Smdodd 112350039Smdoddchar * 112450039Smdoddinput (int *cmd) 112550039Smdodd{ 112650039Smdodd#define MAXLINE 80 112750039Smdodd static EditLine *el = NULL; 112850039Smdodd static History *hist = NULL; 112984261Sobrien HistEvent he; 113050039Smdodd static char buf[MAXLINE]; 113150039Smdodd int num = 0; 113250071Smdodd int len; 113350039Smdodd const char *bp = NULL; 113410099Sjkh char *p; 113510099Sjkh 113610099Sjkh do { 113750039Smdodd if (verbose) { 113850039Smdodd if (!el) { 113984261Sobrien el = el_init("cdcontrol", stdin, stdout, 114084261Sobrien stderr); 114150039Smdodd hist = history_init(); 114284261Sobrien history(hist, &he, H_EVENT, 100); 114350039Smdodd el_set(el, EL_HIST, history, hist); 114450039Smdodd el_set(el, EL_EDITOR, "emacs"); 114550039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 114650039Smdodd el_set(el, EL_SIGNAL, 1); 114750042Smdodd el_source(el, NULL); 114850039Smdodd } 114963070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 115063070Smckay *cmd = CMD_QUIT; 115163070Smckay fprintf (stderr, "\r\n"); 115250039Smdodd return (0); 115363070Smckay } 115450039Smdodd 115550071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 115650071Smdodd memcpy(buf, bp, len); 115750071Smdodd buf[len] = 0; 115884261Sobrien history(hist, &he, H_ENTER, bp); 115950039Smdodd#undef MAXLINE 116050039Smdodd 116150039Smdodd } else { 116250039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 116350039Smdodd *cmd = CMD_QUIT; 116450039Smdodd fprintf (stderr, "\r\n"); 116550039Smdodd return (0); 116650039Smdodd } 116710099Sjkh } 116810099Sjkh p = parse (buf, cmd); 116910099Sjkh } while (! p); 117010099Sjkh return (p); 117110099Sjkh} 117210099Sjkh 117310099Sjkhchar *parse (char *buf, int *cmd) 117410099Sjkh{ 117510099Sjkh struct cmdtab *c; 117610099Sjkh char *p; 117787568Smikeh unsigned int len; 117810099Sjkh 117913985Sache for (p=buf; isspace (*p); p++) 118013985Sache continue; 118110099Sjkh 118213985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 118313985Sache *cmd = CMD_PLAY; 118413985Sache return (p); 118577168Skris } else if (*p == '+') { 118677168Skris *cmd = CMD_NEXT; 118777168Skris return (p + 1); 118877168Skris } else if (*p == '-') { 118977168Skris *cmd = CMD_PREVIOUS; 119077168Skris return (p + 1); 119113985Sache } 119210099Sjkh 119313985Sache for (buf = p; *p && ! isspace (*p); p++) 119413985Sache continue; 119596214Smaxim 119613985Sache len = p - buf; 119710099Sjkh if (! len) 119810099Sjkh return (0); 119913985Sache 120087573Smikeh if (*p) { /* It must be a spacing character! */ 120113985Sache char *q; 120213985Sache 120313985Sache *p++ = 0; 120413985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 120513985Sache continue; 120613985Sache *q = 0; 120713985Sache } 120813985Sache 120910099Sjkh *cmd = -1; 121010099Sjkh for (c=cmdtab; c->name; ++c) { 121113985Sache /* Is it an exact match? */ 121213985Sache if (! strcasecmp (buf, c->name)) { 121313985Sache *cmd = c->command; 121413985Sache break; 121513985Sache } 121613985Sache 121713985Sache /* Try short hand forms then... */ 121813985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 121913985Sache if (*cmd != -1 && *cmd != c->command) { 122029103Scharnier warnx("ambiguous command"); 122113985Sache return (0); 122213985Sache } 122310099Sjkh *cmd = c->command; 122413985Sache } 122513985Sache } 122610099Sjkh 122710099Sjkh if (*cmd == -1) { 122829103Scharnier warnx("invalid command, enter ``help'' for commands"); 122910099Sjkh return (0); 123010099Sjkh } 123113985Sache 123213985Sache while (isspace (*p)) 123313985Sache p++; 123410099Sjkh return p; 123510099Sjkh} 123610099Sjkh 123710099Sjkhint open_cd () 123810099Sjkh{ 123954164Sjoe char devbuf[MAXPATHLEN]; 124010099Sjkh 124110099Sjkh if (fd > -1) 124210099Sjkh return (1); 124313985Sache 124454164Sjoe if (*cdname == '/') { 124554164Sjoe snprintf (devbuf, MAXPATHLEN, "%s", cdname); 124661105Smsmith } else { 124769793Sobrien snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 124854164Sjoe } 124913985Sache 125010099Sjkh fd = open (devbuf, O_RDONLY); 125113985Sache 125210099Sjkh if (fd < 0 && errno == ENOENT) { 125313985Sache strcat (devbuf, DEFAULT_CD_PARTITION); 125410099Sjkh fd = open (devbuf, O_RDONLY); 125510099Sjkh } 125613985Sache 125710099Sjkh if (fd < 0) { 125813985Sache if (errno == ENXIO) { 125913985Sache /* ENXIO has an overloaded meaning here. 126013985Sache * The original "Device not configured" should 126113985Sache * be interpreted as "No disc in drive %s". */ 126229103Scharnier warnx("no disc in drive %s", devbuf); 126313985Sache return (0); 126410099Sjkh } 126529103Scharnier err(1, "%s", devbuf); 126610099Sjkh } 126710099Sjkh return (1); 126810099Sjkh} 1269