Initial revision
[opensuse:hwinfo.git] / src / hd / cdrom.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <linux/iso_fs.h>
9
10 #include "hd.h"
11 #include "hd_int.h"
12 #include "cdrom.h"
13
14 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
15  * special CDROM scanning
16  *
17  * Although CDROM devices hasve already been handled by the normal scan
18  * functions, this goes through the kernel info file
19  * /proc/sys/dev/cdrom/info just to check that we didn't miss one.
20  *
21  * The main purpose however is that you can just call this function to get
22  * CDROM drives added to the hardware list *without* going through a full
23  * scan again.
24  *
25  * This is particularly handy if you just loaded a module and want to know
26  * just if this has activated a CDROM drive.
27  *
28  * AND, if requested, it will look for CDs in those drives. (And read the
29  * disk label.)
30  *
31  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32  */
33
34
35 static void read_cdroms(hd_data_t *hd_data);
36 static void dump_cdrom_data(hd_data_t *hd_data);
37
38 void hd_scan_cdrom(hd_data_t *hd_data)
39 {
40   int found, prog_cnt = 0;
41   hd_t *hd;
42   str_list_t *sl, **prev;
43
44   if(!(hd_data->probe & (1 << pr_cdrom))) return;
45
46   hd_data->module = mod_cdrom;
47
48   /* some clean-up */
49   remove_hd_entries(hd_data);
50   hd_data->cdrom = NULL;
51
52   PROGRESS(1, 0, "get devices");
53
54   read_cdroms(hd_data);
55   if((hd_data->debug & HD_DEB_CDROM)) dump_cdrom_data(hd_data);
56
57   PROGRESS(2, 0, "build list");
58
59   for(hd = hd_data->hd; hd; hd = hd->next) {
60     /* look for existing entries... */
61     if(
62       hd->base_class == bc_storage_device &&
63       hd->sub_class == sc_sdev_cdrom
64     ) {
65       found = 0;
66       for(sl = *(prev = &hd_data->cdrom); sl; sl = *(prev = &sl->next)) {
67         /* ...and remove those from the CDROM list */
68         if(sl->str && !strcmp(hd->unix_dev_name, sl->str)) {
69           sl->str = free_mem(sl->str);
70           *prev = sl->next;
71           free_mem(sl);
72           sl = *prev;
73           found = 1;
74           break;
75         }
76       }
77       /* Oops, we didn't find our entries in the 'official' kernel list? */
78       if(!found && (hd_data->debug & HD_DEB_CDROM)) {
79         ADD2LOG("CD drive \"%s\" not in kernel CD list\n", hd->unix_dev_name);
80       }
81     }
82   }
83
84   /*
85    * everything still in hd_data->cdrom are new entries
86    */
87   for(sl = hd_data->cdrom; sl; sl = sl->next) {
88     hd = add_hd_entry(hd_data, __LINE__, 0);
89     hd->base_class = bc_storage_device;
90     hd->sub_class = sc_sdev_cdrom;
91     hd->unix_dev_name = new_str(sl->str);
92     hd->bus = bus_none;
93   }
94
95   /*
96    * look for a CD and get some info
97    */
98   if(!(hd_data->probe & (1 << pr_cdrom_info))) return;
99
100   for(hd = hd_data->hd; hd; hd = hd->next) {
101     if(
102       hd->base_class == bc_storage_device &&
103       hd->sub_class == sc_sdev_cdrom &&
104       hd->unix_dev_name
105     ) {
106       PROGRESS(3, ++prog_cnt, "read cdrom");
107       hd_read_cdrom_info(hd);
108     }
109   }
110 }
111
112
113 /*
114  * Read the CDROM info, if there is a CD inserted.
115  * returns NULL if nothing was found
116  */
117 cdrom_info_t *hd_read_cdrom_info(hd_t *hd)
118 {
119   int fd;
120   char *s;
121   cdrom_info_t *ci;
122   struct iso_primary_descriptor iso_desc;
123
124   /* free existing entry */
125   if(hd->detail) {
126     if(hd->detail->type == hd_detail_cdrom) {
127       ci = hd->detail->cdrom.data;
128       if(ci->volume) free_mem(ci->volume);
129       if(ci->publisher) free_mem(ci->publisher);
130       if(ci->preparer) free_mem(ci->preparer);
131       if(ci->application) free_mem(ci->application);
132       if(ci->creation_date) free_mem(ci->creation_date);
133       free_mem(ci);
134     }
135     hd->detail = free_mem(hd->detail);
136   }
137
138   if((fd = open(hd->unix_dev_name, O_RDONLY)) < 0) {
139     /* we are here if there is no CD in the drive */
140     return NULL;
141   }
142
143   if(
144     lseek(fd, 0x8000, SEEK_SET) >= 0 &&
145     read(fd, &iso_desc, sizeof iso_desc) == sizeof iso_desc
146   ) {
147     hd->detail = new_mem(sizeof *hd->detail);
148     hd->detail->type = hd_detail_cdrom;
149     hd->detail->cdrom.data = ci = new_mem(sizeof *ci);
150
151     /* now, fill in the fields */
152     s = canon_str(iso_desc.volume_id, sizeof iso_desc.volume_id);
153     if(!*s) s = free_mem(s);
154     ci->volume = s;
155
156     s = canon_str(iso_desc.publisher_id, sizeof iso_desc.publisher_id);
157     if(!*s) s = free_mem(s);
158     ci->publisher = s;
159
160     s = canon_str(iso_desc.preparer_id, sizeof iso_desc.preparer_id);
161     if(!*s) s = free_mem(s);
162     ci->preparer = s;
163
164     s = canon_str(iso_desc.application_id, sizeof iso_desc.application_id);
165     if(!*s) s = free_mem(s);
166     ci->application = s;
167
168     s = canon_str(iso_desc.creation_date, sizeof iso_desc.creation_date);
169     if(!*s) s = free_mem(s);
170     ci->creation_date = s;
171   }
172   else {
173     ci = NULL;
174   }
175
176   close(fd);
177
178   return ci;
179 }
180
181
182 /*
183  * Read the list of CDROM devices known to the kernel. The info is taken
184  * from /proc/sys/dev/cdrom/info.
185  */
186 void read_cdroms(hd_data_t *hd_data)
187 {
188   char *s, *t, *v;
189   str_list_t *sl, *sl0, *sl1;
190
191   if(!(sl0 = read_file(PROC_CDROM_INFO, 2, 1))) return;
192
193   for(sl = sl0; sl; sl = sl->next) {
194     if(strstr(sl->str, "drive name:") == sl->str) {
195       s = sl->str + sizeof "drive name:" - 1;
196       while((t = strsep(&s, " \t\n"))) {
197         if(!*t) continue;
198         v = new_mem(sizeof "/dev/" + strlen(t));
199         strcat(strcpy(v, "/dev/"), t);
200         add_str_list(&hd_data->cdrom, v);
201       }
202       break;
203     }  
204   }
205   free_str_list(sl0);
206
207   /*
208    * reverse the list order (cf. PROC_PCI_DEVICES)
209    */
210   for(sl0 = NULL, sl = hd_data->cdrom; sl; sl = sl->next) {
211     if(sl->str) {
212       sl1 = new_mem(sizeof *sl1);
213       sl1->str = sl->str;
214       sl->str = NULL;
215       sl1->next = sl0;
216       sl0 = sl1;
217     }
218   }
219   free_str_list(hd_data->cdrom);
220   hd_data->cdrom = sl0;
221 }
222
223
224 /*
225  * Add some CDROM data to the global log.
226  */
227 void dump_cdrom_data(hd_data_t *hd_data)
228 {
229   str_list_t *sl;
230
231   ADD2LOG("----- kernel CDROM list -----\n");
232   for(sl = hd_data->cdrom; sl; sl = sl->next) {
233     ADD2LOG("  %s\n", sl->str);
234   }
235   ADD2LOG("----- kernel CDROM list end -----\n");
236 }
237
238