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>
32 // FindPackages - Find the package files on the CDROM /*{{{*/
33 // ---------------------------------------------------------------------
34 /* We look over the cdrom for package files. This is a recursive
35 search that short circuits when it his a package file in the dir.
36 This speeds it up greatly as the majority of the size is in the
38 bool pkgCdrom::FindPackages(string CD
,
40 vector
<string
> &SList
,
41 vector
<string
> &SigList
,
42 vector
<string
> &TransList
,
43 string
&InfoDir
, pkgCdromStatus
*log
,
46 static ino_t Inodes
[9];
49 // if we have a look we "pulse" now
56 if (CD
[CD
.length()-1] != '/')
59 if (chdir(CD
.c_str()) != 0)
60 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
62 // Look for a .disk subdirectory
63 if (DirectoryExists(".disk") == true)
65 if (InfoDir
.empty() == true)
66 InfoDir
= CD
+ ".disk/";
69 // Don't look into directories that have been marked to ingore.
70 if (RealFileExists(".aptignr") == true)
73 /* Check _first_ for a signature file as apt-cdrom assumes that all files
74 under a Packages/Source file are in control of that file and stops
77 if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
79 SigList
.push_back(CD
);
82 /* Aha! We found some package files. We assume that everything under
83 this dir is controlled by those package files so we don't look down
85 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
86 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
87 c
!= compressor
.end(); ++c
)
89 if (RealFileExists(std::string("Packages").append(c
->Extension
).c_str()) == false)
92 if (_config
->FindB("Debug::aptcdrom",false) == true)
93 std::clog
<< "Found Packages in " << CD
<< std::endl
;
96 // Continue down if thorough is given
97 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
101 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
102 c
!= compressor
.end(); ++c
)
104 if (RealFileExists(std::string("Sources").append(c
->Extension
).c_str()) == false)
107 if (_config
->FindB("Debug::aptcdrom",false) == true)
108 std::clog
<< "Found Sources in " << CD
<< std::endl
;
111 // Continue down if thorough is given
112 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
117 // see if we find translation indices
118 if (DirectoryExists("i18n") == true)
121 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
123 if(strncmp(Dir
->d_name
, "Translation-", strlen("Translation-")) != 0)
125 string file
= Dir
->d_name
;
126 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
127 c
!= compressor
.end(); ++c
)
129 string fileext
= flExtension(file
);
132 else if (fileext
.empty() == false)
133 fileext
= "." + fileext
;
135 if (c
->Extension
== fileext
)
137 if (_config
->FindB("Debug::aptcdrom",false) == true)
138 std::clog
<< "Found translation " << Dir
->d_name
<< " in " << CD
<< "i18n/" << std::endl
;
139 file
.erase(file
.size() - fileext
.size());
140 TransList
.push_back(CD
+ "i18n/" + file
);
150 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
152 // Run over the directory
153 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
156 if (strcmp(Dir
->d_name
,".") == 0 ||
157 strcmp(Dir
->d_name
,"..") == 0 ||
158 //strcmp(Dir->d_name,"source") == 0 ||
159 strcmp(Dir
->d_name
,".disk") == 0 ||
160 strcmp(Dir
->d_name
,"experimental") == 0 ||
161 strcmp(Dir
->d_name
,"binary-all") == 0 ||
162 strcmp(Dir
->d_name
,"debian-installer") == 0)
165 // See if the name is a sub directory
167 if (stat(Dir
->d_name
,&Buf
) != 0)
170 if (S_ISDIR(Buf
.st_mode
) == 0)
174 for (I
= 0; I
!= Depth
; I
++)
175 if (Inodes
[I
] == Buf
.st_ino
)
180 // Store the inodes weve seen
181 Inodes
[Depth
] = Buf
.st_ino
;
184 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
187 if (chdir(CD
.c_str()) != 0)
189 _error
->Errno("chdir","Unable to change to %s", CD
.c_str());
197 return !_error
->PendingError();
200 // Score - We compute a 'score' for a path /*{{{*/
201 // ---------------------------------------------------------------------
202 /* Paths are scored based on how close they come to what I consider
203 normal. That is ones that have 'dist' 'stable' 'testing' will score
204 higher than ones without. */
205 int pkgCdrom::Score(string Path
)
208 if (Path
.find("stable/") != string::npos
)
210 if (Path
.find("/binary-") != string::npos
)
212 if (Path
.find("testing/") != string::npos
)
214 if (Path
.find("unstable/") != string::npos
)
216 if (Path
.find("/dists/") != string::npos
)
218 if (Path
.find("/main/") != string::npos
)
220 if (Path
.find("/contrib/") != string::npos
)
222 if (Path
.find("/non-free/") != string::npos
)
224 if (Path
.find("/non-US/") != string::npos
)
226 if (Path
.find("/source/") != string::npos
)
228 if (Path
.find("/debian/") != string::npos
)
231 // check for symlinks in the patch leading to the actual file
232 // a symlink gets a big penalty
234 string statPath
= flNotFile(Path
);
235 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount");
236 while(statPath
!= cdromPath
&& statPath
!= "./") {
237 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
238 if (lstat(statPath
.c_str(),&Buf
) == 0) {
239 if(S_ISLNK(Buf
.st_mode
)) {
244 statPath
= flNotFile(statPath
); // descent
250 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
251 // ---------------------------------------------------------------------
252 /* Here we drop everything that is not this machines arch */
253 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
256 for (unsigned int I
= 0; I
< List
.size(); I
++)
258 const char *Str
= List
[I
].c_str();
259 const char *Start
, *End
;
260 if ((Start
= strstr(Str
,"/binary-")) == 0)
263 // Between Start and End is the architecture
265 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
266 APT::Configuration::checkArchitecture(string(Start
, End
)) == true)
267 continue; // okay, architecture is accepted
269 // not accepted -> Erase it
270 List
.erase(List
.begin() + I
);
271 --I
; // the next entry is at the same index after the erase
277 // DropTranslation - Dump unwanted Translation-<lang> files /*{{{*/
278 // ---------------------------------------------------------------------
279 /* Here we drop everything that is not configured in Acquire::Languages */
280 bool pkgCdrom::DropTranslation(vector
<string
> &List
)
282 for (unsigned int I
= 0; I
< List
.size(); I
++)
285 if ((Start
= strstr(List
[I
].c_str(), "/Translation-")) == NULL
)
287 Start
+= strlen("/Translation-");
289 if (APT::Configuration::checkLanguage(Start
, true) == true)
292 // not accepted -> Erase it
293 List
.erase(List
.begin() + I
);
294 --I
; // the next entry is at the same index after the erase
300 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
301 // ---------------------------------------------------------------------
302 /* Here we go and stat every file that we found and strip dup inodes. */
303 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
305 bool couldFindAllFiles
= true;
306 // Get a list of all the inodes
307 ino_t
*Inodes
= new ino_t
[List
.size()];
308 for (unsigned int I
= 0; I
!= List
.size(); ++I
)
313 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
314 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
315 c
!= compressor
.end(); ++c
)
317 std::string filename
= std::string(List
[I
]).append(Name
).append(c
->Extension
);
318 if (stat(filename
.c_str(), &Buf
) != 0)
320 Inodes
[I
] = Buf
.st_ino
;
327 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(), Name
);
328 couldFindAllFiles
= false;
334 for (unsigned int I
= 0; I
!= List
.size(); I
++)
338 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
341 if (Inodes
[J
] == 0 || Inodes
[J
] != Inodes
[I
])
344 // We score the two paths.. and erase one
345 int ScoreA
= Score(List
[I
]);
346 int ScoreB
= Score(List
[J
]);
358 // Wipe erased entries
359 for (unsigned int I
= 0; I
< List
.size();)
361 if (List
[I
].empty() == false)
364 List
.erase(List
.begin()+I
);
367 return couldFindAllFiles
;
370 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
371 // ---------------------------------------------------------------------
372 /* This takes the list of source list expressed entires and collects
373 similar ones to form a single entry for each dist */
374 void pkgCdrom::ReduceSourcelist(string
/*CD*/,vector
<string
> &List
)
376 sort(List
.begin(),List
.end());
378 // Collect similar entries
379 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
382 string::size_type Space
= (*I
).find(' ');
383 if (Space
== string::npos
)
385 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
386 if (SSpace
== string::npos
)
389 string Word1
= string(*I
,Space
,SSpace
-Space
);
390 string Prefix
= string(*I
,0,Space
);
391 string Component
= string(*I
,SSpace
);
392 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; ++J
)
395 string::size_type Space2
= (*J
).find(' ');
396 if (Space2
== string::npos
)
398 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
399 if (SSpace2
== string::npos
)
402 if (string(*J
,0,Space2
) != Prefix
)
404 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
407 string Component2
= string(*J
, SSpace2
) + " ";
408 if (Component2
.find(Component
+ " ") == std::string::npos
)
414 // Wipe erased entries
415 for (unsigned int I
= 0; I
< List
.size();)
417 if (List
[I
].empty() == false)
420 List
.erase(List
.begin()+I
);
424 // WriteDatabase - Write the CDROM Database file /*{{{*/
425 // ---------------------------------------------------------------------
426 /* We rewrite the configuration class associated with the cdrom database. */
427 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
429 string DFile
= _config
->FindFile("Dir::State::cdroms");
430 string NewFile
= DFile
+ ".new";
432 unlink(NewFile
.c_str());
433 ofstream
Out(NewFile
.c_str());
435 return _error
->Errno("ofstream::ofstream",
436 "Failed to open %s.new",DFile
.c_str());
438 /* Write out all of the configuration directives by walking the
439 configuration tree */
440 Cnf
.Dump(Out
, NULL
, "%f \"%v\";\n", false);
444 if (FileExists(DFile
) == true)
445 rename(DFile
.c_str(), (DFile
+ '~').c_str());
446 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
447 return _error
->Errno("rename","Failed to rename %s.new to %s",
448 DFile
.c_str(),DFile
.c_str());
453 // WriteSourceList - Write an updated sourcelist /*{{{*/
454 // ---------------------------------------------------------------------
455 /* This reads the old source list and copies it into the new one. It
456 appends the new CDROM entires just after the first block of comments.
457 This places them first in the file. It also removes any old entries
458 that were the same. */
459 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
461 if (List
.empty() == true)
464 string File
= _config
->FindFile("Dir::Etc::sourcelist");
466 // Open the stream for reading
467 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
470 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
472 string NewFile
= File
+ ".new";
473 unlink(NewFile
.c_str());
474 ofstream
Out(NewFile
.c_str());
476 return _error
->Errno("ofstream::ofstream",
477 "Failed to open %s.new",File
.c_str());
479 // Create a short uri without the path
480 string ShortURI
= "cdrom:[" + Name
+ "]/";
481 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
492 while (F
.eof() == false)
494 F
.getline(Buffer
,sizeof(Buffer
));
496 if (F
.fail() && !F
.eof())
497 return _error
->Error(_("Line %u too long in source list %s."),
498 CurLine
,File
.c_str());
499 _strtabexpand(Buffer
,sizeof(Buffer
));
503 if (Buffer
[0] == '#' || Buffer
[0] == 0)
505 Out
<< Buffer
<< endl
;
511 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
513 string::size_type Space
= (*I
).find(' ');
514 if (Space
== string::npos
)
515 return _error
->Error("Internal error");
516 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
517 " " << string(*I
,Space
+1) << endl
;
525 const char *C
= Buffer
;
526 if (ParseQuoteWord(C
,cType
) == false ||
527 ParseQuoteWord(C
,URI
) == false)
529 Out
<< Buffer
<< endl
;
533 // Emit lines like this one
534 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
535 string(URI
,0,ShortURI
.length()) != ShortURI2
))
537 Out
<< Buffer
<< endl
;
542 // Just in case the file was empty
545 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
547 string::size_type Space
= (*I
).find(' ');
548 if (Space
== string::npos
)
549 return _error
->Error("Internal error");
551 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
552 " " << string(*I
,Space
+1) << endl
;
558 rename(File
.c_str(), (File
+ '~').c_str());
559 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
560 return _error
->Errno("rename","Failed to rename %s.new to %s",
561 File
.c_str(),File
.c_str());
566 bool pkgCdrom::UnmountCDROM(std::string
const &CDROM
, pkgCdromStatus
* const log
)/*{{{*/
568 if (_config
->FindB("APT::CDROM::NoMount",false) == true)
571 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
572 return UnmountCdrom(CDROM
);
575 bool pkgCdrom::MountAndIdentCDROM(Configuration
&Database
, std::string
&CDROM
, std::string
&ident
, pkgCdromStatus
* const log
, bool const interactive
)/*{{{*/
578 CDROM
= _config
->FindDir("Acquire::cdrom::mount");
580 CDROM
= SafeGetCWD() + '/' + CDROM
;
585 log
->SetTotal(STEP_LAST
);
586 strprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
587 log
->Update(msg
, STEP_PREPARE
);
590 // Unmount the CD and get the user to put in the one they want
591 if (_config
->FindB("APT::CDROM::NoMount", false) == false)
593 if (interactive
== true)
595 UnmountCDROM(CDROM
, log
);
599 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
600 if(!log
->ChangeCdrom()) {
607 // Mount the new CDROM
609 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
611 if (MountCdrom(CDROM
) == false)
612 return _error
->Error("Failed to mount the cdrom.");
615 if (IsMounted(CDROM
) == false)
616 return _error
->Error("Failed to mount the cdrom.");
618 // Hash the CD to get an ID
620 log
->Update(_("Identifying... "), STEP_IDENT
);
622 if (IdentCdrom(CDROM
,ident
) == false)
627 UnmountCDROM(CDROM
, NULL
);
634 strprintf(msg
, "[%s]\n", ident
.c_str());
639 string DFile
= _config
->FindFile("Dir::State::cdroms");
640 if (FileExists(DFile
) == true)
642 if (ReadConfigFile(Database
,DFile
) == false)
644 UnmountCDROM(CDROM
, NULL
);
645 return _error
->Error("Unable to read the cdrom database %s",
652 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
654 Configuration Database
;
656 if (MountAndIdentCDROM(Database
, CDROM
, ident
, log
, false) == false)
662 strprintf(msg
, _("Stored label: %s\n"),
663 Database
.Find("CD::"+ident
).c_str());
667 // Unmount and finish
668 UnmountCDROM(CDROM
, log
);
672 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
674 Configuration Database
;
675 std::string ID
, CDROM
;
676 if (MountAndIdentCDROM(Database
, CDROM
, ID
, log
, true) == false)
680 log
->Update(_("Scanning disc for index files...\n"),STEP_SCAN
);
682 // Get the CD structure
684 vector
<string
> SourceList
;
685 vector
<string
> SigList
;
686 vector
<string
> TransList
;
687 string StartDir
= SafeGetCWD();
689 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
693 UnmountCDROM(CDROM
, NULL
);
697 if (chdir(StartDir
.c_str()) != 0)
699 UnmountCDROM(CDROM
, NULL
);
700 return _error
->Errno("chdir","Unable to change to %s", StartDir
.c_str());
703 if (_config
->FindB("Debug::aptcdrom",false) == true)
705 cout
<< "I found (binary):" << endl
;
706 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
708 cout
<< "I found (source):" << endl
;
709 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
711 cout
<< "I found (Signatures):" << endl
;
712 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
716 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
719 DropBinaryArch(List
);
720 DropRepeats(List
,"Packages");
721 DropRepeats(SourceList
,"Sources");
722 // FIXME: We ignore stat() errors here as we usually have only one of those in use
723 // This has little potencial to drop 'valid' stat() errors as we know that one of these
724 // files need to exist, but it would be better if we would check it here
725 _error
->PushToStack();
726 DropRepeats(SigList
,"Release.gpg");
727 DropRepeats(SigList
,"InRelease");
728 _error
->RevertToStack();
729 DropRepeats(TransList
,"");
730 if (_config
->FindB("APT::CDROM::DropTranslation", true) == true)
731 DropTranslation(TransList
);
734 strprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
735 "%zu translation indexes and %zu signatures\n"),
736 List
.size(), SourceList
.size(), TransList
.size(),
738 log
->Update(msg
, STEP_SCAN
);
741 if (List
.empty() == true && SourceList
.empty() == true)
743 UnmountCDROM(CDROM
, NULL
);
744 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
747 // Check if the CD is in the database
749 if (Database
.Exists("CD::" + ID
) == false ||
750 _config
->FindB("APT::CDROM::Rename",false) == true)
752 // Try to use the CDs label if at all possible
753 if (InfoDir
.empty() == false &&
754 FileExists(InfoDir
+ "/info") == true)
756 ifstream
F((InfoDir
+ "/info").c_str());
760 if (Name
.empty() == false)
762 // Escape special characters
763 string::iterator J
= Name
.begin();
764 for (; J
!= Name
.end(); ++J
)
765 if (*J
== '"' || *J
== ']' || *J
== '[')
771 strprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
774 Database
.Set("CD::" + ID
+ "::Label",Name
);
778 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
779 Name
.empty() == true)
783 UnmountCDROM(CDROM
, NULL
);
784 return _error
->Error("No disc name found and no way to ask for it");
788 if(!log
->AskCdromName(Name
)) {
790 UnmountCDROM(CDROM
, NULL
);
793 cout
<< "Name: '" << Name
<< "'" << endl
;
795 if (Name
.empty() == false &&
796 Name
.find('"') == string::npos
&&
797 Name
.find('[') == string::npos
&&
798 Name
.find(']') == string::npos
)
800 log
->Update(_("That is not a valid name, try again.\n"));
805 Name
= Database
.Find("CD::" + ID
);
807 // Escape special characters
808 string::iterator J
= Name
.begin();
809 for (; J
!= Name
.end(); ++J
)
810 if (*J
== '"' || *J
== ']' || *J
== '[')
813 Database
.Set("CD::" + ID
,Name
);
817 strprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
819 log
->Update(_("Copying package lists..."), STEP_COPY
);
822 // check for existence and possibly create state directory for copying
823 string
const listDir
= _config
->FindDir("Dir::State::lists");
824 string
const partialListDir
= listDir
+ "partial/";
825 if (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::State"), partialListDir
) == false &&
826 CreateAPTDirectoryIfNeeded(listDir
, partialListDir
) == false)
828 UnmountCDROM(CDROM
, NULL
);
829 return _error
->Errno("cdrom", _("List directory %spartial is missing."), listDir
.c_str());
832 // take care of the signatures and copy them if they are ok
833 // (we do this before PackageCopy as it modifies "List" and "SourceList")
834 SigVerify SignVerify
;
835 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
837 // Copy the package files to the state directory
840 TranslationsCopy TransCopy
;
841 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
842 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
843 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
845 UnmountCDROM(CDROM
, NULL
);
849 // reduce the List so that it takes less space in sources.list
850 ReduceSourcelist(CDROM
,List
);
851 ReduceSourcelist(CDROM
,SourceList
);
853 // Write the database and sourcelist
854 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
856 if (WriteDatabase(Database
) == false)
858 UnmountCDROM(CDROM
, NULL
);
863 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
864 if (WriteSourceList(Name
,List
,false) == false ||
865 WriteSourceList(Name
,SourceList
,true) == false)
867 UnmountCDROM(CDROM
, NULL
);
872 // Print the sourcelist entries
874 log
->Update(_("Source list entries for this disc are:\n"));
876 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
878 string::size_type Space
= (*I
).find(' ');
879 if (Space
== string::npos
)
881 UnmountCDROM(CDROM
, NULL
);
882 return _error
->Error("Internal error");
888 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
889 " " << string(*I
,Space
+1) << endl
;
890 log
->Update(msg
.str());
894 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
896 string::size_type Space
= (*I
).find(' ');
897 if (Space
== string::npos
)
899 UnmountCDROM(CDROM
, NULL
);
900 return _error
->Error("Internal error");
905 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
906 " " << string(*I
,Space
+1) << endl
;
907 log
->Update(msg
.str());
911 // Unmount and finish
912 UnmountCDROM(CDROM
, log
);
916 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
917 : libudev_handle(NULL
), udev_new(NULL
), udev_enumerate_add_match_property(NULL
),
918 udev_enumerate_scan_devices(NULL
), udev_enumerate_get_list_entry(NULL
),
919 udev_device_new_from_syspath(NULL
), udev_enumerate_get_udev(NULL
),
920 udev_list_entry_get_name(NULL
), udev_device_get_devnode(NULL
),
921 udev_enumerate_new(NULL
), udev_list_entry_get_next(NULL
),
922 udev_device_get_property_value(NULL
), udev_enumerate_add_match_sysattr(NULL
)
928 pkgUdevCdromDevices::Dlopen() /*{{{*/
931 if(libudev_handle
!= NULL
)
934 // see if we can get libudev
935 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
939 // get the pointers to the udev structs
941 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
942 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
943 udev_enumerate_add_match_sysattr
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_sysattr");
944 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
945 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
946 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
947 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
948 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
949 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
950 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
951 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
952 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
958 // convenience interface, this will just call ScanForRemovable
960 pkgUdevCdromDevices::Scan()
962 bool CdromOnly
= _config
->FindB("APT::cdrom::CdromOnly", true);
963 return ScanForRemovable(CdromOnly
);
968 pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly
)
970 vector
<CdromDevice
> cdrom_devices
;
971 struct udev_enumerate
*enumerate
;
972 struct udev_list_entry
*l
, *devices
;
973 struct udev
*udev_ctx
;
975 if(libudev_handle
== NULL
)
976 return cdrom_devices
;
978 udev_ctx
= udev_new();
979 enumerate
= udev_enumerate_new (udev_ctx
);
981 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
983 udev_enumerate_add_match_sysattr(enumerate
, "removable", "1");
986 udev_enumerate_scan_devices (enumerate
);
987 devices
= udev_enumerate_get_list_entry (enumerate
);
988 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
991 struct udev_device
*udevice
;
992 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
995 const char* devnode
= udev_device_get_devnode(udevice
);
997 // try fstab_dir first
999 const char* mp
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
1001 mountpath
= string(mp
);
1003 mountpath
= FindMountPointForDevice(devnode
);
1005 // fill in the struct
1006 cdrom
.DeviceName
= string(devnode
);
1007 if (mountpath
!= "") {
1008 cdrom
.MountPath
= mountpath
;
1009 string s
= mountpath
;
1010 cdrom
.Mounted
= IsMounted(s
);
1012 cdrom
.Mounted
= false;
1013 cdrom
.MountPath
= "";
1015 cdrom_devices
.push_back(cdrom
);
1017 return cdrom_devices
;
1021 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
1023 if (libudev_handle
!= NULL
)
1024 dlclose(libudev_handle
);