* Patch from Eric Wong <normalperson@yhbt.net> to inclu...
[ntk/apt.git] / methods / cdrom.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: cdrom.cc,v 1.21 2004/01/07 20:39:38 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
17 #include <sys/stat.h>
18 #include <unistd.h>
19
20 #include <iostream>
21 #include <apti18n.h>
22 /*}}}*/
23
24 using namespace std;
25
26 class CDROMMethod : public pkgAcqMethod
27 {
28 bool DatabaseLoaded;
29 ::Configuration Database;
30 string CurrentID;
31 string CDROM;
32 bool Mounted;
33
34 virtual bool Fetch(FetchItem *Itm);
35 string GetID(string Name);
36 virtual void Exit();
37
38 public:
39
40 CDROMMethod();
41 };
42
43 // CDROMMethod::CDROMethod - Constructor /*{{{*/
44 // ---------------------------------------------------------------------
45 /* */
46 CDROMMethod::CDROMMethod() : pkgAcqMethod("1.0",SingleInstance | LocalOnly |
47 SendConfig | NeedsCleanup |
48 Removable),
49 DatabaseLoaded(false),
50 Mounted(false)
51 {
52 };
53 /*}}}*/
54 // CDROMMethod::Exit - Unmount the disc if necessary /*{{{*/
55 // ---------------------------------------------------------------------
56 /* */
57 void CDROMMethod::Exit()
58 {
59 if (Mounted == true)
60 UnmountCdrom(CDROM);
61 }
62 /*}}}*/
63 // CDROMMethod::GetID - Search the database for a matching string /*{{{*/
64 // ---------------------------------------------------------------------
65 /* */
66 string CDROMMethod::GetID(string Name)
67 {
68 // Search for an ID
69 const Configuration::Item *Top = Database.Tree("CD");
70 if (Top != 0)
71 Top = Top->Child;
72
73 for (; Top != 0;)
74 {
75 if (Top->Value == Name)
76 return Top->Tag;
77
78 Top = Top->Next;
79 }
80 return string();
81 }
82 /*}}}*/
83 // CDROMMethod::Fetch - Fetch a file /*{{{*/
84 // ---------------------------------------------------------------------
85 /* */
86 bool CDROMMethod::Fetch(FetchItem *Itm)
87 {
88 URI Get = Itm->Uri;
89 string File = Get.Path;
90 FetchResult Res;
91
92 bool Debug = _config->FindB("Debug::Acquire::cdrom",false);
93
94 /* All IMS queries are returned as a hit, CDROMs are readonly so
95 time stamps never change */
96 if (Itm->LastModified != 0)
97 {
98 Res.LastModified = Itm->LastModified;
99 Res.IMSHit = true;
100 Res.Filename = File;
101 URIDone(Res);
102 return true;
103 }
104
105 // Load the database
106 if (DatabaseLoaded == false)
107 {
108 // Read the database
109 string DFile = _config->FindFile("Dir::State::cdroms");
110 if (FileExists(DFile) == true)
111 {
112 if (ReadConfigFile(Database,DFile) == false)
113 return _error->Error(_("Unable to read the cdrom database %s"),
114 DFile.c_str());
115 }
116 DatabaseLoaded = true;
117 }
118
119 // All non IMS queries for package files fail.
120 if (Itm->IndexFile == true || GetID(Get.Host).empty() == true)
121 {
122 Fail(_("Please use apt-cdrom to make this CD recognized by APT."
123 " apt-get update cannot be used to add new CDs"));
124 return true;
125 }
126
127 // We already have a CD inserted, but it is the wrong one
128 if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Host)
129 {
130 Fail(_("Wrong CD"),true);
131 return true;
132 }
133
134 CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
135 if (CDROM[0] == '.')
136 CDROM= SafeGetCWD() + '/' + CDROM;
137 string NewID;
138 while (CurrentID.empty() == true)
139 {
140 bool Hit = false;
141 Mounted = MountCdrom(CDROM);
142 for (unsigned int Version = 2; Version != 0; Version--)
143 {
144 if (IdentCdrom(CDROM,NewID,Version) == false)
145 return false;
146
147 if (Debug == true)
148 clog << "ID " << Version << " " << NewID << endl;
149
150 // A hit
151 if (Database.Find("CD::" + NewID) == Get.Host)
152 {
153 Hit = true;
154 break;
155 }
156 }
157
158 if (Hit == true)
159 break;
160
161 // I suppose this should prompt somehow?
162 if (UnmountCdrom(CDROM) == false)
163 return _error->Error(_("Unable to unmount the CD-ROM in %s, it may still be in use."),
164 CDROM.c_str());
165 if (MediaFail(Get.Host,CDROM) == false)
166 {
167 CurrentID = "FAIL";
168 Fail(_("Wrong CD"),true);
169 return true;
170 }
171 }
172
173 // Found a CD
174 Res.Filename = CDROM + File;
175 struct stat Buf;
176 if (stat(Res.Filename.c_str(),&Buf) != 0)
177 return _error->Error(_("File not found"));
178
179 if (NewID.empty() == false)
180 CurrentID = NewID;
181 Res.LastModified = Buf.st_mtime;
182 Res.Size = Buf.st_size;
183 URIDone(Res);
184 return true;
185 }
186 /*}}}*/
187
188 int main()
189 {
190 CDROMMethod Mth;
191 return Mth.Run();
192 }