1 /*
2  * cdaccess.c
3  * System-dependent code to access extended CD information
4  *
5  * Based on a contribution by Erik Andersen
6  *
7  * Copyright (c) 2003 Christoph Pfisterer
8  *
9  * Permission is hereby granted, free of charge, to any person
10  * obtaining a copy of this software and associated documentation
11  * files (the "Software"), to deal in the Software without
12  * restriction, including without limitation the rights to use, copy,
13  * modify, merge, publish, distribute, sublicense, and/or sell copies
14  * of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  */
29 
30 #include "global.h"
31 
32 
33 #ifdef USE_IOCTL_LINUX
34 #include <sys/ioctl.h>
35 #include <linux/cdrom.h>
36 #define DO_CDACCESS 1
37 #endif  /* USE_IOCTL_LINUX */
38 
39 
40 #ifdef DO_CDACCESS
41 
42 /*
43  * CDDB stuff
44  */
45 
46 static int cddb_sum(int n);
47 
48 #define LBA_TO_SECS(lba) (((lba) + 150) / 75)
49 
50 
51 /*
52  * CD structure:
53  * Tries to get the CD TOC using out-of-band means (i.e. ioctl()),
54  * prints the info, and analyzes just the data tracks. Quite
55  * system-dependent, but layed out for porability.
56  */
57 
analyze_cdaccess(int fd,SOURCE * s,int level)58 int analyze_cdaccess(int fd, SOURCE *s, int level)
59 {
60   int i;
61   int first, last, ntracks;
62   int cksum, totaltime, seconds;
63   u4 diskid;
64   u1 ctrl[100];
65   u4 lba[100], length;
66   char human_readable_size[256];
67 #ifdef USE_IOCTL_LINUX
68   struct cdrom_tochdr tochdr;
69   struct cdrom_tocentry tocentry;
70 #endif
71 
72   /* read TOC header */
73 #ifdef USE_IOCTL_LINUX
74   if (ioctl(fd, CDROMREADTOCHDR, &tochdr) < 0) {
75     return 0;
76   }
77   first = tochdr.cdth_trk0;
78   last  = tochdr.cdth_trk1;
79 #endif
80 
81   ntracks = last + 1 - first;
82   if (ntracks > 99)  /* natural limit */
83     return 0;
84 
85   /* read per-track data from TOC */
86   for (i = 0; i <= ntracks; i++) {
87 #ifdef USE_IOCTL_LINUX
88     if (i == ntracks)
89       tocentry.cdte_track = CDROM_LEADOUT;
90     else
91       tocentry.cdte_track = first + i;
92     tocentry.cdte_format = CDROM_LBA;
93     if (ioctl(fd, CDROMREADTOCENTRY, &tocentry) < 0) {
94       //printf("CDROMREADTOCENTRY: %s: ", strerror(errno));
95       return 0;
96     }
97     ctrl[i] = tocentry.cdte_ctrl;
98     lba[i] = tocentry.cdte_addr.lba;
99 #endif
100   }
101 
102   /* System-dependent code ends here. From now on, we use the data
103      in first, last, ntracks, ctrl[], and lba[]. We also assume
104      all systems treat actual data access the same way... */
105 
106   /* calculate CDDB disk id */
107   cksum = 0;
108   for (i = 0; i < ntracks; i++) {
109     cksum += cddb_sum(LBA_TO_SECS(lba[i]));
110   }
111   totaltime = LBA_TO_SECS(lba[ntracks]) - LBA_TO_SECS(lba[0]);
112   diskid = (u4)(cksum % 0xff) << 24 | (u4)totaltime << 8 | (u4)ntracks;
113 
114   /* print disk info */
115   print_line(level, "CD-ROM, %d track%s, CDDB disk ID %08lX",
116 	     ntracks, (ntracks != 1) ? "s" : "", diskid);
117 
118   /* Loop over each track */
119   for (i = 0; i < ntracks; i++) {
120     /* length of track in sectors */
121     length = lba[i+1] - lba[i];
122 
123     if ((ctrl[i] & 0x4) == 0) {
124       /* Audio track, one sector holds 2352 actual data bytes */
125       seconds = length / 75;
126       format_size(human_readable_size, (u8)length * 2352);
127       print_line(level, "Track %d: Audio track, %s, %3d min %02d sec",
128 		 first + i, human_readable_size,
129 		 seconds / 60, seconds % 60);
130 
131     } else {
132       /* Data track, one sector holds 2048 actual data bytes */
133       format_size(human_readable_size, length * 2048);
134       print_line(level, "Track %d: Data track, %s",
135 		 first + i, human_readable_size);
136 
137       /* NOTE: we adjust the length to stay clear of padding or
138 	 post-gap stuff */
139       analyze_source_special(s, level + 1,
140 			     (u8)lba[i] * 2048, (u8)(length - 250) * 2048);
141     }
142   }
143 
144   return 1;
145 }
146 
147 /*
148  * helper function: calculate cddb disk id
149  */
150 
cddb_sum(int n)151 static int cddb_sum(int n)
152 {
153   /* a number like 2344 becomes 2+3+4+4 (13) */
154   int ret = 0;
155 
156   while (n > 0) {
157     ret = ret + (n % 10);
158     n = n / 10;
159   }
160 
161   return ret;
162 }
163 
164 
165 #else   /* DO_CDACCESS */
166 
167 /*
168  * the system is not supported, so use a dummy function
169  */
170 
analyze_cdaccess(int fd,SOURCE * s,int level)171 int analyze_cdaccess(int fd, SOURCE *s, int level)
172 {
173   return 0;
174 }
175 
176 #endif  /* DO_CDACCESS */
177 
178 
179 /* EOF */
180