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