merge lp:~mvo/apt/sha512-template to get fixes for the
[ntk/apt.git] / apt-pkg / cdrom.cc
1 /*
2 */
3
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>
9 #include<apt-pkg/aptconfiguration.h>
10
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>
20 #include <algorithm>
21 #include <dlfcn.h>
22
23 #include "indexcopy.h"
24
25 using 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. */
33 bool pkgCdrom::FindPackages(string CD,
34 vector<string> &List,
35 vector<string> &SList,
36 vector<string> &SigList,
37 vector<string> &TransList,
38 string &InfoDir, pkgCdromStatus *log,
39 unsigned int Depth)
40 {
41 static ino_t Inodes[9];
42 DIR *D;
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 }
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
117
118 D = opendir(".");
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
154 if (FindPackages(CD + Dir->d_name,List,SList,SigList,TransList,InfoDir,log,Depth+1) == false)
155 break;
156
157 if (chdir(CD.c_str()) != 0)
158 {
159 _error->Errno("chdir","Unable to change to %s", CD.c_str());
160 closedir(D);
161 return false;
162 }
163 };
164
165 closedir(D);
166
167 return !_error->PendingError();
168 }
169 /*}}}*/
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. */
175 int 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;
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);
205 string cdromPath = _config->FindDir("Acquire::cdrom::mount");
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
217 return Res;
218 }
219 /*}}}*/
220 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
221 // ---------------------------------------------------------------------
222 /* Here we drop everything that is not this machines arch */
223 bool pkgCdrom::DropBinaryArch(vector<string> &List)
224 {
225
226 for (unsigned int I = 0; I < List.size(); I++)
227 {
228 const char *Str = List[I].c_str();
229 const char *Start, *End;
230 if ((Start = strstr(Str,"/binary-")) == 0)
231 continue;
232
233 // Between Start and End is the architecture
234 Start += 8;
235 if ((End = strstr(Start,"/")) != 0 && Start != End &&
236 APT::Configuration::checkArchitecture(string(Start, End)) == true)
237 continue; // okay, architecture is accepted
238
239 // not accepted -> Erase it
240 List.erase(List.begin() + I);
241 --I; // the next entry is at the same index after the erase
242 }
243
244 return true;
245 }
246 /*}}}*/
247 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
248 // ---------------------------------------------------------------------
249 /* Here we go and stat every file that we found and strip dup inodes. */
250 bool 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
264 if (_error->PendingError() == true) {
265 delete[] Inodes;
266 return false;
267 }
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 }
290 delete[] Inodes;
291
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 /*}}}*/
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 */
308 void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
309 {
310 sort(List.begin(),List.end());
311
312 // Collect similar entries
313 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
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);
325 for (vector<string>::iterator J = List.begin(); J != I; J++)
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. */
358 bool 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
392 link(DFile.c_str(),string(DFile + '~').c_str());
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. */
406 bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
407 {
408 if (List.size() == 0)
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++;
443 if (F.fail() && !F.eof())
444 return _error->Error(_("Line %u too long in source list %s."),
445 CurLine,File.c_str());
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 {
458 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
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 {
492 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
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 }
512 /*}}}*/
513 bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
514 {
515 stringstream msg;
516
517 // Startup
518 string CDROM = _config->FindDir("Acquire::cdrom::mount");
519 if (CDROM[0] == '.')
520 CDROM= SafeGetCWD() + '/' + CDROM;
521
522 if (log != NULL)
523 {
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 }
529 if (MountCdrom(CDROM) == false)
530 return _error->Error("Failed to mount the cdrom.");
531
532 // Hash the CD to get an ID
533 if (log != NULL)
534 log->Update(_("Identifying.. "));
535
536
537 if (IdentCdrom(CDROM,ident) == false)
538 {
539 ident = "";
540 return false;
541 }
542
543 if (log != NULL)
544 {
545 msg.str("");
546 ioprintf(msg, "[%s]\n",ident.c_str());
547 log->Update(msg.str());
548 }
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 }
559 if (log != NULL)
560 {
561 msg.str("");
562 ioprintf(msg, _("Stored label: %s\n"),
563 Database.Find("CD::"+ident).c_str());
564 log->Update(msg.str());
565 }
566
567 // Unmount and finish
568 if (_config->FindB("APT::CDROM::NoMount",false) == false)
569 {
570 if (log != NULL)
571 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
572 UnmountCdrom(CDROM);
573 }
574
575 return true;
576 }
577 /*}}}*/
578 bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
579 {
580 stringstream msg;
581
582 // Startup
583 string CDROM = _config->FindDir("Acquire::cdrom::mount");
584 if (CDROM[0] == '.')
585 CDROM= SafeGetCWD() + '/' + CDROM;
586
587 if(log != NULL)
588 {
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 {
600 if (ReadConfigFile(Database,DFile) == false)
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 {
608 if(log != NULL)
609 log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
610 UnmountCdrom(CDROM);
611
612 if(log != NULL)
613 {
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
622 if(log != NULL)
623 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
624
625 if (MountCdrom(CDROM) == false)
626 return _error->Error("Failed to mount the cdrom.");
627 }
628
629 // Hash the CD to get an ID
630 if(log != NULL)
631 log->Update(_("Identifying.. "), STEP_IDENT);
632 string ID;
633 if (IdentCdrom(CDROM,ID) == false)
634 {
635 if (log != NULL)
636 log->Update("\n");
637 return false;
638 }
639 if(log != NULL)
640 {
641 log->Update("["+ID+"]\n");
642 log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
643 }
644
645 // Get the CD structure
646 vector<string> List;
647 vector<string> SourceList;
648 vector<string> SigList;
649 vector<string> TransList;
650 string StartDir = SafeGetCWD();
651 string InfoDir;
652 if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
653 {
654 if (log != NULL)
655 log->Update("\n");
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;
664 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
665 cout << *I << endl;
666 cout << "I found (source):" << endl;
667 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
668 cout << *I << endl;
669 cout << "I found (Signatures):" << endl;
670 for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); I++)
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");
681 DropRepeats(TransList,"");
682 if(log != NULL) {
683 msg.str("");
684 ioprintf(msg, _("Found %zu package indexes, %zu source indexes, "
685 "%zu translation indexes and %zu signatures\n"),
686 List.size(), SourceList.size(), TransList.size(),
687 SigList.size());
688 log->Update(msg.str(), STEP_SCAN);
689 }
690
691 if (List.size() == 0 && SourceList.size() == 0)
692 {
693 if (_config->FindB("APT::CDROM::NoMount",false) == false)
694 UnmountCdrom(CDROM);
695 return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
696 }
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();
715 for (; J != Name.end(); J++)
716 if (*J == '"' || *J == ']' || *J == '[')
717 *J = '_';
718
719 if(log != NULL)
720 {
721 msg.str("");
722 ioprintf(msg, _("Found label '%s'\n"), Name.c_str());
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 {
732 if(log == NULL)
733 {
734 if (_config->FindB("APT::CDROM::NoMount",false) == false)
735 UnmountCdrom(CDROM);
736 return _error->Error("No disc name found and no way to ask for it");
737 }
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();
760 for (; J != Name.end(); J++)
761 if (*J == '"' || *J == ']' || *J == '[')
762 *J = '_';
763
764 Database.Set("CD::" + ID,Name);
765 if(log != NULL)
766 {
767 msg.str("");
768 ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
769 log->Update(msg.str());
770 log->Update(_("Copying package lists..."), STEP_COPY);
771 }
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;
780 TranslationsCopy TransCopy;
781 if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
782 SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
783 TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
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
796 if(log != NULL)
797 log->Update(_("Writing new source list\n"), STEP_WRITE);
798 if (WriteSourceList(Name,List,false) == false ||
799 WriteSourceList(Name,SourceList,true) == false)
800 return false;
801 }
802
803 // Print the sourcelist entries
804 if(log != NULL)
805 log->Update(_("Source list entries for this disc are:\n"));
806
807 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
808 {
809 string::size_type Space = (*I).find(' ');
810 if (Space == string::npos)
811 {
812 if (_config->FindB("APT::CDROM::NoMount",false) == false)
813 UnmountCdrom(CDROM);
814 return _error->Error("Internal error");
815 }
816
817 if(log != NULL)
818 {
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
826 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
827 {
828 string::size_type Space = (*I).find(' ');
829 if (Space == string::npos)
830 {
831 if (_config->FindB("APT::CDROM::NoMount",false) == false)
832 UnmountCdrom(CDROM);
833 return _error->Error("Internal error");
834 }
835
836 if(log != NULL) {
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
844 // Unmount and finish
845 if (_config->FindB("APT::CDROM::NoMount",false) == false) {
846 if (log != NULL)
847 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
848 UnmountCdrom(CDROM);
849 }
850
851 return true;
852 }
853 /*}}}*/
854 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
855 : libudev_handle(NULL)
856 {
857
858 }
859 /*}}}*/
860
861 bool
862 pkgUdevCdromDevices::Dlopen() /*{{{*/
863 {
864 // alread open
865 if(libudev_handle != NULL)
866 return true;
867
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");
877 #if 0 // FIXME: uncomment on next ABI break
878 udev_enumerate_add_match_sysattr = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_sysattr");
879 #endif
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 }
892 /*}}}*/
893
894 /*{{{*/
895 // compatiblity only with the old API/ABI, can be removed on the next
896 // ABI break
897 vector<CdromDevice>
898 pkgUdevCdromDevices::Scan()
899 {
900 bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true);
901 return ScanForRemovable(CdromOnly);
902 };
903 /*}}}*/
904 /*{{{*/
905 vector<CdromDevice>
906 pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
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);
918 if (CdromOnly)
919 udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
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
925 udev_enumerate_add_match_sysattr(enumerate, "removable", "1");
926 }
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);
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
945 mountpath = FindMountPointForDevice(devnode);
946
947 // fill in the struct
948 cdrom.DeviceName = string(devnode);
949 if (mountpath != "") {
950 cdrom.MountPath = mountpath;
951 string s = string(mountpath);
952 cdrom.Mounted = IsMounted(s);
953 } else {
954 cdrom.Mounted = false;
955 cdrom.MountPath = "";
956 }
957 cdrom_devices.push_back(cdrom);
958 }
959 return cdrom_devices;
960 }
961 /*}}}*/
962
963 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
964 {
965 if (libudev_handle != NULL)
966 dlclose(libudev_handle);
967 }
968 /*}}}*/