4 #include<apt-pkg/init.h>
5 #include<apt-pkg/error.h>
6 #include<apt-pkg/cdromutl.h>
7 #include<apt-pkg/strutl.h>
8 #include<apt-pkg/cdrom.h>
9 #include<apt-pkg/aptconfiguration.h>
23 #include "indexcopy.h"
27 // FindPackages - Find the package files on the CDROM /*{{{*/
28 // ---------------------------------------------------------------------
29 /* We look over the cdrom for package files. This is a recursive
30 search that short circuits when it his a package file in the dir.
31 This speeds it up greatly as the majority of the size is in the
33 bool pkgCdrom::FindPackages(string CD
,
35 vector
<string
> &SList
,
36 vector
<string
> &SigList
,
37 vector
<string
> &TransList
,
38 string
&InfoDir
, pkgCdromStatus
*log
,
41 static ino_t Inodes
[9];
44 // if we have a look we "pulse" now
51 if (CD
[CD
.length()-1] != '/')
54 if (chdir(CD
.c_str()) != 0)
55 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
57 // Look for a .disk subdirectory
59 if (stat(".disk",&Buf
) == 0)
61 if (InfoDir
.empty() == true)
62 InfoDir
= CD
+ ".disk/";
65 // Don't look into directories that have been marked to ingore.
66 if (stat(".aptignr",&Buf
) == 0)
70 /* Check _first_ for a signature file as apt-cdrom assumes that all files
71 under a Packages/Source file are in control of that file and stops
74 if (stat("Release.gpg",&Buf
) == 0)
76 SigList
.push_back(CD
);
78 /* Aha! We found some package files. We assume that everything under
79 this dir is controlled by those package files so we don't look down
81 if (stat("Packages",&Buf
) == 0 || stat("Packages.gz",&Buf
) == 0)
85 // Continue down if thorough is given
86 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
89 if (stat("Sources.gz",&Buf
) == 0 || stat("Sources",&Buf
) == 0)
93 // Continue down if thorough is given
94 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
98 // see if we find translatin indexes
99 if (stat("i18n",&Buf
) == 0)
102 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
104 if(strstr(Dir
->d_name
,"Translation") != NULL
)
106 if (_config
->FindB("Debug::aptcdrom",false) == true)
107 std::clog
<< "found translations: " << Dir
->d_name
<< "\n";
108 string file
= Dir
->d_name
;
109 if(file
.substr(file
.size()-3,file
.size()) == ".gz")
110 file
= file
.substr(0,file
.size()-3);
111 TransList
.push_back(CD
+"i18n/"+ file
);
120 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
122 // Run over the directory
123 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
126 if (strcmp(Dir
->d_name
,".") == 0 ||
127 strcmp(Dir
->d_name
,"..") == 0 ||
128 //strcmp(Dir->d_name,"source") == 0 ||
129 strcmp(Dir
->d_name
,".disk") == 0 ||
130 strcmp(Dir
->d_name
,"experimental") == 0 ||
131 strcmp(Dir
->d_name
,"binary-all") == 0 ||
132 strcmp(Dir
->d_name
,"debian-installer") == 0)
135 // See if the name is a sub directory
137 if (stat(Dir
->d_name
,&Buf
) != 0)
140 if (S_ISDIR(Buf
.st_mode
) == 0)
144 for (I
= 0; I
!= Depth
; I
++)
145 if (Inodes
[I
] == Buf
.st_ino
)
150 // Store the inodes weve seen
151 Inodes
[Depth
] = Buf
.st_ino
;
154 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
157 if (chdir(CD
.c_str()) != 0)
158 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
163 return !_error
->PendingError();
166 // Score - We compute a 'score' for a path /*{{{*/
167 // ---------------------------------------------------------------------
168 /* Paths are scored based on how close they come to what I consider
169 normal. That is ones that have 'dist' 'stable' 'testing' will score
170 higher than ones without. */
171 int pkgCdrom::Score(string Path
)
174 if (Path
.find("stable/") != string::npos
)
176 if (Path
.find("/binary-") != string::npos
)
178 if (Path
.find("testing/") != string::npos
)
180 if (Path
.find("unstable/") != string::npos
)
182 if (Path
.find("/dists/") != string::npos
)
184 if (Path
.find("/main/") != string::npos
)
186 if (Path
.find("/contrib/") != string::npos
)
188 if (Path
.find("/non-free/") != string::npos
)
190 if (Path
.find("/non-US/") != string::npos
)
192 if (Path
.find("/source/") != string::npos
)
194 if (Path
.find("/debian/") != string::npos
)
197 // check for symlinks in the patch leading to the actual file
198 // a symlink gets a big penalty
200 string statPath
= flNotFile(Path
);
201 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
202 while(statPath
!= cdromPath
&& statPath
!= "./") {
203 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
204 if (lstat(statPath
.c_str(),&Buf
) == 0) {
205 if(S_ISLNK(Buf
.st_mode
)) {
210 statPath
= flNotFile(statPath
); // descent
216 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
217 // ---------------------------------------------------------------------
218 /* Here we drop everything that is not this machines arch */
219 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
222 for (unsigned int I
= 0; I
< List
.size(); I
++)
224 const char *Str
= List
[I
].c_str();
225 const char *Start
, *End
;
226 if ((Start
= strstr(Str
,"/binary-")) == 0)
229 // Between Start and End is the architecture
231 if ((End
= strstr(Start
,"/")) != 0 && Start
!= End
&&
232 APT::Configuration::checkArchitecture(string(Start
, --End
)) == true)
233 continue; // okay, architecture is accepted
235 // not accepted -> Erase it
236 List
.erase(List
.begin() + I
);
237 --I
; // the next entry is at the same index after the erase
243 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
244 // ---------------------------------------------------------------------
245 /* Here we go and stat every file that we found and strip dup inodes. */
246 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
248 // Get a list of all the inodes
249 ino_t
*Inodes
= new ino_t
[List
.size()];
250 for (unsigned int I
= 0; I
!= List
.size(); I
++)
253 if (stat((List
[I
] + Name
).c_str(),&Buf
) != 0 &&
254 stat((List
[I
] + Name
+ ".gz").c_str(),&Buf
) != 0)
255 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(),
257 Inodes
[I
] = Buf
.st_ino
;
260 if (_error
->PendingError() == true)
264 for (unsigned int I
= 0; I
!= List
.size(); I
++)
266 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
269 if (Inodes
[J
] != Inodes
[I
])
272 // We score the two paths.. and erase one
273 int ScoreA
= Score(List
[I
]);
274 int ScoreB
= Score(List
[J
]);
285 // Wipe erased entries
286 for (unsigned int I
= 0; I
< List
.size();)
288 if (List
[I
].empty() == false)
291 List
.erase(List
.begin()+I
);
297 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
298 // ---------------------------------------------------------------------
299 /* This takes the list of source list expressed entires and collects
300 similar ones to form a single entry for each dist */
301 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
)
303 sort(List
.begin(),List
.end());
305 // Collect similar entries
306 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
309 string::size_type Space
= (*I
).find(' ');
310 if (Space
== string::npos
)
312 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
313 if (SSpace
== string::npos
)
316 string Word1
= string(*I
,Space
,SSpace
-Space
);
317 string Prefix
= string(*I
,0,Space
);
318 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
321 string::size_type Space2
= (*J
).find(' ');
322 if (Space2
== string::npos
)
324 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
325 if (SSpace2
== string::npos
)
328 if (string(*J
,0,Space2
) != Prefix
)
330 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
333 *J
+= string(*I
,SSpace
);
338 // Wipe erased entries
339 for (unsigned int I
= 0; I
< List
.size();)
341 if (List
[I
].empty() == false)
344 List
.erase(List
.begin()+I
);
348 // WriteDatabase - Write the CDROM Database file /*{{{*/
349 // ---------------------------------------------------------------------
350 /* We rewrite the configuration class associated with the cdrom database. */
351 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
353 string DFile
= _config
->FindFile("Dir::State::cdroms");
354 string NewFile
= DFile
+ ".new";
356 unlink(NewFile
.c_str());
357 ofstream
Out(NewFile
.c_str());
359 return _error
->Errno("ofstream::ofstream",
360 "Failed to open %s.new",DFile
.c_str());
362 /* Write out all of the configuration directives by walking the
363 configuration tree */
364 const Configuration::Item
*Top
= Cnf
.Tree(0);
367 // Print the config entry
368 if (Top
->Value
.empty() == false)
369 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
377 while (Top
!= 0 && Top
->Next
== 0)
385 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
386 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
387 return _error
->Errno("rename","Failed to rename %s.new to %s",
388 DFile
.c_str(),DFile
.c_str());
393 // WriteSourceList - Write an updated sourcelist /*{{{*/
394 // ---------------------------------------------------------------------
395 /* This reads the old source list and copies it into the new one. It
396 appends the new CDROM entires just after the first block of comments.
397 This places them first in the file. It also removes any old entries
398 that were the same. */
399 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
401 if (List
.size() == 0)
404 string File
= _config
->FindFile("Dir::Etc::sourcelist");
406 // Open the stream for reading
407 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
410 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
412 string NewFile
= File
+ ".new";
413 unlink(NewFile
.c_str());
414 ofstream
Out(NewFile
.c_str());
416 return _error
->Errno("ofstream::ofstream",
417 "Failed to open %s.new",File
.c_str());
419 // Create a short uri without the path
420 string ShortURI
= "cdrom:[" + Name
+ "]/";
421 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
432 while (F
.eof() == false)
434 F
.getline(Buffer
,sizeof(Buffer
));
436 if (F
.fail() && !F
.eof())
437 return _error
->Error(_("Line %u too long in source list %s."),
438 CurLine
,File
.c_str());
439 _strtabexpand(Buffer
,sizeof(Buffer
));
443 if (Buffer
[0] == '#' || Buffer
[0] == 0)
445 Out
<< Buffer
<< endl
;
451 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
453 string::size_type Space
= (*I
).find(' ');
454 if (Space
== string::npos
)
455 return _error
->Error("Internal error");
456 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
457 " " << string(*I
,Space
+1) << endl
;
465 const char *C
= Buffer
;
466 if (ParseQuoteWord(C
,cType
) == false ||
467 ParseQuoteWord(C
,URI
) == false)
469 Out
<< Buffer
<< endl
;
473 // Emit lines like this one
474 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
475 string(URI
,0,ShortURI
.length()) != ShortURI2
))
477 Out
<< Buffer
<< endl
;
482 // Just in case the file was empty
485 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
487 string::size_type Space
= (*I
).find(' ');
488 if (Space
== string::npos
)
489 return _error
->Error("Internal error");
491 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
492 " " << string(*I
,Space
+1) << endl
;
498 rename(File
.c_str(),string(File
+ '~').c_str());
499 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
500 return _error
->Errno("rename","Failed to rename %s.new to %s",
501 File
.c_str(),File
.c_str());
506 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
511 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
513 CDROM
= SafeGetCWD() + '/' + CDROM
;
517 ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
519 log
->Update(msg
.str());
521 if (MountCdrom(CDROM
) == false)
522 return _error
->Error("Failed to mount the cdrom.");
524 // Hash the CD to get an ID
526 log
->Update(_("Identifying.. "));
529 if (IdentCdrom(CDROM
,ident
) == false)
536 ioprintf(msg
, "[%s]\n",ident
.c_str());
537 log
->Update(msg
.str());
541 Configuration Database
;
542 string DFile
= _config
->FindFile("Dir::State::cdroms");
543 if (FileExists(DFile
) == true)
545 if (ReadConfigFile(Database
,DFile
) == false)
546 return _error
->Error("Unable to read the cdrom database %s",
551 ioprintf(msg
, _("Stored label: %s\n"),
552 Database
.Find("CD::"+ident
).c_str());
553 log
->Update(msg
.str());
556 // Unmount and finish
557 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
558 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
565 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
570 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
572 CDROM
= SafeGetCWD() + '/' + CDROM
;
575 log
->SetTotal(STEP_LAST
);
577 ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
578 log
->Update(msg
.str(), STEP_PREPARE
);
582 Configuration Database
;
583 string DFile
= _config
->FindFile("Dir::State::cdroms");
584 if (FileExists(DFile
) == true)
586 if (ReadConfigFile(Database
,DFile
) == false)
587 return _error
->Error("Unable to read the cdrom database %s",
591 // Unmount the CD and get the user to put in the one they want
592 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
595 log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
);
599 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
600 if(!log
->ChangeCdrom()) {
606 // Mount the new CDROM
607 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
608 if (MountCdrom(CDROM
) == false)
609 return _error
->Error("Failed to mount the cdrom.");
612 // Hash the CD to get an ID
614 log
->Update(_("Identifying.. "), STEP_IDENT
);
616 if (IdentCdrom(CDROM
,ID
) == false)
622 log
->Update("["+ID
+"]\n");
625 log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
);
627 // Get the CD structure
629 vector
<string
> SourceList
;
630 vector
<string
> SigList
;
631 vector
<string
> TransList
;
632 string StartDir
= SafeGetCWD();
634 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
640 chdir(StartDir
.c_str());
642 if (_config
->FindB("Debug::aptcdrom",false) == true)
644 cout
<< "I found (binary):" << endl
;
645 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
647 cout
<< "I found (source):" << endl
;
648 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); I
++)
650 cout
<< "I found (Signatures):" << endl
;
651 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); I
++)
655 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
658 DropBinaryArch(List
);
659 DropRepeats(List
,"Packages");
660 DropRepeats(SourceList
,"Sources");
661 DropRepeats(SigList
,"Release.gpg");
662 DropRepeats(TransList
,"");
665 ioprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
666 "%zu translation indexes and %zu signatures\n"),
667 List
.size(), SourceList
.size(), TransList
.size(),
669 log
->Update(msg
.str(), STEP_SCAN
);
672 if (List
.size() == 0 && SourceList
.size() == 0)
674 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
676 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
679 // Check if the CD is in the database
681 if (Database
.Exists("CD::" + ID
) == false ||
682 _config
->FindB("APT::CDROM::Rename",false) == true)
684 // Try to use the CDs label if at all possible
685 if (InfoDir
.empty() == false &&
686 FileExists(InfoDir
+ "/info") == true)
688 ifstream
F(string(InfoDir
+ "/info").c_str());
692 if (Name
.empty() == false)
694 // Escape special characters
695 string::iterator J
= Name
.begin();
696 for (; J
!= Name
.end(); J
++)
697 if (*J
== '"' || *J
== ']' || *J
== '[')
702 ioprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
703 log
->Update(msg
.str());
705 Database
.Set("CD::" + ID
+ "::Label",Name
);
709 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
710 Name
.empty() == true)
714 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
716 return _error
->Error("No disc name found and no way to ask for it");
720 if(!log
->AskCdromName(Name
)) {
724 cout
<< "Name: '" << Name
<< "'" << endl
;
726 if (Name
.empty() == false &&
727 Name
.find('"') == string::npos
&&
728 Name
.find('[') == string::npos
&&
729 Name
.find(']') == string::npos
)
731 log
->Update(_("That is not a valid name, try again.\n"));
736 Name
= Database
.Find("CD::" + ID
);
738 // Escape special characters
739 string::iterator J
= Name
.begin();
740 for (; J
!= Name
.end(); J
++)
741 if (*J
== '"' || *J
== ']' || *J
== '[')
744 Database
.Set("CD::" + ID
,Name
);
747 ioprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
748 log
->Update(msg
.str());
751 log
->Update(_("Copying package lists..."), STEP_COPY
);
752 // take care of the signatures and copy them if they are ok
753 // (we do this before PackageCopy as it modifies "List" and "SourceList")
754 SigVerify SignVerify
;
755 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
757 // Copy the package files to the state directory
760 TranslationsCopy TransCopy
;
761 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
762 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
763 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
766 // reduce the List so that it takes less space in sources.list
767 ReduceSourcelist(CDROM
,List
);
768 ReduceSourcelist(CDROM
,SourceList
);
770 // Write the database and sourcelist
771 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
773 if (WriteDatabase(Database
) == false)
777 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
779 if (WriteSourceList(Name
,List
,false) == false ||
780 WriteSourceList(Name
,SourceList
,true) == false)
784 // Print the sourcelist entries
786 log
->Update(_("Source list entries for this disc are:\n"));
788 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
790 string::size_type Space
= (*I
).find(' ');
791 if (Space
== string::npos
)
793 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
795 return _error
->Error("Internal error");
800 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
801 " " << string(*I
,Space
+1) << endl
;
802 log
->Update(msg
.str());
806 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); I
++)
808 string::size_type Space
= (*I
).find(' ');
809 if (Space
== string::npos
)
811 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
813 return _error
->Error("Internal error");
818 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
819 " " << string(*I
,Space
+1) << endl
;
820 log
->Update(msg
.str());
824 // Unmount and finish
825 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
826 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
833 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
834 : libudev_handle(NULL
)
841 pkgUdevCdromDevices::Dlopen() /*{{{*/
844 if(libudev_handle
!= NULL
)
847 // see if we can get libudev
848 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
852 // get the pointers to the udev structs
854 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
855 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
856 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
857 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
858 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
859 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
860 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
861 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
862 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
863 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
864 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
870 pkgUdevCdromDevices::Scan() /*{{{*/
872 vector
<CdromDevice
> cdrom_devices
;
873 struct udev_enumerate
*enumerate
;
874 struct udev_list_entry
*l
, *devices
;
875 struct udev
*udev_ctx
;
877 if(libudev_handle
== NULL
)
878 return cdrom_devices
;
880 udev_ctx
= udev_new();
881 enumerate
= udev_enumerate_new (udev_ctx
);
882 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
884 udev_enumerate_scan_devices (enumerate
);
885 devices
= udev_enumerate_get_list_entry (enumerate
);
886 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
889 struct udev_device
*udevice
;
890 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
893 const char* devnode
= udev_device_get_devnode(udevice
);
894 const char* mountpath
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
896 // fill in the struct
897 cdrom
.DeviceName
= string(devnode
);
899 cdrom
.MountPath
= mountpath
;
900 string s
= string(mountpath
);
901 cdrom
.Mounted
= IsMounted(s
);
903 cdrom
.Mounted
= false;
904 cdrom
.MountPath
= "";
906 cdrom_devices
.push_back(cdrom
);
908 return cdrom_devices
;
912 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
914 if (libudev_handle
!= NULL
)
915 dlclose(libudev_handle
);