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