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 <apt-pkg/aptconfiguration.h>
10 #include <apt-pkg/configuration.h>
11 #include <apt-pkg/fileutl.h>
12 #include <apt-pkg/indexcopy.h>
33 // FindPackages - Find the package files on the CDROM /*{{{*/
34 // ---------------------------------------------------------------------
35 /* We look over the cdrom for package files. This is a recursive
36 search that short circuits when it his a package file in the dir.
37 This speeds it up greatly as the majority of the size is in the
39 bool pkgCdrom::FindPackages(string CD
,
41 vector
<string
> &SList
,
42 vector
<string
> &SigList
,
43 vector
<string
> &TransList
,
44 string
&InfoDir
, pkgCdromStatus
*log
,
47 static ino_t Inodes
[9];
50 // if we have a look we "pulse" now
57 if (CD
[CD
.length()-1] != '/')
60 if (chdir(CD
.c_str()) != 0)
61 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
63 // Look for a .disk subdirectory
64 if (DirectoryExists(".disk") == true)
66 if (InfoDir
.empty() == true)
67 InfoDir
= CD
+ ".disk/";
70 // Don't look into directories that have been marked to ingore.
71 if (RealFileExists(".aptignr") == true)
74 /* Check _first_ for a signature file as apt-cdrom assumes that all files
75 under a Packages/Source file are in control of that file and stops
78 if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
80 SigList
.push_back(CD
);
83 /* Aha! We found some package files. We assume that everything under
84 this dir is controlled by those package files so we don't look down
86 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
87 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
88 c
!= compressor
.end(); ++c
)
90 if (RealFileExists(std::string("Packages").append(c
->Extension
).c_str()) == false)
93 if (_config
->FindB("Debug::aptcdrom",false) == true)
94 std::clog
<< "Found Packages in " << CD
<< std::endl
;
97 // Continue down if thorough is given
98 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
102 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
103 c
!= compressor
.end(); ++c
)
105 if (RealFileExists(std::string("Sources").append(c
->Extension
).c_str()) == false)
108 if (_config
->FindB("Debug::aptcdrom",false) == true)
109 std::clog
<< "Found Sources in " << CD
<< std::endl
;
112 // Continue down if thorough is given
113 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
118 // see if we find translation indices
119 if (DirectoryExists("i18n") == true)
122 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
124 if(strncmp(Dir
->d_name
, "Translation-", strlen("Translation-")) != 0)
126 string file
= Dir
->d_name
;
127 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
128 c
!= compressor
.end(); ++c
)
130 string fileext
= flExtension(file
);
133 else if (fileext
.empty() == false)
134 fileext
= "." + fileext
;
136 if (c
->Extension
== fileext
)
138 if (_config
->FindB("Debug::aptcdrom",false) == true)
139 std::clog
<< "Found translation " << Dir
->d_name
<< " in " << CD
<< "i18n/" << std::endl
;
140 file
.erase(file
.size() - fileext
.size());
141 TransList
.push_back(CD
+ "i18n/" + file
);
151 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
153 // Run over the directory
154 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
157 if (strcmp(Dir
->d_name
,".") == 0 ||
158 strcmp(Dir
->d_name
,"..") == 0 ||
159 //strcmp(Dir->d_name,"source") == 0 ||
160 strcmp(Dir
->d_name
,".disk") == 0 ||
161 strcmp(Dir
->d_name
,"experimental") == 0 ||
162 strcmp(Dir
->d_name
,"binary-all") == 0 ||
163 strcmp(Dir
->d_name
,"debian-installer") == 0)
166 // See if the name is a sub directory
168 if (stat(Dir
->d_name
,&Buf
) != 0)
171 if (S_ISDIR(Buf
.st_mode
) == 0)
175 for (I
= 0; I
!= Depth
; I
++)
176 if (Inodes
[I
] == Buf
.st_ino
)
181 // Store the inodes weve seen
182 Inodes
[Depth
] = Buf
.st_ino
;
185 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
188 if (chdir(CD
.c_str()) != 0)
190 _error
->Errno("chdir","Unable to change to %s", CD
.c_str());
198 return !_error
->PendingError();
201 // Score - We compute a 'score' for a path /*{{{*/
202 // ---------------------------------------------------------------------
203 /* Paths are scored based on how close they come to what I consider
204 normal. That is ones that have 'dist' 'stable' 'testing' will score
205 higher than ones without. */
206 int pkgCdrom::Score(string Path
)
209 if (Path
.find("stable/") != string::npos
)
211 if (Path
.find("/binary-") != string::npos
)
213 if (Path
.find("testing/") != string::npos
)
215 if (Path
.find("unstable/") != string::npos
)
217 if (Path
.find("/dists/") != string::npos
)
219 if (Path
.find("/main/") != string::npos
)
221 if (Path
.find("/contrib/") != string::npos
)
223 if (Path
.find("/non-free/") != string::npos
)
225 if (Path
.find("/non-US/") != string::npos
)
227 if (Path
.find("/source/") != string::npos
)
229 if (Path
.find("/debian/") != string::npos
)
232 // check for symlinks in the patch leading to the actual file
233 // a symlink gets a big penalty
235 string statPath
= flNotFile(Path
);
236 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount");
237 while(statPath
!= cdromPath
&& statPath
!= "./") {
238 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
239 if (lstat(statPath
.c_str(),&Buf
) == 0) {
240 if(S_ISLNK(Buf
.st_mode
)) {
245 statPath
= flNotFile(statPath
); // descent
251 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
252 // ---------------------------------------------------------------------
253 /* Here we drop everything that is not this machines arch */
254 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
257 for (unsigned int I
= 0; I
< List
.size(); I
++)
259 const char *Str
= List
[I
].c_str();
260 const char *Start
, *End
;
261 if ((Start
= strstr(Str
,"/binary-")) == 0)
264 // Between Start and End is the architecture
266 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
267 APT::Configuration::checkArchitecture(string(Start
, End
)) == true)
268 continue; // okay, architecture is accepted
270 // not accepted -> Erase it
271 List
.erase(List
.begin() + I
);
272 --I
; // the next entry is at the same index after the erase
278 // DropTranslation - Dump unwanted Translation-<lang> files /*{{{*/
279 // ---------------------------------------------------------------------
280 /* Here we drop everything that is not configured in Acquire::Languages */
281 bool pkgCdrom::DropTranslation(vector
<string
> &List
)
283 for (unsigned int I
= 0; I
< List
.size(); I
++)
286 if ((Start
= strstr(List
[I
].c_str(), "/Translation-")) == NULL
)
288 Start
+= strlen("/Translation-");
290 if (APT::Configuration::checkLanguage(Start
, true) == true)
293 // not accepted -> Erase it
294 List
.erase(List
.begin() + I
);
295 --I
; // the next entry is at the same index after the erase
301 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
302 // ---------------------------------------------------------------------
303 /* Here we go and stat every file that we found and strip dup inodes. */
304 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
306 bool couldFindAllFiles
= true;
307 // Get a list of all the inodes
308 ino_t
*Inodes
= new ino_t
[List
.size()];
309 for (unsigned int I
= 0; I
!= List
.size(); ++I
)
314 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
315 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
316 c
!= compressor
.end(); ++c
)
318 std::string filename
= std::string(List
[I
]).append(Name
).append(c
->Extension
);
319 if (stat(filename
.c_str(), &Buf
) != 0)
321 Inodes
[I
] = Buf
.st_ino
;
328 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(), Name
);
329 couldFindAllFiles
= false;
335 for (unsigned int I
= 0; I
!= List
.size(); I
++)
339 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
342 if (Inodes
[J
] == 0 || Inodes
[J
] != Inodes
[I
])
345 // We score the two paths.. and erase one
346 int ScoreA
= Score(List
[I
]);
347 int ScoreB
= Score(List
[J
]);
359 // Wipe erased entries
360 for (unsigned int I
= 0; I
< List
.size();)
362 if (List
[I
].empty() == false)
365 List
.erase(List
.begin()+I
);
368 return couldFindAllFiles
;
371 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
372 // ---------------------------------------------------------------------
373 /* This takes the list of source list expressed entires and collects
374 similar ones to form a single entry for each dist */
375 void pkgCdrom::ReduceSourcelist(string
/*CD*/,vector
<string
> &List
)
377 sort(List
.begin(),List
.end());
379 // Collect similar entries
380 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
383 string::size_type Space
= (*I
).find(' ');
384 if (Space
== string::npos
)
386 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
387 if (SSpace
== string::npos
)
390 string Word1
= string(*I
,Space
,SSpace
-Space
);
391 string Prefix
= string(*I
,0,Space
);
392 string Component
= string(*I
,SSpace
);
393 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; ++J
)
396 string::size_type Space2
= (*J
).find(' ');
397 if (Space2
== string::npos
)
399 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
400 if (SSpace2
== string::npos
)
403 if (string(*J
,0,Space2
) != Prefix
)
405 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
408 string Component2
= string(*J
, SSpace2
) + " ";
409 if (Component2
.find(Component
+ " ") == std::string::npos
)
415 // Wipe erased entries
416 for (unsigned int I
= 0; I
< List
.size();)
418 if (List
[I
].empty() == false)
421 List
.erase(List
.begin()+I
);
425 // WriteDatabase - Write the CDROM Database file /*{{{*/
426 // ---------------------------------------------------------------------
427 /* We rewrite the configuration class associated with the cdrom database. */
428 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
430 string DFile
= _config
->FindFile("Dir::State::cdroms");
431 string NewFile
= DFile
+ ".new";
433 unlink(NewFile
.c_str());
434 ofstream
Out(NewFile
.c_str());
436 return _error
->Errno("ofstream::ofstream",
437 "Failed to open %s.new",DFile
.c_str());
439 /* Write out all of the configuration directives by walking the
440 configuration tree */
441 Cnf
.Dump(Out
, NULL
, "%f \"%v\";\n", false);
445 if (FileExists(DFile
) == true)
446 rename(DFile
.c_str(), (DFile
+ '~').c_str());
447 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
448 return _error
->Errno("rename","Failed to rename %s.new to %s",
449 DFile
.c_str(),DFile
.c_str());
454 // WriteSourceList - Write an updated sourcelist /*{{{*/
455 // ---------------------------------------------------------------------
456 /* This reads the old source list and copies it into the new one. It
457 appends the new CDROM entires just after the first block of comments.
458 This places them first in the file. It also removes any old entries
459 that were the same. */
460 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
462 if (List
.empty() == true)
465 string File
= _config
->FindFile("Dir::Etc::sourcelist");
467 // Open the stream for reading
468 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
470 if (F
.fail() == true)
471 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
473 string NewFile
= File
+ ".new";
474 unlink(NewFile
.c_str());
475 ofstream
Out(NewFile
.c_str());
477 return _error
->Errno("ofstream::ofstream",
478 "Failed to open %s.new",File
.c_str());
480 // Create a short uri without the path
481 string ShortURI
= "cdrom:[" + Name
+ "]/";
482 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
493 while (F
.eof() == false)
495 F
.getline(Buffer
,sizeof(Buffer
));
497 if (F
.fail() && !F
.eof())
498 return _error
->Error(_("Line %u too long in source list %s."),
499 CurLine
,File
.c_str());
500 _strtabexpand(Buffer
,sizeof(Buffer
));
504 if (Buffer
[0] == '#' || Buffer
[0] == 0)
506 Out
<< Buffer
<< endl
;
512 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
514 string::size_type Space
= (*I
).find(' ');
515 if (Space
== string::npos
)
516 return _error
->Error("Internal error");
517 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
518 " " << string(*I
,Space
+1) << endl
;
526 const char *C
= Buffer
;
527 if (ParseQuoteWord(C
,cType
) == false ||
528 ParseQuoteWord(C
,URI
) == false)
530 Out
<< Buffer
<< endl
;
534 // Emit lines like this one
535 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
536 string(URI
,0,ShortURI
.length()) != ShortURI2
))
538 Out
<< Buffer
<< endl
;
543 // Just in case the file was empty
546 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
548 string::size_type Space
= (*I
).find(' ');
549 if (Space
== string::npos
)
550 return _error
->Error("Internal error");
552 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
553 " " << string(*I
,Space
+1) << endl
;
559 rename(File
.c_str(), (File
+ '~').c_str());
560 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
561 return _error
->Errno("rename","Failed to rename %s.new to %s",
562 File
.c_str(),File
.c_str());
567 bool pkgCdrom::UnmountCDROM(std::string
const &CDROM
, pkgCdromStatus
* const log
)/*{{{*/
569 if (_config
->FindB("APT::CDROM::NoMount",false) == true)
572 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
573 return UnmountCdrom(CDROM
);
576 bool pkgCdrom::MountAndIdentCDROM(Configuration
&Database
, std::string
&CDROM
, std::string
&ident
, pkgCdromStatus
* const log
, bool const interactive
)/*{{{*/
579 CDROM
= _config
->FindDir("Acquire::cdrom::mount");
581 CDROM
= SafeGetCWD() + '/' + CDROM
;
586 log
->SetTotal(STEP_LAST
);
587 strprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
588 log
->Update(msg
, STEP_PREPARE
);
591 // Unmount the CD and get the user to put in the one they want
592 if (_config
->FindB("APT::CDROM::NoMount", false) == false)
594 if (interactive
== true)
596 UnmountCDROM(CDROM
, log
);
600 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
601 if(!log
->ChangeCdrom()) {
608 // Mount the new CDROM
610 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
612 if (MountCdrom(CDROM
) == false)
613 return _error
->Error("Failed to mount the cdrom.");
616 if (IsMounted(CDROM
) == false)
617 return _error
->Error("Failed to mount the cdrom.");
619 // Hash the CD to get an ID
621 log
->Update(_("Identifying... "), STEP_IDENT
);
623 if (IdentCdrom(CDROM
,ident
) == false)
628 UnmountCDROM(CDROM
, NULL
);
635 strprintf(msg
, "[%s]\n", ident
.c_str());
640 string DFile
= _config
->FindFile("Dir::State::cdroms");
641 if (FileExists(DFile
) == true)
643 if (ReadConfigFile(Database
,DFile
) == false)
645 UnmountCDROM(CDROM
, NULL
);
646 return _error
->Error("Unable to read the cdrom database %s",
653 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
655 Configuration Database
;
657 if (MountAndIdentCDROM(Database
, CDROM
, ident
, log
, false) == false)
663 strprintf(msg
, _("Stored label: %s\n"),
664 Database
.Find("CD::"+ident
).c_str());
668 // Unmount and finish
669 UnmountCDROM(CDROM
, log
);
673 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
675 Configuration Database
;
676 std::string ID
, CDROM
;
677 if (MountAndIdentCDROM(Database
, CDROM
, ID
, log
, true) == false)
681 log
->Update(_("Scanning disc for index files...\n"),STEP_SCAN
);
683 // Get the CD structure
685 vector
<string
> SourceList
;
686 vector
<string
> SigList
;
687 vector
<string
> TransList
;
688 string StartDir
= SafeGetCWD();
690 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
694 UnmountCDROM(CDROM
, NULL
);
698 if (chdir(StartDir
.c_str()) != 0)
700 UnmountCDROM(CDROM
, NULL
);
701 return _error
->Errno("chdir","Unable to change to %s", StartDir
.c_str());
704 if (_config
->FindB("Debug::aptcdrom",false) == true)
706 cout
<< "I found (binary):" << endl
;
707 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
709 cout
<< "I found (source):" << endl
;
710 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
712 cout
<< "I found (Signatures):" << endl
;
713 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
717 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
720 DropBinaryArch(List
);
721 DropRepeats(List
,"Packages");
722 DropRepeats(SourceList
,"Sources");
723 // FIXME: We ignore stat() errors here as we usually have only one of those in use
724 // This has little potencial to drop 'valid' stat() errors as we know that one of these
725 // files need to exist, but it would be better if we would check it here
726 _error
->PushToStack();
727 DropRepeats(SigList
,"Release.gpg");
728 DropRepeats(SigList
,"InRelease");
729 _error
->RevertToStack();
730 DropRepeats(TransList
,"");
731 if (_config
->FindB("APT::CDROM::DropTranslation", true) == true)
732 DropTranslation(TransList
);
735 strprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
736 "%zu translation indexes and %zu signatures\n"),
737 List
.size(), SourceList
.size(), TransList
.size(),
739 log
->Update(msg
, STEP_SCAN
);
742 if (List
.empty() == true && SourceList
.empty() == true)
744 UnmountCDROM(CDROM
, NULL
);
745 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
748 // Check if the CD is in the database
750 if (Database
.Exists("CD::" + ID
) == false ||
751 _config
->FindB("APT::CDROM::Rename",false) == true)
753 // Try to use the CDs label if at all possible
754 if (InfoDir
.empty() == false &&
755 FileExists(InfoDir
+ "/info") == true)
757 ifstream
F((InfoDir
+ "/info").c_str());
758 if (F
.good() == true)
761 if (Name
.empty() == false)
763 // Escape special characters
764 string::iterator J
= Name
.begin();
765 for (; J
!= Name
.end(); ++J
)
766 if (*J
== '"' || *J
== ']' || *J
== '[')
772 strprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
775 Database
.Set("CD::" + ID
+ "::Label",Name
);
779 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
780 Name
.empty() == true)
784 UnmountCDROM(CDROM
, NULL
);
785 return _error
->Error("No disc name found and no way to ask for it");
789 if(!log
->AskCdromName(Name
)) {
791 UnmountCDROM(CDROM
, NULL
);
794 cout
<< "Name: '" << Name
<< "'" << endl
;
796 if (Name
.empty() == false &&
797 Name
.find('"') == string::npos
&&
798 Name
.find('[') == string::npos
&&
799 Name
.find(']') == string::npos
)
801 log
->Update(_("That is not a valid name, try again.\n"));
806 Name
= Database
.Find("CD::" + ID
);
808 // Escape special characters
809 string::iterator J
= Name
.begin();
810 for (; J
!= Name
.end(); ++J
)
811 if (*J
== '"' || *J
== ']' || *J
== '[')
814 Database
.Set("CD::" + ID
,Name
);
818 strprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
820 log
->Update(_("Copying package lists..."), STEP_COPY
);
823 // check for existence and possibly create state directory for copying
824 string
const listDir
= _config
->FindDir("Dir::State::lists");
825 string
const partialListDir
= listDir
+ "partial/";
826 mode_t
const mode
= umask(S_IWGRP
| S_IWOTH
);
827 bool const creation_fail
= (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::State"), partialListDir
) == false &&
828 CreateAPTDirectoryIfNeeded(listDir
, partialListDir
) == false);
830 if (creation_fail
== true)
832 UnmountCDROM(CDROM
, NULL
);
833 return _error
->Errno("cdrom", _("List directory %spartial is missing."), listDir
.c_str());
836 // take care of the signatures and copy them if they are ok
837 // (we do this before PackageCopy as it modifies "List" and "SourceList")
838 SigVerify SignVerify
;
839 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
841 // Copy the package files to the state directory
844 TranslationsCopy TransCopy
;
845 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
846 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
847 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
849 UnmountCDROM(CDROM
, NULL
);
853 // reduce the List so that it takes less space in sources.list
854 ReduceSourcelist(CDROM
,List
);
855 ReduceSourcelist(CDROM
,SourceList
);
857 // Write the database and sourcelist
858 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
860 if (WriteDatabase(Database
) == false)
862 UnmountCDROM(CDROM
, NULL
);
867 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
868 if (WriteSourceList(Name
,List
,false) == false ||
869 WriteSourceList(Name
,SourceList
,true) == false)
871 UnmountCDROM(CDROM
, NULL
);
876 // Print the sourcelist entries
878 log
->Update(_("Source list entries for this disc are:\n"));
880 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
882 string::size_type Space
= (*I
).find(' ');
883 if (Space
== string::npos
)
885 UnmountCDROM(CDROM
, NULL
);
886 return _error
->Error("Internal error");
892 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
893 " " << string(*I
,Space
+1) << endl
;
894 log
->Update(msg
.str());
898 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
900 string::size_type Space
= (*I
).find(' ');
901 if (Space
== string::npos
)
903 UnmountCDROM(CDROM
, NULL
);
904 return _error
->Error("Internal error");
909 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
910 " " << string(*I
,Space
+1) << endl
;
911 log
->Update(msg
.str());
915 // Unmount and finish
916 UnmountCDROM(CDROM
, log
);
920 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
921 : d(NULL
), libudev_handle(NULL
), udev_new(NULL
), udev_enumerate_add_match_property(NULL
),
922 udev_enumerate_scan_devices(NULL
), udev_enumerate_get_list_entry(NULL
),
923 udev_device_new_from_syspath(NULL
), udev_enumerate_get_udev(NULL
),
924 udev_list_entry_get_name(NULL
), udev_device_get_devnode(NULL
),
925 udev_enumerate_new(NULL
), udev_list_entry_get_next(NULL
),
926 udev_device_get_property_value(NULL
), udev_enumerate_add_match_sysattr(NULL
)
931 bool pkgUdevCdromDevices::Dlopen() /*{{{*/
934 if(libudev_handle
!= NULL
)
937 // see if we can get libudev
938 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
942 // get the pointers to the udev structs
944 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
945 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
946 udev_enumerate_add_match_sysattr
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_sysattr");
947 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
948 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
949 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
950 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
951 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
952 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
953 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
954 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
955 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
960 // convenience interface, this will just call ScanForRemovable /*{{{*/
961 vector
<CdromDevice
> pkgUdevCdromDevices::Scan()
963 bool CdromOnly
= _config
->FindB("APT::cdrom::CdromOnly", true);
964 return ScanForRemovable(CdromOnly
);
967 vector
<CdromDevice
> pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly
)/*{{{*/
969 vector
<CdromDevice
> cdrom_devices
;
970 struct udev_enumerate
*enumerate
;
971 struct udev_list_entry
*l
, *devices
;
972 struct udev
*udev_ctx
;
974 if(libudev_handle
== NULL
)
975 return cdrom_devices
;
977 udev_ctx
= udev_new();
978 enumerate
= udev_enumerate_new (udev_ctx
);
980 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
982 udev_enumerate_add_match_sysattr(enumerate
, "removable", "1");
985 udev_enumerate_scan_devices (enumerate
);
986 devices
= udev_enumerate_get_list_entry (enumerate
);
987 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
990 struct udev_device
*udevice
;
991 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
994 const char* devnode
= udev_device_get_devnode(udevice
);
996 // try fstab_dir first
998 const char* mp
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
1000 mountpath
= string(mp
);
1002 mountpath
= FindMountPointForDevice(devnode
);
1004 // fill in the struct
1005 cdrom
.DeviceName
= string(devnode
);
1006 if (mountpath
!= "") {
1007 cdrom
.MountPath
= mountpath
;
1008 string s
= mountpath
;
1009 cdrom
.Mounted
= IsMounted(s
);
1011 cdrom
.Mounted
= false;
1012 cdrom
.MountPath
= "";
1014 cdrom_devices
.push_back(cdrom
);
1016 return cdrom_devices
;
1020 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
1022 if (libudev_handle
!= NULL
)
1023 dlclose(libudev_handle
);
1027 pkgCdromStatus::pkgCdromStatus() : d(NULL
), totalSteps(0) {}
1028 pkgCdromStatus::~pkgCdromStatus() {}
1030 pkgCdrom::pkgCdrom() : d(NULL
) {}
1031 pkgCdrom::~pkgCdrom() {}