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