cdcontrol.c revision 96213
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 96213 2002-05-08 07:32:40Z maxim $"; 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 12287573Smikehint setvol __P((int, int)); 12387573Smikehint read_toc_entrys __P((int)); 12487573Smikehint play_msf __P((int, int, int, int, int, int)); 12587573Smikehint play_track __P((int, int, int, int)); 12687573Smikehint get_vol __P((int *, int *)); 12787573Smikehint status __P((int *, int *, int *, int *)); 12887573Smikehint open_cd __P((void)); 12987573Smikehint next_prev __P((char *arg, int)); 13087573Smikehint play __P((char *arg)); 13187573Smikehint info __P((char *arg)); 13287573Smikehint cdid __P((void)); 13387573Smikehint pstatus __P((char *arg)); 13487573Smikehchar *input __P((int *)); 13587573Smikehvoid prtrack __P((struct cd_toc_entry *e, int lastflag)); 13687573Smikehvoid lba2msf __P((unsigned long lba, 13787573Smikeh u_char *m, u_char *s, u_char *f)); 13887573Smikehunsigned int msf2lba __P((u_char m, u_char s, u_char f)); 13987573Smikehint play_blocks __P((int blk, int len)); 14087573Smikehint run __P((int cmd, char *arg)); 14187573Smikehchar *parse __P((char *buf, int *cmd)); 14287573Smikehvoid help __P((void)); 14387573Smikehvoid usage __P((void)); 14487573Smikehchar *use_cdrom_instead __P((const char *)); 14587573Smikeh__const char *strstatus __P((int)); 14687573Smikehstatic u_int dbprog_discid __P((void)); 14787573Smikeh__const char *cdcontrol_prompt __P((void)); 14810099Sjkh 14910099Sjkhvoid help () 15010099Sjkh{ 15110099Sjkh struct cmdtab *c; 15287568Smikeh const char *s; 15387568Smikeh char n; 15413985Sache int i; 15510099Sjkh 15610099Sjkh for (c=cmdtab; c->name; ++c) { 15710099Sjkh if (! c->args) 15810099Sjkh continue; 15913985Sache printf("\t"); 16013985Sache for (i = c->min, s = c->name; *s; s++, i--) { 16113985Sache if (i > 0) 16213985Sache n = toupper(*s); 16313985Sache else 16413985Sache n = *s; 16513985Sache putchar(n); 16613985Sache } 16710099Sjkh if (*c->args) 16810099Sjkh printf (" %s", c->args); 16910099Sjkh printf ("\n"); 17010099Sjkh } 17113985Sache printf ("\n\tThe word \"play\" is not required for the play commands.\n"); 17213985Sache printf ("\tThe plain target address is taken as a synonym for play.\n"); 17310099Sjkh} 17410099Sjkh 17510099Sjkhvoid usage () 17610099Sjkh{ 17743479Sbillf fprintf (stderr, "usage: cdcontrol [-sv] [-f device] [command ...]\n"); 17810099Sjkh exit (1); 17910099Sjkh} 18010099Sjkh 18187568Smikehchar *use_cdrom_instead(const char *old_envvar) 18271122Sjoe{ 18371122Sjoe char *device; 18471122Sjoe 18571122Sjoe device = getenv(old_envvar); 18671122Sjoe if (device) 18771122Sjoe warnx("%s environment variable deprecated, " 18871122Sjoe "please use CDROM in the future.", old_envvar); 18971122Sjoe return device; 19071122Sjoe} 19171122Sjoe 19271122Sjoe 19310099Sjkhint main (int argc, char **argv) 19410099Sjkh{ 19510099Sjkh int cmd; 19610099Sjkh char *arg; 19710099Sjkh 19810099Sjkh for (;;) { 19910099Sjkh switch (getopt (argc, argv, "svhf:")) { 20010099Sjkh case EOF: 20110099Sjkh break; 20210099Sjkh case 's': 20310099Sjkh verbose = 0; 20410099Sjkh continue; 20510099Sjkh case 'v': 20610099Sjkh verbose = 2; 20710099Sjkh continue; 20810099Sjkh case 'f': 20910099Sjkh cdname = optarg; 21010099Sjkh continue; 21110099Sjkh case 'h': 21210099Sjkh default: 21310099Sjkh usage (); 21410099Sjkh } 21510099Sjkh break; 21610099Sjkh } 21710099Sjkh argc -= optind; 21810099Sjkh argv += optind; 21910099Sjkh 22013985Sache if (argc > 0 && ! strcasecmp (*argv, "help")) 22110099Sjkh usage (); 22210099Sjkh 22310099Sjkh if (! cdname) { 22470149Sdes cdname = getenv("CDROM"); 22570149Sdes } 22670149Sdes 22775324Sjoe if (! cdname) 22875324Sjoe cdname = use_cdrom_instead("MUSIC_CD"); 22975324Sjoe if (! cdname) 23075324Sjoe cdname = use_cdrom_instead("CD_DRIVE"); 23175324Sjoe if (! cdname) 23275324Sjoe cdname = use_cdrom_instead("DISC"); 23375324Sjoe if (! cdname) 23475324Sjoe cdname = use_cdrom_instead("CDPLAY"); 23575324Sjoe 23670149Sdes if (! cdname) { 23713985Sache cdname = DEFAULT_CD_DRIVE; 23829103Scharnier warnx("no CD device name specified, defaulting to %s", cdname); 23910099Sjkh } 24010099Sjkh 24110099Sjkh if (argc > 0) { 24210099Sjkh char buf[80], *p; 24310099Sjkh int len; 24410099Sjkh 24513985Sache for (p=buf; argc-->0; ++argv) { 24610099Sjkh len = strlen (*argv); 24713985Sache 24810099Sjkh if (p + len >= buf + sizeof (buf) - 1) 24910099Sjkh usage (); 25013985Sache 25110099Sjkh if (p > buf) 25210099Sjkh *p++ = ' '; 25313985Sache 25410099Sjkh strcpy (p, *argv); 25510099Sjkh p += len; 25610099Sjkh } 25710099Sjkh *p = 0; 25810099Sjkh arg = parse (buf, &cmd); 25913985Sache return (run (cmd, arg)); 26010099Sjkh } 26110099Sjkh 26210099Sjkh if (verbose == 1) 26310099Sjkh verbose = isatty (0); 26413985Sache 26510099Sjkh if (verbose) { 26613985Sache printf ("Compact Disc Control utility, version %s\n", VERSION); 26710099Sjkh printf ("Type `?' for command list\n\n"); 26810099Sjkh } 26910099Sjkh 27010099Sjkh for (;;) { 27110099Sjkh arg = input (&cmd); 27210099Sjkh if (run (cmd, arg) < 0) { 27310099Sjkh if (verbose) 27429103Scharnier warn(NULL); 27510099Sjkh close (fd); 27610099Sjkh fd = -1; 27710099Sjkh } 27810099Sjkh fflush (stdout); 27910099Sjkh } 28010099Sjkh} 28110099Sjkh 28210099Sjkhint run (int cmd, char *arg) 28310099Sjkh{ 28496213Smaxim long speed; 28510099Sjkh int l, r, rc; 28696213Smaxim char *ep; 28710099Sjkh 28810099Sjkh switch (cmd) { 28913985Sache 29010099Sjkh case CMD_QUIT: 29110099Sjkh exit (0); 29210099Sjkh 29313985Sache case CMD_INFO: 29413985Sache if (fd < 0 && ! open_cd ()) 29513985Sache return (0); 29610099Sjkh 29710099Sjkh return info (arg); 29810099Sjkh 29963091Sjoe case CMD_CDID: 30063091Sjoe if (fd < 0 && ! open_cd ()) 30163091Sjoe return (0); 30263091Sjoe 30363091Sjoe return cdid (); 30463091Sjoe 30513884Sache case CMD_STATUS: 30613985Sache if (fd < 0 && ! open_cd ()) 30713985Sache return (0); 30813985Sache 30913884Sache return pstatus (arg); 31013884Sache 31177168Skris case CMD_NEXT: 31277168Skris case CMD_PREVIOUS: 31377168Skris if (fd < 0 && ! open_cd ()) 31477168Skris return (0); 31577168Skris 31677168Skris while (isspace (*arg)) 31777168Skris arg++; 31877168Skris 31977168Skris return next_prev (arg, cmd); 32077168Skris 32110099Sjkh case CMD_PAUSE: 32213985Sache if (fd < 0 && ! open_cd ()) 32313985Sache return (0); 32413985Sache 32510099Sjkh return ioctl (fd, CDIOCPAUSE); 32610099Sjkh 32710099Sjkh case CMD_RESUME: 32813985Sache if (fd < 0 && ! open_cd ()) 32913985Sache return (0); 33013985Sache 33110099Sjkh return ioctl (fd, CDIOCRESUME); 33210099Sjkh 33310099Sjkh case CMD_STOP: 33413985Sache if (fd < 0 && ! open_cd ()) 33513985Sache return (0); 33610099Sjkh 33713985Sache rc = ioctl (fd, CDIOCSTOP); 33813985Sache 33913985Sache (void) ioctl (fd, CDIOCALLOW); 34013985Sache 34113985Sache return (rc); 34213985Sache 34313884Sache case CMD_RESET: 34413985Sache if (fd < 0 && ! open_cd ()) 34513985Sache return (0); 34613985Sache 34713884Sache rc = ioctl (fd, CDIOCRESET); 34813884Sache if (rc < 0) 34913884Sache return rc; 35013884Sache close(fd); 35113884Sache fd = -1; 35213884Sache return (0); 35313884Sache 35410099Sjkh case CMD_DEBUG: 35513985Sache if (fd < 0 && ! open_cd ()) 35613985Sache return (0); 35713985Sache 35813985Sache if (! strcasecmp (arg, "on")) 35910099Sjkh return ioctl (fd, CDIOCSETDEBUG); 36013985Sache 36113985Sache if (! strcasecmp (arg, "off")) 36210099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 36313985Sache 36429103Scharnier warnx("invalid command arguments"); 36513985Sache 36610099Sjkh return (0); 36710099Sjkh 36810099Sjkh case CMD_EJECT: 36913985Sache if (fd < 0 && ! open_cd ()) 37013985Sache return (0); 37113985Sache 37210099Sjkh (void) ioctl (fd, CDIOCALLOW); 37310099Sjkh rc = ioctl (fd, CDIOCEJECT); 37410099Sjkh if (rc < 0) 37510099Sjkh return (rc); 37613865Sache return (0); 37713865Sache 37813985Sache case CMD_CLOSE: 37913985Sache if (fd < 0 && ! open_cd ()) 38013985Sache return (0); 38113985Sache 38213985Sache (void) ioctl (fd, CDIOCALLOW); 38313865Sache rc = ioctl (fd, CDIOCCLOSE); 38413865Sache if (rc < 0) 38513865Sache return (rc); 38613865Sache close(fd); 38710099Sjkh fd = -1; 38810099Sjkh return (0); 38910099Sjkh 39010099Sjkh case CMD_PLAY: 39113985Sache if (fd < 0 && ! open_cd ()) 39213985Sache return (0); 39313985Sache 39413985Sache while (isspace (*arg)) 39513985Sache arg++; 39613985Sache 39710099Sjkh return play (arg); 39810099Sjkh 39913884Sache case CMD_SET: 40013985Sache if (! strcasecmp (arg, "msf")) 40113884Sache msf = 1; 40213985Sache else if (! strcasecmp (arg, "lba")) 40313884Sache msf = 0; 40413884Sache else 40529103Scharnier warnx("invalid command arguments"); 40613884Sache return (0); 40713884Sache 40810099Sjkh case CMD_VOLUME: 40913985Sache if (fd < 0 && !open_cd ()) 41013985Sache return (0); 41110099Sjkh 41213985Sache if (! strncasecmp (arg, "left", strlen(arg))) 41310099Sjkh return ioctl (fd, CDIOCSETLEFT); 41413985Sache 41513985Sache if (! strncasecmp (arg, "right", strlen(arg))) 41610099Sjkh return ioctl (fd, CDIOCSETRIGHT); 41713985Sache 41813985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 41910099Sjkh return ioctl (fd, CDIOCSETMONO); 42013985Sache 42113985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 42210099Sjkh return ioctl (fd, CDIOCSETSTERIO); 42310099Sjkh 42413985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 42513985Sache return ioctl (fd, CDIOCSETMUTE); 42613985Sache 42710099Sjkh if (2 != sscanf (arg, "%d %d", &l, &r)) { 42829103Scharnier warnx("invalid command arguments"); 42910099Sjkh return (0); 43010099Sjkh } 43113985Sache 43210099Sjkh return setvol (l, r); 43313985Sache 43496213Smaxim case CMD_SPEED: 43596213Smaxim if (fd < 0 && ! open_cd ()) 43696213Smaxim return (0); 43796213Smaxim 43896213Smaxim errno = 0; 43996213Smaxim speed = strtol(arg, &ep, 10); 44096213Smaxim if (*ep || ep == arg || speed <= 0 || speed > INT_MAX || 44196213Smaxim errno != 0) { 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; 101910099Sjkh lba2msf (len, &m, &s, &f); 102010099Sjkh 102110099Sjkh /* Print duration, block, length, type */ 102210099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 102313985Sache (e->control & 4) ? "data" : "audio"); 102410099Sjkh} 102510099Sjkh 102610099Sjkhint play_track (int tstart, int istart, int tend, int iend) 102710099Sjkh{ 102810099Sjkh struct ioc_play_track t; 102910099Sjkh 103010099Sjkh t.start_track = tstart; 103110099Sjkh t.start_index = istart; 103210099Sjkh t.end_track = tend; 103310099Sjkh t.end_index = iend; 103413985Sache 103510099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 103610099Sjkh} 103710099Sjkh 103810099Sjkhint play_blocks (int blk, int len) 103910099Sjkh{ 104013985Sache struct ioc_play_blocks t; 104110099Sjkh 104210099Sjkh t.blk = blk; 104310099Sjkh t.len = len; 104413985Sache 104510099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 104610099Sjkh} 104710099Sjkh 104813985Sacheint setvol (int left, int right) 104910099Sjkh{ 105013985Sache struct ioc_vol v; 105110099Sjkh 105213985Sache v.vol[0] = left; 105313985Sache v.vol[1] = right; 105410099Sjkh v.vol[2] = 0; 105510099Sjkh v.vol[3] = 0; 105613985Sache 105710099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 105810099Sjkh} 105910099Sjkh 106010099Sjkhint read_toc_entrys (int len) 106110099Sjkh{ 106210099Sjkh struct ioc_read_toc_entry t; 106310099Sjkh 106413884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 106513737Sache t.starting_track = 0; 106610099Sjkh t.data_len = len; 106710099Sjkh t.data = toc_buffer; 106813985Sache 106913985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 107010099Sjkh} 107110099Sjkh 107210099Sjkhint play_msf (int start_m, int start_s, int start_f, 107313985Sache int end_m, int end_s, int end_f) 107410099Sjkh{ 107587573Smikeh struct ioc_play_msf a; 107610099Sjkh 107710099Sjkh a.start_m = start_m; 107810099Sjkh a.start_s = start_s; 107910099Sjkh a.start_f = start_f; 108010099Sjkh a.end_m = end_m; 108110099Sjkh a.end_s = end_s; 108210099Sjkh a.end_f = end_f; 108313985Sache 108410099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 108510099Sjkh} 108610099Sjkh 108710099Sjkhint status (int *trk, int *min, int *sec, int *frame) 108810099Sjkh{ 108910099Sjkh struct ioc_read_subchannel s; 109010099Sjkh struct cd_sub_channel_info data; 109113884Sache u_char mm, ss, ff; 109210099Sjkh 109310099Sjkh bzero (&s, sizeof (s)); 109410099Sjkh s.data = &data; 109510099Sjkh s.data_len = sizeof (data); 109613884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 109710099Sjkh s.data_format = CD_CURRENT_POSITION; 109813985Sache 109910099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 110010099Sjkh return -1; 110113985Sache 110210099Sjkh *trk = s.data->what.position.track_number; 110313884Sache if (msf) { 110413884Sache *min = s.data->what.position.reladdr.msf.minute; 110513884Sache *sec = s.data->what.position.reladdr.msf.second; 110613884Sache *frame = s.data->what.position.reladdr.msf.frame; 110713884Sache } else { 110813884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 110913884Sache &mm, &ss, &ff); 111013884Sache *min = mm; 111113884Sache *sec = ss; 111213884Sache *frame = ff; 111313884Sache } 111413985Sache 111510099Sjkh return s.data->header.audio_status; 111610099Sjkh} 111710099Sjkh 111850039Smdoddconst char * 111950039Smdoddcdcontrol_prompt() 112010099Sjkh{ 112150039Smdodd return ("cdcontrol> "); 112250039Smdodd} 112350039Smdodd 112450039Smdoddchar * 112550039Smdoddinput (int *cmd) 112650039Smdodd{ 112750039Smdodd#define MAXLINE 80 112850039Smdodd static EditLine *el = NULL; 112950039Smdodd static History *hist = NULL; 113084261Sobrien HistEvent he; 113150039Smdodd static char buf[MAXLINE]; 113250039Smdodd int num = 0; 113350071Smdodd int len; 113450039Smdodd const char *bp = NULL; 113510099Sjkh char *p; 113610099Sjkh 113710099Sjkh do { 113850039Smdodd if (verbose) { 113950039Smdodd if (!el) { 114084261Sobrien el = el_init("cdcontrol", stdin, stdout, 114184261Sobrien stderr); 114250039Smdodd hist = history_init(); 114384261Sobrien history(hist, &he, H_EVENT, 100); 114450039Smdodd el_set(el, EL_HIST, history, hist); 114550039Smdodd el_set(el, EL_EDITOR, "emacs"); 114650039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 114750039Smdodd el_set(el, EL_SIGNAL, 1); 114850042Smdodd el_source(el, NULL); 114950039Smdodd } 115063070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 115163070Smckay *cmd = CMD_QUIT; 115263070Smckay fprintf (stderr, "\r\n"); 115350039Smdodd return (0); 115463070Smckay } 115550039Smdodd 115650071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 115750071Smdodd memcpy(buf, bp, len); 115850071Smdodd buf[len] = 0; 115984261Sobrien history(hist, &he, H_ENTER, bp); 116050039Smdodd#undef MAXLINE 116150039Smdodd 116250039Smdodd } else { 116350039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 116450039Smdodd *cmd = CMD_QUIT; 116550039Smdodd fprintf (stderr, "\r\n"); 116650039Smdodd return (0); 116750039Smdodd } 116810099Sjkh } 116910099Sjkh p = parse (buf, cmd); 117010099Sjkh } while (! p); 117110099Sjkh return (p); 117210099Sjkh} 117310099Sjkh 117410099Sjkhchar *parse (char *buf, int *cmd) 117510099Sjkh{ 117610099Sjkh struct cmdtab *c; 117710099Sjkh char *p; 117887568Smikeh unsigned int len; 117910099Sjkh 118013985Sache for (p=buf; isspace (*p); p++) 118113985Sache continue; 118210099Sjkh 118313985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 118413985Sache *cmd = CMD_PLAY; 118513985Sache return (p); 118677168Skris } else if (*p == '+') { 118777168Skris *cmd = CMD_NEXT; 118877168Skris return (p + 1); 118977168Skris } else if (*p == '-') { 119077168Skris *cmd = CMD_PREVIOUS; 119177168Skris return (p + 1); 119213985Sache } 119310099Sjkh 119413985Sache for (buf = p; *p && ! isspace (*p); p++) 119513985Sache continue; 119613985Sache 119713985Sache len = p - buf; 119810099Sjkh if (! len) 119910099Sjkh return (0); 120013985Sache 120187573Smikeh if (*p) { /* It must be a spacing character! */ 120213985Sache char *q; 120313985Sache 120413985Sache *p++ = 0; 120513985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 120613985Sache continue; 120713985Sache *q = 0; 120813985Sache } 120913985Sache 121010099Sjkh *cmd = -1; 121110099Sjkh for (c=cmdtab; c->name; ++c) { 121213985Sache /* Is it an exact match? */ 121313985Sache if (! strcasecmp (buf, c->name)) { 121413985Sache *cmd = c->command; 121513985Sache break; 121613985Sache } 121713985Sache 121813985Sache /* Try short hand forms then... */ 121913985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 122013985Sache if (*cmd != -1 && *cmd != c->command) { 122129103Scharnier warnx("ambiguous command"); 122213985Sache return (0); 122313985Sache } 122410099Sjkh *cmd = c->command; 122513985Sache } 122613985Sache } 122710099Sjkh 122810099Sjkh if (*cmd == -1) { 122929103Scharnier warnx("invalid command, enter ``help'' for commands"); 123010099Sjkh return (0); 123110099Sjkh } 123213985Sache 123313985Sache while (isspace (*p)) 123413985Sache p++; 123510099Sjkh return p; 123610099Sjkh} 123710099Sjkh 123810099Sjkhint open_cd () 123910099Sjkh{ 124054164Sjoe char devbuf[MAXPATHLEN]; 124110099Sjkh 124210099Sjkh if (fd > -1) 124310099Sjkh return (1); 124413985Sache 124554164Sjoe if (*cdname == '/') { 124654164Sjoe snprintf (devbuf, MAXPATHLEN, "%s", cdname); 124761105Smsmith } else { 124869793Sobrien snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 124954164Sjoe } 125013985Sache 125110099Sjkh fd = open (devbuf, O_RDONLY); 125213985Sache 125310099Sjkh if (fd < 0 && errno == ENOENT) { 125413985Sache strcat (devbuf, DEFAULT_CD_PARTITION); 125510099Sjkh fd = open (devbuf, O_RDONLY); 125610099Sjkh } 125713985Sache 125810099Sjkh if (fd < 0) { 125913985Sache if (errno == ENXIO) { 126013985Sache /* ENXIO has an overloaded meaning here. 126113985Sache * The original "Device not configured" should 126213985Sache * be interpreted as "No disc in drive %s". */ 126329103Scharnier warnx("no disc in drive %s", devbuf); 126413985Sache return (0); 126510099Sjkh } 126629103Scharnier err(1, "%s", devbuf); 126710099Sjkh } 126810099Sjkh return (1); 126910099Sjkh} 1270