3
|
1 #include <stdio.h>
|
|
2 #include <stdlib.h>
|
|
3 #include <unistd.h>
|
|
4 #include <sysexits.h>
|
|
5 #include <fcntl.h>
|
|
6 #include <sys/errno.h>
|
|
7 #include <sys/ioctl.h>
|
|
8 #include <sys/cdio.h>
|
|
9
|
|
10 int cddb_sum(int n);
|
|
11 unsigned long cddb_discid(int tot_trks, struct cd_toc_entry *cdtoc);
|
|
12 void usage(void);
|
|
13
|
|
14 int
|
|
15 main(int argc, char **argv)
|
|
16 {
|
|
17 int cd_fd, tot_tracks, i, machine, disc_length, tracknums;
|
|
18 unsigned long disc_id;
|
|
19 struct ioc_toc_header toc_head;
|
|
20 struct ioc_read_toc_entry toc_entries_head;
|
|
21 struct cd_toc_entry *toc_entries;
|
|
22 char cd_path[256], ch;
|
|
23
|
|
24 /* Default CD path */
|
|
25 strcpy(cd_path, "/dev/cd0c");
|
|
26
|
|
27 /* Default to human readable */
|
|
28 machine = 0;
|
|
29
|
|
30 /* Default to no track number stuff */
|
|
31 tracknums = 0;
|
|
32
|
|
33 while ((ch = getopt(argc, argv, "f:mhn")) != -1) {
|
|
34 switch(ch) {
|
|
35 case 'f':
|
|
36 if (strlen(optarg) > 255) {
|
|
37 warnx("Filename too long");
|
|
38 exit(EX_USAGE);
|
|
39 }
|
|
40
|
|
41 strcpy(cd_path, optarg);
|
|
42 break;
|
|
43
|
|
44 case 'm':
|
|
45 machine = 1;
|
|
46 break;
|
|
47
|
|
48 case 'n':
|
|
49 tracknums = 1;
|
|
50 break;
|
|
51
|
|
52 case '?':
|
|
53 case 'h':
|
|
54 default:
|
|
55 usage();
|
|
56 break;
|
|
57 }
|
|
58 }
|
|
59
|
7
|
60 if ((cd_fd = open(cd_path, O_RDONLY)) == -1) {
|
3
|
61 warnx("Failed to open %s, reason: %s", cd_path, strerror(errno));
|
|
62 exit(EX_IOERR);
|
|
63 }
|
|
64
|
|
65 if (ioctl(cd_fd, CDIOREADTOCHEADER, &toc_head) == -1) {
|
|
66 warnx("Failed to get TOC header, reason: %s", strerror(errno));
|
|
67 exit(EX_UNAVAILABLE);
|
|
68 }
|
|
69
|
|
70 tot_tracks = toc_head.ending_track - toc_head.starting_track + 1;
|
|
71
|
|
72 toc_entries = (struct cd_toc_entry *)malloc(sizeof(struct cd_toc_entry) * (tot_tracks + 1));
|
|
73 if (toc_entries == NULL) {
|
|
74 warnx("Couldn't allocate memeory for TOC entries");
|
|
75 exit(EX_UNAVAILABLE);
|
|
76 }
|
|
77
|
|
78 toc_entries_head.data = toc_entries;
|
|
79 toc_entries_head.data_len = sizeof(struct cd_toc_entry) * (tot_tracks + 1);
|
|
80 toc_entries_head.starting_track = 0;
|
|
81 toc_entries_head.address_format = CD_MSF_FORMAT;
|
|
82
|
|
83 if (ioctl(cd_fd, CDIOREADTOCENTRYS, &toc_entries_head) == -1) {
|
|
84 warnx("Failed to get TOC entries, reason: %s\n", strerror(errno));
|
|
85 exit(EX_UNAVAILABLE);
|
|
86 }
|
|
87
|
|
88 if (tracknums) {
|
|
89 for (i = 1; i <= tot_tracks; i++)
|
|
90 if (!(toc_entries[i].control & 4))
|
|
91 printf("%d ", i);
|
|
92
|
|
93 printf("\n");
|
|
94
|
|
95 exit(0);
|
|
96 }
|
|
97
|
|
98 disc_id = cddb_discid(tot_tracks, toc_entries);
|
|
99 disc_length = (toc_entries[tot_tracks].addr.msf.minute * 60) +
|
|
100 (toc_entries[tot_tracks].addr.msf.second);
|
|
101
|
|
102 if (machine == 0) {
|
|
103 printf("Start track = %d, end track = %d, length = %d\n", toc_head.starting_track,
|
|
104 toc_head.ending_track, toc_head.len);
|
|
105 printf("Disc ID is %08x\n", disc_id);
|
|
106 printf("Length is %d seconds\n", disc_length);
|
|
107 } else {
|
|
108 printf("%08x", disc_id);
|
|
109 }
|
|
110
|
|
111 for (i = 0; i < tot_tracks; i++) {
|
|
112 if (machine == 0) {
|
|
113 printf("Track %d, Minute = %d, Second = %d, Frame = %d, Type = %s, Offset = %d\n",
|
|
114 toc_entries[i].track, toc_entries[i].addr.msf.minute,
|
|
115 toc_entries[i].addr.msf.second, toc_entries[i].addr.msf.frame,
|
|
116 (toc_entries[i].control & 4) ? "data" : "audio",
|
|
117 (toc_entries[i].addr.msf.minute * 60 * 75) +
|
|
118 (toc_entries[i].addr.msf.second * 75) +
|
|
119 toc_entries[i].addr.msf.frame);
|
|
120 } else {
|
|
121 printf(" %d", (toc_entries[i].addr.msf.minute * 60 * 75) +
|
|
122 (toc_entries[i].addr.msf.second * 75) +
|
|
123 toc_entries[i].addr.msf.frame);
|
|
124 }
|
|
125
|
|
126 }
|
|
127
|
|
128 if (machine == 1) {
|
|
129 printf(" %d\n", disc_length);
|
|
130 }
|
|
131 }
|
|
132
|
|
133 int
|
|
134 cddb_sum(int n)
|
|
135 {
|
|
136 int ret;
|
|
137
|
|
138 /* For backward compatibility this algorithm must not change */
|
|
139
|
|
140 ret = 0;
|
|
141
|
|
142 while (n > 0) {
|
|
143 ret = ret + (n % 10);
|
|
144 n = n / 10;
|
|
145 }
|
|
146
|
|
147 return (ret);
|
|
148 }
|
|
149
|
|
150 unsigned long
|
|
151 cddb_discid(int tot_trks, struct cd_toc_entry *cdtoc)
|
|
152 {
|
|
153 int i,
|
|
154 t = 0,
|
|
155 n = 0;
|
|
156
|
|
157 /* For backward compatibility this algorithm must not change */
|
|
158
|
|
159 i = 0;
|
|
160
|
|
161 while (i < tot_trks) {
|
|
162 n = n + cddb_sum((cdtoc[i].addr.msf.minute * 60)
|
|
163 + cdtoc[i].addr.msf.second);
|
|
164 i++;
|
|
165 }
|
|
166 t = ((cdtoc[tot_trks].addr.msf.minute * 60) +
|
|
167 cdtoc[tot_trks].addr.msf.second) -
|
|
168 ((cdtoc[0].addr.msf.minute * 60) +
|
|
169 cdtoc[0].addr.msf.second);
|
|
170
|
|
171 return ((n % 0xff) << 24 | t << 8 | tot_trks);
|
|
172 }
|
|
173
|
|
174 void
|
|
175 usage(void)
|
|
176 {
|
|
177 printf("Usage:\n");
|
|
178 printf("cddb-id [-f <cd-dev>] [-m]\n");
|
|
179 printf("<cd-dev> is the cd device to use (Default: /dev/cd0c)\n");
|
|
180 printf("-m causes machine readable output\n");
|
|
181 exit(EX_USAGE);
|
|
182 }
|