4 #include<apt-pkg/init.h>
5 #include<apt-pkg/error.h>
6 #include<apt-pkg/cdromutl.h>
7 #include<apt-pkg/strutl.h>
8 #include<apt-pkg/cdrom.h>
9 #include<apt-pkg/aptconfiguration.h>
23 #include "indexcopy.h"
27 // FindPackages - Find the package files on the CDROM /*{{{*/
28 // ---------------------------------------------------------------------
29 /* We look over the cdrom for package files. This is a recursive
30 search that short circuits when it his a package file in the dir.
31 This speeds it up greatly as the majority of the size is in the
33 bool pkgCdrom::FindPackages(string CD
,
35 vector
<string
> &SList
,
36 vector
<string
> &SigList
,
37 vector
<string
> &TransList
,
38 string
&InfoDir
, pkgCdromStatus
*log
,
41 static ino_t Inodes
[9];
44 // if we have a look we "pulse" now
51 if (CD
[CD
.length()-1] != '/')
54 if (chdir(CD
.c_str()) != 0)
55 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
57 // Look for a .disk subdirectory
59 if (stat(".disk",&Buf
) == 0)
61 if (InfoDir
.empty() == true)
62 InfoDir
= CD
+ ".disk/";
65 // Don't look into directories that have been marked to ingore.
66 if (stat(".aptignr",&Buf
) == 0)
70 /* Check _first_ for a signature file as apt-cdrom assumes that all files
71 under a Packages/Source file are in control of that file and stops
74 if (stat("Release.gpg",&Buf
) == 0)
76 SigList
.push_back(CD
);
78 /* Aha! We found some package files. We assume that everything under
79 this dir is controlled by those package files so we don't look down
81 if (stat("Packages",&Buf
) == 0 || stat("Packages.gz",&Buf
) == 0)
85 // Continue down if thorough is given
86 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
89 if (stat("Sources.gz",&Buf
) == 0 || stat("Sources",&Buf
) == 0)
93 // Continue down if thorough is given
94 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
98 // see if we find translatin indexes
99 if (stat("i18n",&Buf
) == 0)
102 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
104 if(strstr(Dir
->d_name
,"Translation") != NULL
)
106 if (_config
->FindB("Debug::aptcdrom",false) == true)
107 std::clog
<< "found translations: " << Dir
->d_name
<< "\n";
108 string file
= Dir
->d_name
;
109 if(file
.substr(file
.size()-3,file
.size()) == ".gz")
110 file
= file
.substr(0,file
.size()-3);
111 TransList
.push_back(CD
+"i18n/"+ file
);
120 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
122 // Run over the directory
123 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
126 if (strcmp(Dir
->d_name
,".") == 0 ||
127 strcmp(Dir
->d_name
,"..") == 0 ||
128 //strcmp(Dir->d_name,"source") == 0 ||
129 strcmp(Dir
->d_name
,".disk") == 0 ||
130 strcmp(Dir
->d_name
,"experimental") == 0 ||
131 strcmp(Dir
->d_name
,"binary-all") == 0 ||
132 strcmp(Dir
->d_name
,"debian-installer") == 0)
135 // See if the name is a sub directory
137 if (stat(Dir
->d_name
,&Buf
) != 0)
140 if (S_ISDIR(Buf
.st_mode
) == 0)
144 for (I
= 0; I
!= Depth
; I
++)
145 if (Inodes
[I
] == Buf
.st_ino
)
150 // Store the inodes weve seen
151 Inodes
[Depth
] = Buf
.st_ino
;
154 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
157 if (chdir(CD
.c_str()) != 0)
159 _error
->Errno("chdir","Unable to change to %s", CD
.c_str());
167 return !_error
->PendingError();
170 // Score - We compute a 'score' for a path /*{{{*/
171 // ---------------------------------------------------------------------
172 /* Paths are scored based on how close they come to what I consider
173 normal. That is ones that have 'dist' 'stable' 'testing' will score
174 higher than ones without. */
175 int pkgCdrom::Score(string Path
)
178 if (Path
.find("stable/") != string::npos
)
180 if (Path
.find("/binary-") != string::npos
)
182 if (Path
.find("testing/") != string::npos
)
184 if (Path
.find("unstable/") != string::npos
)
186 if (Path
.find("/dists/") != string::npos
)
188 if (Path
.find("/main/") != string::npos
)
190 if (Path
.find("/contrib/") != string::npos
)
192 if (Path
.find("/non-free/") != string::npos
)
194 if (Path
.find("/non-US/") != string::npos
)
196 if (Path
.find("/source/") != string::npos
)
198 if (Path
.find("/debian/") != string::npos
)
201 // check for symlinks in the patch leading to the actual file
202 // a symlink gets a big penalty
204 string statPath
= flNotFile(Path
);
205 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount");
206 while(statPath
!= cdromPath
&& statPath
!= "./") {
207 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
208 if (lstat(statPath
.c_str(),&Buf
) == 0) {
209 if(S_ISLNK(Buf
.st_mode
)) {
214 statPath
= flNotFile(statPath
); // descent
220 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
221 // ---------------------------------------------------------------------
222 /* Here we drop everything that is not this machines arch */
223 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
226 for (unsigned int I
= 0; I
< List
.size(); I
++)
228 const char *Str
= List
[I
].c_str();
229 const char *Start
, *End
;
230 if ((Start
= strstr(Str
,"/binary-")) == 0)
233 // Between Start and End is the architecture
235 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
236 APT::Configuration::checkArchitecture(string(Start
, End
)) == true)
237 continue; // okay, architecture is accepted
239 // not accepted -> Erase it
240 List
.erase(List
.begin() + I
);
241 --I
; // the next entry is at the same index after the erase
247 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
248 // ---------------------------------------------------------------------
249 /* Here we go and stat every file that we found and strip dup inodes. */
250 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
252 // Get a list of all the inodes
253 ino_t
*Inodes
= new ino_t
[List
.size()];
254 for (unsigned int I
= 0; I
!= List
.size(); I
++)
257 if (stat((List
[I
] + Name
).c_str(),&Buf
) != 0 &&
258 stat((List
[I
] + Name
+ ".gz").c_str(),&Buf
) != 0)
259 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(),
261 Inodes
[I
] = Buf
.st_ino
;
264 if (_error
->PendingError() == true) {
270 for (unsigned int I
= 0; I
!= List
.size(); I
++)
272 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
275 if (Inodes
[J
] != Inodes
[I
])
278 // We score the two paths.. and erase one
279 int ScoreA
= Score(List
[I
]);
280 int ScoreB
= Score(List
[J
]);
292 // Wipe erased entries
293 for (unsigned int I
= 0; I
< List
.size();)
295 if (List
[I
].empty() == false)
298 List
.erase(List
.begin()+I
);
304 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
305 // ---------------------------------------------------------------------
306 /* This takes the list of source list expressed entires and collects
307 similar ones to form a single entry for each dist */
308 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
)
310 sort(List
.begin(),List
.end());
312 // Collect similar entries
313 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
316 string::size_type Space
= (*I
).find(' ');
317 if (Space
== string::npos
)
319 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
320 if (SSpace
== string::npos
)
323 string Word1
= string(*I
,Space
,SSpace
-Space
);
324 string Prefix
= string(*I
,0,Space
);
325 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
328 string::size_type Space2
= (*J
).find(' ');
329 if (Space2
== string::npos
)
331 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
332 if (SSpace2
== string::npos
)
335 if (string(*J
,0,Space2
) != Prefix
)
337 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
340 *J
+= string(*I
,SSpace
);
345 // Wipe erased entries
346 for (unsigned int I
= 0; I
< List
.size();)
348 if (List
[I
].empty() == false)
351 List
.erase(List
.begin()+I
);
355 // WriteDatabase - Write the CDROM Database file /*{{{*/
356 // ---------------------------------------------------------------------
357 /* We rewrite the configuration class associated with the cdrom database. */
358 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
360 string DFile
= _config
->FindFile("Dir::State::cdroms");
361 string NewFile
= DFile
+ ".new";
363 unlink(NewFile
.c_str());
364 ofstream
Out(NewFile
.c_str());
366 return _error
->Errno("ofstream::ofstream",
367 "Failed to open %s.new",DFile
.c_str());
369 /* Write out all of the configuration directives by walking the
370 configuration tree */
371 const Configuration::Item
*Top
= Cnf
.Tree(0);
374 // Print the config entry
375 if (Top
->Value
.empty() == false)
376 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
384 while (Top
!= 0 && Top
->Next
== 0)
392 link(DFile
.c_str(),string(DFile
+ '~').c_str());
393 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
394 return _error
->Errno("rename","Failed to rename %s.new to %s",
395 DFile
.c_str(),DFile
.c_str());
400 // WriteSourceList - Write an updated sourcelist /*{{{*/
401 // ---------------------------------------------------------------------
402 /* This reads the old source list and copies it into the new one. It
403 appends the new CDROM entires just after the first block of comments.
404 This places them first in the file. It also removes any old entries
405 that were the same. */
406 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
408 if (List
.size() == 0)
411 string File
= _config
->FindFile("Dir::Etc::sourcelist");
413 // Open the stream for reading
414 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
417 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
419 string NewFile
= File
+ ".new";
420 unlink(NewFile
.c_str());
421 ofstream
Out(NewFile
.c_str());
423 return _error
->Errno("ofstream::ofstream",
424 "Failed to open %s.new",File
.c_str());
426 // Create a short uri without the path
427 string ShortURI
= "cdrom:[" + Name
+ "]/";
428 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
439 while (F
.eof() == false)
441 F
.getline(Buffer
,sizeof(Buffer
));
443 if (F
.fail() && !F
.eof())
444 return _error
->Error(_("Line %u too long in source list %s."),
445 CurLine
,File
.c_str());
446 _strtabexpand(Buffer
,sizeof(Buffer
));
450 if (Buffer
[0] == '#' || Buffer
[0] == 0)
452 Out
<< Buffer
<< endl
;
458 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
460 string::size_type Space
= (*I
).find(' ');
461 if (Space
== string::npos
)
462 return _error
->Error("Internal error");
463 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
464 " " << string(*I
,Space
+1) << endl
;
472 const char *C
= Buffer
;
473 if (ParseQuoteWord(C
,cType
) == false ||
474 ParseQuoteWord(C
,URI
) == false)
476 Out
<< Buffer
<< endl
;
480 // Emit lines like this one
481 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
482 string(URI
,0,ShortURI
.length()) != ShortURI2
))
484 Out
<< Buffer
<< endl
;
489 // Just in case the file was empty
492 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
494 string::size_type Space
= (*I
).find(' ');
495 if (Space
== string::npos
)
496 return _error
->Error("Internal error");
498 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
499 " " << string(*I
,Space
+1) << endl
;
505 rename(File
.c_str(),string(File
+ '~').c_str());
506 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
507 return _error
->Errno("rename","Failed to rename %s.new to %s",
508 File
.c_str(),File
.c_str());
513 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
518 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
520 CDROM
= SafeGetCWD() + '/' + CDROM
;
525 ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
527 log
->Update(msg
.str());
529 if (MountCdrom(CDROM
) == false)
530 return _error
->Error("Failed to mount the cdrom.");
532 // Hash the CD to get an ID
534 log
->Update(_("Identifying.. "));
537 if (IdentCdrom(CDROM
,ident
) == false)
546 ioprintf(msg
, "[%s]\n",ident
.c_str());
547 log
->Update(msg
.str());
551 Configuration Database
;
552 string DFile
= _config
->FindFile("Dir::State::cdroms");
553 if (FileExists(DFile
) == true)
555 if (ReadConfigFile(Database
,DFile
) == false)
556 return _error
->Error("Unable to read the cdrom database %s",
562 ioprintf(msg
, _("Stored label: %s\n"),
563 Database
.Find("CD::"+ident
).c_str());
564 log
->Update(msg
.str());
567 // Unmount and finish
568 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
571 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
578 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
583 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
585 CDROM
= SafeGetCWD() + '/' + CDROM
;
589 log
->SetTotal(STEP_LAST
);
591 ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
592 log
->Update(msg
.str(), STEP_PREPARE
);
596 Configuration Database
;
597 string DFile
= _config
->FindFile("Dir::State::cdroms");
598 if (FileExists(DFile
) == true)
600 if (ReadConfigFile(Database
,DFile
) == false)
601 return _error
->Error("Unable to read the cdrom database %s",
605 // Unmount the CD and get the user to put in the one they want
606 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
609 log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
);
614 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
615 if(!log
->ChangeCdrom()) {
621 // Mount the new CDROM
623 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
625 if (MountCdrom(CDROM
) == false)
626 return _error
->Error("Failed to mount the cdrom.");
629 // Hash the CD to get an ID
631 log
->Update(_("Identifying.. "), STEP_IDENT
);
633 if (IdentCdrom(CDROM
,ID
) == false)
641 log
->Update("["+ID
+"]\n");
642 log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
);
645 // Get the CD structure
647 vector
<string
> SourceList
;
648 vector
<string
> SigList
;
649 vector
<string
> TransList
;
650 string StartDir
= SafeGetCWD();
652 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
659 chdir(StartDir
.c_str());
661 if (_config
->FindB("Debug::aptcdrom",false) == true)
663 cout
<< "I found (binary):" << endl
;
664 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
666 cout
<< "I found (source):" << endl
;
667 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); I
++)
669 cout
<< "I found (Signatures):" << endl
;
670 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); I
++)
674 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
677 DropBinaryArch(List
);
678 DropRepeats(List
,"Packages");
679 DropRepeats(SourceList
,"Sources");
680 DropRepeats(SigList
,"Release.gpg");
681 DropRepeats(TransList
,"");
684 ioprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
685 "%zu translation indexes and %zu signatures\n"),
686 List
.size(), SourceList
.size(), TransList
.size(),
688 log
->Update(msg
.str(), STEP_SCAN
);
691 if (List
.size() == 0 && SourceList
.size() == 0)
693 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
695 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
698 // Check if the CD is in the database
700 if (Database
.Exists("CD::" + ID
) == false ||
701 _config
->FindB("APT::CDROM::Rename",false) == true)
703 // Try to use the CDs label if at all possible
704 if (InfoDir
.empty() == false &&
705 FileExists(InfoDir
+ "/info") == true)
707 ifstream
F(string(InfoDir
+ "/info").c_str());
711 if (Name
.empty() == false)
713 // Escape special characters
714 string::iterator J
= Name
.begin();
715 for (; J
!= Name
.end(); J
++)
716 if (*J
== '"' || *J
== ']' || *J
== '[')
722 ioprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
723 log
->Update(msg
.str());
725 Database
.Set("CD::" + ID
+ "::Label",Name
);
729 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
730 Name
.empty() == true)
734 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
736 return _error
->Error("No disc name found and no way to ask for it");
740 if(!log
->AskCdromName(Name
)) {
744 cout
<< "Name: '" << Name
<< "'" << endl
;
746 if (Name
.empty() == false &&
747 Name
.find('"') == string::npos
&&
748 Name
.find('[') == string::npos
&&
749 Name
.find(']') == string::npos
)
751 log
->Update(_("That is not a valid name, try again.\n"));
756 Name
= Database
.Find("CD::" + ID
);
758 // Escape special characters
759 string::iterator J
= Name
.begin();
760 for (; J
!= Name
.end(); J
++)
761 if (*J
== '"' || *J
== ']' || *J
== '[')
764 Database
.Set("CD::" + ID
,Name
);
768 ioprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
769 log
->Update(msg
.str());
770 log
->Update(_("Copying package lists..."), STEP_COPY
);
772 // take care of the signatures and copy them if they are ok
773 // (we do this before PackageCopy as it modifies "List" and "SourceList")
774 SigVerify SignVerify
;
775 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
777 // Copy the package files to the state directory
780 TranslationsCopy TransCopy
;
781 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
782 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
783 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
786 // reduce the List so that it takes less space in sources.list
787 ReduceSourcelist(CDROM
,List
);
788 ReduceSourcelist(CDROM
,SourceList
);
790 // Write the database and sourcelist
791 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
793 if (WriteDatabase(Database
) == false)
797 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
798 if (WriteSourceList(Name
,List
,false) == false ||
799 WriteSourceList(Name
,SourceList
,true) == false)
803 // Print the sourcelist entries
805 log
->Update(_("Source list entries for this disc are:\n"));
807 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
809 string::size_type Space
= (*I
).find(' ');
810 if (Space
== string::npos
)
812 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
814 return _error
->Error("Internal error");
820 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
821 " " << string(*I
,Space
+1) << endl
;
822 log
->Update(msg
.str());
826 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); I
++)
828 string::size_type Space
= (*I
).find(' ');
829 if (Space
== string::npos
)
831 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
833 return _error
->Error("Internal error");
838 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
839 " " << string(*I
,Space
+1) << endl
;
840 log
->Update(msg
.str());
844 // Unmount and finish
845 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
847 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
854 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
855 : libudev_handle(NULL
)
862 pkgUdevCdromDevices::Dlopen() /*{{{*/
865 if(libudev_handle
!= NULL
)
868 // see if we can get libudev
869 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
873 // get the pointers to the udev structs
875 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
876 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
877 udev_enumerate_add_match_sysattr
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_sysattr");
878 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
879 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
880 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
881 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
882 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
883 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
884 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
885 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
886 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
892 // convenience interface, this will just call ScanForRemovable
894 pkgUdevCdromDevices::Scan()
896 bool CdromOnly
= _config
->FindB("APT::cdrom::CdromOnly", true);
897 return ScanForRemovable(CdromOnly
);
902 pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly
)
904 vector
<CdromDevice
> cdrom_devices
;
905 struct udev_enumerate
*enumerate
;
906 struct udev_list_entry
*l
, *devices
;
907 struct udev
*udev_ctx
;
909 if(libudev_handle
== NULL
)
910 return cdrom_devices
;
912 udev_ctx
= udev_new();
913 enumerate
= udev_enumerate_new (udev_ctx
);
915 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
917 udev_enumerate_add_match_sysattr(enumerate
, "removable", "1");
920 udev_enumerate_scan_devices (enumerate
);
921 devices
= udev_enumerate_get_list_entry (enumerate
);
922 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
925 struct udev_device
*udevice
;
926 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
929 const char* devnode
= udev_device_get_devnode(udevice
);
931 // try fstab_dir first
933 const char* mp
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
935 mountpath
= string(mp
);
937 mountpath
= FindMountPointForDevice(devnode
);
939 // fill in the struct
940 cdrom
.DeviceName
= string(devnode
);
941 if (mountpath
!= "") {
942 cdrom
.MountPath
= mountpath
;
943 string s
= string(mountpath
);
944 cdrom
.Mounted
= IsMounted(s
);
946 cdrom
.Mounted
= false;
947 cdrom
.MountPath
= "";
949 cdrom_devices
.push_back(cdrom
);
951 return cdrom_devices
;
955 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
957 if (libudev_handle
!= NULL
)
958 dlclose(libudev_handle
);