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