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>
11 #include<apt-pkg/configuration.h>
12 #include<apt-pkg/fileutl.h>
24 #include "indexcopy.h"
30 // FindPackages - Find the package files on the CDROM /*{{{*/
31 // ---------------------------------------------------------------------
32 /* We look over the cdrom for package files. This is a recursive
33 search that short circuits when it his a package file in the dir.
34 This speeds it up greatly as the majority of the size is in the
36 bool pkgCdrom::FindPackages(string CD
,
38 vector
<string
> &SList
,
39 vector
<string
> &SigList
,
40 vector
<string
> &TransList
,
41 string
&InfoDir
, pkgCdromStatus
*log
,
44 static ino_t Inodes
[9];
47 // if we have a look we "pulse" now
54 if (CD
[CD
.length()-1] != '/')
57 if (chdir(CD
.c_str()) != 0)
58 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
60 // Look for a .disk subdirectory
61 if (DirectoryExists(".disk") == true)
63 if (InfoDir
.empty() == true)
64 InfoDir
= CD
+ ".disk/";
67 // Don't look into directories that have been marked to ingore.
68 if (RealFileExists(".aptignr") == true)
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 (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
77 SigList
.push_back(CD
);
80 /* Aha! We found some package files. We assume that everything under
81 this dir is controlled by those package files so we don't look down
83 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
84 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
85 c
!= compressor
.end(); ++c
)
87 if (RealFileExists(std::string("Packages").append(c
->Extension
).c_str()) == false)
90 if (_config
->FindB("Debug::aptcdrom",false) == true)
91 std::clog
<< "Found Packages in " << CD
<< std::endl
;
94 // Continue down if thorough is given
95 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
99 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
100 c
!= compressor
.end(); ++c
)
102 if (RealFileExists(std::string("Sources").append(c
->Extension
).c_str()) == false)
105 if (_config
->FindB("Debug::aptcdrom",false) == true)
106 std::clog
<< "Found Sources in " << CD
<< std::endl
;
109 // Continue down if thorough is given
110 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
115 // see if we find translation indices
116 if (DirectoryExists("i18n") == true)
119 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
121 if(strncmp(Dir
->d_name
, "Translation-", strlen("Translation-")) != 0)
123 string file
= Dir
->d_name
;
124 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
125 c
!= compressor
.end(); ++c
)
127 string fileext
= flExtension(file
);
130 else if (fileext
.empty() == false)
131 fileext
= "." + fileext
;
133 if (c
->Extension
== fileext
)
135 if (_config
->FindB("Debug::aptcdrom",false) == true)
136 std::clog
<< "Found translation " << Dir
->d_name
<< " in " << CD
<< "i18n/" << std::endl
;
137 file
.erase(file
.size() - fileext
.size());
138 TransList
.push_back(CD
+ "i18n/" + file
);
148 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
150 // Run over the directory
151 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
154 if (strcmp(Dir
->d_name
,".") == 0 ||
155 strcmp(Dir
->d_name
,"..") == 0 ||
156 //strcmp(Dir->d_name,"source") == 0 ||
157 strcmp(Dir
->d_name
,".disk") == 0 ||
158 strcmp(Dir
->d_name
,"experimental") == 0 ||
159 strcmp(Dir
->d_name
,"binary-all") == 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 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
276 // ---------------------------------------------------------------------
277 /* Here we go and stat every file that we found and strip dup inodes. */
278 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
280 // Get a list of all the inodes
281 ino_t
*Inodes
= new ino_t
[List
.size()];
282 for (unsigned int I
= 0; I
!= List
.size(); ++I
)
287 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
288 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
289 c
!= compressor
.end(); ++c
)
291 std::string filename
= std::string(List
[I
]).append(Name
).append(c
->Extension
);
292 if (stat(filename
.c_str(), &Buf
) != 0)
294 Inodes
[I
] = Buf
.st_ino
;
300 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(), Name
);
303 if (_error
->PendingError() == true) {
309 for (unsigned int I
= 0; I
!= List
.size(); I
++)
311 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
314 if (Inodes
[J
] != Inodes
[I
])
317 // We score the two paths.. and erase one
318 int ScoreA
= Score(List
[I
]);
319 int ScoreB
= Score(List
[J
]);
331 // Wipe erased entries
332 for (unsigned int I
= 0; I
< List
.size();)
334 if (List
[I
].empty() == false)
337 List
.erase(List
.begin()+I
);
343 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
344 // ---------------------------------------------------------------------
345 /* This takes the list of source list expressed entires and collects
346 similar ones to form a single entry for each dist */
347 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
)
349 sort(List
.begin(),List
.end());
351 // Collect similar entries
352 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
355 string::size_type Space
= (*I
).find(' ');
356 if (Space
== string::npos
)
358 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
359 if (SSpace
== string::npos
)
362 string Word1
= string(*I
,Space
,SSpace
-Space
);
363 string Prefix
= string(*I
,0,Space
);
364 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; ++J
)
367 string::size_type Space2
= (*J
).find(' ');
368 if (Space2
== string::npos
)
370 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
371 if (SSpace2
== string::npos
)
374 if (string(*J
,0,Space2
) != Prefix
)
376 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
379 *J
+= string(*I
,SSpace
);
384 // Wipe erased entries
385 for (unsigned int I
= 0; I
< List
.size();)
387 if (List
[I
].empty() == false)
390 List
.erase(List
.begin()+I
);
394 // WriteDatabase - Write the CDROM Database file /*{{{*/
395 // ---------------------------------------------------------------------
396 /* We rewrite the configuration class associated with the cdrom database. */
397 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
399 string DFile
= _config
->FindFile("Dir::State::cdroms");
400 string NewFile
= DFile
+ ".new";
402 unlink(NewFile
.c_str());
403 ofstream
Out(NewFile
.c_str());
405 return _error
->Errno("ofstream::ofstream",
406 "Failed to open %s.new",DFile
.c_str());
408 /* Write out all of the configuration directives by walking the
409 configuration tree */
410 const Configuration::Item
*Top
= Cnf
.Tree(0);
413 // Print the config entry
414 if (Top
->Value
.empty() == false)
415 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
423 while (Top
!= 0 && Top
->Next
== 0)
431 link(DFile
.c_str(),string(DFile
+ '~').c_str());
432 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
433 return _error
->Errno("rename","Failed to rename %s.new to %s",
434 DFile
.c_str(),DFile
.c_str());
439 // WriteSourceList - Write an updated sourcelist /*{{{*/
440 // ---------------------------------------------------------------------
441 /* This reads the old source list and copies it into the new one. It
442 appends the new CDROM entires just after the first block of comments.
443 This places them first in the file. It also removes any old entries
444 that were the same. */
445 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
447 if (List
.empty() == true)
450 string File
= _config
->FindFile("Dir::Etc::sourcelist");
452 // Open the stream for reading
453 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
456 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
458 string NewFile
= File
+ ".new";
459 unlink(NewFile
.c_str());
460 ofstream
Out(NewFile
.c_str());
462 return _error
->Errno("ofstream::ofstream",
463 "Failed to open %s.new",File
.c_str());
465 // Create a short uri without the path
466 string ShortURI
= "cdrom:[" + Name
+ "]/";
467 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
478 while (F
.eof() == false)
480 F
.getline(Buffer
,sizeof(Buffer
));
482 if (F
.fail() && !F
.eof())
483 return _error
->Error(_("Line %u too long in source list %s."),
484 CurLine
,File
.c_str());
485 _strtabexpand(Buffer
,sizeof(Buffer
));
489 if (Buffer
[0] == '#' || Buffer
[0] == 0)
491 Out
<< Buffer
<< endl
;
497 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
499 string::size_type Space
= (*I
).find(' ');
500 if (Space
== string::npos
)
501 return _error
->Error("Internal error");
502 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
503 " " << string(*I
,Space
+1) << endl
;
511 const char *C
= Buffer
;
512 if (ParseQuoteWord(C
,cType
) == false ||
513 ParseQuoteWord(C
,URI
) == false)
515 Out
<< Buffer
<< endl
;
519 // Emit lines like this one
520 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
521 string(URI
,0,ShortURI
.length()) != ShortURI2
))
523 Out
<< Buffer
<< endl
;
528 // Just in case the file was empty
531 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
533 string::size_type Space
= (*I
).find(' ');
534 if (Space
== string::npos
)
535 return _error
->Error("Internal error");
537 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
538 " " << string(*I
,Space
+1) << endl
;
544 rename(File
.c_str(),string(File
+ '~').c_str());
545 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
546 return _error
->Errno("rename","Failed to rename %s.new to %s",
547 File
.c_str(),File
.c_str());
552 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
557 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
559 CDROM
= SafeGetCWD() + '/' + CDROM
;
564 ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
566 log
->Update(msg
.str());
568 if (MountCdrom(CDROM
) == false)
569 return _error
->Error("Failed to mount the cdrom.");
571 // Hash the CD to get an ID
573 log
->Update(_("Identifying.. "));
576 if (IdentCdrom(CDROM
,ident
) == false)
585 ioprintf(msg
, "[%s]\n",ident
.c_str());
586 log
->Update(msg
.str());
590 Configuration Database
;
591 string DFile
= _config
->FindFile("Dir::State::cdroms");
592 if (FileExists(DFile
) == true)
594 if (ReadConfigFile(Database
,DFile
) == false)
595 return _error
->Error("Unable to read the cdrom database %s",
601 ioprintf(msg
, _("Stored label: %s\n"),
602 Database
.Find("CD::"+ident
).c_str());
603 log
->Update(msg
.str());
606 // Unmount and finish
607 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
610 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
617 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
622 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
624 CDROM
= SafeGetCWD() + '/' + CDROM
;
628 log
->SetTotal(STEP_LAST
);
630 ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
631 log
->Update(msg
.str(), STEP_PREPARE
);
635 Configuration Database
;
636 string DFile
= _config
->FindFile("Dir::State::cdroms");
637 if (FileExists(DFile
) == true)
639 if (ReadConfigFile(Database
,DFile
) == false)
640 return _error
->Error("Unable to read the cdrom database %s",
644 // Unmount the CD and get the user to put in the one they want
645 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
648 log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
);
653 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
654 if(!log
->ChangeCdrom()) {
660 // Mount the new CDROM
662 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
664 if (MountCdrom(CDROM
) == false)
665 return _error
->Error("Failed to mount the cdrom.");
668 // Hash the CD to get an ID
670 log
->Update(_("Identifying.. "), STEP_IDENT
);
672 if (IdentCdrom(CDROM
,ID
) == false)
680 log
->Update("["+ID
+"]\n");
681 log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
);
684 // Get the CD structure
686 vector
<string
> SourceList
;
687 vector
<string
> SigList
;
688 vector
<string
> TransList
;
689 string StartDir
= SafeGetCWD();
691 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
698 chdir(StartDir
.c_str());
700 if (_config
->FindB("Debug::aptcdrom",false) == true)
702 cout
<< "I found (binary):" << endl
;
703 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
705 cout
<< "I found (source):" << endl
;
706 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
708 cout
<< "I found (Signatures):" << endl
;
709 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
713 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
716 DropBinaryArch(List
);
717 DropRepeats(List
,"Packages");
718 DropRepeats(SourceList
,"Sources");
719 DropRepeats(SigList
,"Release.gpg");
720 DropRepeats(SigList
,"InRelease");
721 DropRepeats(TransList
,"");
724 ioprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
725 "%zu translation indexes and %zu signatures\n"),
726 List
.size(), SourceList
.size(), TransList
.size(),
728 log
->Update(msg
.str(), STEP_SCAN
);
731 if (List
.empty() == true && SourceList
.empty() == true)
733 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
735 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
738 // Check if the CD is in the database
740 if (Database
.Exists("CD::" + ID
) == false ||
741 _config
->FindB("APT::CDROM::Rename",false) == true)
743 // Try to use the CDs label if at all possible
744 if (InfoDir
.empty() == false &&
745 FileExists(InfoDir
+ "/info") == true)
747 ifstream
F(string(InfoDir
+ "/info").c_str());
751 if (Name
.empty() == false)
753 // Escape special characters
754 string::iterator J
= Name
.begin();
755 for (; J
!= Name
.end(); ++J
)
756 if (*J
== '"' || *J
== ']' || *J
== '[')
762 ioprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
763 log
->Update(msg
.str());
765 Database
.Set("CD::" + ID
+ "::Label",Name
);
769 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
770 Name
.empty() == true)
774 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
776 return _error
->Error("No disc name found and no way to ask for it");
780 if(!log
->AskCdromName(Name
)) {
784 cout
<< "Name: '" << Name
<< "'" << endl
;
786 if (Name
.empty() == false &&
787 Name
.find('"') == string::npos
&&
788 Name
.find('[') == string::npos
&&
789 Name
.find(']') == string::npos
)
791 log
->Update(_("That is not a valid name, try again.\n"));
796 Name
= Database
.Find("CD::" + ID
);
798 // Escape special characters
799 string::iterator J
= Name
.begin();
800 for (; J
!= Name
.end(); ++J
)
801 if (*J
== '"' || *J
== ']' || *J
== '[')
804 Database
.Set("CD::" + ID
,Name
);
808 ioprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
809 log
->Update(msg
.str());
810 log
->Update(_("Copying package lists..."), STEP_COPY
);
812 // take care of the signatures and copy them if they are ok
813 // (we do this before PackageCopy as it modifies "List" and "SourceList")
814 SigVerify SignVerify
;
815 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
817 // Copy the package files to the state directory
820 TranslationsCopy TransCopy
;
821 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
822 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
823 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
826 // reduce the List so that it takes less space in sources.list
827 ReduceSourcelist(CDROM
,List
);
828 ReduceSourcelist(CDROM
,SourceList
);
830 // Write the database and sourcelist
831 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
833 if (WriteDatabase(Database
) == false)
837 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
838 if (WriteSourceList(Name
,List
,false) == false ||
839 WriteSourceList(Name
,SourceList
,true) == false)
843 // Print the sourcelist entries
845 log
->Update(_("Source list entries for this disc are:\n"));
847 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
849 string::size_type Space
= (*I
).find(' ');
850 if (Space
== string::npos
)
852 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
854 return _error
->Error("Internal error");
860 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
861 " " << string(*I
,Space
+1) << endl
;
862 log
->Update(msg
.str());
866 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
868 string::size_type Space
= (*I
).find(' ');
869 if (Space
== string::npos
)
871 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
873 return _error
->Error("Internal error");
878 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
879 " " << string(*I
,Space
+1) << endl
;
880 log
->Update(msg
.str());
884 // Unmount and finish
885 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
887 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
894 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
895 : libudev_handle(NULL
)
902 pkgUdevCdromDevices::Dlopen() /*{{{*/
905 if(libudev_handle
!= NULL
)
908 // see if we can get libudev
909 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
913 // get the pointers to the udev structs
915 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
916 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
917 udev_enumerate_add_match_sysattr
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_sysattr");
918 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
919 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
920 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
921 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
922 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
923 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
924 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
925 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
926 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
932 // convenience interface, this will just call ScanForRemovable
934 pkgUdevCdromDevices::Scan()
936 bool CdromOnly
= _config
->FindB("APT::cdrom::CdromOnly", true);
937 return ScanForRemovable(CdromOnly
);
942 pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly
)
944 vector
<CdromDevice
> cdrom_devices
;
945 struct udev_enumerate
*enumerate
;
946 struct udev_list_entry
*l
, *devices
;
947 struct udev
*udev_ctx
;
949 if(libudev_handle
== NULL
)
950 return cdrom_devices
;
952 udev_ctx
= udev_new();
953 enumerate
= udev_enumerate_new (udev_ctx
);
955 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
957 udev_enumerate_add_match_sysattr(enumerate
, "removable", "1");
960 udev_enumerate_scan_devices (enumerate
);
961 devices
= udev_enumerate_get_list_entry (enumerate
);
962 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
965 struct udev_device
*udevice
;
966 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
969 const char* devnode
= udev_device_get_devnode(udevice
);
971 // try fstab_dir first
973 const char* mp
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
975 mountpath
= string(mp
);
977 mountpath
= FindMountPointForDevice(devnode
);
979 // fill in the struct
980 cdrom
.DeviceName
= string(devnode
);
981 if (mountpath
!= "") {
982 cdrom
.MountPath
= mountpath
;
983 string s
= string(mountpath
);
984 cdrom
.Mounted
= IsMounted(s
);
986 cdrom
.Mounted
= false;
987 cdrom
.MountPath
= "";
989 cdrom_devices
.push_back(cdrom
);
991 return cdrom_devices
;
995 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
997 if (libudev_handle
!= NULL
)
998 dlclose(libudev_handle
);