cdcontrol.c revision 13737
110099Sjkh/* 210099Sjkh * 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 410099Sjkh * Andrew A. Chernov. 510099Sjkh */ 610099Sjkh#include <stdio.h> 710099Sjkh#include <stdlib.h> 810099Sjkh#include <string.h> 910099Sjkh#include <unistd.h> 1010099Sjkh#include <errno.h> 1110099Sjkh#include <sys/file.h> 1210099Sjkh#include <sys/cdio.h> 1310099Sjkh#include <sys/ioctl.h> 1410099Sjkh 1510099Sjkh#define VERSION "1.0" 1610099Sjkh 1710099Sjkh/* 1810099Sjkh * Audio Status Codes 1910099Sjkh */ 2010099Sjkh#define ASTS_INVALID 0x00 /* Audio status byte not valid */ 2110099Sjkh#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 2210099Sjkh#define ASTS_PAUSED 0x12 /* Audio play operation paused */ 2310099Sjkh#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 2410099Sjkh#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 2510099Sjkh#define ASTS_VOID 0x15 /* No current audio status to return */ 2610099Sjkh 2710099Sjkhstruct cmdtab { 2810099Sjkh int command; 2910099Sjkh char *name; 3010099Sjkh char *args; 3110099Sjkh} cmdtab[] = { 3210099Sjkh#define CMD_DEBUG 1 3310099Sjkh { CMD_DEBUG, "Debug", "[ on | off | reset ]", }, 3410099Sjkh#define CMD_EJECT 2 3510099Sjkh { CMD_EJECT, "Eject", "", }, 3610099Sjkh#define CMD_HELP 3 3710099Sjkh { CMD_HELP, "?", 0, }, 3810099Sjkh { CMD_HELP, "Help", "", }, 3910099Sjkh#define CMD_INFO 4 4010099Sjkh { CMD_INFO, "Info", "", }, 4110099Sjkh#define CMD_PAUSE 5 4210099Sjkh { CMD_PAUSE, "PAuse", "", }, 4310099Sjkh#define CMD_PLAY 6 4410099Sjkh { CMD_PLAY, "P", 0, }, 4510099Sjkh { CMD_PLAY, "Play", "min1:sec1.fr1 [ min2:sec2.fr2 ]", }, 4610099Sjkh { CMD_PLAY, "Play", "track1.index1 [ track2.index2 ]", }, 4710099Sjkh { CMD_PLAY, "Play", "#block [ len ]", }, 4810099Sjkh#define CMD_QUIT 7 4910099Sjkh { CMD_QUIT, "Quit", "", }, 5010099Sjkh#define CMD_RESUME 8 5110099Sjkh { CMD_RESUME, "Resume", "", }, 5210099Sjkh#define CMD_STOP 9 5310099Sjkh { CMD_STOP, "Stop", "", }, 5410099Sjkh#define CMD_VOLUME 10 5510099Sjkh { CMD_VOLUME, "Volume", "<l> <r> | left | right | mute | mono | stereo", }, 5610099Sjkh { 0, 0, }, 5710099Sjkh}; 5810099Sjkh 5910099Sjkhstruct cd_toc_entry toc_buffer[100]; 6010099Sjkh 6110099Sjkhchar *cdname; 6210099Sjkhint fd = -1; 6310099Sjkhint verbose = 1; 6410099Sjkh 6510099Sjkhextern char *optarg; 6610099Sjkhextern int optind; 6710099Sjkh 6810099Sjkhint setvol (int, int); 6910099Sjkhint read_toc_entrys (int); 7010099Sjkhint play_msf (int, int, int, int, int, int); 7110099Sjkhint play_track (int, int, int, int); 7210099Sjkhint get_vol (int *, int *); 7310099Sjkhint status (int *, int *, int *, int *); 7410099Sjkhint open_cd (void); 7510099Sjkhint play (char *arg); 7610099Sjkhint info (char *arg); 7710099Sjkhchar *input (int*); 7810099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag); 7910099Sjkhvoid lba2msf (int lba, u_char *m, u_char *s, u_char *f); 8010099Sjkhint msf2lba (u_char m, u_char s, u_char f); 8110099Sjkhint play_blocks (int blk, int len); 8210099Sjkhint run (int cmd, char *arg); 8310099Sjkhchar *parse (char *buf, int *cmd); 8410099Sjkh 8510099Sjkhextern int errno; 8610099Sjkh 8710099Sjkhvoid help () 8810099Sjkh{ 8910099Sjkh struct cmdtab *c; 9010099Sjkh 9110099Sjkh for (c=cmdtab; c->name; ++c) { 9210099Sjkh if (! c->args) 9310099Sjkh continue; 9410099Sjkh printf ("\t%s", c->name); 9510099Sjkh if (*c->args) 9610099Sjkh printf (" %s", c->args); 9710099Sjkh printf ("\n"); 9810099Sjkh } 9910099Sjkh} 10010099Sjkh 10110099Sjkhvoid usage () 10210099Sjkh{ 10310099Sjkh printf ("Usage:\n\tcdcontrol [ -vs ] [ -f disc ] [ command args... ]\n"); 10410099Sjkh printf ("Options:\n"); 10510099Sjkh printf ("\t-v - verbose mode\n"); 10610099Sjkh printf ("\t-s - silent mode\n"); 10710099Sjkh printf ("\t-f disc - device name such as /dev/cd0c\n"); 10810099Sjkh printf ("\tDISC - shell variable with device name\n"); 10910099Sjkh printf ("Commands:\n"); 11010099Sjkh help (); 11110099Sjkh exit (1); 11210099Sjkh} 11310099Sjkh 11410099Sjkhint main (int argc, char **argv) 11510099Sjkh{ 11610099Sjkh int cmd; 11710099Sjkh char *arg; 11810099Sjkh 11910099Sjkh cdname = getenv ("DISC"); 12010099Sjkh if (! cdname) 12110099Sjkh cdname = getenv ("CDPLAY"); 12210099Sjkh 12310099Sjkh for (;;) { 12410099Sjkh switch (getopt (argc, argv, "svhf:")) { 12510099Sjkh case EOF: 12610099Sjkh break; 12710099Sjkh case 's': 12810099Sjkh verbose = 0; 12910099Sjkh continue; 13010099Sjkh case 'v': 13110099Sjkh verbose = 2; 13210099Sjkh continue; 13310099Sjkh case 'f': 13410099Sjkh cdname = optarg; 13510099Sjkh continue; 13610099Sjkh case 'h': 13710099Sjkh default: 13810099Sjkh usage (); 13910099Sjkh } 14010099Sjkh break; 14110099Sjkh } 14210099Sjkh argc -= optind; 14310099Sjkh argv += optind; 14410099Sjkh 14510099Sjkh if (argc > 0 && strcasecmp (*argv, "help") == 0) 14610099Sjkh usage (); 14710099Sjkh 14810099Sjkh if (! cdname) { 14910099Sjkh fprintf (stderr, "No CD device name specified.\n"); 15010099Sjkh usage (); 15110099Sjkh } 15210099Sjkh 15310099Sjkh if (argc > 0) { 15410099Sjkh char buf[80], *p; 15510099Sjkh int len; 15610099Sjkh 15710099Sjkh for (p=buf; argc-- > 0; ++argv) { 15810099Sjkh len = strlen (*argv); 15910099Sjkh if (p + len >= buf + sizeof (buf) - 1) 16010099Sjkh usage (); 16110099Sjkh if (p > buf) 16210099Sjkh *p++ = ' '; 16310099Sjkh strcpy (p, *argv); 16410099Sjkh p += len; 16510099Sjkh } 16610099Sjkh *p = 0; 16710099Sjkh arg = parse (buf, &cmd); 16810099Sjkh return run (cmd, arg); 16910099Sjkh } 17010099Sjkh 17110099Sjkh if (verbose == 1) 17210099Sjkh verbose = isatty (0); 17310099Sjkh if (verbose) { 17410099Sjkh printf ("Compact Disc Control Utility, Version %s\n", VERSION); 17510099Sjkh printf ("Type `?' for command list\n\n"); 17610099Sjkh } 17710099Sjkh 17810099Sjkh for (;;) { 17910099Sjkh arg = input (&cmd); 18010099Sjkh if (run (cmd, arg) < 0) { 18110099Sjkh if (verbose) 18210099Sjkh perror ("cdplay"); 18310099Sjkh close (fd); 18410099Sjkh fd = -1; 18510099Sjkh } 18610099Sjkh fflush (stdout); 18710099Sjkh } 18810099Sjkh} 18910099Sjkh 19010099Sjkhint run (int cmd, char *arg) 19110099Sjkh{ 19210099Sjkh int l, r, rc; 19310099Sjkh 19410099Sjkh switch (cmd) { 19510099Sjkh case CMD_QUIT: 19610099Sjkh exit (0); 19710099Sjkh 19810099Sjkh default: 19910099Sjkh case CMD_HELP: 20010099Sjkh help (); 20110099Sjkh return (0); 20210099Sjkh 20310099Sjkh case CMD_INFO: 20410099Sjkh if (fd<0 && ! open_cd ()) return (0); 20510099Sjkh return info (arg); 20610099Sjkh 20710099Sjkh case CMD_PAUSE: 20810099Sjkh if (fd<0 && ! open_cd ()) return (0); 20910099Sjkh return ioctl (fd, CDIOCPAUSE); 21010099Sjkh 21110099Sjkh case CMD_RESUME: 21210099Sjkh if (fd<0 && ! open_cd ()) return (0); 21310099Sjkh return ioctl (fd, CDIOCRESUME); 21410099Sjkh 21510099Sjkh case CMD_STOP: 21610099Sjkh if (fd<0 && ! open_cd ()) return (0); 21710099Sjkh return ioctl (fd, CDIOCSTOP); 21810099Sjkh 21910099Sjkh case CMD_DEBUG: 22010099Sjkh if (fd<0 && ! open_cd ()) return (0); 22110099Sjkh if (strcasecmp (arg, "on") == 0) 22210099Sjkh return ioctl (fd, CDIOCSETDEBUG); 22310099Sjkh if (strcasecmp (arg, "off") == 0) 22410099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 22510099Sjkh if (strcasecmp (arg, "reset") == 0) 22610099Sjkh return ioctl (fd, CDIOCRESET); 22710099Sjkh printf ("Invalid command arguments\n"); 22810099Sjkh return (0); 22910099Sjkh 23010099Sjkh case CMD_EJECT: 23110099Sjkh if (fd<0 && ! open_cd ()) return (0); 23210099Sjkh (void) ioctl (fd, CDIOCALLOW); 23310099Sjkh rc = ioctl (fd, CDIOCEJECT); 23410099Sjkh if (rc < 0) 23510099Sjkh return (rc); 23610099Sjkh close (fd); 23710099Sjkh fd = -1; 23810099Sjkh return (0); 23910099Sjkh 24010099Sjkh case CMD_PLAY: 24110099Sjkh if (fd<0 && ! open_cd ()) return (0); 24210099Sjkh return play (arg); 24310099Sjkh 24410099Sjkh case CMD_VOLUME: 24510099Sjkh if (fd<0 && ! open_cd ()) return (0); 24610099Sjkh 24710099Sjkh if (strcasecmp (arg, "left") == 0) 24810099Sjkh return ioctl (fd, CDIOCSETLEFT); 24910099Sjkh else if (strcasecmp (arg, "right") == 0) 25010099Sjkh return ioctl (fd, CDIOCSETRIGHT); 25110099Sjkh else if (strcasecmp (arg, "mute") == 0) 25210099Sjkh return ioctl (fd, CDIOCSETMUTE); 25310099Sjkh else if (strcasecmp (arg, "mono") == 0) 25410099Sjkh return ioctl (fd, CDIOCSETMONO); 25510099Sjkh else if (strcasecmp (arg, "stereo") == 0) 25610099Sjkh return ioctl (fd, CDIOCSETSTERIO); 25710099Sjkh 25810099Sjkh if (2 != sscanf (arg, "%d %d", &l, &r)) { 25910099Sjkh printf ("Invalid command arguments\n"); 26010099Sjkh return (0); 26110099Sjkh } 26210099Sjkh return setvol (l, r); 26310099Sjkh } 26410099Sjkh} 26510099Sjkh 26610099Sjkhint play (char *arg) 26710099Sjkh{ 26810099Sjkh struct ioc_toc_header h; 26910099Sjkh int rc, n, start, end = 0, istart = 1, iend = 1; 27010099Sjkh 27110099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 27210099Sjkh if (rc < 0) 27310099Sjkh return (rc); 27410099Sjkh 27510099Sjkh n = h.ending_track - h.starting_track + 1; 27610099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 27710099Sjkh if (rc < 0) 27810099Sjkh return (rc); 27910099Sjkh 28010099Sjkh if (! *arg) 28110099Sjkh /* 28210099Sjkh * Play the whole disc 28310099Sjkh */ 28410099Sjkh return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 28510099Sjkh toc_buffer[n].addr.msf.second, 28610099Sjkh toc_buffer[n].addr.msf.frame)); 28710099Sjkh 28810099Sjkh if (strchr (arg, '#')) { 28910099Sjkh /* 29010099Sjkh * Play block #blk [ len ] 29110099Sjkh */ 29210099Sjkh int blk, len = 0; 29310099Sjkh 29410099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 29510099Sjkh 1 != sscanf (arg, "#%d", &blk)) { 29610099Sjkherr: printf ("Invalid command arguments\n"); 29710099Sjkh return (0); 29810099Sjkh } 29910099Sjkh if (len == 0) 30010099Sjkh len = msf2lba (toc_buffer[n].addr.msf.minute, 30110099Sjkh toc_buffer[n].addr.msf.second, 30210099Sjkh toc_buffer[n].addr.msf.frame) - blk; 30310099Sjkh return play_blocks (blk, len); 30410099Sjkh } 30510099Sjkh 30610099Sjkh if (strchr (arg, ':')) { 30710099Sjkh /* 30810099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 30910099Sjkh */ 31010099Sjkh int m1, m2 = 0, s1, s2 = 0, f1 = 0, f2 = 0; 31110099Sjkh 31210099Sjkh if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", &m1, &s1, &f1, &m2, &s2, &f2) && 31310099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 31410099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 31510099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 31610099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 31710099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 31810099Sjkh goto err; 31910099Sjkh if (m2 == 0) { 32010099Sjkh m2 = toc_buffer[n].addr.msf.minute; 32110099Sjkh s2 = toc_buffer[n].addr.msf.second; 32210099Sjkh f2 = toc_buffer[n].addr.msf.frame; 32310099Sjkh } 32410099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 32510099Sjkh } 32610099Sjkh 32710099Sjkh /* 32810099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 32910099Sjkh */ 33010099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 33110099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 33210099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 33310099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 33410099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 33510099Sjkh 1 != sscanf (arg, "%d", &start)) 33610099Sjkh goto err; 33710099Sjkh if (end == 0) 33810099Sjkh end = n; 33910099Sjkh return play_track (start, istart, end, iend); 34010099Sjkh} 34110099Sjkh 34210099Sjkhchar *strstatus (int sts) 34310099Sjkh{ 34410099Sjkh switch (sts) { 34510099Sjkh case ASTS_INVALID: return ("invalid"); 34610099Sjkh case ASTS_PLAYING: return ("playing"); 34710099Sjkh case ASTS_PAUSED: return ("paused"); 34810099Sjkh case ASTS_COMPLETED: return ("completed"); 34910099Sjkh case ASTS_ERROR: return ("error"); 35010099Sjkh case ASTS_VOID: return ("void"); 35110099Sjkh default: return ("??"); 35210099Sjkh } 35310099Sjkh} 35410099Sjkh 35510099Sjkhint info (char *arg) 35610099Sjkh{ 35710099Sjkh struct ioc_toc_header h; 35810099Sjkh struct ioc_vol v; 35910099Sjkh int rc, i, n, trk, m, s, f; 36010099Sjkh 36110099Sjkh rc = status (&trk, &m, &s, &f); 36210099Sjkh if (rc >= 0) 36310099Sjkh if (verbose) 36410099Sjkh printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 36510099Sjkh rc, strstatus (rc), trk, m, s, f); 36610099Sjkh else 36710099Sjkh printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 36810099Sjkh else 36910099Sjkh printf ("No current status info\n"); 37010099Sjkh 37110099Sjkh rc = ioctl (fd, CDIOCGETVOL, &v); 37210099Sjkh if (rc >= 0) 37310099Sjkh if (verbose) 37410099Sjkh printf ("Left volume = %d, right volume = %d\n", 37510099Sjkh v.vol[0], v.vol[1]); 37610099Sjkh else 37710099Sjkh printf ("%d %d\n", v.vol[0], v.vol[1]); 37810099Sjkh else 37910099Sjkh printf ("No volume info\n"); 38010099Sjkh 38110099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 38210099Sjkh if (rc >= 0) 38310099Sjkh if (verbose) 38410099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 38510099Sjkh h.starting_track, h.ending_track, h.len); 38610099Sjkh else 38710099Sjkh printf ("%d %d %d\n", h.starting_track, 38810099Sjkh h.ending_track, h.len); 38910099Sjkh else { 39010099Sjkh perror ("getting toc header"); 39110099Sjkh return (rc); 39210099Sjkh } 39310099Sjkh 39410099Sjkh n = h.ending_track - h.starting_track + 1; 39510099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 39610099Sjkh if (rc < 0) 39710099Sjkh return (rc); 39810099Sjkh if (verbose) { 39910099Sjkh printf ("track start duration block length type\n"); 40010099Sjkh printf ("-------------------------------------------------\n"); 40110099Sjkh } 40210099Sjkh for (i = 0; i < n; i++) { 40310099Sjkh printf ("%5d ", toc_buffer[i].track); 40410099Sjkh prtrack (toc_buffer + i, 0); 40510099Sjkh } 40610099Sjkh printf (" end "); 40710099Sjkh prtrack (toc_buffer + n, 1); 40810099Sjkh return (0); 40910099Sjkh} 41010099Sjkh 41110099Sjkhvoid lba2msf (int lba, u_char *m, u_char *s, u_char *f) 41210099Sjkh{ 41310099Sjkh lba += 150; /* block start offset */ 41410099Sjkh lba &= 0xffffff; /* negative lbas use only 24 bits */ 41510099Sjkh *m = lba / (60 * 75); 41610099Sjkh lba %= (60 * 75); 41710099Sjkh *s = lba / 75; 41810099Sjkh *f = lba % 75; 41910099Sjkh} 42010099Sjkh 42110099Sjkhint msf2lba (u_char m, u_char s, u_char f) 42210099Sjkh{ 42310099Sjkh return (((m * 60) + s) * 75 + f) - 150; 42410099Sjkh} 42510099Sjkh 42610099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag) 42710099Sjkh{ 42810099Sjkh int block, next, len; 42910099Sjkh u_char m, s, f; 43010099Sjkh 43110099Sjkh /* Print track start */ 43210099Sjkh printf ("%2d:%02d.%02d ", e->addr.msf.minute, 43310099Sjkh e->addr.msf.second, e->addr.msf.frame); 43410099Sjkh 43510099Sjkh block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 43610099Sjkh e->addr.msf.frame); 43710099Sjkh if (lastflag) { 43810099Sjkh /* Last track -- print block */ 43910099Sjkh printf (" - %6d - -\n", block); 44010099Sjkh return; 44110099Sjkh } 44210099Sjkh 44310099Sjkh next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 44410099Sjkh e[1].addr.msf.frame); 44510099Sjkh len = next - block; 44610099Sjkh lba2msf (len, &m, &s, &f); 44710099Sjkh 44810099Sjkh /* Print duration, block, length, type */ 44910099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 45010099Sjkh e->control & 4 ? "data" : "audio"); 45110099Sjkh} 45210099Sjkh 45310099Sjkhint play_track (int tstart, int istart, int tend, int iend) 45410099Sjkh{ 45510099Sjkh struct ioc_play_track t; 45610099Sjkh 45710099Sjkh t.start_track = tstart; 45810099Sjkh t.start_index = istart; 45910099Sjkh t.end_track = tend; 46010099Sjkh t.end_index = iend; 46110099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 46210099Sjkh} 46310099Sjkh 46410099Sjkhint play_blocks (int blk, int len) 46510099Sjkh{ 46610099Sjkh struct ioc_play_blocks t; 46710099Sjkh 46810099Sjkh t.blk = blk; 46910099Sjkh t.len = len; 47010099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 47110099Sjkh} 47210099Sjkh 47310099Sjkhint setvol (int l, int r) 47410099Sjkh{ 47510099Sjkh struct ioc_vol v; 47610099Sjkh 47710099Sjkh v.vol[0] = l; 47810099Sjkh v.vol[1] = r; 47910099Sjkh v.vol[2] = 0; 48010099Sjkh v.vol[3] = 0; 48110099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 48210099Sjkh} 48310099Sjkh 48410099Sjkhint read_toc_entrys (int len) 48510099Sjkh{ 48610099Sjkh struct ioc_read_toc_entry t; 48710099Sjkh 48810099Sjkh t.address_format = CD_MSF_FORMAT; 48913737Sache t.starting_track = 0; 49010099Sjkh t.data_len = len; 49110099Sjkh t.data = toc_buffer; 49210099Sjkh return ioctl (fd, CDIOREADTOCENTRYS, (char *) &t); 49310099Sjkh} 49410099Sjkh 49510099Sjkhint play_msf (int start_m, int start_s, int start_f, 49610099Sjkh int end_m, int end_s, int end_f) 49710099Sjkh{ 49810099Sjkh struct ioc_play_msf a; 49910099Sjkh 50010099Sjkh a.start_m = start_m; 50110099Sjkh a.start_s = start_s; 50210099Sjkh a.start_f = start_f; 50310099Sjkh a.end_m = end_m; 50410099Sjkh a.end_s = end_s; 50510099Sjkh a.end_f = end_f; 50610099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 50710099Sjkh} 50810099Sjkh 50910099Sjkhint status (int *trk, int *min, int *sec, int *frame) 51010099Sjkh{ 51110099Sjkh struct ioc_read_subchannel s; 51210099Sjkh struct cd_sub_channel_info data; 51310099Sjkh 51410099Sjkh bzero (&s, sizeof (s)); 51510099Sjkh s.data = &data; 51610099Sjkh s.data_len = sizeof (data); 51710099Sjkh s.address_format = CD_MSF_FORMAT; 51810099Sjkh s.data_format = CD_CURRENT_POSITION; 51910099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 52010099Sjkh return -1; 52110099Sjkh *trk = s.data->what.position.track_number; 52210099Sjkh *min = s.data->what.position.reladdr.msf.minute; 52310099Sjkh *sec = s.data->what.position.reladdr.msf.second; 52410099Sjkh *frame = s.data->what.position.reladdr.msf.frame; 52510099Sjkh return s.data->header.audio_status; 52610099Sjkh} 52710099Sjkh 52810099Sjkhchar *input (int *cmd) 52910099Sjkh{ 53010099Sjkh static char buf[80]; 53110099Sjkh char *p; 53210099Sjkh 53310099Sjkh do { 53410099Sjkh if (verbose) 53510099Sjkh fprintf (stderr, "cd> "); 53610099Sjkh if (! fgets (buf, sizeof (buf), stdin)) { 53710099Sjkh *cmd = CMD_QUIT; 53810099Sjkh return 0; 53910099Sjkh } 54010099Sjkh p = parse (buf, cmd); 54110099Sjkh } while (! p); 54210099Sjkh return (p); 54310099Sjkh} 54410099Sjkh 54510099Sjkhchar *parse (char *buf, int *cmd) 54610099Sjkh{ 54710099Sjkh struct cmdtab *c; 54810099Sjkh char *p; 54910099Sjkh int len; 55010099Sjkh 55110099Sjkh for (p=buf; *p; ++p) 55210099Sjkh if (*p == '\t') 55310099Sjkh *p = ' '; 55410099Sjkh else if (*p == '\n') 55510099Sjkh *p = 0; 55610099Sjkh 55710099Sjkh for (p=buf; *p; ++p) 55810099Sjkh if (*p == ' ') { 55910099Sjkh *p++ = 0; 56010099Sjkh break; 56110099Sjkh } 56210099Sjkh while (*p == ' ') 56310099Sjkh ++p; 56410099Sjkh 56510099Sjkh len = strlen (buf); 56610099Sjkh if (! len) 56710099Sjkh return (0); 56810099Sjkh *cmd = -1; 56910099Sjkh for (c=cmdtab; c->name; ++c) { 57010099Sjkh /* Try short command form. */ 57110099Sjkh if (! c->args && len == strlen (c->name) && 57210099Sjkh strncasecmp (buf, c->name, len) == 0) { 57310099Sjkh *cmd = c->command; 57410099Sjkh break; 57510099Sjkh } 57610099Sjkh 57710099Sjkh /* Try long form. */ 57810099Sjkh if (strncasecmp (buf, c->name, len) != 0) 57910099Sjkh continue; 58010099Sjkh 58110099Sjkh /* Check inambiguity. */ 58210099Sjkh if (*cmd != -1) { 58310099Sjkh fprintf (stderr, "Ambiguous command\n"); 58410099Sjkh return (0); 58510099Sjkh } 58610099Sjkh *cmd = c->command; 58710099Sjkh } 58810099Sjkh if (*cmd == -1) { 58910099Sjkh fprintf (stderr, "Invalid command, enter ``help'' for command list\n"); 59010099Sjkh return (0); 59110099Sjkh } 59210099Sjkh return p; 59310099Sjkh} 59410099Sjkh 59510099Sjkhint open_cd () 59610099Sjkh{ 59710099Sjkh char devbuf[80]; 59810099Sjkh 59910099Sjkh if (fd > -1) 60010099Sjkh return (1); 60110099Sjkh if (*cdname == '/') 60210099Sjkh strcpy (devbuf, cdname); 60310099Sjkh else if (*cdname == 'r') 60410099Sjkh sprintf (devbuf, "/dev/%s", cdname); 60510099Sjkh else 60610099Sjkh sprintf (devbuf, "/dev/r%s", cdname); 60710099Sjkh fd = open (devbuf, O_RDONLY); 60810099Sjkh if (fd < 0 && errno == ENOENT) { 60910099Sjkh strcat (devbuf, "c"); 61010099Sjkh fd = open (devbuf, O_RDONLY); 61110099Sjkh } 61210099Sjkh if (fd < 0) { 61310099Sjkh if (errno != ENXIO) { 61410099Sjkh perror (devbuf); 61510099Sjkh exit (1); 61610099Sjkh } 61710099Sjkh /* open says 'Device not configured' if no cd in */ 61810099Sjkh fprintf (stderr, "open: No CD in\n"); 61910099Sjkh return (0); 62010099Sjkh } 62110099Sjkh return (1); 62210099Sjkh} 623