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)
72 /* Check _first_ for a signature file as apt-cdrom assumes that all files
73 under a Packages/Source file are in control of that file and stops
76 if (RealFileExists("Release.gpg") == true)
78 SigList
.push_back(CD
);
81 /* Aha! We found some package files. We assume that everything under
82 this dir is controlled by those package files so we don't look down
84 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
85 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
86 c
!= compressor
.end(); ++c
)
88 if (RealFileExists(std::string("Packages").append(c
->Extension
).c_str()) == false)
91 if (_config
->FindB("Debug::aptcdrom",false) == true)
92 std::clog
<< "Found Packages in " << CD
<< std::endl
;
95 // Continue down if thorough is given
96 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
100 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
101 c
!= compressor
.end(); ++c
)
103 if (RealFileExists(std::string("Sources").append(c
->Extension
).c_str()) == false)
106 if (_config
->FindB("Debug::aptcdrom",false) == true)
107 std::clog
<< "Found Sources in " << CD
<< std::endl
;
110 // Continue down if thorough is given
111 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
116 // see if we find translation indices
117 if (DirectoryExists("i18n") == true)
120 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
122 if(strncmp(Dir
->d_name
, "Translation-", strlen("Translation-")) != 0)
124 string file
= Dir
->d_name
;
125 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
126 c
!= compressor
.end(); ++c
)
128 string fileext
= flExtension(file
);
131 else if (fileext
.empty() == false)
132 fileext
= "." + fileext
;
134 if (c
->Extension
== fileext
)
136 if (_config
->FindB("Debug::aptcdrom",false) == true)
137 std::clog
<< "Found translation " << Dir
->d_name
<< " in " << CD
<< "i18n/" << std::endl
;
138 file
.erase(file
.size() - fileext
.size());
139 TransList
.push_back(CD
+ "i18n/" + file
);
149 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
151 // Run over the directory
152 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
155 if (strcmp(Dir
->d_name
,".") == 0 ||
156 strcmp(Dir
->d_name
,"..") == 0 ||
157 //strcmp(Dir->d_name,"source") == 0 ||
158 strcmp(Dir
->d_name
,".disk") == 0 ||
159 strcmp(Dir
->d_name
,"experimental") == 0 ||
160 strcmp(Dir
->d_name
,"binary-all") == 0 ||
161 strcmp(Dir
->d_name
,"debian-installer") == 0)
164 // See if the name is a sub directory
166 if (stat(Dir
->d_name
,&Buf
) != 0)
169 if (S_ISDIR(Buf
.st_mode
) == 0)
173 for (I
= 0; I
!= Depth
; I
++)
174 if (Inodes
[I
] == Buf
.st_ino
)
179 // Store the inodes weve seen
180 Inodes
[Depth
] = Buf
.st_ino
;
183 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
186 if (chdir(CD
.c_str()) != 0)
188 _error
->Errno("chdir","Unable to change to %s", CD
.c_str());
196 return !_error
->PendingError();
199 // Score - We compute a 'score' for a path /*{{{*/
200 // ---------------------------------------------------------------------
201 /* Paths are scored based on how close they come to what I consider
202 normal. That is ones that have 'dist' 'stable' 'testing' will score
203 higher than ones without. */
204 int pkgCdrom::Score(string Path
)
207 if (Path
.find("stable/") != string::npos
)
209 if (Path
.find("/binary-") != string::npos
)
211 if (Path
.find("testing/") != string::npos
)
213 if (Path
.find("unstable/") != string::npos
)
215 if (Path
.find("/dists/") != string::npos
)
217 if (Path
.find("/main/") != string::npos
)
219 if (Path
.find("/contrib/") != string::npos
)
221 if (Path
.find("/non-free/") != string::npos
)
223 if (Path
.find("/non-US/") != string::npos
)
225 if (Path
.find("/source/") != string::npos
)
227 if (Path
.find("/debian/") != string::npos
)
230 // check for symlinks in the patch leading to the actual file
231 // a symlink gets a big penalty
233 string statPath
= flNotFile(Path
);
234 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount");
235 while(statPath
!= cdromPath
&& statPath
!= "./") {
236 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
237 if (lstat(statPath
.c_str(),&Buf
) == 0) {
238 if(S_ISLNK(Buf
.st_mode
)) {
243 statPath
= flNotFile(statPath
); // descent
249 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
250 // ---------------------------------------------------------------------
251 /* Here we drop everything that is not this machines arch */
252 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
255 for (unsigned int I
= 0; I
< List
.size(); I
++)
257 const char *Str
= List
[I
].c_str();
258 const char *Start
, *End
;
259 if ((Start
= strstr(Str
,"/binary-")) == 0)
262 // Between Start and End is the architecture
264 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
265 APT::Configuration::checkArchitecture(string(Start
, End
)) == true)
266 continue; // okay, architecture is accepted
268 // not accepted -> Erase it
269 List
.erase(List
.begin() + I
);
270 --I
; // the next entry is at the same index after the erase
276 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
277 // ---------------------------------------------------------------------
278 /* Here we go and stat every file that we found and strip dup inodes. */
279 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
281 // Get a list of all the inodes
282 ino_t
*Inodes
= new ino_t
[List
.size()];
283 for (unsigned int I
= 0; I
!= List
.size(); ++I
)
288 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
289 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
290 c
!= compressor
.end(); ++c
)
292 std::string filename
= std::string(List
[I
]).append(Name
).append(c
->Extension
);
293 if (stat(filename
.c_str(), &Buf
) != 0)
295 Inodes
[I
] = Buf
.st_ino
;
301 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(), Name
);
304 if (_error
->PendingError() == true) {
310 for (unsigned int I
= 0; I
!= List
.size(); I
++)
312 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
315 if (Inodes
[J
] != Inodes
[I
])
318 // We score the two paths.. and erase one
319 int ScoreA
= Score(List
[I
]);
320 int ScoreB
= Score(List
[J
]);
332 // Wipe erased entries
333 for (unsigned int I
= 0; I
< List
.size();)
335 if (List
[I
].empty() == false)
338 List
.erase(List
.begin()+I
);
344 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
345 // ---------------------------------------------------------------------
346 /* This takes the list of source list expressed entires and collects
347 similar ones to form a single entry for each dist */
348 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
)
350 sort(List
.begin(),List
.end());
352 // Collect similar entries
353 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
356 string::size_type Space
= (*I
).find(' ');
357 if (Space
== string::npos
)
359 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
360 if (SSpace
== string::npos
)
363 string Word1
= string(*I
,Space
,SSpace
-Space
);
364 string Prefix
= string(*I
,0,Space
);
365 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; ++J
)
368 string::size_type Space2
= (*J
).find(' ');
369 if (Space2
== string::npos
)
371 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
372 if (SSpace2
== string::npos
)
375 if (string(*J
,0,Space2
) != Prefix
)
377 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
380 *J
+= string(*I
,SSpace
);
385 // Wipe erased entries
386 for (unsigned int I
= 0; I
< List
.size();)
388 if (List
[I
].empty() == false)
391 List
.erase(List
.begin()+I
);
395 // WriteDatabase - Write the CDROM Database file /*{{{*/
396 // ---------------------------------------------------------------------
397 /* We rewrite the configuration class associated with the cdrom database. */
398 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
400 string DFile
= _config
->FindFile("Dir::State::cdroms");
401 string NewFile
= DFile
+ ".new";
403 unlink(NewFile
.c_str());
404 ofstream
Out(NewFile
.c_str());
406 return _error
->Errno("ofstream::ofstream",
407 "Failed to open %s.new",DFile
.c_str());
409 /* Write out all of the configuration directives by walking the
410 configuration tree */
411 const Configuration::Item
*Top
= Cnf
.Tree(0);
414 // Print the config entry
415 if (Top
->Value
.empty() == false)
416 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
424 while (Top
!= 0 && Top
->Next
== 0)
432 link(DFile
.c_str(),string(DFile
+ '~').c_str());
433 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
434 return _error
->Errno("rename","Failed to rename %s.new to %s",
435 DFile
.c_str(),DFile
.c_str());
440 // WriteSourceList - Write an updated sourcelist /*{{{*/
441 // ---------------------------------------------------------------------
442 /* This reads the old source list and copies it into the new one. It
443 appends the new CDROM entires just after the first block of comments.
444 This places them first in the file. It also removes any old entries
445 that were the same. */
446 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
448 if (List
.empty() == true)
451 string File
= _config
->FindFile("Dir::Etc::sourcelist");
453 // Open the stream for reading
454 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
457 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
459 string NewFile
= File
+ ".new";
460 unlink(NewFile
.c_str());
461 ofstream
Out(NewFile
.c_str());
463 return _error
->Errno("ofstream::ofstream",
464 "Failed to open %s.new",File
.c_str());
466 // Create a short uri without the path
467 string ShortURI
= "cdrom:[" + Name
+ "]/";
468 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
479 while (F
.eof() == false)
481 F
.getline(Buffer
,sizeof(Buffer
));
483 if (F
.fail() && !F
.eof())
484 return _error
->Error(_("Line %u too long in source list %s."),
485 CurLine
,File
.c_str());
486 _strtabexpand(Buffer
,sizeof(Buffer
));
490 if (Buffer
[0] == '#' || Buffer
[0] == 0)
492 Out
<< Buffer
<< endl
;
498 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
500 string::size_type Space
= (*I
).find(' ');
501 if (Space
== string::npos
)
502 return _error
->Error("Internal error");
503 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
504 " " << string(*I
,Space
+1) << endl
;
512 const char *C
= Buffer
;
513 if (ParseQuoteWord(C
,cType
) == false ||
514 ParseQuoteWord(C
,URI
) == false)
516 Out
<< Buffer
<< endl
;
520 // Emit lines like this one
521 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
522 string(URI
,0,ShortURI
.length()) != ShortURI2
))
524 Out
<< Buffer
<< endl
;
529 // Just in case the file was empty
532 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
534 string::size_type Space
= (*I
).find(' ');
535 if (Space
== string::npos
)
536 return _error
->Error("Internal error");
538 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
539 " " << string(*I
,Space
+1) << endl
;
545 rename(File
.c_str(),string(File
+ '~').c_str());
546 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
547 return _error
->Errno("rename","Failed to rename %s.new to %s",
548 File
.c_str(),File
.c_str());
553 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
558 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
560 CDROM
= SafeGetCWD() + '/' + CDROM
;
565 ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
567 log
->Update(msg
.str());
569 if (MountCdrom(CDROM
) == false)
570 return _error
->Error("Failed to mount the cdrom.");
572 // Hash the CD to get an ID
574 log
->Update(_("Identifying.. "));
577 if (IdentCdrom(CDROM
,ident
) == false)
586 ioprintf(msg
, "[%s]\n",ident
.c_str());
587 log
->Update(msg
.str());
591 Configuration Database
;
592 string DFile
= _config
->FindFile("Dir::State::cdroms");
593 if (FileExists(DFile
) == true)
595 if (ReadConfigFile(Database
,DFile
) == false)
596 return _error
->Error("Unable to read the cdrom database %s",
602 ioprintf(msg
, _("Stored label: %s\n"),
603 Database
.Find("CD::"+ident
).c_str());
604 log
->Update(msg
.str());
607 // Unmount and finish
608 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
611 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
618 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
623 string CDROM
= _config
->FindDir("Acquire::cdrom::mount");
625 CDROM
= SafeGetCWD() + '/' + CDROM
;
629 log
->SetTotal(STEP_LAST
);
631 ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
632 log
->Update(msg
.str(), STEP_PREPARE
);
636 Configuration Database
;
637 string DFile
= _config
->FindFile("Dir::State::cdroms");
638 if (FileExists(DFile
) == true)
640 if (ReadConfigFile(Database
,DFile
) == false)
641 return _error
->Error("Unable to read the cdrom database %s",
645 // Unmount the CD and get the user to put in the one they want
646 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
649 log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
);
654 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
655 if(!log
->ChangeCdrom()) {
661 // Mount the new CDROM
663 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
665 if (MountCdrom(CDROM
) == false)
666 return _error
->Error("Failed to mount the cdrom.");
669 // Hash the CD to get an ID
671 log
->Update(_("Identifying.. "), STEP_IDENT
);
673 if (IdentCdrom(CDROM
,ID
) == false)
681 log
->Update("["+ID
+"]\n");
682 log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
);
685 // Get the CD structure
687 vector
<string
> SourceList
;
688 vector
<string
> SigList
;
689 vector
<string
> TransList
;
690 string StartDir
= SafeGetCWD();
692 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
699 chdir(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 DropRepeats(SigList
,"Release.gpg");
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
);