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