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