prototype for libudev dlopen() type of cdrom detection
[ntk/apt.git] / methods / cdrom.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: cdrom.cc,v 1.20.2.1 2004/01/16 18:58:50 mdz Exp $
4 /* ######################################################################
5
6 CDROM URI method for APT
7
8 ##################################################################### */
9 /*}}}*/
10 // Include Files /*{{{*/
11 #include <apt-pkg/acquire-method.h>
12 #include <apt-pkg/cdromutl.h>
13 #include <apt-pkg/error.h>
14 #include <apt-pkg/configuration.h>
15 #include <apt-pkg/fileutl.h>
16 #include <apt-pkg/hashes.h>
17
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <dlfcn.h>
21
22 #include <iostream>
23 #include <apti18n.h>
24 /*}}}*/
25
26 using namespace std;
27
28 struct udev;
29 struct udev_list_entry;
30
31 // libudev dlopen stucture
32 struct udev_p {
33 struct udev* (*udev_new)(void);
34 int (*udev_enumerate_add_match_property)(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
35 int (*udev_enumerate_scan_devices)(struct udev_enumerate *udev_enumerate);
36 struct udev_list_entry *(*udev_enumerate_get_list_entry)(struct udev_enumerate *udev_enumerate);
37 struct udev_device *(*udev_device_new_from_syspath)(struct udev *udev, const char *syspath);
38 struct udev *(*udev_enumerate_get_udev)(struct udev_enumerate *udev_enumerate);
39 const char *(*udev_list_entry_get_name)(struct udev_list_entry *list_entry);
40 const char *(*udev_device_get_devnode)(struct udev_device *udev_device);
41 struct udev_enumerate *(*udev_enumerate_new) (struct udev *udev);
42 struct udev_list_entry *(*udev_list_entry_get_next)(struct udev_list_entry *list_entry);
43 };
44
45 class CDROMMethod : public pkgAcqMethod
46 {
47 bool DatabaseLoaded;
48 ::Configuration Database;
49 string CurrentID;
50 string CDROM;
51 bool MountedByApt;
52 vector<string> CdromDevices;
53
54 virtual bool Fetch(FetchItem *Itm);
55 string GetID(string Name);
56 virtual void Exit();
57
58 public:
59
60 CDROMMethod();
61 };
62
63 // CDROMMethod::CDROMethod - Constructor /*{{{*/
64 // ---------------------------------------------------------------------
65 /* */
66 CDROMMethod::CDROMMethod() : pkgAcqMethod("1.0",SingleInstance | LocalOnly |
67 SendConfig | NeedsCleanup |
68 Removable),
69 DatabaseLoaded(false),
70 MountedByApt(false)
71 {
72 // see if we can get libudev
73 void *h = dlopen("libudev.so.0", RTLD_LAZY);
74 if (h) {
75 // the pointers for the udev struct
76 struct udev_p p;
77 p.udev_new = (udev* (*)(void)) dlsym(h, "udev_new");
78 p.udev_enumerate_add_match_property = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_property");
79 p.udev_enumerate_scan_devices = (int (*)(udev_enumerate*))dlsym(h, "udev_enumerate_scan_devices");
80 p.udev_enumerate_get_list_entry = (udev_list_entry* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_list_entry");
81 p.udev_device_new_from_syspath = (udev_device* (*)(udev*, const char*))dlsym(h, "udev_device_new_from_syspath");
82 p.udev_enumerate_get_udev = (udev* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_udev");
83 p.udev_list_entry_get_name = (const char* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_name");
84 p.udev_device_get_devnode = (const char* (*)(udev_device*))dlsym(h, "udev_device_get_devnode");
85 p.udev_enumerate_new = (udev_enumerate* (*)(udev*))dlsym(h, "udev_enumerate_new");
86 p.udev_list_entry_get_next = (udev_list_entry* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_next");
87 struct udev_enumerate *enumerate;
88 struct udev_list_entry *l, *devices;
89 struct udev *udev_ctx;
90
91 udev_ctx = p.udev_new();
92 enumerate = p.udev_enumerate_new (udev_ctx);
93 p.udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
94
95 p.udev_enumerate_scan_devices (enumerate);
96 devices = p.udev_enumerate_get_list_entry (enumerate);
97 for (l = devices; l != NULL; l = p.udev_list_entry_get_next (l))
98 {
99 struct udev_device *udevice;
100 udevice = p.udev_device_new_from_syspath (p.udev_enumerate_get_udev (enumerate), p.udev_list_entry_get_name (l));
101 if (udevice == NULL)
102 continue;
103 const char* devnode = p.udev_device_get_devnode(udevice);
104 //std::cerr << devnode << std::endl;
105 CdromDevices.push_back(string(devnode));
106 }
107 }
108
109
110 };
111 /*}}}*/
112 // CDROMMethod::Exit - Unmount the disc if necessary /*{{{*/
113 // ---------------------------------------------------------------------
114 /* */
115 void CDROMMethod::Exit()
116 {
117 if (MountedByApt == true)
118 UnmountCdrom(CDROM);
119 }
120 /*}}}*/
121 // CDROMMethod::GetID - Search the database for a matching string /*{{{*/
122 // ---------------------------------------------------------------------
123 /* */
124 string CDROMMethod::GetID(string Name)
125 {
126 // Search for an ID
127 const Configuration::Item *Top = Database.Tree("CD");
128 if (Top != 0)
129 Top = Top->Child;
130
131 for (; Top != 0;)
132 {
133 if (Top->Value == Name)
134 return Top->Tag;
135
136 Top = Top->Next;
137 }
138 return string();
139 }
140 /*}}}*/
141 // CDROMMethod::Fetch - Fetch a file /*{{{*/
142 // ---------------------------------------------------------------------
143 /* */
144 bool CDROMMethod::Fetch(FetchItem *Itm)
145 {
146 URI Get = Itm->Uri;
147 string File = Get.Path;
148 FetchResult Res;
149
150 bool Debug = _config->FindB("Debug::Acquire::cdrom",false);
151
152 /* All IMS queries are returned as a hit, CDROMs are readonly so
153 time stamps never change */
154 if (Itm->LastModified != 0)
155 {
156 Res.LastModified = Itm->LastModified;
157 Res.IMSHit = true;
158 Res.Filename = Itm->DestFile;
159 URIDone(Res);
160 return true;
161 }
162
163 // Load the database
164 if (DatabaseLoaded == false)
165 {
166 // Read the database
167 string DFile = _config->FindFile("Dir::State::cdroms");
168 if (FileExists(DFile) == true)
169 {
170 if (ReadConfigFile(Database,DFile) == false)
171 return _error->Error(_("Unable to read the cdrom database %s"),
172 DFile.c_str());
173 }
174 DatabaseLoaded = true;
175 }
176
177 // All non IMS queries for package files fail.
178 if (Itm->IndexFile == true || GetID(Get.Host).empty() == true)
179 {
180 Fail(_("Please use apt-cdrom to make this CD-ROM recognized by APT."
181 " apt-get update cannot be used to add new CD-ROMs"));
182 return true;
183 }
184
185 // We already have a CD inserted, but it is the wrong one
186 if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Host)
187 {
188 Fail(_("Wrong CD-ROM"),true);
189 return true;
190 }
191
192 CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
193 if (CDROM[0] == '.')
194 CDROM= SafeGetCWD() + '/' + CDROM;
195 string NewID;
196 while (CurrentID.empty() == true)
197 {
198 bool Hit = false;
199 if(!IsMounted(CDROM))
200 MountedByApt = MountCdrom(CDROM);
201 for (unsigned int Version = 2; Version != 0; Version--)
202 {
203 if (IdentCdrom(CDROM,NewID,Version) == false)
204 return false;
205
206 if (Debug == true)
207 clog << "ID " << Version << " " << NewID << endl;
208
209 // A hit
210 if (Database.Find("CD::" + NewID) == Get.Host)
211 {
212 Hit = true;
213 break;
214 }
215 }
216
217 if (Hit == true)
218 break;
219
220 // I suppose this should prompt somehow?
221 if (_config->FindB("APT::CDROM::NoMount",false) == false &&
222 UnmountCdrom(CDROM) == false)
223 return _error->Error(_("Unable to unmount the CD-ROM in %s, it may still be in use."),
224 CDROM.c_str());
225 if (MediaFail(Get.Host,CDROM) == false)
226 {
227 CurrentID = "FAIL";
228 return _error->Error(_("Disk not found."));
229 }
230 }
231
232 // Found a CD
233 Res.Filename = CDROM + File;
234 struct stat Buf;
235 if (stat(Res.Filename.c_str(),&Buf) != 0)
236 return _error->Error(_("File not found"));
237
238 if (NewID.empty() == false)
239 CurrentID = NewID;
240 Res.LastModified = Buf.st_mtime;
241 Res.Size = Buf.st_size;
242
243 Hashes Hash;
244 FileFd Fd(Res.Filename, FileFd::ReadOnly);
245 Hash.AddFD(Fd.Fd(), Fd.Size());
246 Res.TakeHashes(Hash);
247
248 URIDone(Res);
249 return true;
250 }
251 /*}}}*/
252
253 int main()
254 {
255 setlocale(LC_ALL, "");
256
257 CDROMMethod Mth;
258 return Mth.Run();
259 }