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