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