]> git.saurik.com Git - apt.git/blob - methods/cdrom.cc
rred: truncate result file before writing to it
[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 <config.h>
12
13 #include <apt-pkg/cdrom.h>
14 #include <apt-pkg/cdromutl.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/configuration.h>
17 #include <apt-pkg/fileutl.h>
18 #include <apt-pkg/strutl.h>
19 #include <apt-pkg/hashes.h>
20
21 #include "aptmethod.h"
22
23 #include <string>
24 #include <vector>
25 #include <sys/stat.h>
26
27 #include <iostream>
28 #include <apti18n.h>
29 /*}}}*/
30
31 using namespace std;
32
33 class CDROMMethod : public aptMethod
34 {
35 bool DatabaseLoaded;
36 bool Debug;
37
38 ::Configuration Database;
39 string CurrentID;
40 string CDROM;
41 bool MountedByApt;
42 pkgUdevCdromDevices UdevCdroms;
43
44 bool IsCorrectCD(URI want, string MountPath, string& NewID);
45 bool AutoDetectAndMount(const URI, string &NewID);
46 virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE;
47 string GetID(string Name);
48 virtual void Exit() APT_OVERRIDE;
49
50 public:
51
52 CDROMMethod();
53 };
54
55 // CDROMMethod::CDROMethod - Constructor /*{{{*/
56 // ---------------------------------------------------------------------
57 /* */
58 CDROMMethod::CDROMMethod() : aptMethod("cdrom", "1.0",SingleInstance | LocalOnly |
59 SendConfig | NeedsCleanup |
60 Removable),
61 DatabaseLoaded(false),
62 Debug(false),
63 MountedByApt(false)
64 {
65 UdevCdroms.Dlopen();
66 }
67 /*}}}*/
68 // CDROMMethod::Exit - Unmount the disc if necessary /*{{{*/
69 // ---------------------------------------------------------------------
70 /* */
71 void CDROMMethod::Exit()
72 {
73 if (MountedByApt == true)
74 UnmountCdrom(CDROM);
75 }
76 /*}}}*/
77 // CDROMMethod::GetID - Search the database for a matching string /*{{{*/
78 // ---------------------------------------------------------------------
79 /* */
80 string CDROMMethod::GetID(string Name)
81 {
82 // Search for an ID
83 const Configuration::Item *Top = Database.Tree("CD");
84 if (Top != 0)
85 Top = Top->Child;
86
87 for (; Top != 0;)
88 {
89 if (Top->Value == Name)
90 return Top->Tag;
91
92 Top = Top->Next;
93 }
94 return string();
95 }
96 /*}}}*/
97 // CDROMMethod::AutoDetectAndMount /*{{{*/
98 // ---------------------------------------------------------------------
99 /* Modifies class varaiable CDROM to the mountpoint */
100 bool CDROMMethod::AutoDetectAndMount(const URI Get, string &NewID)
101 {
102 vector<struct CdromDevice> v = UdevCdroms.Scan();
103
104 // first check if its mounted somewhere already
105 for (unsigned int i=0; i < v.size(); i++)
106 {
107 if (v[i].Mounted)
108 {
109 if (Debug)
110 clog << "Checking mounted cdrom device " << v[i].DeviceName << endl;
111 if (IsCorrectCD(Get, v[i].MountPath, NewID))
112 {
113 CDROM = v[i].MountPath;
114 return true;
115 }
116 }
117 }
118
119 // we are not supposed to mount, exit
120 if (_config->FindB("APT::CDROM::NoMount",false) == true)
121 return false;
122
123 // check if we have the mount point
124 string AptMountPoint = _config->FindDir("Dir::Media::MountPath");
125 if (!FileExists(AptMountPoint))
126 mkdir(AptMountPoint.c_str(), 0750);
127
128 // now try mounting
129 for (unsigned int i=0; i < v.size(); i++)
130 {
131 if (!v[i].Mounted)
132 {
133 if(MountCdrom(AptMountPoint, v[i].DeviceName))
134 {
135 if (IsCorrectCD(Get, AptMountPoint, NewID))
136 {
137 MountedByApt = true;
138 CDROM = AptMountPoint;
139 return true;
140 } else {
141 UnmountCdrom(AptMountPoint);
142 }
143 }
144 }
145 }
146
147 return false;
148 }
149 /*}}}*/
150 // CDROMMethod::IsCorrectCD /*{{{*/
151 // ---------------------------------------------------------------------
152 /* */
153 bool CDROMMethod::IsCorrectCD(URI want, string MountPath, string& NewID)
154 {
155 for (unsigned int Version = 2; Version != 0; Version--)
156 {
157 if (IdentCdrom(MountPath,NewID,Version) == false)
158 return false;
159
160 if (Debug)
161 clog << "ID " << Version << " " << NewID << endl;
162
163 // A hit
164 if (Database.Find("CD::" + NewID) == want.Host)
165 return true;
166 }
167
168 return false;
169 }
170 /*}}}*/
171 // CDROMMethod::Fetch - Fetch a file /*{{{*/
172 // ---------------------------------------------------------------------
173 /* */
174 bool CDROMMethod::Fetch(FetchItem *Itm)
175 {
176 FetchResult Res;
177
178 URI Get = Itm->Uri;
179 string File = Get.Path;
180 Debug = _config->FindB("Debug::Acquire::cdrom", false);
181
182 if (Debug)
183 clog << "CDROMMethod::Fetch " << Itm->Uri << endl;
184
185 /* All IMS queries are returned as a hit, CDROMs are readonly so
186 time stamps never change */
187 if (Itm->LastModified != 0)
188 {
189 Res.LastModified = Itm->LastModified;
190 Res.IMSHit = true;
191 Res.Filename = Itm->DestFile;
192 URIDone(Res);
193 return true;
194 }
195
196 // Load the database
197 if (DatabaseLoaded == false)
198 {
199 // Read the database
200 string DFile = _config->FindFile("Dir::State::cdroms");
201 if (FileExists(DFile) == true)
202 {
203 if (ReadConfigFile(Database,DFile) == false)
204 return _error->Error(_("Unable to read the cdrom database %s"),
205 DFile.c_str());
206 }
207 DatabaseLoaded = true;
208 }
209
210 // All non IMS queries for package files fail.
211 if (Itm->IndexFile == true || GetID(Get.Host).empty() == true)
212 {
213 Fail(_("Please use apt-cdrom to make this CD-ROM recognized by APT."
214 " apt-get update cannot be used to add new CD-ROMs"));
215 return true;
216 }
217
218 // We already have a CD inserted, but it is the wrong one
219 if (CurrentID.empty() == false &&
220 CurrentID != "FAIL" &&
221 Database.Find("CD::" + CurrentID) != Get.Host)
222 {
223 Fail(_("Wrong CD-ROM"),true);
224 return true;
225 }
226
227 bool AutoDetect = _config->FindB("Acquire::cdrom::AutoDetect", true);
228 CDROM = _config->FindDir("Acquire::cdrom::mount");
229 if (Debug)
230 clog << "Looking for CDROM at " << CDROM << endl;
231
232 if (CDROM[0] == '.')
233 CDROM= SafeGetCWD() + '/' + CDROM;
234
235 string NewID;
236 while (CurrentID.empty() == true)
237 {
238 if (AutoDetect)
239 AutoDetectAndMount(Get, NewID);
240
241 if(!IsMounted(CDROM))
242 MountedByApt = MountCdrom(CDROM);
243
244 if (IsCorrectCD(Get, CDROM, NewID))
245 break;
246
247 // I suppose this should prompt somehow?
248 if (_config->FindB("APT::CDROM::NoMount",false) == false &&
249 UnmountCdrom(CDROM) == false)
250 return _error->Error(_("Unable to unmount the CD-ROM in %s, it may still be in use."),
251 CDROM.c_str());
252 if (MediaFail(Get.Host,CDROM) == false)
253 {
254 CurrentID = "FAIL";
255 return _error->Error(_("Disk not found."));
256 }
257 }
258
259 // Found a CD
260 Res.Filename = CDROM + File;
261 struct stat Buf;
262 if (stat(Res.Filename.c_str(),&Buf) != 0)
263 return _error->Error(_("File not found"));
264
265 URIStart(Res);
266 if (NewID.empty() == false)
267 CurrentID = NewID;
268 Res.LastModified = Buf.st_mtime;
269 Res.Size = Buf.st_size;
270
271 Hashes Hash(Itm->ExpectedHashes);
272 FileFd Fd(Res.Filename, FileFd::ReadOnly);
273 Hash.AddFD(Fd);
274 Res.TakeHashes(Hash);
275
276 URIDone(Res);
277 return true;
278 }
279 /*}}}*/
280
281 int main()
282 {
283 _config->CndSet("Binary::cdrom::Debug::NoDropPrivs", true);
284 return CDROMMethod().Run();
285 }