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
62 if (stat(".disk",&Buf
) == 0)
64 if (InfoDir
.empty() == true)
65 InfoDir
= CD
+ ".disk/";
68 // Don't look into directories that have been marked to ingore.
69 if (stat(".aptignr",&Buf
) == 0)
73 /* Check _first_ for a signature file as apt-cdrom assumes that all files
74 under a Packages/Source file are in control of that file and stops
77 if (stat("Release.gpg",&Buf
) == 0)
79 SigList
.push_back(CD
);
82 /* Aha! We found some package files. We assume that everything under
83 this dir is controlled by those package files so we don't look down
85 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
86 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
87 c
!= compressor
.end(); ++c
)
89 if (stat(std::string("Packages").append(c
->Extension
).c_str(), &Buf
) != 0)
92 if (_config
->FindB("Debug::aptcdrom",false) == true)
93 std::clog
<< "Found Packages in " << CD
<< std::endl
;
96 // Continue down if thorough is given
97 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
101 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
102 c
!= compressor
.end(); ++c
)
104 if (stat(std::string("Sources").append(c
->Extension
).c_str(), &Buf
) != 0)
107 if (_config
->FindB("Debug::aptcdrom",false) == true)
108 std::clog
<< "Found Sources in " << CD
<< std::endl
;
111 // Continue down if thorough is given
112 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
117 // see if we find translation indices
118 if (DirectoryExists("i18n") == true)
121 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
123 if(strncmp(Dir
->d_name
, "Translation-", strlen("Translation-")) != 0)
125 string file
= Dir
->d_name
;
126 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
127 c
!= compressor
.end(); ++c
)
129 string fileext
= flExtension(file
);
132 else if (fileext
.empty() == false)
133 fileext
= "." + fileext
;
135 if (c
->Extension
== fileext
)
137 if (_config
->FindB("Debug::aptcdrom",false) == true)
138 std::clog
<< "Found translation " << Dir
->d_name
<< " in " << CD
<< "i18n/" << std::endl
;
139 file
.erase(file
.size() - fileext
.size());
140 TransList
.push_back(CD
+ "i18n/" + file
);
150 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
152 // Run over the directory
153 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
156 if (strcmp(Dir
->d_name
,".") == 0 ||
157 strcmp(Dir
->d_name
,"..") == 0 ||
158 //strcmp(Dir->d_name,"source") == 0 ||
159 strcmp(Dir
->d_name
,".disk") == 0 ||
160 strcmp(Dir
->d_name
,"experimental") == 0 ||
161 strcmp(Dir
->d_name
,"binary-all") == 0 ||
162 strcmp(Dir
->d_name
,"debian-installer") == 0)
165 // See if the name is a sub directory
167 if (stat(Dir
->d_name
,&Buf
) != 0)
170 if (S_ISDIR(Buf
.st_mode
) == 0)
174 for (I
= 0; I
!= Depth
; I
++)
175 if (Inodes
[I
] == Buf
.st_ino
)
180 // Store the inodes weve seen
181 Inodes
[Depth
] = Buf
.st_ino
;
184 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
187 if (chdir(CD
.c_str()) != 0)
189 _error
->Errno("chdir","Unable to change to %s", CD
.c_str());
197 return !_error
->PendingError();
200 // Score - We compute a 'score' for a path /*{{{*/
201 // ---------------------------------------------------------------------
202 /* Paths are scored based on how close they come to what I consider
203 normal. That is ones that have 'dist' 'stable' 'testing' will score
204 higher than ones without. */
205 int pkgCdrom::Score(string Path
)
208 if (Path
.find("stable/") != string::npos
)
210 if (Path
.find("/binary-") != string::npos
)
212 if (Path
.find("testing/") != string::npos
)
214 if (Path
.find("unstable/") != string::npos
)
216 if (Path
.find("/dists/") != string::npos
)
218 if (Path
.find("/main/") != string::npos
)
220 if (Path
.find("/contrib/") != string::npos
)
222 if (Path
.find("/non-free/") != string::npos
)
224 if (Path
.find("/non-US/") != string::npos
)
226 if (Path
.find("/source/") != string::npos
)
228 if (Path
.find("/debian/") != string::npos
)
231 // check for symlinks in the patch leading to the actual file
232 // a symlink gets a big penalty
234 string statPath
= flNotFile(Path
);
235 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount");
236 while(statPath
!= cdromPath
&& statPath
!= "./") {
237 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
238 if (lstat(statPath
.c_str(),&Buf
) == 0) {
239 if(S_ISLNK(Buf
.st_mode
)) {
244 statPath
= flNotFile(statPath
); // descent
250 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
251 // ---------------------------------------------------------------------
252 /* Here we drop everything that is not this machines arch */
253 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
256 for (unsigned int I
= 0; I
< List
.size(); I
++)
258 const char *Str
= List
[I
].c_str();
259 const char *Start
, *End
;
260 if ((Start
= strstr(Str
,"/binary-")) == 0)
263 // Between Start and End is the architecture
265 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
266 APT::Configuration::checkArchitecture(string(Start
, End
)) == true)
267 continue; // okay, architecture is accepted
269 // not accepted -> Erase it
270 List
.erase(List
.begin() + I
);
271 --I
; // the next entry is at the same index after the erase
277 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
278 // ---------------------------------------------------------------------
279 /* Here we go and stat every file that we found and strip dup inodes. */
280 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
282 // Get a list of all the inodes
283 ino_t
*Inodes
= new ino_t
[List
.size()];
284 for (unsigned int I
= 0; I
!= List
.size(); ++I
)
289 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
290 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
291 c
!= compressor
.end(); ++c
)
293 std::string filename
= std::string(List
[I
]).append(Name
).append(c
->Extension
);
294 if (stat(filename
.c_str(), &Buf
) != 0)
296 Inodes
[I
] = Buf
.st_ino
;
302 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(), Name
);
305 if (_error
->PendingError() == true) {
311 for (unsigned int I
= 0; I
!= List
.size(); I
++)
313 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
316 if (Inodes
[J
] != Inodes
[I
])
319 // We score the two paths.. and erase one
320 int ScoreA
= Score(List
[I
]);
321 int ScoreB
= Score(List
[J
]);
333 // Wipe erased entries
334 for (unsigned int I
= 0; I
< List
.size();)
336 if (List
[I
].empty() == false)
339 List
.erase(List
.begin()+I
);
345 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
346 // ---------------------------------------------------------------------
347 /* This takes the list of source list expressed entires and collects
348 similar ones to form a single entry for each dist */
349 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
)
351 sort(List
.begin(),List
.end());
353 // Collect similar entries
354 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
357 string::size_type Space
= (*I
).find(' ');
358 if (Space
== string::npos
)
360 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
361 if (SSpace
== string::npos
)
364 string Word1
= string(*I
,Space
,SSpace
-Space
);
365 string Prefix
= string(*I
,0,Space
);
366 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; ++J
)
369 string::size_type Space2
= (*J
).find(' ');
370 if (Space2
== string::npos
)
372 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
373 if (SSpace2
== string::npos
)
376 if (string(*J
,0,Space2
) != Prefix
)
378 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
381 *J
+= string(*I
,SSpace
);
386 // Wipe erased entries
387 for (unsigned int I
= 0; I
< List
.size();)
389 if (List
[I
].empty() == false)
392 List
.erase(List
.begin()+I
);
396 // WriteDatabase - Write the CDROM Database file /*{{{*/
397 // ---------------------------------------------------------------------
398 /* We rewrite the configuration class associated with the cdrom database. */
399 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
401 string DFile
= _config
->FindFile("Dir::State::cdroms");
402 string NewFile
= DFile
+ ".new";
404 unlink(NewFile
.c_str());
405 ofstream
Out(NewFile
.c_str());
407 return _error
->Errno("ofstream::ofstream",
408 "Failed to open %s.new",DFile
.c_str());
410 /* Write out all of the configuration directives by walking the
411 configuration tree */
412 const Configuration::Item
*Top
= Cnf
.Tree(0);
415 // Print the config entry
416 if (Top
->Value
.empty() == false)
417 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
425 while (Top
!= 0 && Top
->Next
== 0)
433 link(DFile
.c_str(),string(DFile
+ '~').c_str());
434 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
435 return _error
->Errno("rename","Failed to rename %s.new to %s",
436 DFile
.c_str(),DFile
.c_str());
441 // WriteSourceList - Write an updated sourcelist /*{{{*/
442 // ---------------------------------------------------------------------
443 /* This reads the old source list and copies it into the new one. It
444 appends the new CDROM entires just after the first block of comments.
445 This places them first in the file. It also removes any old entries
446 that were the same. */
447 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
449 if (List
.empty() == true)
452 string File
= _config
->FindFile("Dir::Etc::sourcelist");
454 // Open the stream for reading
455 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
458 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
460 string NewFile
= File
+ ".new";
461 unlink(NewFile
.c_str());
462 ofstream
Out(NewFile
.c_str());
464 return _error
->Errno("ofstream::ofstream",
465 "Failed to open %s.new",File
.c_str());
467 // Create a short uri without the path
468 string ShortURI
= "cdrom:[" + Name
+ "]/";
469 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
480 while (F
.eof() == false)
482 F
.getline(Buffer
,sizeof(Buffer
));
484 if (F
.fail() && !F
.eof())
485 return _error
->Error(_("Line %u too long in source list %s."),
486 CurLine
,File
.c_str());
487 _strtabexpand(Buffer
,sizeof(Buffer
));
491 if (Buffer
[0] == '#' || Buffer
[0] == 0)
493 Out
<< Buffer
<< endl
;
499 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
501 string::size_type Space
= (*I
).find(' ');
502 if (Space
== string::npos
)
503 return _error
->Error("Internal error");
504 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
505 " " << string(*I
,Space
+1) << endl
;
513 const char *C
= Buffer
;
514 if (ParseQuoteWord(C
,cType
) == false ||
515 ParseQuoteWord(C
,URI
) == false)
517 Out
<< Buffer
<< endl
;
521 // Emit lines like this one
522 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
523 string(URI
,0,ShortURI
.length()) != ShortURI2
))
525 Out
<< Buffer
<< endl
;
530 // Just in case the file was empty
533 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
535 string::size_type Space
= (*I
).find(' ');
536 if (Space
== string::npos
)
537 return _error
->Error("Internal error");
539 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
540 " " << string(*I
,Space
+1) << endl
;
546 rename(File
.c_str(),string(File
+ '~').c_str());
547 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
548 return _error
->Errno("rename","Failed to rename %s.new to %s",
549 File
.c_str(),File
.c_str());
554 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
559 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
561 CDROM
= SafeGetCWD() + '/' + CDROM
;
566 ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
568 log
->Update(msg
.str());
570 if (MountCdrom(CDROM
) == false)
571 return _error
->Error("Failed to mount the cdrom.");
573 // Hash the CD to get an ID
575 log
->Update(_("Identifying.. "));
578 if (IdentCdrom(CDROM
,ident
) == false)
587 ioprintf(msg
, "[%s]\n",ident
.c_str());
588 log
->Update(msg
.str());
592 Configuration Database
;
593 string DFile
= _config
->FindFile("Dir::State::cdroms");
594 if (FileExists(DFile
) == true)
596 if (ReadConfigFile(Database
,DFile
) == false)
597 return _error
->Error("Unable to read the cdrom database %s",
603 ioprintf(msg
, _("Stored label: %s\n"),
604 Database
.Find("CD::"+ident
).c_str());
605 log
->Update(msg
.str());
608 // Unmount and finish
609 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
612 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
619 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
624 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
626 CDROM
= SafeGetCWD() + '/' + CDROM
;
630 log
->SetTotal(STEP_LAST
);
632 ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
633 log
->Update(msg
.str(), STEP_PREPARE
);
637 Configuration Database
;
638 string DFile
= _config
->FindFile("Dir::State::cdroms");
639 if (FileExists(DFile
) == true)
641 if (ReadConfigFile(Database
,DFile
) == false)
642 return _error
->Error("Unable to read the cdrom database %s",
646 // Unmount the CD and get the user to put in the one they want
647 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
650 log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
);
655 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
656 if(!log
->ChangeCdrom()) {
662 // Mount the new CDROM
664 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
666 if (MountCdrom(CDROM
) == false)
667 return _error
->Error("Failed to mount the cdrom.");
670 // Hash the CD to get an ID
672 log
->Update(_("Identifying.. "), STEP_IDENT
);
674 if (IdentCdrom(CDROM
,ID
) == false)
682 log
->Update("["+ID
+"]\n");
683 log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
);
686 // Get the CD structure
688 vector
<string
> SourceList
;
689 vector
<string
> SigList
;
690 vector
<string
> TransList
;
691 string StartDir
= SafeGetCWD();
693 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
700 chdir(StartDir
.c_str());
702 if (_config
->FindB("Debug::aptcdrom",false) == true)
704 cout
<< "I found (binary):" << endl
;
705 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
707 cout
<< "I found (source):" << endl
;
708 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
710 cout
<< "I found (Signatures):" << endl
;
711 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
715 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
718 DropBinaryArch(List
);
719 DropRepeats(List
,"Packages");
720 DropRepeats(SourceList
,"Sources");
721 DropRepeats(SigList
,"Release.gpg");
722 DropRepeats(TransList
,"");
725 ioprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
726 "%zu translation indexes and %zu signatures\n"),
727 List
.size(), SourceList
.size(), TransList
.size(),
729 log
->Update(msg
.str(), STEP_SCAN
);
732 if (List
.empty() == true && SourceList
.empty() == true)
734 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
736 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
739 // Check if the CD is in the database
741 if (Database
.Exists("CD::" + ID
) == false ||
742 _config
->FindB("APT::CDROM::Rename",false) == true)
744 // Try to use the CDs label if at all possible
745 if (InfoDir
.empty() == false &&
746 FileExists(InfoDir
+ "/info") == true)
748 ifstream
F(string(InfoDir
+ "/info").c_str());
752 if (Name
.empty() == false)
754 // Escape special characters
755 string::iterator J
= Name
.begin();
756 for (; J
!= Name
.end(); ++J
)
757 if (*J
== '"' || *J
== ']' || *J
== '[')
763 ioprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
764 log
->Update(msg
.str());
766 Database
.Set("CD::" + ID
+ "::Label",Name
);
770 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
771 Name
.empty() == true)
775 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
777 return _error
->Error("No disc name found and no way to ask for it");
781 if(!log
->AskCdromName(Name
)) {
785 cout
<< "Name: '" << Name
<< "'" << endl
;
787 if (Name
.empty() == false &&
788 Name
.find('"') == string::npos
&&
789 Name
.find('[') == string::npos
&&
790 Name
.find(']') == string::npos
)
792 log
->Update(_("That is not a valid name, try again.\n"));
797 Name
= Database
.Find("CD::" + ID
);
799 // Escape special characters
800 string::iterator J
= Name
.begin();
801 for (; J
!= Name
.end(); ++J
)
802 if (*J
== '"' || *J
== ']' || *J
== '[')
805 Database
.Set("CD::" + ID
,Name
);
809 ioprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
810 log
->Update(msg
.str());
811 log
->Update(_("Copying package lists..."), STEP_COPY
);
813 // take care of the signatures and copy them if they are ok
814 // (we do this before PackageCopy as it modifies "List" and "SourceList")
815 SigVerify SignVerify
;
816 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
818 // Copy the package files to the state directory
821 TranslationsCopy TransCopy
;
822 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
823 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
824 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
827 // reduce the List so that it takes less space in sources.list
828 ReduceSourcelist(CDROM
,List
);
829 ReduceSourcelist(CDROM
,SourceList
);
831 // Write the database and sourcelist
832 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
834 if (WriteDatabase(Database
) == false)
838 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
839 if (WriteSourceList(Name
,List
,false) == false ||
840 WriteSourceList(Name
,SourceList
,true) == false)
844 // Print the sourcelist entries
846 log
->Update(_("Source list entries for this disc are:\n"));
848 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
850 string::size_type Space
= (*I
).find(' ');
851 if (Space
== string::npos
)
853 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
855 return _error
->Error("Internal error");
861 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
862 " " << string(*I
,Space
+1) << endl
;
863 log
->Update(msg
.str());
867 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); ++I
)
869 string::size_type Space
= (*I
).find(' ');
870 if (Space
== string::npos
)
872 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
874 return _error
->Error("Internal error");
879 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
880 " " << string(*I
,Space
+1) << endl
;
881 log
->Update(msg
.str());
885 // Unmount and finish
886 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
888 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
895 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
896 : libudev_handle(NULL
)
903 pkgUdevCdromDevices::Dlopen() /*{{{*/
906 if(libudev_handle
!= NULL
)
909 // see if we can get libudev
910 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
914 // get the pointers to the udev structs
916 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
917 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
918 udev_enumerate_add_match_sysattr
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_sysattr");
919 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
920 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
921 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
922 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
923 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
924 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
925 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
926 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
927 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
933 // convenience interface, this will just call ScanForRemovable
935 pkgUdevCdromDevices::Scan()
937 bool CdromOnly
= _config
->FindB("APT::cdrom::CdromOnly", true);
938 return ScanForRemovable(CdromOnly
);
943 pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly
)
945 vector
<CdromDevice
> cdrom_devices
;
946 struct udev_enumerate
*enumerate
;
947 struct udev_list_entry
*l
, *devices
;
948 struct udev
*udev_ctx
;
950 if(libudev_handle
== NULL
)
951 return cdrom_devices
;
953 udev_ctx
= udev_new();
954 enumerate
= udev_enumerate_new (udev_ctx
);
956 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
958 udev_enumerate_add_match_sysattr(enumerate
, "removable", "1");
961 udev_enumerate_scan_devices (enumerate
);
962 devices
= udev_enumerate_get_list_entry (enumerate
);
963 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
966 struct udev_device
*udevice
;
967 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
970 const char* devnode
= udev_device_get_devnode(udevice
);
972 // try fstab_dir first
974 const char* mp
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
976 mountpath
= string(mp
);
978 mountpath
= FindMountPointForDevice(devnode
);
980 // fill in the struct
981 cdrom
.DeviceName
= string(devnode
);
982 if (mountpath
!= "") {
983 cdrom
.MountPath
= mountpath
;
984 string s
= string(mountpath
);
985 cdrom
.Mounted
= IsMounted(s
);
987 cdrom
.Mounted
= false;
988 cdrom
.MountPath
= "";
990 cdrom_devices
.push_back(cdrom
);
992 return cdrom_devices
;
996 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
998 if (libudev_handle
!= NULL
)
999 dlclose(libudev_handle
);