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 (InfoDir
.empty() == true)
66 if (DirectoryExists(".disk") == true)
67 InfoDir
= 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
,".disk") == 0 ||
160 strcmp(Dir
->d_name
,"debian-installer") == 0)
163 // See if the name is a sub directory
165 if (stat(Dir
->d_name
,&Buf
) != 0)
168 if (S_ISDIR(Buf
.st_mode
) == 0)
172 for (I
= 0; I
!= Depth
; I
++)
173 if (Inodes
[I
] == Buf
.st_ino
)
178 // Store the inodes weve seen
179 Inodes
[Depth
] = Buf
.st_ino
;
182 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
185 if (chdir(CD
.c_str()) != 0)
187 _error
->Errno("chdir","Unable to change to %s", CD
.c_str());
195 return !_error
->PendingError();
198 // Score - We compute a 'score' for a path /*{{{*/
199 // ---------------------------------------------------------------------
200 /* Paths are scored based on how close they come to what I consider
201 normal. That is ones that have 'dist' 'stable' 'testing' will score
202 higher than ones without. */
203 int pkgCdrom::Score(string Path
)
206 if (Path
.find("stable/") != string::npos
)
208 if (Path
.find("/binary-") != string::npos
)
210 if (Path
.find("testing/") != string::npos
)
212 if (Path
.find("unstable/") != string::npos
)
214 if (Path
.find("/dists/") != string::npos
)
216 if (Path
.find("/main/") != string::npos
)
218 if (Path
.find("/contrib/") != string::npos
)
220 if (Path
.find("/non-free/") != string::npos
)
222 if (Path
.find("/non-US/") != string::npos
)
224 if (Path
.find("/source/") != string::npos
)
226 if (Path
.find("/debian/") != string::npos
)
229 // check for symlinks in the patch leading to the actual file
230 // a symlink gets a big penalty
232 string statPath
= flNotFile(Path
);
233 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount");
234 while(statPath
!= cdromPath
&& statPath
!= "./") {
235 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
236 if (lstat(statPath
.c_str(),&Buf
) == 0) {
237 if(S_ISLNK(Buf
.st_mode
)) {
242 statPath
= flNotFile(statPath
); // descent
248 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
249 // ---------------------------------------------------------------------
250 /* Here we drop everything that is not this machines arch */
251 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
254 for (unsigned int I
= 0; I
< List
.size(); I
++)
256 const char *Str
= List
[I
].c_str();
257 const char *Start
, *End
;
258 if ((Start
= strstr(Str
,"/binary-")) == 0)
261 // Between Start and End is the architecture
263 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
264 APT::Configuration::checkArchitecture(string(Start
, End
)) == true)
265 continue; // okay, architecture is accepted
267 // not accepted -> Erase it
268 List
.erase(List
.begin() + I
);
269 --I
; // the next entry is at the same index after the erase
275 // DropTranslation - Dump unwanted Translation-<lang> files /*{{{*/
276 // ---------------------------------------------------------------------
277 /* Here we drop everything that is not configured in Acquire::Languages */
278 bool pkgCdrom::DropTranslation(vector
<string
> &List
)
280 for (unsigned int I
= 0; I
< List
.size(); I
++)
283 if ((Start
= strstr(List
[I
].c_str(), "/Translation-")) == NULL
)
285 Start
+= strlen("/Translation-");
287 if (APT::Configuration::checkLanguage(Start
, true) == true)
290 // not accepted -> Erase it
291 List
.erase(List
.begin() + I
);
292 --I
; // the next entry is at the same index after the erase
298 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
299 // ---------------------------------------------------------------------
300 /* Here we go and stat every file that we found and strip dup inodes. */
301 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
303 bool couldFindAllFiles
= true;
304 // Get a list of all the inodes
305 ino_t
*Inodes
= new ino_t
[List
.size()];
306 for (unsigned int I
= 0; I
!= List
.size(); ++I
)
311 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
312 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
313 c
!= compressor
.end(); ++c
)
315 std::string filename
= std::string(List
[I
]).append(Name
).append(c
->Extension
);
316 if (stat(filename
.c_str(), &Buf
) != 0)
318 Inodes
[I
] = Buf
.st_ino
;
325 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(), Name
);
326 couldFindAllFiles
= false;
332 for (unsigned int I
= 0; I
!= List
.size(); I
++)
336 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
339 if (Inodes
[J
] == 0 || Inodes
[J
] != Inodes
[I
])
342 // We score the two paths.. and erase one
343 int ScoreA
= Score(List
[I
]);
344 int ScoreB
= Score(List
[J
]);
356 // Wipe erased entries
357 for (unsigned int I
= 0; I
< List
.size();)
359 if (List
[I
].empty() == false)
362 List
.erase(List
.begin()+I
);
365 return couldFindAllFiles
;
368 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
369 // ---------------------------------------------------------------------
370 /* This takes the list of source list expressed entries and collects
371 similar ones to form a single entry for each dist */
372 void pkgCdrom::ReduceSourcelist(string
/*CD*/,vector
<string
> &List
)
374 sort(List
.begin(),List
.end());
376 // Collect similar entries
377 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
380 string::size_type Space
= (*I
).find(' ');
381 if (Space
== string::npos
)
383 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
384 if (SSpace
== string::npos
)
387 string Word1
= string(*I
,Space
,SSpace
-Space
);
388 string Prefix
= string(*I
,0,Space
);
389 string Component
= string(*I
,SSpace
);
390 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; ++J
)
393 string::size_type Space2
= (*J
).find(' ');
394 if (Space2
== string::npos
)
396 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
397 if (SSpace2
== string::npos
)
400 if (string(*J
,0,Space2
) != Prefix
)
402 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
405 string Component2
= string(*J
, SSpace2
) + " ";
406 if (Component2
.find(Component
+ " ") == std::string::npos
)
412 // Wipe erased entries
413 for (unsigned int I
= 0; I
< List
.size();)
415 if (List
[I
].empty() == false)
418 List
.erase(List
.begin()+I
);
422 // WriteDatabase - Write the CDROM Database file /*{{{*/
423 // ---------------------------------------------------------------------
424 /* We rewrite the configuration class associated with the cdrom database. */
425 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
427 string DFile
= _config
->FindFile("Dir::State::cdroms");
428 string NewFile
= DFile
+ ".new";
430 RemoveFile("WriteDatabase", NewFile
);
431 ofstream
Out(NewFile
.c_str());
433 return _error
->Errno("ofstream::ofstream",
434 "Failed to open %s.new",DFile
.c_str());
436 /* Write out all of the configuration directives by walking the
437 configuration tree */
438 Cnf
.Dump(Out
, NULL
, "%f \"%v\";\n", false);
442 if (FileExists(DFile
) == true)
443 rename(DFile
.c_str(), (DFile
+ '~').c_str());
444 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
445 return _error
->Errno("rename","Failed to rename %s.new to %s",
446 DFile
.c_str(),DFile
.c_str());
451 // WriteSourceList - Write an updated sourcelist /*{{{*/
452 // ---------------------------------------------------------------------
453 /* This reads the old source list and copies it into the new one. It
454 appends the new CDROM entries just after the first block of comments.
455 This places them first in the file. It also removes any old entries
456 that were the same. */
457 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
459 if (List
.empty() == true)
462 string File
= _config
->FindFile("Dir::Etc::sourcelist");
464 // Open the stream for reading
465 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
467 if (F
.fail() == true)
468 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
470 string NewFile
= File
+ ".new";
471 RemoveFile("WriteDatabase", NewFile
);
472 ofstream
Out(NewFile
.c_str());
474 return _error
->Errno("ofstream::ofstream",
475 "Failed to open %s.new",File
.c_str());
477 // Create a short uri without the path
478 string ShortURI
= "cdrom:[" + Name
+ "]/";
479 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
490 while (F
.eof() == false)
492 F
.getline(Buffer
,sizeof(Buffer
));
494 if (F
.fail() && !F
.eof())
495 return _error
->Error(_("Line %u too long in source list %s."),
496 CurLine
,File
.c_str());
497 _strtabexpand(Buffer
,sizeof(Buffer
));
501 if (Buffer
[0] == '#' || Buffer
[0] == 0)
503 Out
<< Buffer
<< endl
;
509 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
511 string::size_type Space
= (*I
).find(' ');
512 if (Space
== string::npos
)
513 return _error
->Error("Internal error");
514 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
515 " " << string(*I
,Space
+1) << endl
;
523 const char *C
= Buffer
;
524 if (ParseQuoteWord(C
,cType
) == false ||
525 ParseQuoteWord(C
,URI
) == false)
527 Out
<< Buffer
<< endl
;
531 // Emit lines like this one
532 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
533 string(URI
,0,ShortURI
.length()) != ShortURI2
))
535 Out
<< Buffer
<< endl
;
540 // Just in case the file was empty
543 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
545 string::size_type Space
= (*I
).find(' ');
546 if (Space
== string::npos
)
547 return _error
->Error("Internal error");
549 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
550 " " << string(*I
,Space
+1) << endl
;
556 rename(File
.c_str(), (File
+ '~').c_str());
557 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
558 return _error
->Errno("rename","Failed to rename %s.new to %s",
559 File
.c_str(),File
.c_str());
564 bool pkgCdrom::UnmountCDROM(std::string
const &CDROM
, pkgCdromStatus
* const log
)/*{{{*/
566 if (_config
->FindB("APT::CDROM::NoMount",false) == true)
569 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
570 return UnmountCdrom(CDROM
);
573 bool pkgCdrom::MountAndIdentCDROM(Configuration
&Database
, std::string
&CDROM
, std::string
&ident
, pkgCdromStatus
* const log
, bool const interactive
)/*{{{*/
576 CDROM
= _config
->FindDir("Acquire::cdrom::mount");
578 CDROM
= SafeGetCWD() + '/' + CDROM
;
583 log
->SetTotal(STEP_LAST
);
584 strprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
585 log
->Update(msg
, STEP_PREPARE
);
588 // Unmount the CD and get the user to put in the one they want
589 if (_config
->FindB("APT::CDROM::NoMount", false) == false)
591 if (interactive
== true)
593 UnmountCDROM(CDROM
, log
);
597 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
598 if(!log
->ChangeCdrom()) {
605 // Mount the new CDROM
607 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
609 if (MountCdrom(CDROM
) == false)
610 return _error
->Error("Failed to mount the cdrom.");
613 if (IsMounted(CDROM
) == false)
614 return _error
->Error("Failed to mount the cdrom.");
616 // Hash the CD to get an ID
618 log
->Update(_("Identifying... "), STEP_IDENT
);
620 if (IdentCdrom(CDROM
,ident
) == false)
625 UnmountCDROM(CDROM
, NULL
);
632 strprintf(msg
, "[%s]\n", ident
.c_str());
637 string DFile
= _config
->FindFile("Dir::State::cdroms");
638 if (FileExists(DFile
) == true)
640 if (ReadConfigFile(Database
,DFile
) == false)
642 UnmountCDROM(CDROM
, NULL
);
643 return _error
->Error("Unable to read the cdrom database %s",
650 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
652 Configuration Database
;
654 if (MountAndIdentCDROM(Database
, CDROM
, ident
, log
, false) == false)
660 strprintf(msg
, _("Stored label: %s\n"),
661 Database
.Find("CD::"+ident
).c_str());
665 // Unmount and finish
666 UnmountCDROM(CDROM
, log
);
670 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
672 Configuration Database
;
673 std::string ID
, CDROM
;
674 if (MountAndIdentCDROM(Database
, CDROM
, ID
, log
, true) == false)
678 log
->Update(_("Scanning disc for index files...\n"),STEP_SCAN
);
680 // Get the CD structure
682 vector
<string
> SourceList
;
683 vector
<string
> SigList
;
684 vector
<string
> TransList
;
685 string StartDir
= SafeGetCWD();
687 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
691 UnmountCDROM(CDROM
, NULL
);
695 if (chdir(StartDir
.c_str()) != 0)
697 UnmountCDROM(CDROM
, NULL
);
698 return _error
->Errno("chdir","Unable to change to %s", StartDir
.c_str());
701 if (_config
->FindB("Debug::aptcdrom",false) == true)
703 cout
<< "I found (binary):" << endl
;
704 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
706 cout
<< "I found (source):" << endl
;
707 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
709 cout
<< "I found (Signatures):" << endl
;
710 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
714 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
717 DropBinaryArch(List
);
718 DropRepeats(List
,"Packages");
719 DropRepeats(SourceList
,"Sources");
720 // FIXME: We ignore stat() errors here as we usually have only one of those in use
721 // This has little potencial to drop 'valid' stat() errors as we know that one of these
722 // files need to exist, but it would be better if we would check it here
723 _error
->PushToStack();
724 DropRepeats(SigList
,"Release.gpg");
725 DropRepeats(SigList
,"InRelease");
726 _error
->RevertToStack();
727 DropRepeats(TransList
,"");
728 if (_config
->FindB("APT::CDROM::DropTranslation", true) == true)
729 DropTranslation(TransList
);
732 strprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
733 "%zu translation indexes and %zu signatures\n"),
734 List
.size(), SourceList
.size(), TransList
.size(),
736 log
->Update(msg
, STEP_SCAN
);
739 if (List
.empty() == true && SourceList
.empty() == true)
741 UnmountCDROM(CDROM
, NULL
);
742 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
745 // Check if the CD is in the database
747 if (Database
.Exists("CD::" + ID
) == false ||
748 _config
->FindB("APT::CDROM::Rename",false) == true)
750 // Try to use the CDs label if at all possible
751 if (InfoDir
.empty() == false &&
752 FileExists(InfoDir
+ "/info") == true)
754 ifstream
F((InfoDir
+ "/info").c_str());
755 if (F
.good() == true)
758 if (Name
.empty() == false)
760 // Escape special characters
761 string::iterator J
= Name
.begin();
762 for (; J
!= Name
.end(); ++J
)
763 if (*J
== '"' || *J
== ']' || *J
== '[')
769 strprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
772 Database
.Set("CD::" + ID
+ "::Label",Name
);
776 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
777 Name
.empty() == true)
781 UnmountCDROM(CDROM
, NULL
);
782 return _error
->Error("No disc name found and no way to ask for it");
786 if(!log
->AskCdromName(Name
)) {
788 UnmountCDROM(CDROM
, NULL
);
791 cout
<< "Name: '" << Name
<< "'" << endl
;
793 if (Name
.empty() == false &&
794 Name
.find('"') == string::npos
&&
795 Name
.find('[') == string::npos
&&
796 Name
.find(']') == string::npos
)
798 log
->Update(_("That is not a valid name, try again.\n"));
803 Name
= Database
.Find("CD::" + ID
);
805 // Escape special characters
806 string::iterator J
= Name
.begin();
807 for (; J
!= Name
.end(); ++J
)
808 if (*J
== '"' || *J
== ']' || *J
== '[')
811 Database
.Set("CD::" + ID
,Name
);
815 strprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
817 log
->Update(_("Copying package lists..."), STEP_COPY
);
820 // check for existence and possibly create state directory for copying
821 string
const listDir
= _config
->FindDir("Dir::State::lists");
822 string
const partialListDir
= listDir
+ "partial/";
823 mode_t
const mode
= umask(S_IWGRP
| S_IWOTH
);
824 bool const creation_fail
= (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::State"), partialListDir
) == false &&
825 CreateAPTDirectoryIfNeeded(listDir
, partialListDir
) == false);
827 if (creation_fail
== true)
829 UnmountCDROM(CDROM
, NULL
);
830 return _error
->Errno("cdrom", _("List directory %spartial is missing."), listDir
.c_str());
833 // take care of the signatures and copy them if they are ok
834 // (we do this before PackageCopy as it modifies "List" and "SourceList")
835 SigVerify SignVerify
;
836 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
838 // Copy the package files to the state directory
841 TranslationsCopy TransCopy
;
842 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
843 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
844 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
846 UnmountCDROM(CDROM
, NULL
);
850 // reduce the List so that it takes less space in sources.list
851 ReduceSourcelist(CDROM
,List
);
852 ReduceSourcelist(CDROM
,SourceList
);
854 // Write the database and sourcelist
855 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
857 if (WriteDatabase(Database
) == false)
859 UnmountCDROM(CDROM
, NULL
);
864 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
865 if (WriteSourceList(Name
,List
,false) == false ||
866 WriteSourceList(Name
,SourceList
,true) == false)
868 UnmountCDROM(CDROM
, NULL
);
873 // Print the sourcelist entries
875 log
->Update(_("Source list entries for this disc are:\n"));
877 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
879 string::size_type Space
= (*I
).find(' ');
880 if (Space
== string::npos
)
882 UnmountCDROM(CDROM
, NULL
);
883 return _error
->Error("Internal error");
889 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
890 " " << string(*I
,Space
+1) << endl
;
891 log
->Update(msg
.str());
895 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
897 string::size_type Space
= (*I
).find(' ');
898 if (Space
== string::npos
)
900 UnmountCDROM(CDROM
, NULL
);
901 return _error
->Error("Internal error");
906 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
907 " " << string(*I
,Space
+1) << endl
;
908 log
->Update(msg
.str());
912 // Unmount and finish
913 UnmountCDROM(CDROM
, log
);
917 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
918 : d(NULL
), libudev_handle(NULL
), udev_new(NULL
), udev_enumerate_add_match_property(NULL
),
919 udev_enumerate_scan_devices(NULL
), udev_enumerate_get_list_entry(NULL
),
920 udev_device_new_from_syspath(NULL
), udev_enumerate_get_udev(NULL
),
921 udev_list_entry_get_name(NULL
), udev_device_get_devnode(NULL
),
922 udev_enumerate_new(NULL
), udev_list_entry_get_next(NULL
),
923 udev_device_get_property_value(NULL
), udev_enumerate_add_match_sysattr(NULL
)
928 bool 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");
957 // convenience interface, this will just call ScanForRemovable /*{{{*/
958 vector
<CdromDevice
> pkgUdevCdromDevices::Scan()
960 bool CdromOnly
= _config
->FindB("APT::cdrom::CdromOnly", true);
961 return ScanForRemovable(CdromOnly
);
964 vector
<CdromDevice
> pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly
)/*{{{*/
966 vector
<CdromDevice
> cdrom_devices
;
967 struct udev_enumerate
*enumerate
;
968 struct udev_list_entry
*l
, *devices
;
969 struct udev
*udev_ctx
;
971 if(libudev_handle
== NULL
)
972 return cdrom_devices
;
974 udev_ctx
= udev_new();
975 enumerate
= udev_enumerate_new (udev_ctx
);
977 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
979 udev_enumerate_add_match_sysattr(enumerate
, "removable", "1");
982 udev_enumerate_scan_devices (enumerate
);
983 devices
= udev_enumerate_get_list_entry (enumerate
);
984 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
987 struct udev_device
*udevice
;
988 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
991 const char* devnode
= udev_device_get_devnode(udevice
);
993 // try fstab_dir first
995 const char* mp
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
997 mountpath
= string(mp
);
999 mountpath
= FindMountPointForDevice(devnode
);
1001 // fill in the struct
1002 cdrom
.DeviceName
= string(devnode
);
1003 if (mountpath
!= "") {
1004 cdrom
.MountPath
= mountpath
;
1005 string s
= mountpath
;
1006 cdrom
.Mounted
= IsMounted(s
);
1008 cdrom
.Mounted
= false;
1009 cdrom
.MountPath
= "";
1011 cdrom_devices
.push_back(cdrom
);
1013 return cdrom_devices
;
1017 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
1019 if (libudev_handle
!= NULL
)
1020 dlclose(libudev_handle
);
1024 pkgCdromStatus::pkgCdromStatus() : d(NULL
), totalSteps(0) {}
1025 pkgCdromStatus::~pkgCdromStatus() {}
1027 pkgCdrom::pkgCdrom() : d(NULL
) {}
1028 pkgCdrom::~pkgCdrom() {}