]> git.saurik.com Git - apt.git/blob - apt-pkg/cdrom.cc
8e746ee3013f16ad9ae4b02b521f3cc4f3368ccb
[apt.git] / apt-pkg / cdrom.cc
1 /*
2 */
3 #include<config.h>
4
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>
10 #include<apt-pkg/aptconfiguration.h>
11 #include<apt-pkg/configuration.h>
12 #include<apt-pkg/fileutl.h>
13
14 #include<sstream>
15 #include<fstream>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <dirent.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <algorithm>
22 #include <dlfcn.h>
23
24 #include "indexcopy.h"
25
26 #include<apti18n.h>
27
28 using 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. */
36 bool pkgCdrom::FindPackages(string CD,
37 vector<string> &List,
38 vector<string> &SList,
39 vector<string> &SigList,
40 vector<string> &TransList,
41 string &InfoDir, pkgCdromStatus *log,
42 unsigned int Depth)
43 {
44 static ino_t Inodes[9];
45 DIR *D;
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 if (DirectoryExists(".disk") == true)
62 {
63 if (InfoDir.empty() == true)
64 InfoDir = CD + ".disk/";
65 }
66
67 // Don't look into directories that have been marked to ingore.
68 if (RealFileExists(".aptignr") == true)
69 return true;
70
71 /* Check _first_ for a signature file as apt-cdrom assumes that all files
72 under a Packages/Source file are in control of that file and stops
73 the scanning
74 */
75 if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
76 {
77 SigList.push_back(CD);
78 }
79
80 /* Aha! We found some package files. We assume that everything under
81 this dir is controlled by those package files so we don't look down
82 anymore */
83 std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
84 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
85 c != compressor.end(); ++c)
86 {
87 if (RealFileExists(std::string("Packages").append(c->Extension).c_str()) == false)
88 continue;
89
90 if (_config->FindB("Debug::aptcdrom",false) == true)
91 std::clog << "Found Packages in " << CD << std::endl;
92 List.push_back(CD);
93
94 // Continue down if thorough is given
95 if (_config->FindB("APT::CDROM::Thorough",false) == false)
96 return true;
97 break;
98 }
99 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
100 c != compressor.end(); ++c)
101 {
102 if (RealFileExists(std::string("Sources").append(c->Extension).c_str()) == false)
103 continue;
104
105 if (_config->FindB("Debug::aptcdrom",false) == true)
106 std::clog << "Found Sources in " << CD << std::endl;
107 SList.push_back(CD);
108
109 // Continue down if thorough is given
110 if (_config->FindB("APT::CDROM::Thorough",false) == false)
111 return true;
112 break;
113 }
114
115 // see if we find translation indices
116 if (DirectoryExists("i18n") == true)
117 {
118 D = opendir("i18n");
119 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
120 {
121 if(strncmp(Dir->d_name, "Translation-", strlen("Translation-")) != 0)
122 continue;
123 string file = Dir->d_name;
124 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
125 c != compressor.end(); ++c)
126 {
127 string fileext = flExtension(file);
128 if (file == fileext)
129 fileext.clear();
130 else if (fileext.empty() == false)
131 fileext = "." + fileext;
132
133 if (c->Extension == fileext)
134 {
135 if (_config->FindB("Debug::aptcdrom",false) == true)
136 std::clog << "Found translation " << Dir->d_name << " in " << CD << "i18n/" << std::endl;
137 file.erase(file.size() - fileext.size());
138 TransList.push_back(CD + "i18n/" + file);
139 break;
140 }
141 }
142 }
143 closedir(D);
144 }
145
146 D = opendir(".");
147 if (D == 0)
148 return _error->Errno("opendir","Unable to read %s",CD.c_str());
149
150 // Run over the directory
151 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
152 {
153 // Skip some files..
154 if (strcmp(Dir->d_name,".") == 0 ||
155 strcmp(Dir->d_name,"..") == 0 ||
156 //strcmp(Dir->d_name,"source") == 0 ||
157 strcmp(Dir->d_name,".disk") == 0 ||
158 strcmp(Dir->d_name,"experimental") == 0 ||
159 strcmp(Dir->d_name,"binary-all") == 0 ||
160 strcmp(Dir->d_name,"debian-installer") == 0)
161 continue;
162
163 // See if the name is a sub directory
164 struct stat Buf;
165 if (stat(Dir->d_name,&Buf) != 0)
166 continue;
167
168 if (S_ISDIR(Buf.st_mode) == 0)
169 continue;
170
171 unsigned int I;
172 for (I = 0; I != Depth; I++)
173 if (Inodes[I] == Buf.st_ino)
174 break;
175 if (I != Depth)
176 continue;
177
178 // Store the inodes weve seen
179 Inodes[Depth] = Buf.st_ino;
180
181 // Descend
182 if (FindPackages(CD + Dir->d_name,List,SList,SigList,TransList,InfoDir,log,Depth+1) == false)
183 break;
184
185 if (chdir(CD.c_str()) != 0)
186 {
187 _error->Errno("chdir","Unable to change to %s", CD.c_str());
188 closedir(D);
189 return false;
190 }
191 };
192
193 closedir(D);
194
195 return !_error->PendingError();
196 }
197 /*}}}*/
198 // Score - We compute a 'score' for a path /*{{{*/
199 // ---------------------------------------------------------------------
200 /* Paths are scored based on how close they come to what I consider
201 normal. That is ones that have 'dist' 'stable' 'testing' will score
202 higher than ones without. */
203 int pkgCdrom::Score(string Path)
204 {
205 int Res = 0;
206 if (Path.find("stable/") != string::npos)
207 Res += 29;
208 if (Path.find("/binary-") != string::npos)
209 Res += 20;
210 if (Path.find("testing/") != string::npos)
211 Res += 28;
212 if (Path.find("unstable/") != string::npos)
213 Res += 27;
214 if (Path.find("/dists/") != string::npos)
215 Res += 40;
216 if (Path.find("/main/") != string::npos)
217 Res += 20;
218 if (Path.find("/contrib/") != string::npos)
219 Res += 20;
220 if (Path.find("/non-free/") != string::npos)
221 Res += 20;
222 if (Path.find("/non-US/") != string::npos)
223 Res += 20;
224 if (Path.find("/source/") != string::npos)
225 Res += 10;
226 if (Path.find("/debian/") != string::npos)
227 Res -= 10;
228
229 // check for symlinks in the patch leading to the actual file
230 // a symlink gets a big penalty
231 struct stat Buf;
232 string statPath = flNotFile(Path);
233 string cdromPath = _config->FindDir("Acquire::cdrom::mount");
234 while(statPath != cdromPath && statPath != "./") {
235 statPath.resize(statPath.size()-1); // remove the trailing '/'
236 if (lstat(statPath.c_str(),&Buf) == 0) {
237 if(S_ISLNK(Buf.st_mode)) {
238 Res -= 60;
239 break;
240 }
241 }
242 statPath = flNotFile(statPath); // descent
243 }
244
245 return Res;
246 }
247 /*}}}*/
248 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
249 // ---------------------------------------------------------------------
250 /* Here we drop everything that is not this machines arch */
251 bool pkgCdrom::DropBinaryArch(vector<string> &List)
252 {
253
254 for (unsigned int I = 0; I < List.size(); I++)
255 {
256 const char *Str = List[I].c_str();
257 const char *Start, *End;
258 if ((Start = strstr(Str,"/binary-")) == 0)
259 continue;
260
261 // Between Start and End is the architecture
262 Start += 8;
263 if ((End = strstr(Start,"/")) != 0 && Start != End &&
264 APT::Configuration::checkArchitecture(string(Start, End)) == true)
265 continue; // okay, architecture is accepted
266
267 // not accepted -> Erase it
268 List.erase(List.begin() + I);
269 --I; // the next entry is at the same index after the erase
270 }
271
272 return true;
273 }
274 /*}}}*/
275 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
276 // ---------------------------------------------------------------------
277 /* Here we go and stat every file that we found and strip dup inodes. */
278 bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
279 {
280 bool couldFindAllFiles = true;
281 // Get a list of all the inodes
282 ino_t *Inodes = new ino_t[List.size()];
283 for (unsigned int I = 0; I != List.size(); ++I)
284 {
285 struct stat Buf;
286 bool found = false;
287
288 std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
289 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
290 c != compressor.end(); ++c)
291 {
292 std::string filename = std::string(List[I]).append(Name).append(c->Extension);
293 if (stat(filename.c_str(), &Buf) != 0)
294 continue;
295 Inodes[I] = Buf.st_ino;
296 found = true;
297 break;
298 }
299
300 if (found == false)
301 {
302 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(), Name);
303 couldFindAllFiles = false;
304 Inodes[I] = 0;
305 }
306 }
307
308 // Look for dups
309 for (unsigned int I = 0; I != List.size(); I++)
310 {
311 if (Inodes[I] == 0)
312 continue;
313 for (unsigned int J = I+1; J < List.size(); J++)
314 {
315 // No match
316 if (Inodes[J] == 0 || Inodes[J] != Inodes[I])
317 continue;
318
319 // We score the two paths.. and erase one
320 int ScoreA = Score(List[I]);
321 int ScoreB = Score(List[J]);
322 if (ScoreA < ScoreB)
323 {
324 List[I] = string();
325 break;
326 }
327
328 List[J] = string();
329 }
330 }
331 delete[] Inodes;
332
333 // Wipe erased entries
334 for (unsigned int I = 0; I < List.size();)
335 {
336 if (List[I].empty() == false)
337 I++;
338 else
339 List.erase(List.begin()+I);
340 }
341
342 return couldFindAllFiles;
343 }
344 /*}}}*/
345 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
346 // ---------------------------------------------------------------------
347 /* This takes the list of source list expressed entires and collects
348 similar ones to form a single entry for each dist */
349 void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
350 {
351 sort(List.begin(),List.end());
352
353 // Collect similar entries
354 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
355 {
356 // Find a space..
357 string::size_type Space = (*I).find(' ');
358 if (Space == string::npos)
359 continue;
360 string::size_type SSpace = (*I).find(' ',Space + 1);
361 if (SSpace == string::npos)
362 continue;
363
364 string Word1 = string(*I,Space,SSpace-Space);
365 string Prefix = string(*I,0,Space);
366 string Component = string(*I,SSpace);
367 for (vector<string>::iterator J = List.begin(); J != I; ++J)
368 {
369 // Find a space..
370 string::size_type Space2 = (*J).find(' ');
371 if (Space2 == string::npos)
372 continue;
373 string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
374 if (SSpace2 == string::npos)
375 continue;
376
377 if (string(*J,0,Space2) != Prefix)
378 continue;
379 if (string(*J,Space2,SSpace2-Space2) != Word1)
380 continue;
381
382 string Component2 = string(*J, SSpace2) + " ";
383 if (Component2.find(Component + " ") == std::string::npos)
384 *J += Component;
385 I->clear();
386 }
387 }
388
389 // Wipe erased entries
390 for (unsigned int I = 0; I < List.size();)
391 {
392 if (List[I].empty() == false)
393 I++;
394 else
395 List.erase(List.begin()+I);
396 }
397 }
398 /*}}}*/
399 // WriteDatabase - Write the CDROM Database file /*{{{*/
400 // ---------------------------------------------------------------------
401 /* We rewrite the configuration class associated with the cdrom database. */
402 bool pkgCdrom::WriteDatabase(Configuration &Cnf)
403 {
404 string DFile = _config->FindFile("Dir::State::cdroms");
405 string NewFile = DFile + ".new";
406
407 unlink(NewFile.c_str());
408 ofstream Out(NewFile.c_str());
409 if (!Out)
410 return _error->Errno("ofstream::ofstream",
411 "Failed to open %s.new",DFile.c_str());
412
413 /* Write out all of the configuration directives by walking the
414 configuration tree */
415 Cnf.Dump(Out, NULL, "%f \"%v\";\n", false);
416
417 Out.close();
418
419 if (FileExists(DFile) == true)
420 rename(DFile.c_str(), string(DFile + '~').c_str());
421 if (rename(NewFile.c_str(),DFile.c_str()) != 0)
422 return _error->Errno("rename","Failed to rename %s.new to %s",
423 DFile.c_str(),DFile.c_str());
424
425 return true;
426 }
427 /*}}}*/
428 // WriteSourceList - Write an updated sourcelist /*{{{*/
429 // ---------------------------------------------------------------------
430 /* This reads the old source list and copies it into the new one. It
431 appends the new CDROM entires just after the first block of comments.
432 This places them first in the file. It also removes any old entries
433 that were the same. */
434 bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
435 {
436 if (List.empty() == true)
437 return true;
438
439 string File = _config->FindFile("Dir::Etc::sourcelist");
440
441 // Open the stream for reading
442 ifstream F((FileExists(File)?File.c_str():"/dev/null"),
443 ios::in );
444 if (!F != 0)
445 return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
446
447 string NewFile = File + ".new";
448 unlink(NewFile.c_str());
449 ofstream Out(NewFile.c_str());
450 if (!Out)
451 return _error->Errno("ofstream::ofstream",
452 "Failed to open %s.new",File.c_str());
453
454 // Create a short uri without the path
455 string ShortURI = "cdrom:[" + Name + "]/";
456 string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
457
458 string Type;
459 if (Source == true)
460 Type = "deb-src";
461 else
462 Type = "deb";
463
464 char Buffer[300];
465 int CurLine = 0;
466 bool First = true;
467 while (F.eof() == false)
468 {
469 F.getline(Buffer,sizeof(Buffer));
470 CurLine++;
471 if (F.fail() && !F.eof())
472 return _error->Error(_("Line %u too long in source list %s."),
473 CurLine,File.c_str());
474 _strtabexpand(Buffer,sizeof(Buffer));
475 _strstrip(Buffer);
476
477 // Comment or blank
478 if (Buffer[0] == '#' || Buffer[0] == 0)
479 {
480 Out << Buffer << endl;
481 continue;
482 }
483
484 if (First == true)
485 {
486 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
487 {
488 string::size_type Space = (*I).find(' ');
489 if (Space == string::npos)
490 return _error->Error("Internal error");
491 Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
492 " " << string(*I,Space+1) << endl;
493 }
494 }
495 First = false;
496
497 // Grok it
498 string cType;
499 string URI;
500 const char *C = Buffer;
501 if (ParseQuoteWord(C,cType) == false ||
502 ParseQuoteWord(C,URI) == false)
503 {
504 Out << Buffer << endl;
505 continue;
506 }
507
508 // Emit lines like this one
509 if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
510 string(URI,0,ShortURI.length()) != ShortURI2))
511 {
512 Out << Buffer << endl;
513 continue;
514 }
515 }
516
517 // Just in case the file was empty
518 if (First == true)
519 {
520 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
521 {
522 string::size_type Space = (*I).find(' ');
523 if (Space == string::npos)
524 return _error->Error("Internal error");
525
526 Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
527 " " << string(*I,Space+1) << endl;
528 }
529 }
530
531 Out.close();
532
533 rename(File.c_str(),string(File + '~').c_str());
534 if (rename(NewFile.c_str(),File.c_str()) != 0)
535 return _error->Errno("rename","Failed to rename %s.new to %s",
536 File.c_str(),File.c_str());
537
538 return true;
539 }
540 /*}}}*/
541 bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
542 {
543 stringstream msg;
544
545 // Startup
546 string CDROM = _config->FindDir("Acquire::cdrom::mount");
547 if (CDROM[0] == '.')
548 CDROM= SafeGetCWD() + '/' + CDROM;
549
550 if (log != NULL)
551 {
552 msg.str("");
553 ioprintf(msg, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
554 CDROM.c_str());
555 log->Update(msg.str());
556 }
557 if (MountCdrom(CDROM) == false)
558 return _error->Error("Failed to mount the cdrom.");
559
560 // Hash the CD to get an ID
561 if (log != NULL)
562 log->Update(_("Identifying.. "));
563
564
565 if (IdentCdrom(CDROM,ident) == false)
566 {
567 ident = "";
568 return false;
569 }
570
571 if (log != NULL)
572 {
573 msg.str("");
574 ioprintf(msg, "[%s]\n",ident.c_str());
575 log->Update(msg.str());
576 }
577
578 // Read the database
579 Configuration Database;
580 string DFile = _config->FindFile("Dir::State::cdroms");
581 if (FileExists(DFile) == true)
582 {
583 if (ReadConfigFile(Database,DFile) == false)
584 return _error->Error("Unable to read the cdrom database %s",
585 DFile.c_str());
586 }
587 if (log != NULL)
588 {
589 msg.str("");
590 ioprintf(msg, _("Stored label: %s\n"),
591 Database.Find("CD::"+ident).c_str());
592 log->Update(msg.str());
593 }
594
595 // Unmount and finish
596 if (_config->FindB("APT::CDROM::NoMount",false) == false)
597 {
598 if (log != NULL)
599 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
600 UnmountCdrom(CDROM);
601 }
602
603 return true;
604 }
605 /*}}}*/
606 bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
607 {
608 stringstream msg;
609
610 // Startup
611 string CDROM = _config->FindDir("Acquire::cdrom::mount");
612 if (CDROM[0] == '.')
613 CDROM= SafeGetCWD() + '/' + CDROM;
614
615 if(log != NULL)
616 {
617 log->SetTotal(STEP_LAST);
618 msg.str("");
619 ioprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
620 log->Update(msg.str(), STEP_PREPARE);
621 }
622
623 // Read the database
624 Configuration Database;
625 string DFile = _config->FindFile("Dir::State::cdroms");
626 if (FileExists(DFile) == true)
627 {
628 if (ReadConfigFile(Database,DFile) == false)
629 return _error->Error("Unable to read the cdrom database %s",
630 DFile.c_str());
631 }
632
633 // Unmount the CD and get the user to put in the one they want
634 if (_config->FindB("APT::CDROM::NoMount",false) == false)
635 {
636 if(log != NULL)
637 log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
638 UnmountCdrom(CDROM);
639
640 if(log != NULL)
641 {
642 log->Update(_("Waiting for disc...\n"), STEP_WAIT);
643 if(!log->ChangeCdrom()) {
644 // user aborted
645 return false;
646 }
647 }
648
649 // Mount the new CDROM
650 if(log != NULL)
651 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
652
653 if (MountCdrom(CDROM) == false)
654 return _error->Error("Failed to mount the cdrom.");
655 }
656
657 // Hash the CD to get an ID
658 if(log != NULL)
659 log->Update(_("Identifying.. "), STEP_IDENT);
660 string ID;
661 if (IdentCdrom(CDROM,ID) == false)
662 {
663 if (log != NULL)
664 log->Update("\n");
665 return false;
666 }
667 if(log != NULL)
668 {
669 log->Update("["+ID+"]\n");
670 log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
671 }
672
673 // Get the CD structure
674 vector<string> List;
675 vector<string> SourceList;
676 vector<string> SigList;
677 vector<string> TransList;
678 string StartDir = SafeGetCWD();
679 string InfoDir;
680 if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
681 {
682 if (log != NULL)
683 log->Update("\n");
684 return false;
685 }
686
687 if (chdir(StartDir.c_str()) != 0)
688 return _error->Errno("chdir","Unable to change to %s", StartDir.c_str());
689
690 if (_config->FindB("Debug::aptcdrom",false) == true)
691 {
692 cout << "I found (binary):" << endl;
693 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
694 cout << *I << endl;
695 cout << "I found (source):" << endl;
696 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
697 cout << *I << endl;
698 cout << "I found (Signatures):" << endl;
699 for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
700 cout << *I << endl;
701 }
702
703 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
704
705 // Fix up the list
706 DropBinaryArch(List);
707 DropRepeats(List,"Packages");
708 DropRepeats(SourceList,"Sources");
709 // FIXME: We ignore stat() errors here as we usually have only one of those in use
710 // This has little potencial to drop 'valid' stat() errors as we know that one of these
711 // files need to exist, but it would be better if we would check it here
712 _error->PushToStack();
713 DropRepeats(SigList,"Release.gpg");
714 DropRepeats(SigList,"InRelease");
715 _error->RevertToStack();
716 DropRepeats(TransList,"");
717 if(log != NULL) {
718 msg.str("");
719 ioprintf(msg, _("Found %zu package indexes, %zu source indexes, "
720 "%zu translation indexes and %zu signatures\n"),
721 List.size(), SourceList.size(), TransList.size(),
722 SigList.size());
723 log->Update(msg.str(), STEP_SCAN);
724 }
725
726 if (List.empty() == true && SourceList.empty() == true)
727 {
728 if (_config->FindB("APT::CDROM::NoMount",false) == false)
729 UnmountCdrom(CDROM);
730 return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
731 }
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();
750 for (; J != Name.end(); ++J)
751 if (*J == '"' || *J == ']' || *J == '[')
752 *J = '_';
753
754 if(log != NULL)
755 {
756 msg.str("");
757 ioprintf(msg, _("Found label '%s'\n"), Name.c_str());
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 {
767 if(log == NULL)
768 {
769 if (_config->FindB("APT::CDROM::NoMount",false) == false)
770 UnmountCdrom(CDROM);
771 return _error->Error("No disc name found and no way to ask for it");
772 }
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();
795 for (; J != Name.end(); ++J)
796 if (*J == '"' || *J == ']' || *J == '[')
797 *J = '_';
798
799 Database.Set("CD::" + ID,Name);
800 if(log != NULL)
801 {
802 msg.str("");
803 ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
804 log->Update(msg.str());
805 log->Update(_("Copying package lists..."), STEP_COPY);
806 }
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;
815 TranslationsCopy TransCopy;
816 if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
817 SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
818 TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
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
831 if(log != NULL)
832 log->Update(_("Writing new source list\n"), STEP_WRITE);
833 if (WriteSourceList(Name,List,false) == false ||
834 WriteSourceList(Name,SourceList,true) == false)
835 return false;
836 }
837
838 // Print the sourcelist entries
839 if(log != NULL)
840 log->Update(_("Source list entries for this disc are:\n"));
841
842 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
843 {
844 string::size_type Space = (*I).find(' ');
845 if (Space == string::npos)
846 {
847 if (_config->FindB("APT::CDROM::NoMount",false) == false)
848 UnmountCdrom(CDROM);
849 return _error->Error("Internal error");
850 }
851
852 if(log != NULL)
853 {
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
861 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
862 {
863 string::size_type Space = (*I).find(' ');
864 if (Space == string::npos)
865 {
866 if (_config->FindB("APT::CDROM::NoMount",false) == false)
867 UnmountCdrom(CDROM);
868 return _error->Error("Internal error");
869 }
870
871 if(log != NULL) {
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
879 // Unmount and finish
880 if (_config->FindB("APT::CDROM::NoMount",false) == false) {
881 if (log != NULL)
882 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
883 UnmountCdrom(CDROM);
884 }
885
886 return true;
887 }
888 /*}}}*/
889 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
890 : libudev_handle(NULL)
891 {
892
893 }
894 /*}}}*/
895
896 bool
897 pkgUdevCdromDevices::Dlopen() /*{{{*/
898 {
899 // alread open
900 if(libudev_handle != NULL)
901 return true;
902
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");
912 udev_enumerate_add_match_sysattr = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_sysattr");
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 }
925 /*}}}*/
926 /*{{{*/
927 // convenience interface, this will just call ScanForRemovable
928 vector<CdromDevice>
929 pkgUdevCdromDevices::Scan()
930 {
931 bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true);
932 return ScanForRemovable(CdromOnly);
933 };
934 /*}}}*/
935 /*{{{*/
936 vector<CdromDevice>
937 pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
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);
949 if (CdromOnly)
950 udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
951 else {
952 udev_enumerate_add_match_sysattr(enumerate, "removable", "1");
953 }
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);
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
972 mountpath = FindMountPointForDevice(devnode);
973
974 // fill in the struct
975 cdrom.DeviceName = string(devnode);
976 if (mountpath != "") {
977 cdrom.MountPath = mountpath;
978 string s = string(mountpath);
979 cdrom.Mounted = IsMounted(s);
980 } else {
981 cdrom.Mounted = false;
982 cdrom.MountPath = "";
983 }
984 cdrom_devices.push_back(cdrom);
985 }
986 return cdrom_devices;
987 }
988 /*}}}*/
989
990 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
991 {
992 if (libudev_handle != NULL)
993 dlclose(libudev_handle);
994 }
995 /*}}}*/