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