5 #include<apt-pkg/init.h>
6 #include<apt-pkg/error.h>
7 #include<apt-pkg/cdromutl.h>
8 #include<apt-pkg/strutl.h>
9 #include<apt-pkg/cdrom.h>
10 #include<apt-pkg/aptconfiguration.h>
22 #include "indexcopy.h"
28 // FindPackages - Find the package files on the CDROM /*{{{*/
29 // ---------------------------------------------------------------------
30 /* We look over the cdrom for package files. This is a recursive
31 search that short circuits when it his a package file in the dir.
32 This speeds it up greatly as the majority of the size is in the
34 bool pkgCdrom::FindPackages(string CD
,
36 vector
<string
> &SList
,
37 vector
<string
> &SigList
,
38 vector
<string
> &TransList
,
39 string
&InfoDir
, pkgCdromStatus
*log
,
42 static ino_t Inodes
[9];
45 // if we have a look we "pulse" now
52 if (CD
[CD
.length()-1] != '/')
55 if (chdir(CD
.c_str()) != 0)
56 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
58 // Look for a .disk subdirectory
60 if (stat(".disk",&Buf
) == 0)
62 if (InfoDir
.empty() == true)
63 InfoDir
= CD
+ ".disk/";
66 // Don't look into directories that have been marked to ingore.
67 if (stat(".aptignr",&Buf
) == 0)
71 /* Check _first_ for a signature file as apt-cdrom assumes that all files
72 under a Packages/Source file are in control of that file and stops
75 if (stat("Release.gpg",&Buf
) == 0)
77 SigList
.push_back(CD
);
79 /* Aha! We found some package files. We assume that everything under
80 this dir is controlled by those package files so we don't look down
82 if (stat("Packages",&Buf
) == 0 || stat("Packages.gz",&Buf
) == 0)
86 // Continue down if thorough is given
87 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
90 if (stat("Sources.gz",&Buf
) == 0 || stat("Sources",&Buf
) == 0)
94 // Continue down if thorough is given
95 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
99 // see if we find translatin indexes
100 if (stat("i18n",&Buf
) == 0)
103 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
105 if(strstr(Dir
->d_name
,"Translation") != NULL
)
107 if (_config
->FindB("Debug::aptcdrom",false) == true)
108 std::clog
<< "found translations: " << Dir
->d_name
<< "\n";
109 string file
= Dir
->d_name
;
110 if(file
.substr(file
.size()-3,file
.size()) == ".gz")
111 file
= file
.substr(0,file
.size()-3);
112 TransList
.push_back(CD
+"i18n/"+ file
);
121 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
123 // Run over the directory
124 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
127 if (strcmp(Dir
->d_name
,".") == 0 ||
128 strcmp(Dir
->d_name
,"..") == 0 ||
129 //strcmp(Dir->d_name,"source") == 0 ||
130 strcmp(Dir
->d_name
,".disk") == 0 ||
131 strcmp(Dir
->d_name
,"experimental") == 0 ||
132 strcmp(Dir
->d_name
,"binary-all") == 0 ||
133 strcmp(Dir
->d_name
,"debian-installer") == 0)
136 // See if the name is a sub directory
138 if (stat(Dir
->d_name
,&Buf
) != 0)
141 if (S_ISDIR(Buf
.st_mode
) == 0)
145 for (I
= 0; I
!= Depth
; I
++)
146 if (Inodes
[I
] == Buf
.st_ino
)
151 // Store the inodes weve seen
152 Inodes
[Depth
] = Buf
.st_ino
;
155 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
158 if (chdir(CD
.c_str()) != 0)
160 _error
->Errno("chdir","Unable to change to %s", CD
.c_str());
168 return !_error
->PendingError();
171 // Score - We compute a 'score' for a path /*{{{*/
172 // ---------------------------------------------------------------------
173 /* Paths are scored based on how close they come to what I consider
174 normal. That is ones that have 'dist' 'stable' 'testing' will score
175 higher than ones without. */
176 int pkgCdrom::Score(string Path
)
179 if (Path
.find("stable/") != string::npos
)
181 if (Path
.find("/binary-") != string::npos
)
183 if (Path
.find("testing/") != string::npos
)
185 if (Path
.find("unstable/") != string::npos
)
187 if (Path
.find("/dists/") != string::npos
)
189 if (Path
.find("/main/") != string::npos
)
191 if (Path
.find("/contrib/") != string::npos
)
193 if (Path
.find("/non-free/") != string::npos
)
195 if (Path
.find("/non-US/") != string::npos
)
197 if (Path
.find("/source/") != string::npos
)
199 if (Path
.find("/debian/") != string::npos
)
202 // check for symlinks in the patch leading to the actual file
203 // a symlink gets a big penalty
205 string statPath
= flNotFile(Path
);
206 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount");
207 while(statPath
!= cdromPath
&& statPath
!= "./") {
208 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
209 if (lstat(statPath
.c_str(),&Buf
) == 0) {
210 if(S_ISLNK(Buf
.st_mode
)) {
215 statPath
= flNotFile(statPath
); // descent
221 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
222 // ---------------------------------------------------------------------
223 /* Here we drop everything that is not this machines arch */
224 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
227 for (unsigned int I
= 0; I
< List
.size(); I
++)
229 const char *Str
= List
[I
].c_str();
230 const char *Start
, *End
;
231 if ((Start
= strstr(Str
,"/binary-")) == 0)
234 // Between Start and End is the architecture
236 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
237 APT::Configuration::checkArchitecture(string(Start
, End
)) == true)
238 continue; // okay, architecture is accepted
240 // not accepted -> Erase it
241 List
.erase(List
.begin() + I
);
242 --I
; // the next entry is at the same index after the erase
248 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
249 // ---------------------------------------------------------------------
250 /* Here we go and stat every file that we found and strip dup inodes. */
251 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
253 // Get a list of all the inodes
254 ino_t
*Inodes
= new ino_t
[List
.size()];
255 for (unsigned int I
= 0; I
!= List
.size(); I
++)
258 if (stat((List
[I
] + Name
).c_str(),&Buf
) != 0 &&
259 stat((List
[I
] + Name
+ ".gz").c_str(),&Buf
) != 0)
260 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(),
262 Inodes
[I
] = Buf
.st_ino
;
265 if (_error
->PendingError() == true) {
271 for (unsigned int I
= 0; I
!= List
.size(); I
++)
273 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
276 if (Inodes
[J
] != Inodes
[I
])
279 // We score the two paths.. and erase one
280 int ScoreA
= Score(List
[I
]);
281 int ScoreB
= Score(List
[J
]);
293 // Wipe erased entries
294 for (unsigned int I
= 0; I
< List
.size();)
296 if (List
[I
].empty() == false)
299 List
.erase(List
.begin()+I
);
305 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
306 // ---------------------------------------------------------------------
307 /* This takes the list of source list expressed entires and collects
308 similar ones to form a single entry for each dist */
309 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
)
311 sort(List
.begin(),List
.end());
313 // Collect similar entries
314 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
317 string::size_type Space
= (*I
).find(' ');
318 if (Space
== string::npos
)
320 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
321 if (SSpace
== string::npos
)
324 string Word1
= string(*I
,Space
,SSpace
-Space
);
325 string Prefix
= string(*I
,0,Space
);
326 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; ++J
)
329 string::size_type Space2
= (*J
).find(' ');
330 if (Space2
== string::npos
)
332 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
333 if (SSpace2
== string::npos
)
336 if (string(*J
,0,Space2
) != Prefix
)
338 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
341 *J
+= string(*I
,SSpace
);
346 // Wipe erased entries
347 for (unsigned int I
= 0; I
< List
.size();)
349 if (List
[I
].empty() == false)
352 List
.erase(List
.begin()+I
);
356 // WriteDatabase - Write the CDROM Database file /*{{{*/
357 // ---------------------------------------------------------------------
358 /* We rewrite the configuration class associated with the cdrom database. */
359 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
361 string DFile
= _config
->FindFile("Dir::State::cdroms");
362 string NewFile
= DFile
+ ".new";
364 unlink(NewFile
.c_str());
365 ofstream
Out(NewFile
.c_str());
367 return _error
->Errno("ofstream::ofstream",
368 "Failed to open %s.new",DFile
.c_str());
370 /* Write out all of the configuration directives by walking the
371 configuration tree */
372 const Configuration::Item
*Top
= Cnf
.Tree(0);
375 // Print the config entry
376 if (Top
->Value
.empty() == false)
377 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
385 while (Top
!= 0 && Top
->Next
== 0)
393 link(DFile
.c_str(),string(DFile
+ '~').c_str());
394 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
395 return _error
->Errno("rename","Failed to rename %s.new to %s",
396 DFile
.c_str(),DFile
.c_str());
401 // WriteSourceList - Write an updated sourcelist /*{{{*/
402 // ---------------------------------------------------------------------
403 /* This reads the old source list and copies it into the new one. It
404 appends the new CDROM entires just after the first block of comments.
405 This places them first in the file. It also removes any old entries
406 that were the same. */
407 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
409 if (List
.empty() == true)
412 string File
= _config
->FindFile("Dir::Etc::sourcelist");
414 // Open the stream for reading
415 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
418 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
420 string NewFile
= File
+ ".new";
421 unlink(NewFile
.c_str());
422 ofstream
Out(NewFile
.c_str());
424 return _error
->Errno("ofstream::ofstream",
425 "Failed to open %s.new",File
.c_str());
427 // Create a short uri without the path
428 string ShortURI
= "cdrom:[" + Name
+ "]/";
429 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
440 while (F
.eof() == false)
442 F
.getline(Buffer
,sizeof(Buffer
));
444 if (F
.fail() && !F
.eof())
445 return _error
->Error(_("Line %u too long in source list %s."),
446 CurLine
,File
.c_str());
447 _strtabexpand(Buffer
,sizeof(Buffer
));
451 if (Buffer
[0] == '#' || Buffer
[0] == 0)
453 Out
<< Buffer
<< endl
;
459 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
461 string::size_type Space
= (*I
).find(' ');
462 if (Space
== string::npos
)
463 return _error
->Error("Internal error");
464 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
465 " " << string(*I
,Space
+1) << endl
;
473 const char *C
= Buffer
;
474 if (ParseQuoteWord(C
,cType
) == false ||
475 ParseQuoteWord(C
,URI
) == false)
477 Out
<< Buffer
<< endl
;
481 // Emit lines like this one
482 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
483 string(URI
,0,ShortURI
.length()) != ShortURI2
))
485 Out
<< Buffer
<< endl
;
490 // Just in case the file was empty
493 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
495 string::size_type Space
= (*I
).find(' ');
496 if (Space
== string::npos
)
497 return _error
->Error("Internal error");
499 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
500 " " << string(*I
,Space
+1) << endl
;
506 rename(File
.c_str(),string(File
+ '~').c_str());
507 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
508 return _error
->Errno("rename","Failed to rename %s.new to %s",
509 File
.c_str(),File
.c_str());
514 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
519 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
521 CDROM
= SafeGetCWD() + '/' + CDROM
;
526 ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
528 log
->Update(msg
.str());
530 if (MountCdrom(CDROM
) == false)
531 return _error
->Error("Failed to mount the cdrom.");
533 // Hash the CD to get an ID
535 log
->Update(_("Identifying.. "));
538 if (IdentCdrom(CDROM
,ident
) == false)
547 ioprintf(msg
, "[%s]\n",ident
.c_str());
548 log
->Update(msg
.str());
552 Configuration Database
;
553 string DFile
= _config
->FindFile("Dir::State::cdroms");
554 if (FileExists(DFile
) == true)
556 if (ReadConfigFile(Database
,DFile
) == false)
557 return _error
->Error("Unable to read the cdrom database %s",
563 ioprintf(msg
, _("Stored label: %s\n"),
564 Database
.Find("CD::"+ident
).c_str());
565 log
->Update(msg
.str());
568 // Unmount and finish
569 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
572 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
579 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
584 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
586 CDROM
= SafeGetCWD() + '/' + CDROM
;
590 log
->SetTotal(STEP_LAST
);
592 ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
593 log
->Update(msg
.str(), STEP_PREPARE
);
597 Configuration Database
;
598 string DFile
= _config
->FindFile("Dir::State::cdroms");
599 if (FileExists(DFile
) == true)
601 if (ReadConfigFile(Database
,DFile
) == false)
602 return _error
->Error("Unable to read the cdrom database %s",
606 // Unmount the CD and get the user to put in the one they want
607 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
610 log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
);
615 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
616 if(!log
->ChangeCdrom()) {
622 // Mount the new CDROM
624 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
626 if (MountCdrom(CDROM
) == false)
627 return _error
->Error("Failed to mount the cdrom.");
630 // Hash the CD to get an ID
632 log
->Update(_("Identifying.. "), STEP_IDENT
);
634 if (IdentCdrom(CDROM
,ID
) == false)
642 log
->Update("["+ID
+"]\n");
643 log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
);
646 // Get the CD structure
648 vector
<string
> SourceList
;
649 vector
<string
> SigList
;
650 vector
<string
> TransList
;
651 string StartDir
= SafeGetCWD();
653 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
660 chdir(StartDir
.c_str());
662 if (_config
->FindB("Debug::aptcdrom",false) == true)
664 cout
<< "I found (binary):" << endl
;
665 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
667 cout
<< "I found (source):" << endl
;
668 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
670 cout
<< "I found (Signatures):" << endl
;
671 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
675 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
678 DropBinaryArch(List
);
679 DropRepeats(List
,"Packages");
680 DropRepeats(SourceList
,"Sources");
681 DropRepeats(SigList
,"Release.gpg");
682 DropRepeats(TransList
,"");
685 ioprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
686 "%zu translation indexes and %zu signatures\n"),
687 List
.size(), SourceList
.size(), TransList
.size(),
689 log
->Update(msg
.str(), STEP_SCAN
);
692 if (List
.empty() == true && SourceList
.empty() == true)
694 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
696 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
699 // Check if the CD is in the database
701 if (Database
.Exists("CD::" + ID
) == false ||
702 _config
->FindB("APT::CDROM::Rename",false) == true)
704 // Try to use the CDs label if at all possible
705 if (InfoDir
.empty() == false &&
706 FileExists(InfoDir
+ "/info") == true)
708 ifstream
F(string(InfoDir
+ "/info").c_str());
712 if (Name
.empty() == false)
714 // Escape special characters
715 string::iterator J
= Name
.begin();
716 for (; J
!= Name
.end(); ++J
)
717 if (*J
== '"' || *J
== ']' || *J
== '[')
723 ioprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
724 log
->Update(msg
.str());
726 Database
.Set("CD::" + ID
+ "::Label",Name
);
730 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
731 Name
.empty() == true)
735 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
737 return _error
->Error("No disc name found and no way to ask for it");
741 if(!log
->AskCdromName(Name
)) {
745 cout
<< "Name: '" << Name
<< "'" << endl
;
747 if (Name
.empty() == false &&
748 Name
.find('"') == string::npos
&&
749 Name
.find('[') == string::npos
&&
750 Name
.find(']') == string::npos
)
752 log
->Update(_("That is not a valid name, try again.\n"));
757 Name
= Database
.Find("CD::" + ID
);
759 // Escape special characters
760 string::iterator J
= Name
.begin();
761 for (; J
!= Name
.end(); ++J
)
762 if (*J
== '"' || *J
== ']' || *J
== '[')
765 Database
.Set("CD::" + ID
,Name
);
769 ioprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
770 log
->Update(msg
.str());
771 log
->Update(_("Copying package lists..."), STEP_COPY
);
773 // take care of the signatures and copy them if they are ok
774 // (we do this before PackageCopy as it modifies "List" and "SourceList")
775 SigVerify SignVerify
;
776 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
778 // Copy the package files to the state directory
781 TranslationsCopy TransCopy
;
782 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
783 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
784 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
787 // reduce the List so that it takes less space in sources.list
788 ReduceSourcelist(CDROM
,List
);
789 ReduceSourcelist(CDROM
,SourceList
);
791 // Write the database and sourcelist
792 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
794 if (WriteDatabase(Database
) == false)
798 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
799 if (WriteSourceList(Name
,List
,false) == false ||
800 WriteSourceList(Name
,SourceList
,true) == false)
804 // Print the sourcelist entries
806 log
->Update(_("Source list entries for this disc are:\n"));
808 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
810 string::size_type Space
= (*I
).find(' ');
811 if (Space
== string::npos
)
813 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
815 return _error
->Error("Internal error");
821 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
822 " " << string(*I
,Space
+1) << endl
;
823 log
->Update(msg
.str());
827 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
829 string::size_type Space
= (*I
).find(' ');
830 if (Space
== string::npos
)
832 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
834 return _error
->Error("Internal error");
839 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
840 " " << string(*I
,Space
+1) << endl
;
841 log
->Update(msg
.str());
845 // Unmount and finish
846 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
848 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
855 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
856 : libudev_handle(NULL
)
863 pkgUdevCdromDevices::Dlopen() /*{{{*/
866 if(libudev_handle
!= NULL
)
869 // see if we can get libudev
870 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
874 // get the pointers to the udev structs
876 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
877 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
878 udev_enumerate_add_match_sysattr
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_sysattr");
879 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
880 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
881 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
882 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
883 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
884 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
885 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
886 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
887 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
893 // convenience interface, this will just call ScanForRemovable
895 pkgUdevCdromDevices::Scan()
897 bool CdromOnly
= _config
->FindB("APT::cdrom::CdromOnly", true);
898 return ScanForRemovable(CdromOnly
);
903 pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly
)
905 vector
<CdromDevice
> cdrom_devices
;
906 struct udev_enumerate
*enumerate
;
907 struct udev_list_entry
*l
, *devices
;
908 struct udev
*udev_ctx
;
910 if(libudev_handle
== NULL
)
911 return cdrom_devices
;
913 udev_ctx
= udev_new();
914 enumerate
= udev_enumerate_new (udev_ctx
);
916 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
918 udev_enumerate_add_match_sysattr(enumerate
, "removable", "1");
921 udev_enumerate_scan_devices (enumerate
);
922 devices
= udev_enumerate_get_list_entry (enumerate
);
923 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
926 struct udev_device
*udevice
;
927 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
930 const char* devnode
= udev_device_get_devnode(udevice
);
932 // try fstab_dir first
934 const char* mp
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
936 mountpath
= string(mp
);
938 mountpath
= FindMountPointForDevice(devnode
);
940 // fill in the struct
941 cdrom
.DeviceName
= string(devnode
);
942 if (mountpath
!= "") {
943 cdrom
.MountPath
= mountpath
;
944 string s
= string(mountpath
);
945 cdrom
.Mounted
= IsMounted(s
);
947 cdrom
.Mounted
= false;
948 cdrom
.MountPath
= "";
950 cdrom_devices
.push_back(cdrom
);
952 return cdrom_devices
;
956 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
958 if (libudev_handle
!= NULL
)
959 dlclose(libudev_handle
);