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