* apt-pkg/indexcopy.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);
f7f0d6c7 366 for (vector<string>::iterator J = List.begin(); J != I; ++J)
a75c6a6e
MZ
367 {
368 // Find a space..
369 string::size_type Space2 = (*J).find(' ');
370 if (Space2 == string::npos)
371 continue;
372 string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
373 if (SSpace2 == string::npos)
374 continue;
375
376 if (string(*J,0,Space2) != Prefix)
377 continue;
378 if (string(*J,Space2,SSpace2-Space2) != Word1)
379 continue;
380
381 *J += string(*I,SSpace);
382 *I = string();
383 }
384 }
385
386 // Wipe erased entries
387 for (unsigned int I = 0; I < List.size();)
388 {
389 if (List[I].empty() == false)
390 I++;
391 else
392 List.erase(List.begin()+I);
393 }
394}
395 /*}}}*/
396// WriteDatabase - Write the CDROM Database file /*{{{*/
397// ---------------------------------------------------------------------
398/* We rewrite the configuration class associated with the cdrom database. */
399bool pkgCdrom::WriteDatabase(Configuration &Cnf)
400{
401 string DFile = _config->FindFile("Dir::State::cdroms");
402 string NewFile = DFile + ".new";
403
404 unlink(NewFile.c_str());
405 ofstream Out(NewFile.c_str());
406 if (!Out)
407 return _error->Errno("ofstream::ofstream",
408 "Failed to open %s.new",DFile.c_str());
409
410 /* Write out all of the configuration directives by walking the
411 configuration tree */
ab59c1ca 412 Cnf.Dump(Out, NULL, "%f \"%v\";\n", false);
a75c6a6e
MZ
413
414 Out.close();
849e64ac 415
c1cd1ac2
DK
416 if (FileExists(DFile) == true)
417 rename(DFile.c_str(), string(DFile + '~').c_str());
a75c6a6e
MZ
418 if (rename(NewFile.c_str(),DFile.c_str()) != 0)
419 return _error->Errno("rename","Failed to rename %s.new to %s",
420 DFile.c_str(),DFile.c_str());
421
422 return true;
423}
424 /*}}}*/
425// WriteSourceList - Write an updated sourcelist /*{{{*/
426// ---------------------------------------------------------------------
427/* This reads the old source list and copies it into the new one. It
428 appends the new CDROM entires just after the first block of comments.
429 This places them first in the file. It also removes any old entries
430 that were the same. */
431bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
432{
f7f0d6c7 433 if (List.empty() == true)
a75c6a6e
MZ
434 return true;
435
436 string File = _config->FindFile("Dir::Etc::sourcelist");
437
438 // Open the stream for reading
439 ifstream F((FileExists(File)?File.c_str():"/dev/null"),
440 ios::in );
441 if (!F != 0)
442 return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
443
444 string NewFile = File + ".new";
445 unlink(NewFile.c_str());
446 ofstream Out(NewFile.c_str());
447 if (!Out)
448 return _error->Errno("ofstream::ofstream",
449 "Failed to open %s.new",File.c_str());
450
451 // Create a short uri without the path
452 string ShortURI = "cdrom:[" + Name + "]/";
453 string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
454
455 string Type;
456 if (Source == true)
457 Type = "deb-src";
458 else
459 Type = "deb";
460
461 char Buffer[300];
462 int CurLine = 0;
463 bool First = true;
464 while (F.eof() == false)
465 {
466 F.getline(Buffer,sizeof(Buffer));
467 CurLine++;
13e8426f
MV
468 if (F.fail() && !F.eof())
469 return _error->Error(_("Line %u too long in source list %s."),
470 CurLine,File.c_str());
a75c6a6e
MZ
471 _strtabexpand(Buffer,sizeof(Buffer));
472 _strstrip(Buffer);
473
474 // Comment or blank
475 if (Buffer[0] == '#' || Buffer[0] == 0)
476 {
477 Out << Buffer << endl;
478 continue;
479 }
480
481 if (First == true)
482 {
f7f0d6c7 483 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
484 {
485 string::size_type Space = (*I).find(' ');
486 if (Space == string::npos)
487 return _error->Error("Internal error");
488 Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
489 " " << string(*I,Space+1) << endl;
490 }
491 }
492 First = false;
493
494 // Grok it
495 string cType;
496 string URI;
497 const char *C = Buffer;
498 if (ParseQuoteWord(C,cType) == false ||
499 ParseQuoteWord(C,URI) == false)
500 {
501 Out << Buffer << endl;
502 continue;
503 }
504
505 // Emit lines like this one
506 if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
507 string(URI,0,ShortURI.length()) != ShortURI2))
508 {
509 Out << Buffer << endl;
510 continue;
511 }
512 }
513
514 // Just in case the file was empty
515 if (First == true)
516 {
f7f0d6c7 517 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
518 {
519 string::size_type Space = (*I).find(' ');
520 if (Space == string::npos)
521 return _error->Error("Internal error");
522
523 Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
524 " " << string(*I,Space+1) << endl;
525 }
526 }
527
528 Out.close();
529
530 rename(File.c_str(),string(File + '~').c_str());
531 if (rename(NewFile.c_str(),File.c_str()) != 0)
532 return _error->Errno("rename","Failed to rename %s.new to %s",
533 File.c_str(),File.c_str());
534
535 return true;
536}
92fcbfc1
DK
537 /*}}}*/
538bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
a75c6a6e
MZ
539{
540 stringstream msg;
541
542 // Startup
710aba4a 543 string CDROM = _config->FindDir("Acquire::cdrom::mount");
a75c6a6e
MZ
544 if (CDROM[0] == '.')
545 CDROM= SafeGetCWD() + '/' + CDROM;
546
6070a346
DK
547 if (log != NULL)
548 {
a75c6a6e
MZ
549 msg.str("");
550 ioprintf(msg, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
551 CDROM.c_str());
552 log->Update(msg.str());
553 }
70dbf5f8
MV
554 if (MountCdrom(CDROM) == false)
555 return _error->Error("Failed to mount the cdrom.");
a75c6a6e
MZ
556
557 // Hash the CD to get an ID
6070a346 558 if (log != NULL)
a75c6a6e
MZ
559 log->Update(_("Identifying.. "));
560
561
562 if (IdentCdrom(CDROM,ident) == false)
563 {
564 ident = "";
565 return false;
566 }
567
6070a346
DK
568 if (log != NULL)
569 {
570 msg.str("");
571 ioprintf(msg, "[%s]\n",ident.c_str());
572 log->Update(msg.str());
573 }
a75c6a6e
MZ
574
575 // Read the database
576 Configuration Database;
577 string DFile = _config->FindFile("Dir::State::cdroms");
578 if (FileExists(DFile) == true)
579 {
580 if (ReadConfigFile(Database,DFile) == false)
581 return _error->Error("Unable to read the cdrom database %s",
582 DFile.c_str());
583 }
6070a346
DK
584 if (log != NULL)
585 {
a75c6a6e 586 msg.str("");
36fb926e
OS
587 ioprintf(msg, _("Stored label: %s\n"),
588 Database.Find("CD::"+ident).c_str());
a75c6a6e
MZ
589 log->Update(msg.str());
590 }
1fcbe14d
OS
591
592 // Unmount and finish
6070a346
DK
593 if (_config->FindB("APT::CDROM::NoMount",false) == false)
594 {
595 if (log != NULL)
596 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
1fcbe14d
OS
597 UnmountCdrom(CDROM);
598 }
599
a75c6a6e
MZ
600 return true;
601}
92fcbfc1
DK
602 /*}}}*/
603bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
a75c6a6e
MZ
604{
605 stringstream msg;
606
607 // Startup
a9239250 608 string CDROM = _config->FindDir("Acquire::cdrom::mount");
a75c6a6e
MZ
609 if (CDROM[0] == '.')
610 CDROM= SafeGetCWD() + '/' + CDROM;
611
6070a346
DK
612 if(log != NULL)
613 {
a75c6a6e
MZ
614 log->SetTotal(STEP_LAST);
615 msg.str("");
616 ioprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
617 log->Update(msg.str(), STEP_PREPARE);
618 }
619
620 // Read the database
621 Configuration Database;
622 string DFile = _config->FindFile("Dir::State::cdroms");
623 if (FileExists(DFile) == true)
624 {
cdadf54b 625 if (ReadConfigFile(Database,DFile) == false)
a75c6a6e
MZ
626 return _error->Error("Unable to read the cdrom database %s",
627 DFile.c_str());
628 }
629
630 // Unmount the CD and get the user to put in the one they want
631 if (_config->FindB("APT::CDROM::NoMount",false) == false)
632 {
6070a346 633 if(log != NULL)
a75c6a6e
MZ
634 log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
635 UnmountCdrom(CDROM);
636
6070a346
DK
637 if(log != NULL)
638 {
a75c6a6e
MZ
639 log->Update(_("Waiting for disc...\n"), STEP_WAIT);
640 if(!log->ChangeCdrom()) {
641 // user aborted
642 return false;
643 }
644 }
645
646 // Mount the new CDROM
6070a346
DK
647 if(log != NULL)
648 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
649
a75c6a6e
MZ
650 if (MountCdrom(CDROM) == false)
651 return _error->Error("Failed to mount the cdrom.");
652 }
653
654 // Hash the CD to get an ID
6070a346 655 if(log != NULL)
a75c6a6e
MZ
656 log->Update(_("Identifying.. "), STEP_IDENT);
657 string ID;
658 if (IdentCdrom(CDROM,ID) == false)
659 {
6070a346
DK
660 if (log != NULL)
661 log->Update("\n");
a75c6a6e
MZ
662 return false;
663 }
6070a346
DK
664 if(log != NULL)
665 {
a75c6a6e 666 log->Update("["+ID+"]\n");
db0db9fe 667 log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
6070a346
DK
668 }
669
a75c6a6e
MZ
670 // Get the CD structure
671 vector<string> List;
672 vector<string> SourceList;
673 vector<string> SigList;
22f8568d 674 vector<string> TransList;
a75c6a6e
MZ
675 string StartDir = SafeGetCWD();
676 string InfoDir;
22f8568d 677 if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
a75c6a6e 678 {
6070a346
DK
679 if (log != NULL)
680 log->Update("\n");
a75c6a6e
MZ
681 return false;
682 }
683
31bda500
DK
684 if (chdir(StartDir.c_str()) != 0)
685 return _error->Errno("chdir","Unable to change to %s", StartDir.c_str());
a75c6a6e
MZ
686
687 if (_config->FindB("Debug::aptcdrom",false) == true)
688 {
689 cout << "I found (binary):" << endl;
f7f0d6c7 690 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
691 cout << *I << endl;
692 cout << "I found (source):" << endl;
f7f0d6c7 693 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
a75c6a6e
MZ
694 cout << *I << endl;
695 cout << "I found (Signatures):" << endl;
f7f0d6c7 696 for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
a75c6a6e
MZ
697 cout << *I << endl;
698 }
699
700 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
701
702 // Fix up the list
703 DropBinaryArch(List);
704 DropRepeats(List,"Packages");
705 DropRepeats(SourceList,"Sources");
2c405a44
DK
706 // FIXME: We ignore stat() errors here as we usually have only one of those in use
707 // This has little potencial to drop 'valid' stat() errors as we know that one of these
708 // files need to exist, but it would be better if we would check it here
709 _error->PushToStack();
a75c6a6e 710 DropRepeats(SigList,"Release.gpg");
212080b8 711 DropRepeats(SigList,"InRelease");
2c405a44 712 _error->RevertToStack();
22f8568d 713 DropRepeats(TransList,"");
6070a346 714 if(log != NULL) {
a75c6a6e 715 msg.str("");
a376d6fd
OS
716 ioprintf(msg, _("Found %zu package indexes, %zu source indexes, "
717 "%zu translation indexes and %zu signatures\n"),
22f8568d
MV
718 List.size(), SourceList.size(), TransList.size(),
719 SigList.size());
a75c6a6e
MZ
720 log->Update(msg.str(), STEP_SCAN);
721 }
722
f7f0d6c7 723 if (List.empty() == true && SourceList.empty() == true)
cdadf54b 724 {
50959877
MV
725 if (_config->FindB("APT::CDROM::NoMount",false) == false)
726 UnmountCdrom(CDROM);
d720a7d4 727 return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
cdadf54b 728 }
a75c6a6e
MZ
729
730 // Check if the CD is in the database
731 string Name;
732 if (Database.Exists("CD::" + ID) == false ||
733 _config->FindB("APT::CDROM::Rename",false) == true)
734 {
735 // Try to use the CDs label if at all possible
736 if (InfoDir.empty() == false &&
737 FileExists(InfoDir + "/info") == true)
738 {
739 ifstream F(string(InfoDir + "/info").c_str());
740 if (!F == 0)
741 getline(F,Name);
742
743 if (Name.empty() == false)
744 {
745 // Escape special characters
746 string::iterator J = Name.begin();
f7f0d6c7 747 for (; J != Name.end(); ++J)
a75c6a6e
MZ
748 if (*J == '"' || *J == ']' || *J == '[')
749 *J = '_';
750
6070a346
DK
751 if(log != NULL)
752 {
a75c6a6e 753 msg.str("");
ce86ff41 754 ioprintf(msg, _("Found label '%s'\n"), Name.c_str());
a75c6a6e
MZ
755 log->Update(msg.str());
756 }
757 Database.Set("CD::" + ID + "::Label",Name);
758 }
759 }
760
761 if (_config->FindB("APT::CDROM::Rename",false) == true ||
762 Name.empty() == true)
763 {
6070a346 764 if(log == NULL)
cdadf54b 765 {
50959877
MV
766 if (_config->FindB("APT::CDROM::NoMount",false) == false)
767 UnmountCdrom(CDROM);
a75c6a6e 768 return _error->Error("No disc name found and no way to ask for it");
cdadf54b 769 }
a75c6a6e
MZ
770
771 while(true) {
772 if(!log->AskCdromName(Name)) {
773 // user canceld
774 return false;
775 }
776 cout << "Name: '" << Name << "'" << endl;
777
778 if (Name.empty() == false &&
779 Name.find('"') == string::npos &&
780 Name.find('[') == string::npos &&
781 Name.find(']') == string::npos)
782 break;
783 log->Update(_("That is not a valid name, try again.\n"));
784 }
785 }
786 }
787 else
788 Name = Database.Find("CD::" + ID);
789
790 // Escape special characters
791 string::iterator J = Name.begin();
f7f0d6c7 792 for (; J != Name.end(); ++J)
a75c6a6e
MZ
793 if (*J == '"' || *J == ']' || *J == '[')
794 *J = '_';
795
796 Database.Set("CD::" + ID,Name);
6070a346
DK
797 if(log != NULL)
798 {
a75c6a6e 799 msg.str("");
db0db9fe 800 ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
a75c6a6e 801 log->Update(msg.str());
6070a346 802 log->Update(_("Copying package lists..."), STEP_COPY);
a75c6a6e 803 }
a75c6a6e
MZ
804 // take care of the signatures and copy them if they are ok
805 // (we do this before PackageCopy as it modifies "List" and "SourceList")
806 SigVerify SignVerify;
807 SignVerify.CopyAndVerify(CDROM, Name, SigList, List, SourceList);
808
809 // Copy the package files to the state directory
810 PackageCopy Copy;
811 SourceCopy SrcCopy;
22f8568d 812 TranslationsCopy TransCopy;
a75c6a6e 813 if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
22f8568d
MV
814 SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
815 TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
a75c6a6e
MZ
816 return false;
817
818 // reduce the List so that it takes less space in sources.list
819 ReduceSourcelist(CDROM,List);
820 ReduceSourcelist(CDROM,SourceList);
821
822 // Write the database and sourcelist
823 if (_config->FindB("APT::cdrom::NoAct",false) == false)
824 {
825 if (WriteDatabase(Database) == false)
826 return false;
827
6070a346 828 if(log != NULL)
a75c6a6e 829 log->Update(_("Writing new source list\n"), STEP_WRITE);
a75c6a6e
MZ
830 if (WriteSourceList(Name,List,false) == false ||
831 WriteSourceList(Name,SourceList,true) == false)
832 return false;
833 }
834
835 // Print the sourcelist entries
6070a346 836 if(log != NULL)
db0db9fe 837 log->Update(_("Source list entries for this disc are:\n"));
a75c6a6e 838
f7f0d6c7 839 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
a75c6a6e
MZ
840 {
841 string::size_type Space = (*I).find(' ');
842 if (Space == string::npos)
cdadf54b 843 {
50959877
MV
844 if (_config->FindB("APT::CDROM::NoMount",false) == false)
845 UnmountCdrom(CDROM);
a75c6a6e 846 return _error->Error("Internal error");
cdadf54b 847 }
a75c6a6e 848
6070a346
DK
849 if(log != NULL)
850 {
a75c6a6e
MZ
851 msg.str("");
852 msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
853 " " << string(*I,Space+1) << endl;
854 log->Update(msg.str());
855 }
856 }
857
f7f0d6c7 858 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
a75c6a6e
MZ
859 {
860 string::size_type Space = (*I).find(' ');
861 if (Space == string::npos)
cdadf54b 862 {
50959877
MV
863 if (_config->FindB("APT::CDROM::NoMount",false) == false)
864 UnmountCdrom(CDROM);
a75c6a6e 865 return _error->Error("Internal error");
cdadf54b 866 }
a75c6a6e 867
6070a346 868 if(log != NULL) {
a75c6a6e
MZ
869 msg.str("");
870 msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
871 " " << string(*I,Space+1) << endl;
872 log->Update(msg.str());
873 }
874 }
875
a75c6a6e 876 // Unmount and finish
70dbf5f8 877 if (_config->FindB("APT::CDROM::NoMount",false) == false) {
6070a346
DK
878 if (log != NULL)
879 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
a75c6a6e
MZ
880 UnmountCdrom(CDROM);
881 }
882
883 return true;
884}
92fcbfc1 885 /*}}}*/
3e2d7cce 886pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
76fe5db7 887 : libudev_handle(NULL)
cbc9bed8
MV
888{
889
890}
3e2d7cce 891 /*}}}*/
cbc9bed8
MV
892
893bool
3e2d7cce 894pkgUdevCdromDevices::Dlopen() /*{{{*/
cbc9bed8 895{
49cb36fc 896 // alread open
76fe5db7 897 if(libudev_handle != NULL)
49cb36fc
MV
898 return true;
899
cbc9bed8
MV
900 // see if we can get libudev
901 void *h = ::dlopen("libudev.so.0", RTLD_LAZY);
902 if(h == NULL)
903 return false;
904
905 // get the pointers to the udev structs
906 libudev_handle = h;
907 udev_new = (udev* (*)(void)) dlsym(h, "udev_new");
908 udev_enumerate_add_match_property = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_property");
b7bc31eb 909 udev_enumerate_add_match_sysattr = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_sysattr");
cbc9bed8
MV
910 udev_enumerate_scan_devices = (int (*)(udev_enumerate*))dlsym(h, "udev_enumerate_scan_devices");
911 udev_enumerate_get_list_entry = (udev_list_entry* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_list_entry");
912 udev_device_new_from_syspath = (udev_device* (*)(udev*, const char*))dlsym(h, "udev_device_new_from_syspath");
913 udev_enumerate_get_udev = (udev* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_udev");
914 udev_list_entry_get_name = (const char* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_name");
915 udev_device_get_devnode = (const char* (*)(udev_device*))dlsym(h, "udev_device_get_devnode");
916 udev_enumerate_new = (udev_enumerate* (*)(udev*))dlsym(h, "udev_enumerate_new");
917 udev_list_entry_get_next = (udev_list_entry* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_next");
918 udev_device_get_property_value = (const char* (*)(udev_device *, const char *))dlsym(h, "udev_device_get_property_value");
919
920 return true;
921}
3e2d7cce 922 /*}}}*/
f4c4a24e 923 /*{{{*/
f2e4a11d 924// convenience interface, this will just call ScanForRemovable
f4c4a24e
MV
925vector<CdromDevice>
926pkgUdevCdromDevices::Scan()
927{
c9952021
MV
928 bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true);
929 return ScanForRemovable(CdromOnly);
f4c4a24e
MV
930};
931 /*}}}*/
932 /*{{{*/
cbc9bed8 933vector<CdromDevice>
f4c4a24e 934pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
cbc9bed8
MV
935{
936 vector<CdromDevice> cdrom_devices;
937 struct udev_enumerate *enumerate;
938 struct udev_list_entry *l, *devices;
939 struct udev *udev_ctx;
940
941 if(libudev_handle == NULL)
942 return cdrom_devices;
943
944 udev_ctx = udev_new();
945 enumerate = udev_enumerate_new (udev_ctx);
f4c4a24e
MV
946 if (CdromOnly)
947 udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
e344ad65 948 else {
f4c4a24e 949 udev_enumerate_add_match_sysattr(enumerate, "removable", "1");
e344ad65 950 }
cbc9bed8
MV
951
952 udev_enumerate_scan_devices (enumerate);
953 devices = udev_enumerate_get_list_entry (enumerate);
954 for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
955 {
956 CdromDevice cdrom;
957 struct udev_device *udevice;
958 udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), udev_list_entry_get_name (l));
959 if (udevice == NULL)
960 continue;
961 const char* devnode = udev_device_get_devnode(udevice);
02aa6f67
MV
962
963 // try fstab_dir first
964 string mountpath;
965 const char* mp = udev_device_get_property_value(udevice, "FSTAB_DIR");
966 if (mp)
967 mountpath = string(mp);
968 else
ef381816
MV
969 mountpath = FindMountPointForDevice(devnode);
970
cbc9bed8
MV
971 // fill in the struct
972 cdrom.DeviceName = string(devnode);
02aa6f67 973 if (mountpath != "") {
cbc9bed8 974 cdrom.MountPath = mountpath;
be5b5581
MV
975 string s = string(mountpath);
976 cdrom.Mounted = IsMounted(s);
cbc9bed8
MV
977 } else {
978 cdrom.Mounted = false;
979 cdrom.MountPath = "";
980 }
981 cdrom_devices.push_back(cdrom);
982 }
983 return cdrom_devices;
984}
3e2d7cce 985 /*}}}*/
cbc9bed8 986
3e2d7cce 987pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
cbc9bed8 988{
93adae19
MV
989 if (libudev_handle != NULL)
990 dlclose(libudev_handle);
cbc9bed8 991}
3e2d7cce 992 /*}}}*/