* apt-pkg/cdrom.cc:
[ntk/apt.git] / apt-pkg / cdrom.cc
CommitLineData
a75c6a6e
MZ
1/*
2 */
ea542140 3#include<config.h>
a75c6a6e 4
a75c6a6e
MZ
5#include<apt-pkg/init.h>
6#include<apt-pkg/error.h>
7#include<apt-pkg/cdromutl.h>
8#include<apt-pkg/strutl.h>
9#include<apt-pkg/cdrom.h>
5dd4c8b8 10#include<apt-pkg/aptconfiguration.h>
472ff00e
DK
11#include<apt-pkg/configuration.h>
12#include<apt-pkg/fileutl.h>
5dd4c8b8 13
a75c6a6e
MZ
14#include<sstream>
15#include<fstream>
a75c6a6e
MZ
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <dirent.h>
19#include <unistd.h>
20#include <stdio.h>
152ab79e 21#include <algorithm>
cbc9bed8 22#include <dlfcn.h>
a75c6a6e
MZ
23
24#include "indexcopy.h"
25
ea542140
DK
26#include<apti18n.h>
27
a75c6a6e
MZ
28using namespace std;
29
30// FindPackages - Find the package files on the CDROM /*{{{*/
31// ---------------------------------------------------------------------
32/* We look over the cdrom for package files. This is a recursive
33 search that short circuits when it his a package file in the dir.
34 This speeds it up greatly as the majority of the size is in the
35 binary-* sub dirs. */
22f8568d
MV
36bool pkgCdrom::FindPackages(string CD,
37 vector<string> &List,
38 vector<string> &SList,
39 vector<string> &SigList,
40 vector<string> &TransList,
a75c6a6e
MZ
41 string &InfoDir, pkgCdromStatus *log,
42 unsigned int Depth)
43{
44 static ino_t Inodes[9];
22f8568d 45 DIR *D;
a75c6a6e
MZ
46
47 // if we have a look we "pulse" now
48 if(log)
49 log->Update();
50
51 if (Depth >= 7)
52 return true;
53
54 if (CD[CD.length()-1] != '/')
55 CD += '/';
56
57 if (chdir(CD.c_str()) != 0)
58 return _error->Errno("chdir","Unable to change to %s",CD.c_str());
59
60 // Look for a .disk subdirectory
711078ae 61 if (DirectoryExists(".disk") == true)
a75c6a6e
MZ
62 {
63 if (InfoDir.empty() == true)
64 InfoDir = CD + ".disk/";
65 }
66
67 // Don't look into directories that have been marked to ingore.
711078ae 68 if (RealFileExists(".aptignr") == true)
a75c6a6e
MZ
69 return true;
70
a75c6a6e
MZ
71 /* Check _first_ for a signature file as apt-cdrom assumes that all files
72 under a Packages/Source file are in control of that file and stops
73 the scanning
74 */
212080b8 75 if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
a75c6a6e
MZ
76 {
77 SigList.push_back(CD);
78 }
82c8f08e 79
a75c6a6e
MZ
80 /* Aha! We found some package files. We assume that everything under
81 this dir is controlled by those package files so we don't look down
82 anymore */
78c9276d
DK
83 std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
84 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
85 c != compressor.end(); ++c)
86 {
711078ae 87 if (RealFileExists(std::string("Packages").append(c->Extension).c_str()) == false)
78c9276d
DK
88 continue;
89
90 if (_config->FindB("Debug::aptcdrom",false) == true)
91 std::clog << "Found Packages in " << CD << std::endl;
92 List.push_back(CD);
93
94 // Continue down if thorough is given
95 if (_config->FindB("APT::CDROM::Thorough",false) == false)
96 return true;
97 break;
98 }
99 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
100 c != compressor.end(); ++c)
101 {
711078ae 102 if (RealFileExists(std::string("Sources").append(c->Extension).c_str()) == false)
78c9276d
DK
103 continue;
104
105 if (_config->FindB("Debug::aptcdrom",false) == true)
106 std::clog << "Found Sources in " << CD << std::endl;
107 SList.push_back(CD);
108
109 // Continue down if thorough is given
110 if (_config->FindB("APT::CDROM::Thorough",false) == false)
111 return true;
112 break;
113 }
22f8568d 114
01366a44 115 // see if we find translation indices
78c9276d 116 if (DirectoryExists("i18n") == true)
22f8568d
MV
117 {
118 D = opendir("i18n");
119 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
120 {
78c9276d
DK
121 if(strncmp(Dir->d_name, "Translation-", strlen("Translation-")) != 0)
122 continue;
123 string file = Dir->d_name;
124 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
125 c != compressor.end(); ++c)
22f8568d 126 {
78c9276d
DK
127 string fileext = flExtension(file);
128 if (file == fileext)
129 fileext.clear();
130 else if (fileext.empty() == false)
131 fileext = "." + fileext;
132
133 if (c->Extension == fileext)
134 {
135 if (_config->FindB("Debug::aptcdrom",false) == true)
136 std::clog << "Found translation " << Dir->d_name << " in " << CD << "i18n/" << std::endl;
4e86b003 137 file.erase(file.size() - fileext.size());
78c9276d
DK
138 TransList.push_back(CD + "i18n/" + file);
139 break;
140 }
22f8568d
MV
141 }
142 }
143 closedir(D);
144 }
145
22f8568d 146 D = opendir(".");
a75c6a6e
MZ
147 if (D == 0)
148 return _error->Errno("opendir","Unable to read %s",CD.c_str());
149
150 // Run over the directory
151 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
152 {
153 // Skip some files..
154 if (strcmp(Dir->d_name,".") == 0 ||
155 strcmp(Dir->d_name,"..") == 0 ||
156 //strcmp(Dir->d_name,"source") == 0 ||
157 strcmp(Dir->d_name,".disk") == 0 ||
158 strcmp(Dir->d_name,"experimental") == 0 ||
159 strcmp(Dir->d_name,"binary-all") == 0 ||
160 strcmp(Dir->d_name,"debian-installer") == 0)
161 continue;
162
163 // See if the name is a sub directory
164 struct stat Buf;
165 if (stat(Dir->d_name,&Buf) != 0)
166 continue;
167
168 if (S_ISDIR(Buf.st_mode) == 0)
169 continue;
170
171 unsigned int I;
172 for (I = 0; I != Depth; I++)
173 if (Inodes[I] == Buf.st_ino)
174 break;
175 if (I != Depth)
176 continue;
177
178 // Store the inodes weve seen
179 Inodes[Depth] = Buf.st_ino;
180
181 // Descend
22f8568d 182 if (FindPackages(CD + Dir->d_name,List,SList,SigList,TransList,InfoDir,log,Depth+1) == false)
a75c6a6e
MZ
183 break;
184
185 if (chdir(CD.c_str()) != 0)
6070a346
DK
186 {
187 _error->Errno("chdir","Unable to change to %s", CD.c_str());
188 closedir(D);
189 return false;
190 }
a75c6a6e
MZ
191 };
192
193 closedir(D);
194
195 return !_error->PendingError();
196}
92fcbfc1 197 /*}}}*/
a75c6a6e
MZ
198// Score - We compute a 'score' for a path /*{{{*/
199// ---------------------------------------------------------------------
200/* Paths are scored based on how close they come to what I consider
201 normal. That is ones that have 'dist' 'stable' 'testing' will score
202 higher than ones without. */
203int pkgCdrom::Score(string Path)
204{
205 int Res = 0;
206 if (Path.find("stable/") != string::npos)
207 Res += 29;
208 if (Path.find("/binary-") != string::npos)
209 Res += 20;
210 if (Path.find("testing/") != string::npos)
211 Res += 28;
212 if (Path.find("unstable/") != string::npos)
213 Res += 27;
214 if (Path.find("/dists/") != string::npos)
215 Res += 40;
216 if (Path.find("/main/") != string::npos)
217 Res += 20;
218 if (Path.find("/contrib/") != string::npos)
219 Res += 20;
220 if (Path.find("/non-free/") != string::npos)
221 Res += 20;
222 if (Path.find("/non-US/") != string::npos)
223 Res += 20;
224 if (Path.find("/source/") != string::npos)
225 Res += 10;
226 if (Path.find("/debian/") != string::npos)
227 Res -= 10;
872b3d39
MV
228
229 // check for symlinks in the patch leading to the actual file
230 // a symlink gets a big penalty
231 struct stat Buf;
232 string statPath = flNotFile(Path);
710aba4a 233 string cdromPath = _config->FindDir("Acquire::cdrom::mount");
872b3d39
MV
234 while(statPath != cdromPath && statPath != "./") {
235 statPath.resize(statPath.size()-1); // remove the trailing '/'
236 if (lstat(statPath.c_str(),&Buf) == 0) {
237 if(S_ISLNK(Buf.st_mode)) {
238 Res -= 60;
239 break;
240 }
241 }
242 statPath = flNotFile(statPath); // descent
243 }
244
a75c6a6e
MZ
245 return Res;
246}
a75c6a6e
MZ
247 /*}}}*/
248// DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
249// ---------------------------------------------------------------------
250/* Here we drop everything that is not this machines arch */
251bool pkgCdrom::DropBinaryArch(vector<string> &List)
252{
5dd4c8b8 253
a75c6a6e
MZ
254 for (unsigned int I = 0; I < List.size(); I++)
255 {
256 const char *Str = List[I].c_str();
5dd4c8b8
DK
257 const char *Start, *End;
258 if ((Start = strstr(Str,"/binary-")) == 0)
a75c6a6e
MZ
259 continue;
260
5dd4c8b8
DK
261 // Between Start and End is the architecture
262 Start += 8;
263 if ((End = strstr(Start,"/")) != 0 && Start != End &&
73dfa041 264 APT::Configuration::checkArchitecture(string(Start, End)) == true)
5dd4c8b8
DK
265 continue; // okay, architecture is accepted
266
267 // not accepted -> Erase it
a75c6a6e 268 List.erase(List.begin() + I);
5dd4c8b8 269 --I; // the next entry is at the same index after the erase
a75c6a6e
MZ
270 }
271
272 return true;
273}
92fcbfc1 274 /*}}}*/
a75c6a6e
MZ
275// DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
276// ---------------------------------------------------------------------
277/* Here we go and stat every file that we found and strip dup inodes. */
278bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
279{
2c405a44 280 bool couldFindAllFiles = true;
a75c6a6e
MZ
281 // Get a list of all the inodes
282 ino_t *Inodes = new ino_t[List.size()];
78c9276d 283 for (unsigned int I = 0; I != List.size(); ++I)
a75c6a6e
MZ
284 {
285 struct stat Buf;
78c9276d
DK
286 bool found = false;
287
288 std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
289 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
290 c != compressor.end(); ++c)
82c8f08e 291 {
78c9276d 292 std::string filename = std::string(List[I]).append(Name).append(c->Extension);
82c8f08e 293 if (stat(filename.c_str(), &Buf) != 0)
78c9276d
DK
294 continue;
295 Inodes[I] = Buf.st_ino;
296 found = true;
297 break;
82c8f08e 298 }
78c9276d
DK
299
300 if (found == false)
2c405a44
DK
301 {
302 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(), Name);
303 couldFindAllFiles = false;
304 Inodes[I] = 0;
305 }
a75c6a6e 306 }
78c9276d 307
a75c6a6e
MZ
308 // Look for dups
309 for (unsigned int I = 0; I != List.size(); I++)
310 {
2c405a44
DK
311 if (Inodes[I] == 0)
312 continue;
a75c6a6e
MZ
313 for (unsigned int J = I+1; J < List.size(); J++)
314 {
315 // No match
2c405a44 316 if (Inodes[J] == 0 || Inodes[J] != Inodes[I])
a75c6a6e
MZ
317 continue;
318
319 // We score the two paths.. and erase one
320 int ScoreA = Score(List[I]);
321 int ScoreB = Score(List[J]);
322 if (ScoreA < ScoreB)
323 {
324 List[I] = string();
325 break;
326 }
327
328 List[J] = string();
329 }
330 }
3a4477a4
DK
331 delete[] Inodes;
332
a75c6a6e
MZ
333 // Wipe erased entries
334 for (unsigned int I = 0; I < List.size();)
335 {
336 if (List[I].empty() == false)
337 I++;
338 else
339 List.erase(List.begin()+I);
340 }
341
2c405a44 342 return couldFindAllFiles;
a75c6a6e
MZ
343}
344 /*}}}*/
a75c6a6e
MZ
345// ReduceSourceList - Takes the path list and reduces it /*{{{*/
346// ---------------------------------------------------------------------
347/* This takes the list of source list expressed entires and collects
348 similar ones to form a single entry for each dist */
349void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
350{
351 sort(List.begin(),List.end());
352
353 // Collect similar entries
f7f0d6c7 354 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
355 {
356 // Find a space..
357 string::size_type Space = (*I).find(' ');
358 if (Space == string::npos)
359 continue;
360 string::size_type SSpace = (*I).find(' ',Space + 1);
361 if (SSpace == string::npos)
362 continue;
363
364 string Word1 = string(*I,Space,SSpace-Space);
365 string Prefix = string(*I,0,Space);
8628c2f7 366 string Component = string(*I,SSpace);
f7f0d6c7 367 for (vector<string>::iterator J = List.begin(); J != I; ++J)
a75c6a6e
MZ
368 {
369 // Find a space..
370 string::size_type Space2 = (*J).find(' ');
371 if (Space2 == string::npos)
372 continue;
373 string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
374 if (SSpace2 == string::npos)
375 continue;
376
377 if (string(*J,0,Space2) != Prefix)
378 continue;
379 if (string(*J,Space2,SSpace2-Space2) != Word1)
380 continue;
8628c2f7
DK
381
382 string Component2 = string(*J, SSpace2) + " ";
383 if (Component2.find(Component + " ") == std::string::npos)
384 *J += Component;
385 I->clear();
a75c6a6e
MZ
386 }
387 }
388
389 // Wipe erased entries
390 for (unsigned int I = 0; I < List.size();)
391 {
392 if (List[I].empty() == false)
393 I++;
394 else
395 List.erase(List.begin()+I);
396 }
397}
398 /*}}}*/
399// WriteDatabase - Write the CDROM Database file /*{{{*/
400// ---------------------------------------------------------------------
401/* We rewrite the configuration class associated with the cdrom database. */
402bool pkgCdrom::WriteDatabase(Configuration &Cnf)
403{
404 string DFile = _config->FindFile("Dir::State::cdroms");
405 string NewFile = DFile + ".new";
406
407 unlink(NewFile.c_str());
408 ofstream Out(NewFile.c_str());
409 if (!Out)
410 return _error->Errno("ofstream::ofstream",
411 "Failed to open %s.new",DFile.c_str());
412
413 /* Write out all of the configuration directives by walking the
414 configuration tree */
ab59c1ca 415 Cnf.Dump(Out, NULL, "%f \"%v\";\n", false);
a75c6a6e
MZ
416
417 Out.close();
849e64ac 418
c1cd1ac2
DK
419 if (FileExists(DFile) == true)
420 rename(DFile.c_str(), string(DFile + '~').c_str());
a75c6a6e
MZ
421 if (rename(NewFile.c_str(),DFile.c_str()) != 0)
422 return _error->Errno("rename","Failed to rename %s.new to %s",
423 DFile.c_str(),DFile.c_str());
424
425 return true;
426}
427 /*}}}*/
428// WriteSourceList - Write an updated sourcelist /*{{{*/
429// ---------------------------------------------------------------------
430/* This reads the old source list and copies it into the new one. It
431 appends the new CDROM entires just after the first block of comments.
432 This places them first in the file. It also removes any old entries
433 that were the same. */
434bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
435{
f7f0d6c7 436 if (List.empty() == true)
a75c6a6e
MZ
437 return true;
438
439 string File = _config->FindFile("Dir::Etc::sourcelist");
440
441 // Open the stream for reading
442 ifstream F((FileExists(File)?File.c_str():"/dev/null"),
443 ios::in );
444 if (!F != 0)
445 return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
446
447 string NewFile = File + ".new";
448 unlink(NewFile.c_str());
449 ofstream Out(NewFile.c_str());
450 if (!Out)
451 return _error->Errno("ofstream::ofstream",
452 "Failed to open %s.new",File.c_str());
453
454 // Create a short uri without the path
455 string ShortURI = "cdrom:[" + Name + "]/";
456 string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
457
458 string Type;
459 if (Source == true)
460 Type = "deb-src";
461 else
462 Type = "deb";
463
464 char Buffer[300];
465 int CurLine = 0;
466 bool First = true;
467 while (F.eof() == false)
468 {
469 F.getline(Buffer,sizeof(Buffer));
470 CurLine++;
13e8426f
MV
471 if (F.fail() && !F.eof())
472 return _error->Error(_("Line %u too long in source list %s."),
473 CurLine,File.c_str());
a75c6a6e
MZ
474 _strtabexpand(Buffer,sizeof(Buffer));
475 _strstrip(Buffer);
476
477 // Comment or blank
478 if (Buffer[0] == '#' || Buffer[0] == 0)
479 {
480 Out << Buffer << endl;
481 continue;
482 }
483
484 if (First == true)
485 {
f7f0d6c7 486 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
487 {
488 string::size_type Space = (*I).find(' ');
489 if (Space == string::npos)
490 return _error->Error("Internal error");
491 Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
492 " " << string(*I,Space+1) << endl;
493 }
494 }
495 First = false;
496
497 // Grok it
498 string cType;
499 string URI;
500 const char *C = Buffer;
501 if (ParseQuoteWord(C,cType) == false ||
502 ParseQuoteWord(C,URI) == false)
503 {
504 Out << Buffer << endl;
505 continue;
506 }
507
508 // Emit lines like this one
509 if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
510 string(URI,0,ShortURI.length()) != ShortURI2))
511 {
512 Out << Buffer << endl;
513 continue;
514 }
515 }
516
517 // Just in case the file was empty
518 if (First == true)
519 {
f7f0d6c7 520 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
521 {
522 string::size_type Space = (*I).find(' ');
523 if (Space == string::npos)
524 return _error->Error("Internal error");
525
526 Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
527 " " << string(*I,Space+1) << endl;
528 }
529 }
530
531 Out.close();
532
533 rename(File.c_str(),string(File + '~').c_str());
534 if (rename(NewFile.c_str(),File.c_str()) != 0)
535 return _error->Errno("rename","Failed to rename %s.new to %s",
536 File.c_str(),File.c_str());
537
538 return true;
539}
92fcbfc1
DK
540 /*}}}*/
541bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
a75c6a6e
MZ
542{
543 stringstream msg;
544
545 // Startup
710aba4a 546 string CDROM = _config->FindDir("Acquire::cdrom::mount");
a75c6a6e
MZ
547 if (CDROM[0] == '.')
548 CDROM= SafeGetCWD() + '/' + CDROM;
549
6070a346
DK
550 if (log != NULL)
551 {
a75c6a6e
MZ
552 msg.str("");
553 ioprintf(msg, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
554 CDROM.c_str());
555 log->Update(msg.str());
556 }
70dbf5f8
MV
557 if (MountCdrom(CDROM) == false)
558 return _error->Error("Failed to mount the cdrom.");
a75c6a6e
MZ
559
560 // Hash the CD to get an ID
6070a346 561 if (log != NULL)
a75c6a6e
MZ
562 log->Update(_("Identifying.. "));
563
564
565 if (IdentCdrom(CDROM,ident) == false)
566 {
567 ident = "";
568 return false;
569 }
570
6070a346
DK
571 if (log != NULL)
572 {
573 msg.str("");
574 ioprintf(msg, "[%s]\n",ident.c_str());
575 log->Update(msg.str());
576 }
a75c6a6e
MZ
577
578 // Read the database
579 Configuration Database;
580 string DFile = _config->FindFile("Dir::State::cdroms");
581 if (FileExists(DFile) == true)
582 {
583 if (ReadConfigFile(Database,DFile) == false)
584 return _error->Error("Unable to read the cdrom database %s",
585 DFile.c_str());
586 }
6070a346
DK
587 if (log != NULL)
588 {
a75c6a6e 589 msg.str("");
36fb926e
OS
590 ioprintf(msg, _("Stored label: %s\n"),
591 Database.Find("CD::"+ident).c_str());
a75c6a6e
MZ
592 log->Update(msg.str());
593 }
1fcbe14d
OS
594
595 // Unmount and finish
6070a346
DK
596 if (_config->FindB("APT::CDROM::NoMount",false) == false)
597 {
598 if (log != NULL)
599 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
1fcbe14d
OS
600 UnmountCdrom(CDROM);
601 }
602
a75c6a6e
MZ
603 return true;
604}
92fcbfc1
DK
605 /*}}}*/
606bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
a75c6a6e
MZ
607{
608 stringstream msg;
609
610 // Startup
a9239250 611 string CDROM = _config->FindDir("Acquire::cdrom::mount");
a75c6a6e
MZ
612 if (CDROM[0] == '.')
613 CDROM= SafeGetCWD() + '/' + CDROM;
614
6070a346
DK
615 if(log != NULL)
616 {
a75c6a6e
MZ
617 log->SetTotal(STEP_LAST);
618 msg.str("");
619 ioprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
620 log->Update(msg.str(), STEP_PREPARE);
621 }
622
623 // Read the database
624 Configuration Database;
625 string DFile = _config->FindFile("Dir::State::cdroms");
626 if (FileExists(DFile) == true)
627 {
cdadf54b 628 if (ReadConfigFile(Database,DFile) == false)
a75c6a6e
MZ
629 return _error->Error("Unable to read the cdrom database %s",
630 DFile.c_str());
631 }
632
633 // Unmount the CD and get the user to put in the one they want
634 if (_config->FindB("APT::CDROM::NoMount",false) == false)
635 {
6070a346 636 if(log != NULL)
a75c6a6e
MZ
637 log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
638 UnmountCdrom(CDROM);
639
6070a346
DK
640 if(log != NULL)
641 {
a75c6a6e
MZ
642 log->Update(_("Waiting for disc...\n"), STEP_WAIT);
643 if(!log->ChangeCdrom()) {
644 // user aborted
645 return false;
646 }
647 }
648
649 // Mount the new CDROM
6070a346
DK
650 if(log != NULL)
651 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
652
a75c6a6e
MZ
653 if (MountCdrom(CDROM) == false)
654 return _error->Error("Failed to mount the cdrom.");
655 }
656
657 // Hash the CD to get an ID
6070a346 658 if(log != NULL)
a75c6a6e
MZ
659 log->Update(_("Identifying.. "), STEP_IDENT);
660 string ID;
661 if (IdentCdrom(CDROM,ID) == false)
662 {
6070a346
DK
663 if (log != NULL)
664 log->Update("\n");
a75c6a6e
MZ
665 return false;
666 }
6070a346
DK
667 if(log != NULL)
668 {
a75c6a6e 669 log->Update("["+ID+"]\n");
db0db9fe 670 log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
6070a346
DK
671 }
672
a75c6a6e
MZ
673 // Get the CD structure
674 vector<string> List;
675 vector<string> SourceList;
676 vector<string> SigList;
22f8568d 677 vector<string> TransList;
a75c6a6e
MZ
678 string StartDir = SafeGetCWD();
679 string InfoDir;
22f8568d 680 if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
a75c6a6e 681 {
6070a346
DK
682 if (log != NULL)
683 log->Update("\n");
a75c6a6e
MZ
684 return false;
685 }
686
31bda500
DK
687 if (chdir(StartDir.c_str()) != 0)
688 return _error->Errno("chdir","Unable to change to %s", StartDir.c_str());
a75c6a6e
MZ
689
690 if (_config->FindB("Debug::aptcdrom",false) == true)
691 {
692 cout << "I found (binary):" << endl;
f7f0d6c7 693 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
694 cout << *I << endl;
695 cout << "I found (source):" << endl;
f7f0d6c7 696 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
a75c6a6e
MZ
697 cout << *I << endl;
698 cout << "I found (Signatures):" << endl;
f7f0d6c7 699 for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
a75c6a6e
MZ
700 cout << *I << endl;
701 }
702
703 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
704
705 // Fix up the list
706 DropBinaryArch(List);
707 DropRepeats(List,"Packages");
708 DropRepeats(SourceList,"Sources");
2c405a44
DK
709 // FIXME: We ignore stat() errors here as we usually have only one of those in use
710 // This has little potencial to drop 'valid' stat() errors as we know that one of these
711 // files need to exist, but it would be better if we would check it here
712 _error->PushToStack();
a75c6a6e 713 DropRepeats(SigList,"Release.gpg");
212080b8 714 DropRepeats(SigList,"InRelease");
2c405a44 715 _error->RevertToStack();
22f8568d 716 DropRepeats(TransList,"");
6070a346 717 if(log != NULL) {
a75c6a6e 718 msg.str("");
a376d6fd
OS
719 ioprintf(msg, _("Found %zu package indexes, %zu source indexes, "
720 "%zu translation indexes and %zu signatures\n"),
22f8568d
MV
721 List.size(), SourceList.size(), TransList.size(),
722 SigList.size());
a75c6a6e
MZ
723 log->Update(msg.str(), STEP_SCAN);
724 }
725
f7f0d6c7 726 if (List.empty() == true && SourceList.empty() == true)
cdadf54b 727 {
50959877
MV
728 if (_config->FindB("APT::CDROM::NoMount",false) == false)
729 UnmountCdrom(CDROM);
d720a7d4 730 return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
cdadf54b 731 }
a75c6a6e
MZ
732
733 // Check if the CD is in the database
734 string Name;
735 if (Database.Exists("CD::" + ID) == false ||
736 _config->FindB("APT::CDROM::Rename",false) == true)
737 {
738 // Try to use the CDs label if at all possible
739 if (InfoDir.empty() == false &&
740 FileExists(InfoDir + "/info") == true)
741 {
742 ifstream F(string(InfoDir + "/info").c_str());
743 if (!F == 0)
744 getline(F,Name);
745
746 if (Name.empty() == false)
747 {
748 // Escape special characters
749 string::iterator J = Name.begin();
f7f0d6c7 750 for (; J != Name.end(); ++J)
a75c6a6e
MZ
751 if (*J == '"' || *J == ']' || *J == '[')
752 *J = '_';
753
6070a346
DK
754 if(log != NULL)
755 {
a75c6a6e 756 msg.str("");
ce86ff41 757 ioprintf(msg, _("Found label '%s'\n"), Name.c_str());
a75c6a6e
MZ
758 log->Update(msg.str());
759 }
760 Database.Set("CD::" + ID + "::Label",Name);
761 }
762 }
763
764 if (_config->FindB("APT::CDROM::Rename",false) == true ||
765 Name.empty() == true)
766 {
6070a346 767 if(log == NULL)
cdadf54b 768 {
50959877
MV
769 if (_config->FindB("APT::CDROM::NoMount",false) == false)
770 UnmountCdrom(CDROM);
a75c6a6e 771 return _error->Error("No disc name found and no way to ask for it");
cdadf54b 772 }
a75c6a6e
MZ
773
774 while(true) {
775 if(!log->AskCdromName(Name)) {
776 // user canceld
777 return false;
778 }
779 cout << "Name: '" << Name << "'" << endl;
780
781 if (Name.empty() == false &&
782 Name.find('"') == string::npos &&
783 Name.find('[') == string::npos &&
784 Name.find(']') == string::npos)
785 break;
786 log->Update(_("That is not a valid name, try again.\n"));
787 }
788 }
789 }
790 else
791 Name = Database.Find("CD::" + ID);
792
793 // Escape special characters
794 string::iterator J = Name.begin();
f7f0d6c7 795 for (; J != Name.end(); ++J)
a75c6a6e
MZ
796 if (*J == '"' || *J == ']' || *J == '[')
797 *J = '_';
798
799 Database.Set("CD::" + ID,Name);
6070a346
DK
800 if(log != NULL)
801 {
a75c6a6e 802 msg.str("");
db0db9fe 803 ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
a75c6a6e 804 log->Update(msg.str());
6070a346 805 log->Update(_("Copying package lists..."), STEP_COPY);
a75c6a6e 806 }
a75c6a6e
MZ
807 // take care of the signatures and copy them if they are ok
808 // (we do this before PackageCopy as it modifies "List" and "SourceList")
809 SigVerify SignVerify;
810 SignVerify.CopyAndVerify(CDROM, Name, SigList, List, SourceList);
811
812 // Copy the package files to the state directory
813 PackageCopy Copy;
814 SourceCopy SrcCopy;
22f8568d 815 TranslationsCopy TransCopy;
a75c6a6e 816 if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
22f8568d
MV
817 SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
818 TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
a75c6a6e
MZ
819 return false;
820
821 // reduce the List so that it takes less space in sources.list
822 ReduceSourcelist(CDROM,List);
823 ReduceSourcelist(CDROM,SourceList);
824
825 // Write the database and sourcelist
826 if (_config->FindB("APT::cdrom::NoAct",false) == false)
827 {
828 if (WriteDatabase(Database) == false)
829 return false;
830
6070a346 831 if(log != NULL)
a75c6a6e 832 log->Update(_("Writing new source list\n"), STEP_WRITE);
a75c6a6e
MZ
833 if (WriteSourceList(Name,List,false) == false ||
834 WriteSourceList(Name,SourceList,true) == false)
835 return false;
836 }
837
838 // Print the sourcelist entries
6070a346 839 if(log != NULL)
db0db9fe 840 log->Update(_("Source list entries for this disc are:\n"));
a75c6a6e 841
f7f0d6c7 842 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
843 {
844 string::size_type Space = (*I).find(' ');
845 if (Space == string::npos)
cdadf54b 846 {
50959877
MV
847 if (_config->FindB("APT::CDROM::NoMount",false) == false)
848 UnmountCdrom(CDROM);
a75c6a6e 849 return _error->Error("Internal error");
cdadf54b 850 }
a75c6a6e 851
6070a346
DK
852 if(log != NULL)
853 {
a75c6a6e
MZ
854 msg.str("");
855 msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
856 " " << string(*I,Space+1) << endl;
857 log->Update(msg.str());
858 }
859 }
860
f7f0d6c7 861 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
a75c6a6e
MZ
862 {
863 string::size_type Space = (*I).find(' ');
864 if (Space == string::npos)
cdadf54b 865 {
50959877
MV
866 if (_config->FindB("APT::CDROM::NoMount",false) == false)
867 UnmountCdrom(CDROM);
a75c6a6e 868 return _error->Error("Internal error");
cdadf54b 869 }
a75c6a6e 870
6070a346 871 if(log != NULL) {
a75c6a6e
MZ
872 msg.str("");
873 msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
874 " " << string(*I,Space+1) << endl;
875 log->Update(msg.str());
876 }
877 }
878
a75c6a6e 879 // Unmount and finish
70dbf5f8 880 if (_config->FindB("APT::CDROM::NoMount",false) == false) {
6070a346
DK
881 if (log != NULL)
882 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
a75c6a6e
MZ
883 UnmountCdrom(CDROM);
884 }
885
886 return true;
887}
92fcbfc1 888 /*}}}*/
3e2d7cce 889pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
76fe5db7 890 : libudev_handle(NULL)
cbc9bed8
MV
891{
892
893}
3e2d7cce 894 /*}}}*/
cbc9bed8
MV
895
896bool
3e2d7cce 897pkgUdevCdromDevices::Dlopen() /*{{{*/
cbc9bed8 898{
49cb36fc 899 // alread open
76fe5db7 900 if(libudev_handle != NULL)
49cb36fc
MV
901 return true;
902
cbc9bed8
MV
903 // see if we can get libudev
904 void *h = ::dlopen("libudev.so.0", RTLD_LAZY);
905 if(h == NULL)
906 return false;
907
908 // get the pointers to the udev structs
909 libudev_handle = h;
910 udev_new = (udev* (*)(void)) dlsym(h, "udev_new");
911 udev_enumerate_add_match_property = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_property");
b7bc31eb 912 udev_enumerate_add_match_sysattr = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_sysattr");
cbc9bed8
MV
913 udev_enumerate_scan_devices = (int (*)(udev_enumerate*))dlsym(h, "udev_enumerate_scan_devices");
914 udev_enumerate_get_list_entry = (udev_list_entry* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_list_entry");
915 udev_device_new_from_syspath = (udev_device* (*)(udev*, const char*))dlsym(h, "udev_device_new_from_syspath");
916 udev_enumerate_get_udev = (udev* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_udev");
917 udev_list_entry_get_name = (const char* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_name");
918 udev_device_get_devnode = (const char* (*)(udev_device*))dlsym(h, "udev_device_get_devnode");
919 udev_enumerate_new = (udev_enumerate* (*)(udev*))dlsym(h, "udev_enumerate_new");
920 udev_list_entry_get_next = (udev_list_entry* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_next");
921 udev_device_get_property_value = (const char* (*)(udev_device *, const char *))dlsym(h, "udev_device_get_property_value");
922
923 return true;
924}
3e2d7cce 925 /*}}}*/
f4c4a24e 926 /*{{{*/
f2e4a11d 927// convenience interface, this will just call ScanForRemovable
f4c4a24e
MV
928vector<CdromDevice>
929pkgUdevCdromDevices::Scan()
930{
c9952021
MV
931 bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true);
932 return ScanForRemovable(CdromOnly);
f4c4a24e
MV
933};
934 /*}}}*/
935 /*{{{*/
cbc9bed8 936vector<CdromDevice>
f4c4a24e 937pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
cbc9bed8
MV
938{
939 vector<CdromDevice> cdrom_devices;
940 struct udev_enumerate *enumerate;
941 struct udev_list_entry *l, *devices;
942 struct udev *udev_ctx;
943
944 if(libudev_handle == NULL)
945 return cdrom_devices;
946
947 udev_ctx = udev_new();
948 enumerate = udev_enumerate_new (udev_ctx);
f4c4a24e
MV
949 if (CdromOnly)
950 udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
e344ad65 951 else {
f4c4a24e 952 udev_enumerate_add_match_sysattr(enumerate, "removable", "1");
e344ad65 953 }
cbc9bed8
MV
954
955 udev_enumerate_scan_devices (enumerate);
956 devices = udev_enumerate_get_list_entry (enumerate);
957 for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
958 {
959 CdromDevice cdrom;
960 struct udev_device *udevice;
961 udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), udev_list_entry_get_name (l));
962 if (udevice == NULL)
963 continue;
964 const char* devnode = udev_device_get_devnode(udevice);
02aa6f67
MV
965
966 // try fstab_dir first
967 string mountpath;
968 const char* mp = udev_device_get_property_value(udevice, "FSTAB_DIR");
969 if (mp)
970 mountpath = string(mp);
971 else
ef381816
MV
972 mountpath = FindMountPointForDevice(devnode);
973
cbc9bed8
MV
974 // fill in the struct
975 cdrom.DeviceName = string(devnode);
02aa6f67 976 if (mountpath != "") {
cbc9bed8 977 cdrom.MountPath = mountpath;
be5b5581
MV
978 string s = string(mountpath);
979 cdrom.Mounted = IsMounted(s);
cbc9bed8
MV
980 } else {
981 cdrom.Mounted = false;
982 cdrom.MountPath = "";
983 }
984 cdrom_devices.push_back(cdrom);
985 }
986 return cdrom_devices;
987}
3e2d7cce 988 /*}}}*/
cbc9bed8 989
3e2d7cce 990pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
cbc9bed8 991{
93adae19
MV
992 if (libudev_handle != NULL)
993 dlclose(libudev_handle);
cbc9bed8 994}
3e2d7cce 995 /*}}}*/