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