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>
21 #include "indexcopy.h"
25 // FindPackages - Find the package files on the CDROM /*{{{*/
26 // ---------------------------------------------------------------------
27 /* We look over the cdrom for package files. This is a recursive
28 search that short circuits when it his a package file in the dir.
29 This speeds it up greatly as the majority of the size is in the
31 bool pkgCdrom::FindPackages(string CD
,
33 vector
<string
> &SList
,
34 vector
<string
> &SigList
,
35 vector
<string
> &TransList
,
36 string
&InfoDir
, pkgCdromStatus
*log
,
39 static ino_t Inodes
[9];
42 // if we have a look we "pulse" now
49 if (CD
[CD
.length()-1] != '/')
52 if (chdir(CD
.c_str()) != 0)
53 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
55 // Look for a .disk subdirectory
57 if (stat(".disk",&Buf
) == 0)
59 if (InfoDir
.empty() == true)
60 InfoDir
= CD
+ ".disk/";
63 // Don't look into directories that have been marked to ingore.
64 if (stat(".aptignr",&Buf
) == 0)
68 /* Check _first_ for a signature file as apt-cdrom assumes that all files
69 under a Packages/Source file are in control of that file and stops
72 if (stat("Release.gpg",&Buf
) == 0)
74 SigList
.push_back(CD
);
76 /* Aha! We found some package files. We assume that everything under
77 this dir is controlled by those package files so we don't look down
79 if (stat("Packages",&Buf
) == 0 || stat("Packages.gz",&Buf
) == 0)
83 // Continue down if thorough is given
84 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
87 if (stat("Sources.gz",&Buf
) == 0 || stat("Sources",&Buf
) == 0)
91 // Continue down if thorough is given
92 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
96 // see if we find translatin indexes
97 if (stat("i18n",&Buf
) == 0)
100 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
102 if(strstr(Dir
->d_name
,"Translation") != NULL
)
104 if (_config
->FindB("Debug::aptcdrom",false) == true)
105 std::clog
<< "found translations: " << Dir
->d_name
<< "\n";
106 string file
= Dir
->d_name
;
107 if(file
.substr(file
.size()-3,file
.size()) == ".gz")
108 file
= file
.substr(0,file
.size()-3);
109 TransList
.push_back(CD
+"i18n/"+ file
);
118 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
120 // Run over the directory
121 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
124 if (strcmp(Dir
->d_name
,".") == 0 ||
125 strcmp(Dir
->d_name
,"..") == 0 ||
126 //strcmp(Dir->d_name,"source") == 0 ||
127 strcmp(Dir
->d_name
,".disk") == 0 ||
128 strcmp(Dir
->d_name
,"experimental") == 0 ||
129 strcmp(Dir
->d_name
,"binary-all") == 0 ||
130 strcmp(Dir
->d_name
,"debian-installer") == 0)
133 // See if the name is a sub directory
135 if (stat(Dir
->d_name
,&Buf
) != 0)
138 if (S_ISDIR(Buf
.st_mode
) == 0)
142 for (I
= 0; I
!= Depth
; I
++)
143 if (Inodes
[I
] == Buf
.st_ino
)
148 // Store the inodes weve seen
149 Inodes
[Depth
] = Buf
.st_ino
;
152 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false)
155 if (chdir(CD
.c_str()) != 0)
156 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
161 return !_error
->PendingError();
164 // Score - We compute a 'score' for a path /*{{{*/
165 // ---------------------------------------------------------------------
166 /* Paths are scored based on how close they come to what I consider
167 normal. That is ones that have 'dist' 'stable' 'testing' will score
168 higher than ones without. */
169 int pkgCdrom::Score(string Path
)
172 if (Path
.find("stable/") != string::npos
)
174 if (Path
.find("/binary-") != string::npos
)
176 if (Path
.find("testing/") != string::npos
)
178 if (Path
.find("unstable/") != string::npos
)
180 if (Path
.find("/dists/") != string::npos
)
182 if (Path
.find("/main/") != string::npos
)
184 if (Path
.find("/contrib/") != string::npos
)
186 if (Path
.find("/non-free/") != string::npos
)
188 if (Path
.find("/non-US/") != string::npos
)
190 if (Path
.find("/source/") != string::npos
)
192 if (Path
.find("/debian/") != string::npos
)
195 // check for symlinks in the patch leading to the actual file
196 // a symlink gets a big penalty
198 string statPath
= flNotFile(Path
);
199 string cdromPath
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
200 while(statPath
!= cdromPath
&& statPath
!= "./") {
201 statPath
.resize(statPath
.size()-1); // remove the trailing '/'
202 if (lstat(statPath
.c_str(),&Buf
) == 0) {
203 if(S_ISLNK(Buf
.st_mode
)) {
208 statPath
= flNotFile(statPath
); // descent
214 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
215 // ---------------------------------------------------------------------
216 /* Here we drop everything that is not this machines arch */
217 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
)
220 snprintf(S
,sizeof(S
),"/binary-%s/",
221 _config
->Find("Apt::Architecture").c_str());
223 for (unsigned int I
= 0; I
< List
.size(); I
++)
225 const char *Str
= List
[I
].c_str();
228 if ((Res
= strstr(Str
,"/binary-")) == 0)
232 if (strlen(Res
) < strlen(S
))
234 List
.erase(List
.begin() + I
);
239 // See if it is our arch
240 if (stringcmp(Res
,Res
+ strlen(S
),S
) == 0)
244 List
.erase(List
.begin() + I
);
251 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
252 // ---------------------------------------------------------------------
253 /* Here we go and stat every file that we found and strip dup inodes. */
254 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
)
256 // Get a list of all the inodes
257 ino_t
*Inodes
= new ino_t
[List
.size()];
258 for (unsigned int I
= 0; I
!= List
.size(); I
++)
261 if (stat((List
[I
] + Name
).c_str(),&Buf
) != 0 &&
262 stat((List
[I
] + Name
+ ".gz").c_str(),&Buf
) != 0)
263 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(),
265 Inodes
[I
] = Buf
.st_ino
;
268 if (_error
->PendingError() == true)
272 for (unsigned int I
= 0; I
!= List
.size(); I
++)
274 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
277 if (Inodes
[J
] != Inodes
[I
])
280 // We score the two paths.. and erase one
281 int ScoreA
= Score(List
[I
]);
282 int ScoreB
= Score(List
[J
]);
294 // Wipe erased entries
295 for (unsigned int I
= 0; I
< List
.size();)
297 if (List
[I
].empty() == false)
300 List
.erase(List
.begin()+I
);
306 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
307 // ---------------------------------------------------------------------
308 /* This takes the list of source list expressed entires and collects
309 similar ones to form a single entry for each dist */
310 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
)
312 sort(List
.begin(),List
.end());
314 // Collect similar entries
315 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
318 string::size_type Space
= (*I
).find(' ');
319 if (Space
== string::npos
)
321 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
322 if (SSpace
== string::npos
)
325 string Word1
= string(*I
,Space
,SSpace
-Space
);
326 string Prefix
= string(*I
,0,Space
);
327 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
330 string::size_type Space2
= (*J
).find(' ');
331 if (Space2
== string::npos
)
333 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
334 if (SSpace2
== string::npos
)
337 if (string(*J
,0,Space2
) != Prefix
)
339 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
342 *J
+= string(*I
,SSpace
);
347 // Wipe erased entries
348 for (unsigned int I
= 0; I
< List
.size();)
350 if (List
[I
].empty() == false)
353 List
.erase(List
.begin()+I
);
357 // WriteDatabase - Write the CDROM Database file /*{{{*/
358 // ---------------------------------------------------------------------
359 /* We rewrite the configuration class associated with the cdrom database. */
360 bool pkgCdrom::WriteDatabase(Configuration
&Cnf
)
362 string DFile
= _config
->FindFile("Dir::State::cdroms");
363 string NewFile
= DFile
+ ".new";
365 unlink(NewFile
.c_str());
366 ofstream
Out(NewFile
.c_str());
368 return _error
->Errno("ofstream::ofstream",
369 "Failed to open %s.new",DFile
.c_str());
371 /* Write out all of the configuration directives by walking the
372 configuration tree */
373 const Configuration::Item
*Top
= Cnf
.Tree(0);
376 // Print the config entry
377 if (Top
->Value
.empty() == false)
378 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
386 while (Top
!= 0 && Top
->Next
== 0)
394 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
395 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
396 return _error
->Errno("rename","Failed to rename %s.new to %s",
397 DFile
.c_str(),DFile
.c_str());
402 // WriteSourceList - Write an updated sourcelist /*{{{*/
403 // ---------------------------------------------------------------------
404 /* This reads the old source list and copies it into the new one. It
405 appends the new CDROM entires just after the first block of comments.
406 This places them first in the file. It also removes any old entries
407 that were the same. */
408 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
)
410 if (List
.size() == 0)
413 string File
= _config
->FindFile("Dir::Etc::sourcelist");
415 // Open the stream for reading
416 ifstream
F((FileExists(File
)?File
.c_str():"/dev/null"),
419 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
421 string NewFile
= File
+ ".new";
422 unlink(NewFile
.c_str());
423 ofstream
Out(NewFile
.c_str());
425 return _error
->Errno("ofstream::ofstream",
426 "Failed to open %s.new",File
.c_str());
428 // Create a short uri without the path
429 string ShortURI
= "cdrom:[" + Name
+ "]/";
430 string ShortURI2
= "cdrom:" + Name
+ "/"; // For Compatibility
441 while (F
.eof() == false)
443 F
.getline(Buffer
,sizeof(Buffer
));
445 if (F
.fail() && !F
.eof())
446 return _error
->Error(_("Line %u too long in source list %s."),
447 CurLine
,File
.c_str());
448 _strtabexpand(Buffer
,sizeof(Buffer
));
452 if (Buffer
[0] == '#' || Buffer
[0] == 0)
454 Out
<< Buffer
<< endl
;
460 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
462 string::size_type Space
= (*I
).find(' ');
463 if (Space
== string::npos
)
464 return _error
->Error("Internal error");
465 Out
<< Type
<< " cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
466 " " << string(*I
,Space
+1) << endl
;
474 const char *C
= Buffer
;
475 if (ParseQuoteWord(C
,cType
) == false ||
476 ParseQuoteWord(C
,URI
) == false)
478 Out
<< Buffer
<< endl
;
482 // Emit lines like this one
483 if (cType
!= Type
|| (string(URI
,0,ShortURI
.length()) != ShortURI
&&
484 string(URI
,0,ShortURI
.length()) != ShortURI2
))
486 Out
<< Buffer
<< endl
;
491 // Just in case the file was empty
494 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
496 string::size_type Space
= (*I
).find(' ');
497 if (Space
== string::npos
)
498 return _error
->Error("Internal error");
500 Out
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
501 " " << string(*I
,Space
+1) << endl
;
507 rename(File
.c_str(),string(File
+ '~').c_str());
508 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
509 return _error
->Errno("rename","Failed to rename %s.new to %s",
510 File
.c_str(),File
.c_str());
515 bool pkgCdrom::Ident(string
&ident
, pkgCdromStatus
*log
) /*{{{*/
520 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
522 CDROM
= SafeGetCWD() + '/' + CDROM
;
526 ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
528 log
->Update(msg
.str());
530 if (MountCdrom(CDROM
) == false)
531 return _error
->Error("Failed to mount the cdrom.");
533 // Hash the CD to get an ID
535 log
->Update(_("Identifying.. "));
538 if (IdentCdrom(CDROM
,ident
) == false)
545 ioprintf(msg
, "[%s]\n",ident
.c_str());
546 log
->Update(msg
.str());
550 Configuration Database
;
551 string DFile
= _config
->FindFile("Dir::State::cdroms");
552 if (FileExists(DFile
) == true)
554 if (ReadConfigFile(Database
,DFile
) == false)
555 return _error
->Error("Unable to read the cdrom database %s",
560 ioprintf(msg
, _("Stored label: %s\n"),
561 Database
.Find("CD::"+ident
).c_str());
562 log
->Update(msg
.str());
565 // Unmount and finish
566 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
567 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
574 bool pkgCdrom::Add(pkgCdromStatus
*log
) /*{{{*/
579 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
581 CDROM
= SafeGetCWD() + '/' + CDROM
;
584 log
->SetTotal(STEP_LAST
);
586 ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str());
587 log
->Update(msg
.str(), STEP_PREPARE
);
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",
600 // Unmount the CD and get the user to put in the one they want
601 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
604 log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
);
608 log
->Update(_("Waiting for disc...\n"), STEP_WAIT
);
609 if(!log
->ChangeCdrom()) {
615 // Mount the new CDROM
616 log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
);
617 if (MountCdrom(CDROM
) == false)
618 return _error
->Error("Failed to mount the cdrom.");
621 // Hash the CD to get an ID
623 log
->Update(_("Identifying.. "), STEP_IDENT
);
625 if (IdentCdrom(CDROM
,ID
) == false)
631 log
->Update("["+ID
+"]\n");
634 log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
);
636 // Get the CD structure
638 vector
<string
> SourceList
;
639 vector
<string
> SigList
;
640 vector
<string
> TransList
;
641 string StartDir
= SafeGetCWD();
643 if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false)
649 chdir(StartDir
.c_str());
651 if (_config
->FindB("Debug::aptcdrom",false) == true)
653 cout
<< "I found (binary):" << endl
;
654 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
656 cout
<< "I found (source):" << endl
;
657 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); I
++)
659 cout
<< "I found (Signatures):" << endl
;
660 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); I
++)
664 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
667 DropBinaryArch(List
);
668 DropRepeats(List
,"Packages");
669 DropRepeats(SourceList
,"Sources");
670 DropRepeats(SigList
,"Release.gpg");
671 DropRepeats(TransList
,"");
674 ioprintf(msg
, _("Found %zu package indexes, %zu source indexes, "
675 "%zu translation indexes and %zu signatures\n"),
676 List
.size(), SourceList
.size(), TransList
.size(),
678 log
->Update(msg
.str(), STEP_SCAN
);
681 if (List
.size() == 0 && SourceList
.size() == 0)
683 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
685 return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
688 // Check if the CD is in the database
690 if (Database
.Exists("CD::" + ID
) == false ||
691 _config
->FindB("APT::CDROM::Rename",false) == true)
693 // Try to use the CDs label if at all possible
694 if (InfoDir
.empty() == false &&
695 FileExists(InfoDir
+ "/info") == true)
697 ifstream
F(string(InfoDir
+ "/info").c_str());
701 if (Name
.empty() == false)
703 // Escape special characters
704 string::iterator J
= Name
.begin();
705 for (; J
!= Name
.end(); J
++)
706 if (*J
== '"' || *J
== ']' || *J
== '[')
711 ioprintf(msg
, _("Found label '%s'\n"), Name
.c_str());
712 log
->Update(msg
.str());
714 Database
.Set("CD::" + ID
+ "::Label",Name
);
718 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
719 Name
.empty() == true)
723 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
725 return _error
->Error("No disc name found and no way to ask for it");
729 if(!log
->AskCdromName(Name
)) {
733 cout
<< "Name: '" << Name
<< "'" << endl
;
735 if (Name
.empty() == false &&
736 Name
.find('"') == string::npos
&&
737 Name
.find('[') == string::npos
&&
738 Name
.find(']') == string::npos
)
740 log
->Update(_("That is not a valid name, try again.\n"));
745 Name
= Database
.Find("CD::" + ID
);
747 // Escape special characters
748 string::iterator J
= Name
.begin();
749 for (; J
!= Name
.end(); J
++)
750 if (*J
== '"' || *J
== ']' || *J
== '[')
753 Database
.Set("CD::" + ID
,Name
);
756 ioprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str());
757 log
->Update(msg
.str());
760 log
->Update(_("Copying package lists..."), STEP_COPY
);
761 // take care of the signatures and copy them if they are ok
762 // (we do this before PackageCopy as it modifies "List" and "SourceList")
763 SigVerify SignVerify
;
764 SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
);
766 // Copy the package files to the state directory
769 TranslationsCopy TransCopy
;
770 if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false ||
771 SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false ||
772 TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false)
775 // reduce the List so that it takes less space in sources.list
776 ReduceSourcelist(CDROM
,List
);
777 ReduceSourcelist(CDROM
,SourceList
);
779 // Write the database and sourcelist
780 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
782 if (WriteDatabase(Database
) == false)
786 log
->Update(_("Writing new source list\n"), STEP_WRITE
);
788 if (WriteSourceList(Name
,List
,false) == false ||
789 WriteSourceList(Name
,SourceList
,true) == false)
793 // Print the sourcelist entries
795 log
->Update(_("Source list entries for this disc are:\n"));
797 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
799 string::size_type Space
= (*I
).find(' ');
800 if (Space
== string::npos
)
802 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
804 return _error
->Error("Internal error");
809 msg
<< "deb cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
810 " " << string(*I
,Space
+1) << endl
;
811 log
->Update(msg
.str());
815 for (vector
<string
>::iterator I
= SourceList
.begin(); I
!= SourceList
.end(); I
++)
817 string::size_type Space
= (*I
).find(' ');
818 if (Space
== string::npos
)
820 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
822 return _error
->Error("Internal error");
827 msg
<< "deb-src cdrom:[" << Name
<< "]/" << string(*I
,0,Space
) <<
828 " " << string(*I
,Space
+1) << endl
;
829 log
->Update(msg
.str());
833 // Unmount and finish
834 if (_config
->FindB("APT::CDROM::NoMount",false) == false) {
835 log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
);
842 pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
843 : libudev_handle(NULL
)
850 pkgUdevCdromDevices::Dlopen() /*{{{*/
853 if(libudev_handle
!= NULL
)
856 // see if we can get libudev
857 void *h
= ::dlopen("libudev.so.0", RTLD_LAZY
);
861 // get the pointers to the udev structs
863 udev_new
= (udev
* (*)(void)) dlsym(h
, "udev_new");
864 udev_enumerate_add_match_property
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property");
865 udev_enumerate_scan_devices
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices");
866 udev_enumerate_get_list_entry
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry");
867 udev_device_new_from_syspath
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath");
868 udev_enumerate_get_udev
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev");
869 udev_list_entry_get_name
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name");
870 udev_device_get_devnode
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode");
871 udev_enumerate_new
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new");
872 udev_list_entry_get_next
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next");
873 udev_device_get_property_value
= (const char* (*)(udev_device
*, const char *))dlsym(h
, "udev_device_get_property_value");
879 pkgUdevCdromDevices::Scan() /*{{{*/
881 vector
<CdromDevice
> cdrom_devices
;
882 struct udev_enumerate
*enumerate
;
883 struct udev_list_entry
*l
, *devices
;
884 struct udev
*udev_ctx
;
886 if(libudev_handle
== NULL
)
887 return cdrom_devices
;
889 udev_ctx
= udev_new();
890 enumerate
= udev_enumerate_new (udev_ctx
);
891 udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1");
893 udev_enumerate_scan_devices (enumerate
);
894 devices
= udev_enumerate_get_list_entry (enumerate
);
895 for (l
= devices
; l
!= NULL
; l
= udev_list_entry_get_next (l
))
898 struct udev_device
*udevice
;
899 udevice
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
));
902 const char* devnode
= udev_device_get_devnode(udevice
);
903 const char* mountpath
= udev_device_get_property_value(udevice
, "FSTAB_DIR");
905 // fill in the struct
906 cdrom
.DeviceName
= string(devnode
);
908 cdrom
.MountPath
= mountpath
;
909 string s
= string(mountpath
);
910 cdrom
.Mounted
= IsMounted(s
);
912 cdrom
.Mounted
= false;
913 cdrom
.MountPath
= "";
915 cdrom_devices
.push_back(cdrom
);
917 return cdrom_devices
;
921 pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
923 if (libudev_handle
!= NULL
)
924 dlclose(libudev_handle
);