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
]); 
 293    // Wipe erased entries 
 294    for (unsigned int I 
= 0; I 
< List
.size();) 
 296       if (List
[I
].empty() == false) 
 299          List
.erase(List
.begin()+I
); 
 305 // ReduceSourceList - Takes the path list and reduces it                /*{{{*/ 
 306 // --------------------------------------------------------------------- 
 307 /* This takes the list of source list expressed entires and collects 
 308    similar ones to form a single entry for each dist */ 
 309 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
) 
 311    sort(List
.begin(),List
.end()); 
 313    // Collect similar entries 
 314    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
 317       string::size_type Space 
= (*I
).find(' '); 
 318       if (Space 
== string::npos
) 
 320       string::size_type SSpace 
= (*I
).find(' ',Space 
+ 1); 
 321       if (SSpace 
== string::npos
) 
 324       string Word1 
= string(*I
,Space
,SSpace
-Space
); 
 325       string Prefix 
= string(*I
,0,Space
); 
 326       for (vector
<string
>::iterator J 
= List
.begin(); J 
!= I
; J
++) 
 329          string::size_type Space2 
= (*J
).find(' '); 
 330          if (Space2 
== string::npos
) 
 332          string::size_type SSpace2 
= (*J
).find(' ',Space2 
+ 1); 
 333          if (SSpace2 
== string::npos
) 
 336          if (string(*J
,0,Space2
) != Prefix
) 
 338          if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
) 
 341          *J 
+= string(*I
,SSpace
); 
 346    // Wipe erased entries 
 347    for (unsigned int I 
= 0; I 
< List
.size();) 
 349       if (List
[I
].empty() == false) 
 352          List
.erase(List
.begin()+I
); 
 356 // WriteDatabase - Write the CDROM Database file                        /*{{{*/ 
 357 // --------------------------------------------------------------------- 
 358 /* We rewrite the configuration class associated with the cdrom database. */ 
 359 bool pkgCdrom::WriteDatabase(Configuration 
&Cnf
) 
 361    string DFile 
= _config
->FindFile("Dir::State::cdroms"); 
 362    string NewFile 
= DFile 
+ ".new"; 
 364    unlink(NewFile
.c_str()); 
 365    ofstream 
Out(NewFile
.c_str()); 
 367       return _error
->Errno("ofstream::ofstream", 
 368                            "Failed to open %s.new",DFile
.c_str()); 
 370    /* Write out all of the configuration directives by walking the 
 371       configuration tree */ 
 372    const Configuration::Item 
*Top 
= Cnf
.Tree(0); 
 375       // Print the config entry 
 376       if (Top
->Value
.empty() == false) 
 377          Out 
<<  Top
->FullTag() + " \"" << Top
->Value 
<< "\";" << endl
; 
 385       while (Top 
!= 0 && Top
->Next 
== 0) 
 393    rename(DFile
.c_str(),string(DFile 
+ '~').c_str()); 
 394    if (rename(NewFile
.c_str(),DFile
.c_str()) != 0) 
 395       return _error
->Errno("rename","Failed to rename %s.new to %s", 
 396                            DFile
.c_str(),DFile
.c_str()); 
 401 // WriteSourceList - Write an updated sourcelist                        /*{{{*/ 
 402 // --------------------------------------------------------------------- 
 403 /* This reads the old source list and copies it into the new one. It  
 404    appends the new CDROM entires just after the first block of comments. 
 405    This places them first in the file. It also removes any old entries 
 406    that were the same. */ 
 407 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
) 
 409    if (List
.size() == 0) 
 412    string File 
= _config
->FindFile("Dir::Etc::sourcelist"); 
 414    // Open the stream for reading 
 415    ifstream 
F((FileExists(File
)?File
.c_str():"/dev/null"), 
 418       return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str()); 
 420    string NewFile 
= File 
+ ".new"; 
 421    unlink(NewFile
.c_str()); 
 422    ofstream 
Out(NewFile
.c_str()); 
 424       return _error
->Errno("ofstream::ofstream", 
 425                            "Failed to open %s.new",File
.c_str()); 
 427    // Create a short uri without the path 
 428    string ShortURI 
= "cdrom:[" + Name 
+ "]/";    
 429    string ShortURI2 
= "cdrom:" + Name 
+ "/";     // For Compatibility 
 440    while (F
.eof() == false) 
 442       F
.getline(Buffer
,sizeof(Buffer
)); 
 444       if (F
.fail() && !F
.eof()) 
 445          return _error
->Error(_("Line %u too long in source list %s."), 
 446                               CurLine
,File
.c_str()); 
 447       _strtabexpand(Buffer
,sizeof(Buffer
)); 
 451       if (Buffer
[0] == '#' || Buffer
[0] == 0) 
 453          Out 
<< Buffer 
<< endl
; 
 459          for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
 461             string::size_type Space 
= (*I
).find(' '); 
 462             if (Space 
== string::npos
) 
 463                return _error
->Error("Internal error"); 
 464             Out 
<< Type 
<< " cdrom:[" << Name 
<< "]/" << string(*I
,0,Space
) << 
 465                " " << string(*I
,Space
+1) << endl
; 
 473       const char *C 
= Buffer
; 
 474       if (ParseQuoteWord(C
,cType
) == false || 
 475           ParseQuoteWord(C
,URI
) == false) 
 477          Out 
<< Buffer 
<< endl
; 
 481       // Emit lines like this one 
 482       if (cType 
!= Type 
|| (string(URI
,0,ShortURI
.length()) != ShortURI 
&& 
 483           string(URI
,0,ShortURI
.length()) != ShortURI2
)) 
 485          Out 
<< Buffer 
<< endl
; 
 490    // Just in case the file was empty 
 493       for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
 495          string::size_type Space 
= (*I
).find(' '); 
 496          if (Space 
== string::npos
) 
 497             return _error
->Error("Internal error"); 
 499          Out 
<< "deb cdrom:[" << Name 
<< "]/" << string(*I
,0,Space
) <<  
 500             " " << string(*I
,Space
+1) << endl
; 
 506    rename(File
.c_str(),string(File 
+ '~').c_str()); 
 507    if (rename(NewFile
.c_str(),File
.c_str()) != 0) 
 508       return _error
->Errno("rename","Failed to rename %s.new to %s", 
 509                            File
.c_str(),File
.c_str()); 
 514 bool pkgCdrom::Ident(string 
&ident
, pkgCdromStatus 
*log
)                /*{{{*/ 
 519    string CDROM 
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/"); 
 521       CDROM
= SafeGetCWD() + '/' + CDROM
; 
 525       ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"), 
 527       log
->Update(msg
.str()); 
 529    if (MountCdrom(CDROM
) == false) 
 530       return _error
->Error("Failed to mount the cdrom."); 
 532    // Hash the CD to get an ID 
 534       log
->Update(_("Identifying.. ")); 
 537    if (IdentCdrom(CDROM
,ident
) == false) 
 544    ioprintf(msg
, "[%s]\n",ident
.c_str()); 
 545    log
->Update(msg
.str()); 
 549    Configuration Database
; 
 550    string DFile 
= _config
->FindFile("Dir::State::cdroms"); 
 551    if (FileExists(DFile
) == true) 
 553       if (ReadConfigFile(Database
,DFile
) == false) 
 554          return _error
->Error("Unable to read the cdrom database %s", 
 559       ioprintf(msg
, _("Stored label: %s\n"), 
 560       Database
.Find("CD::"+ident
).c_str()); 
 561       log
->Update(msg
.str()); 
 564    // Unmount and finish 
 565    if (_config
->FindB("APT::CDROM::NoMount",false) == false) { 
 566       log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
); 
 573 bool pkgCdrom::Add(pkgCdromStatus 
*log
)                                 /*{{{*/ 
 578    string CDROM 
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/"); 
 580       CDROM
= SafeGetCWD() + '/' + CDROM
; 
 583       log
->SetTotal(STEP_LAST
); 
 585       ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str()); 
 586       log
->Update(msg
.str(), STEP_PREPARE
); 
 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", 
 599    // Unmount the CD and get the user to put in the one they want 
 600    if (_config
->FindB("APT::CDROM::NoMount",false) == false) 
 603          log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
); 
 607          log
->Update(_("Waiting for disc...\n"), STEP_WAIT
); 
 608          if(!log
->ChangeCdrom()) { 
 614       // Mount the new CDROM 
 615       log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
); 
 616       if (MountCdrom(CDROM
) == false) 
 617          return _error
->Error("Failed to mount the cdrom."); 
 620    // Hash the CD to get an ID 
 622       log
->Update(_("Identifying.. "), STEP_IDENT
); 
 624    if (IdentCdrom(CDROM
,ID
) == false) 
 630       log
->Update("["+ID
+"]\n"); 
 633       log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
); 
 635    // Get the CD structure 
 637    vector
<string
> SourceList
; 
 638    vector
<string
> SigList
; 
 639    vector
<string
> TransList
; 
 640    string StartDir 
= SafeGetCWD(); 
 642    if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false) 
 648    chdir(StartDir
.c_str()); 
 650    if (_config
->FindB("Debug::aptcdrom",false) == true) 
 652       cout 
<< "I found (binary):" << endl
; 
 653       for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
 655       cout 
<< "I found (source):" << endl
; 
 656       for (vector
<string
>::iterator I 
= SourceList
.begin(); I 
!= SourceList
.end(); I
++) 
 658       cout 
<< "I found (Signatures):" << endl
; 
 659       for (vector
<string
>::iterator I 
= SigList
.begin(); I 
!= SigList
.end(); I
++) 
 663    //log->Update(_("Cleaning package lists..."), STEP_CLEAN); 
 666    DropBinaryArch(List
); 
 667    DropRepeats(List
,"Packages"); 
 668    DropRepeats(SourceList
,"Sources"); 
 669    DropRepeats(SigList
,"Release.gpg"); 
 670    DropRepeats(TransList
,""); 
 673       ioprintf(msg
, _("Found %zu package indexes, %zu source indexes, " 
 674                       "%zu translation indexes and %zu signatures\n"),  
 675                List
.size(), SourceList
.size(), TransList
.size(), 
 677       log
->Update(msg
.str(), STEP_SCAN
); 
 680    if (List
.size() == 0 && SourceList
.size() == 0)  
 682       if (_config
->FindB("APT::CDROM::NoMount",false) == false)  
 684       return _error
->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?")); 
 687    // Check if the CD is in the database 
 689    if (Database
.Exists("CD::" + ID
) == false || 
 690        _config
->FindB("APT::CDROM::Rename",false) == true) 
 692       // Try to use the CDs label if at all possible 
 693       if (InfoDir
.empty() == false && 
 694           FileExists(InfoDir 
+ "/info") == true) 
 696          ifstream 
F(string(InfoDir 
+ "/info").c_str()); 
 700          if (Name
.empty() == false) 
 702             // Escape special characters 
 703             string::iterator J 
= Name
.begin(); 
 704             for (; J 
!= Name
.end(); J
++) 
 705                if (*J 
== '"' || *J 
== ']' || *J 
== '[') 
 710                ioprintf(msg
, _("Found label '%s'\n"), Name
.c_str()); 
 711                log
->Update(msg
.str()); 
 713             Database
.Set("CD::" + ID 
+ "::Label",Name
); 
 717       if (_config
->FindB("APT::CDROM::Rename",false) == true || 
 718           Name
.empty() == true) 
 722             if (_config
->FindB("APT::CDROM::NoMount",false) == false)  
 724             return _error
->Error("No disc name found and no way to ask for it"); 
 728             if(!log
->AskCdromName(Name
)) { 
 732             cout 
<< "Name: '" << Name 
<< "'" << endl
; 
 734             if (Name
.empty() == false && 
 735                 Name
.find('"') == string::npos 
&& 
 736                 Name
.find('[') == string::npos 
&& 
 737                 Name
.find(']') == string::npos
) 
 739             log
->Update(_("That is not a valid name, try again.\n")); 
 744       Name 
= Database
.Find("CD::" + ID
); 
 746    // Escape special characters 
 747    string::iterator J 
= Name
.begin(); 
 748    for (; J 
!= Name
.end(); J
++) 
 749       if (*J 
== '"' || *J 
== ']' || *J 
== '[') 
 752    Database
.Set("CD::" + ID
,Name
); 
 755       ioprintf(msg
, _("This disc is called: \n'%s'\n"), Name
.c_str()); 
 756       log
->Update(msg
.str()); 
 759    log
->Update(_("Copying package lists..."), STEP_COPY
); 
 760    // take care of the signatures and copy them if they are ok 
 761    // (we do this before PackageCopy as it modifies "List" and "SourceList") 
 762    SigVerify SignVerify
; 
 763    SignVerify
.CopyAndVerify(CDROM
, Name
, SigList
, List
, SourceList
); 
 765    // Copy the package files to the state directory 
 768    TranslationsCopy TransCopy
; 
 769    if (Copy
.CopyPackages(CDROM
,Name
,List
, log
) == false || 
 770        SrcCopy
.CopyPackages(CDROM
,Name
,SourceList
, log
) == false || 
 771        TransCopy
.CopyTranslations(CDROM
,Name
,TransList
, log
) == false) 
 774    // reduce the List so that it takes less space in sources.list 
 775    ReduceSourcelist(CDROM
,List
); 
 776    ReduceSourcelist(CDROM
,SourceList
); 
 778    // Write the database and sourcelist 
 779    if (_config
->FindB("APT::cdrom::NoAct",false) == false) 
 781       if (WriteDatabase(Database
) == false) 
 785          log
->Update(_("Writing new source list\n"), STEP_WRITE
); 
 787       if (WriteSourceList(Name
,List
,false) == false || 
 788           WriteSourceList(Name
,SourceList
,true) == false) 
 792    // Print the sourcelist entries 
 794       log
->Update(_("Source list entries for this disc are:\n")); 
 796    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); I
++) 
 798       string::size_type Space 
= (*I
).find(' '); 
 799       if (Space 
== string::npos
) 
 801          if (_config
->FindB("APT::CDROM::NoMount",false) == false)  
 803          return _error
->Error("Internal error"); 
 808          msg 
<< "deb cdrom:[" << Name 
<< "]/" << string(*I
,0,Space
) <<  
 809             " " << string(*I
,Space
+1) << endl
; 
 810          log
->Update(msg
.str()); 
 814    for (vector
<string
>::iterator I 
= SourceList
.begin(); I 
!= SourceList
.end(); I
++) 
 816       string::size_type Space 
= (*I
).find(' '); 
 817       if (Space 
== string::npos
) 
 819          if (_config
->FindB("APT::CDROM::NoMount",false) == false)  
 821          return _error
->Error("Internal error"); 
 826          msg 
<< "deb-src cdrom:[" << Name 
<< "]/" << string(*I
,0,Space
) <<  
 827             " " << string(*I
,Space
+1) << endl
; 
 828          log
->Update(msg
.str()); 
 832    // Unmount and finish 
 833    if (_config
->FindB("APT::CDROM::NoMount",false) == false) { 
 834       log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
); 
 841 pkgUdevCdromDevices::pkgUdevCdromDevices()                              /*{{{*/ 
 842    : libudev_handle(NULL
) 
 849 pkgUdevCdromDevices::Dlopen()                                           /*{{{*/ 
 852    if(libudev_handle 
!= NULL
) 
 855    // see if we can get libudev 
 856    void *h 
= ::dlopen("libudev.so.0", RTLD_LAZY
); 
 860    // get the pointers to the udev structs 
 862    udev_new 
= (udev
* (*)(void)) dlsym(h
, "udev_new"); 
 863    udev_enumerate_add_match_property 
= (int (*)(udev_enumerate
*, const char*, const char*))dlsym(h
, "udev_enumerate_add_match_property"); 
 864    udev_enumerate_scan_devices 
= (int (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_scan_devices"); 
 865    udev_enumerate_get_list_entry 
= (udev_list_entry
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_list_entry"); 
 866    udev_device_new_from_syspath 
= (udev_device
* (*)(udev
*, const char*))dlsym(h
, "udev_device_new_from_syspath"); 
 867    udev_enumerate_get_udev 
= (udev
* (*)(udev_enumerate
*))dlsym(h
, "udev_enumerate_get_udev"); 
 868    udev_list_entry_get_name 
= (const char* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_name"); 
 869    udev_device_get_devnode 
= (const char* (*)(udev_device
*))dlsym(h
, "udev_device_get_devnode"); 
 870    udev_enumerate_new 
= (udev_enumerate
* (*)(udev
*))dlsym(h
, "udev_enumerate_new"); 
 871    udev_list_entry_get_next 
= (udev_list_entry
* (*)(udev_list_entry
*))dlsym(h
, "udev_list_entry_get_next"); 
 872    udev_device_get_property_value 
= (const char* (*)(udev_device 
*, const char *))dlsym(h
, "udev_device_get_property_value"); 
 878 pkgUdevCdromDevices::Scan()                                             /*{{{*/ 
 880    vector
<CdromDevice
> cdrom_devices
; 
 881    struct udev_enumerate 
*enumerate
; 
 882    struct udev_list_entry 
*l
, *devices
; 
 883    struct udev 
*udev_ctx
; 
 885    if(libudev_handle 
== NULL
) 
 886       return cdrom_devices
; 
 888    udev_ctx 
= udev_new(); 
 889    enumerate 
= udev_enumerate_new (udev_ctx
); 
 890    udev_enumerate_add_match_property(enumerate
, "ID_CDROM", "1"); 
 892    udev_enumerate_scan_devices (enumerate
); 
 893    devices 
= udev_enumerate_get_list_entry (enumerate
); 
 894    for (l 
= devices
; l 
!= NULL
; l 
= udev_list_entry_get_next (l
)) 
 897       struct udev_device 
*udevice
; 
 898       udevice 
= udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate
), udev_list_entry_get_name (l
)); 
 901       const char* devnode 
= udev_device_get_devnode(udevice
); 
 902       const char* mountpath 
= udev_device_get_property_value(udevice
, "FSTAB_DIR"); 
 904       // fill in the struct 
 905       cdrom
.DeviceName 
= string(devnode
); 
 907          cdrom
.MountPath 
= mountpath
; 
 908          string s 
= string(mountpath
); 
 909          cdrom
.Mounted 
= IsMounted(s
); 
 911          cdrom
.Mounted 
= false; 
 912          cdrom
.MountPath 
= ""; 
 914       cdrom_devices
.push_back(cdrom
); 
 916    return cdrom_devices
; 
 920 pkgUdevCdromDevices::~pkgUdevCdromDevices()                             /*{{{*/ 
 922    if (libudev_handle 
!= NULL
) 
 923       dlclose(libudev_handle
);