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) 
  71    /* Check _first_ for a signature file as apt-cdrom assumes that all files 
  72       under a Packages/Source file are in control of that file and stops  
  75    if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true) 
  77       SigList
.push_back(CD
); 
  80    /* Aha! We found some package files. We assume that everything under  
  81       this dir is controlled by those package files so we don't look down 
  83    std::vector
<APT::Configuration::Compressor
> const compressor 
= APT::Configuration::getCompressors(); 
  84    for (std::vector
<APT::Configuration::Compressor
>::const_iterator c 
= compressor
.begin(); 
  85         c 
!= compressor
.end(); ++c
) 
  87       if (RealFileExists(std::string("Packages").append(c
->Extension
).c_str()) == false) 
  90       if (_config
->FindB("Debug::aptcdrom",false) == true) 
  91          std::clog 
<< "Found Packages in " << CD 
<< std::endl
; 
  94       // Continue down if thorough is given 
  95       if (_config
->FindB("APT::CDROM::Thorough",false) == false) 
  99    for (std::vector
<APT::Configuration::Compressor
>::const_iterator c 
= compressor
.begin(); 
 100         c 
!= compressor
.end(); ++c
) 
 102       if (RealFileExists(std::string("Sources").append(c
->Extension
).c_str()) == false) 
 105       if (_config
->FindB("Debug::aptcdrom",false) == true) 
 106          std::clog 
<< "Found Sources in " << CD 
<< std::endl
; 
 109       // Continue down if thorough is given 
 110       if (_config
->FindB("APT::CDROM::Thorough",false) == false) 
 115    // see if we find translation indices 
 116    if (DirectoryExists("i18n") == true) 
 119       for (struct dirent 
*Dir 
= readdir(D
); Dir 
!= 0; Dir 
= readdir(D
)) 
 121          if(strncmp(Dir
->d_name
, "Translation-", strlen("Translation-")) != 0) 
 123          string file 
= Dir
->d_name
; 
 124          for (std::vector
<APT::Configuration::Compressor
>::const_iterator c 
= compressor
.begin(); 
 125               c 
!= compressor
.end(); ++c
) 
 127             string fileext 
= flExtension(file
); 
 130             else if (fileext
.empty() == false) 
 131                fileext 
= "." + fileext
; 
 133             if (c
->Extension 
== fileext
) 
 135                if (_config
->FindB("Debug::aptcdrom",false) == true) 
 136                   std::clog 
<< "Found translation " << Dir
->d_name 
<< " in " << CD 
<< "i18n/" << std::endl
; 
 137                file
.erase(file
.size() - fileext
.size()); 
 138                TransList
.push_back(CD 
+ "i18n/" + file
); 
 148       return _error
->Errno("opendir","Unable to read %s",CD
.c_str()); 
 150    // Run over the directory 
 151    for (struct dirent 
*Dir 
= readdir(D
); Dir 
!= 0; Dir 
= readdir(D
)) 
 154       if (strcmp(Dir
->d_name
,".") == 0 || 
 155           strcmp(Dir
->d_name
,"..") == 0 || 
 156           //strcmp(Dir->d_name,"source") == 0 || 
 157           strcmp(Dir
->d_name
,".disk") == 0 || 
 158           strcmp(Dir
->d_name
,"experimental") == 0 || 
 159           strcmp(Dir
->d_name
,"binary-all") == 0 || 
 160           strcmp(Dir
->d_name
,"debian-installer") == 0) 
 163       // See if the name is a sub directory 
 165       if (stat(Dir
->d_name
,&Buf
) != 0) 
 168       if (S_ISDIR(Buf
.st_mode
) == 0) 
 172       for (I 
= 0; I 
!= Depth
; I
++) 
 173          if (Inodes
[I
] == Buf
.st_ino
) 
 178       // Store the inodes weve seen 
 179       Inodes
[Depth
] = Buf
.st_ino
; 
 182       if (FindPackages(CD 
+ Dir
->d_name
,List
,SList
,SigList
,TransList
,InfoDir
,log
,Depth
+1) == false) 
 185       if (chdir(CD
.c_str()) != 0) 
 187          _error
->Errno("chdir","Unable to change to %s", CD
.c_str()); 
 195    return !_error
->PendingError(); 
 198 // Score - We compute a 'score' for a path                              /*{{{*/ 
 199 // --------------------------------------------------------------------- 
 200 /* Paths are scored based on how close they come to what I consider 
 201    normal. That is ones that have 'dist' 'stable' 'testing' will score 
 202    higher than ones without. */ 
 203 int pkgCdrom::Score(string Path
) 
 206    if (Path
.find("stable/") != string::npos
) 
 208    if (Path
.find("/binary-") != string::npos
) 
 210    if (Path
.find("testing/") != string::npos
) 
 212    if (Path
.find("unstable/") != string::npos
) 
 214    if (Path
.find("/dists/") != string::npos
) 
 216    if (Path
.find("/main/") != string::npos
) 
 218    if (Path
.find("/contrib/") != string::npos
) 
 220    if (Path
.find("/non-free/") != string::npos
) 
 222    if (Path
.find("/non-US/") != string::npos
) 
 224    if (Path
.find("/source/") != string::npos
) 
 226    if (Path
.find("/debian/") != string::npos
) 
 229    // check for symlinks in the patch leading to the actual file 
 230    // a symlink gets a big penalty 
 232    string statPath 
= flNotFile(Path
); 
 233    string cdromPath 
= _config
->FindDir("Acquire::cdrom::mount"); 
 234    while(statPath 
!= cdromPath 
&& statPath 
!= "./") { 
 235       statPath
.resize(statPath
.size()-1);  // remove the trailing '/' 
 236       if (lstat(statPath
.c_str(),&Buf
) == 0) { 
 237         if(S_ISLNK(Buf
.st_mode
)) { 
 242       statPath 
= flNotFile(statPath
); // descent 
 248 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/         /*{{{*/ 
 249 // --------------------------------------------------------------------- 
 250 /* Here we drop everything that is not this machines arch */ 
 251 bool pkgCdrom::DropBinaryArch(vector
<string
> &List
) 
 254    for (unsigned int I 
= 0; I 
< List
.size(); I
++) 
 256       const char *Str 
= List
[I
].c_str(); 
 257       const char *Start
, *End
; 
 258       if ((Start 
= strstr(Str
,"/binary-")) == 0) 
 261       // Between Start and End is the architecture 
 263       if ((End 
= strstr(Start
,"/")) != 0 && Start 
!= End 
&& 
 264           APT::Configuration::checkArchitecture(string(Start
, End
)) == true) 
 265          continue; // okay, architecture is accepted 
 267       // not accepted -> Erase it 
 268       List
.erase(List
.begin() + I
); 
 269       --I
; // the next entry is at the same index after the erase 
 275 // DropRepeats - Drop repeated files resulting from symlinks            /*{{{*/ 
 276 // --------------------------------------------------------------------- 
 277 /* Here we go and stat every file that we found and strip dup inodes. */ 
 278 bool pkgCdrom::DropRepeats(vector
<string
> &List
,const char *Name
) 
 280    // Get a list of all the inodes 
 281    ino_t 
*Inodes 
= new ino_t
[List
.size()]; 
 282    for (unsigned int I 
= 0; I 
!= List
.size(); ++I
) 
 287       std::vector
<APT::Configuration::Compressor
> const compressor 
= APT::Configuration::getCompressors(); 
 288       for (std::vector
<APT::Configuration::Compressor
>::const_iterator c 
= compressor
.begin(); 
 289            c 
!= compressor
.end(); ++c
) 
 291          std::string filename 
= std::string(List
[I
]).append(Name
).append(c
->Extension
); 
 292          if (stat(filename
.c_str(), &Buf
) != 0) 
 294          Inodes
[I
] = Buf
.st_ino
; 
 300          _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(), Name
); 
 303    if (_error
->PendingError() == true) { 
 309    for (unsigned int I 
= 0; I 
!= List
.size(); I
++) 
 311       for (unsigned int J 
= I
+1; J 
< List
.size(); J
++) 
 314          if (Inodes
[J
] != Inodes
[I
]) 
 317          // We score the two paths.. and erase one 
 318          int ScoreA 
= Score(List
[I
]); 
 319          int ScoreB 
= Score(List
[J
]); 
 331    // Wipe erased entries 
 332    for (unsigned int I 
= 0; I 
< List
.size();) 
 334       if (List
[I
].empty() == false) 
 337          List
.erase(List
.begin()+I
); 
 343 // ReduceSourceList - Takes the path list and reduces it                /*{{{*/ 
 344 // --------------------------------------------------------------------- 
 345 /* This takes the list of source list expressed entires and collects 
 346    similar ones to form a single entry for each dist */ 
 347 void pkgCdrom::ReduceSourcelist(string CD
,vector
<string
> &List
) 
 349    sort(List
.begin(),List
.end()); 
 351    // Collect similar entries 
 352    for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
 355       string::size_type Space 
= (*I
).find(' '); 
 356       if (Space 
== string::npos
) 
 358       string::size_type SSpace 
= (*I
).find(' ',Space 
+ 1); 
 359       if (SSpace 
== string::npos
) 
 362       string Word1 
= string(*I
,Space
,SSpace
-Space
); 
 363       string Prefix 
= string(*I
,0,Space
); 
 364       for (vector
<string
>::iterator J 
= List
.begin(); J 
!= I
; ++J
) 
 367          string::size_type Space2 
= (*J
).find(' '); 
 368          if (Space2 
== string::npos
) 
 370          string::size_type SSpace2 
= (*J
).find(' ',Space2 
+ 1); 
 371          if (SSpace2 
== string::npos
) 
 374          if (string(*J
,0,Space2
) != Prefix
) 
 376          if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
) 
 379          *J 
+= string(*I
,SSpace
); 
 384    // Wipe erased entries 
 385    for (unsigned int I 
= 0; I 
< List
.size();) 
 387       if (List
[I
].empty() == false) 
 390          List
.erase(List
.begin()+I
); 
 394 // WriteDatabase - Write the CDROM Database file                        /*{{{*/ 
 395 // --------------------------------------------------------------------- 
 396 /* We rewrite the configuration class associated with the cdrom database. */ 
 397 bool pkgCdrom::WriteDatabase(Configuration 
&Cnf
) 
 399    string DFile 
= _config
->FindFile("Dir::State::cdroms"); 
 400    string NewFile 
= DFile 
+ ".new"; 
 402    unlink(NewFile
.c_str()); 
 403    ofstream 
Out(NewFile
.c_str()); 
 405       return _error
->Errno("ofstream::ofstream", 
 406                            "Failed to open %s.new",DFile
.c_str()); 
 408    /* Write out all of the configuration directives by walking the 
 409       configuration tree */ 
 410    const Configuration::Item 
*Top 
= Cnf
.Tree(0); 
 413       // Print the config entry 
 414       if (Top
->Value
.empty() == false) 
 415          Out 
<<  Top
->FullTag() + " \"" << Top
->Value 
<< "\";" << endl
; 
 423       while (Top 
!= 0 && Top
->Next 
== 0) 
 431    link(DFile
.c_str(),string(DFile 
+ '~').c_str()); 
 432    if (rename(NewFile
.c_str(),DFile
.c_str()) != 0) 
 433       return _error
->Errno("rename","Failed to rename %s.new to %s", 
 434                            DFile
.c_str(),DFile
.c_str()); 
 439 // WriteSourceList - Write an updated sourcelist                        /*{{{*/ 
 440 // --------------------------------------------------------------------- 
 441 /* This reads the old source list and copies it into the new one. It  
 442    appends the new CDROM entires just after the first block of comments. 
 443    This places them first in the file. It also removes any old entries 
 444    that were the same. */ 
 445 bool pkgCdrom::WriteSourceList(string Name
,vector
<string
> &List
,bool Source
) 
 447    if (List
.empty() == true) 
 450    string File 
= _config
->FindFile("Dir::Etc::sourcelist"); 
 452    // Open the stream for reading 
 453    ifstream 
F((FileExists(File
)?File
.c_str():"/dev/null"), 
 456       return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str()); 
 458    string NewFile 
= File 
+ ".new"; 
 459    unlink(NewFile
.c_str()); 
 460    ofstream 
Out(NewFile
.c_str()); 
 462       return _error
->Errno("ofstream::ofstream", 
 463                            "Failed to open %s.new",File
.c_str()); 
 465    // Create a short uri without the path 
 466    string ShortURI 
= "cdrom:[" + Name 
+ "]/";    
 467    string ShortURI2 
= "cdrom:" + Name 
+ "/";     // For Compatibility 
 478    while (F
.eof() == false) 
 480       F
.getline(Buffer
,sizeof(Buffer
)); 
 482       if (F
.fail() && !F
.eof()) 
 483          return _error
->Error(_("Line %u too long in source list %s."), 
 484                               CurLine
,File
.c_str()); 
 485       _strtabexpand(Buffer
,sizeof(Buffer
)); 
 489       if (Buffer
[0] == '#' || Buffer
[0] == 0) 
 491          Out 
<< Buffer 
<< endl
; 
 497          for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
 499             string::size_type Space 
= (*I
).find(' '); 
 500             if (Space 
== string::npos
) 
 501                return _error
->Error("Internal error"); 
 502             Out 
<< Type 
<< " cdrom:[" << Name 
<< "]/" << string(*I
,0,Space
) << 
 503                " " << string(*I
,Space
+1) << endl
; 
 511       const char *C 
= Buffer
; 
 512       if (ParseQuoteWord(C
,cType
) == false || 
 513           ParseQuoteWord(C
,URI
) == false) 
 515          Out 
<< Buffer 
<< endl
; 
 519       // Emit lines like this one 
 520       if (cType 
!= Type 
|| (string(URI
,0,ShortURI
.length()) != ShortURI 
&& 
 521           string(URI
,0,ShortURI
.length()) != ShortURI2
)) 
 523          Out 
<< Buffer 
<< endl
; 
 528    // Just in case the file was empty 
 531       for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
 533          string::size_type Space 
= (*I
).find(' '); 
 534          if (Space 
== string::npos
) 
 535             return _error
->Error("Internal error"); 
 537          Out 
<< "deb cdrom:[" << Name 
<< "]/" << string(*I
,0,Space
) <<  
 538             " " << string(*I
,Space
+1) << endl
; 
 544    rename(File
.c_str(),string(File 
+ '~').c_str()); 
 545    if (rename(NewFile
.c_str(),File
.c_str()) != 0) 
 546       return _error
->Errno("rename","Failed to rename %s.new to %s", 
 547                            File
.c_str(),File
.c_str()); 
 552 bool pkgCdrom::Ident(string 
&ident
, pkgCdromStatus 
*log
)                /*{{{*/ 
 557    string CDROM 
= _config
->FindDir("Acquire::cdrom::mount"); 
 559       CDROM
= SafeGetCWD() + '/' + CDROM
; 
 564       ioprintf(msg
, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"), 
 566       log
->Update(msg
.str()); 
 568    if (MountCdrom(CDROM
) == false) 
 569       return _error
->Error("Failed to mount the cdrom."); 
 571    // Hash the CD to get an ID 
 573       log
->Update(_("Identifying.. ")); 
 576    if (IdentCdrom(CDROM
,ident
) == false) 
 585       ioprintf(msg
, "[%s]\n",ident
.c_str()); 
 586       log
->Update(msg
.str()); 
 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", 
 601       ioprintf(msg
, _("Stored label: %s\n"), 
 602       Database
.Find("CD::"+ident
).c_str()); 
 603       log
->Update(msg
.str()); 
 606    // Unmount and finish 
 607    if (_config
->FindB("APT::CDROM::NoMount",false) == false) 
 610          log
->Update(_("Unmounting CD-ROM...\n"), STEP_LAST
); 
 617 bool pkgCdrom::Add(pkgCdromStatus 
*log
)                                 /*{{{*/ 
 622    string CDROM 
= _config
->FindDir("Acquire::cdrom::mount"); 
 624       CDROM
= SafeGetCWD() + '/' + CDROM
; 
 628       log
->SetTotal(STEP_LAST
); 
 630       ioprintf(msg
, _("Using CD-ROM mount point %s\n"), CDROM
.c_str()); 
 631       log
->Update(msg
.str(), STEP_PREPARE
); 
 635    Configuration Database
; 
 636    string DFile 
= _config
->FindFile("Dir::State::cdroms"); 
 637    if (FileExists(DFile
) == true) 
 639       if (ReadConfigFile(Database
,DFile
) == false)  
 640          return _error
->Error("Unable to read the cdrom database %s", 
 644    // Unmount the CD and get the user to put in the one they want 
 645    if (_config
->FindB("APT::CDROM::NoMount",false) == false) 
 648          log
->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT
); 
 653          log
->Update(_("Waiting for disc...\n"), STEP_WAIT
); 
 654          if(!log
->ChangeCdrom()) { 
 660       // Mount the new CDROM 
 662          log
->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT
); 
 664       if (MountCdrom(CDROM
) == false) 
 665          return _error
->Error("Failed to mount the cdrom."); 
 668    // Hash the CD to get an ID 
 670       log
->Update(_("Identifying.. "), STEP_IDENT
); 
 672    if (IdentCdrom(CDROM
,ID
) == false) 
 680       log
->Update("["+ID
+"]\n"); 
 681       log
->Update(_("Scanning disc for index files..\n"),STEP_SCAN
); 
 684    // Get the CD structure 
 686    vector
<string
> SourceList
; 
 687    vector
<string
> SigList
; 
 688    vector
<string
> TransList
; 
 689    string StartDir 
= SafeGetCWD(); 
 691    if (FindPackages(CDROM
,List
,SourceList
, SigList
,TransList
,InfoDir
,log
) == false) 
 698    chdir(StartDir
.c_str()); 
 700    if (_config
->FindB("Debug::aptcdrom",false) == true) 
 702       cout 
<< "I found (binary):" << endl
; 
 703       for (vector
<string
>::iterator I 
= List
.begin(); I 
!= List
.end(); ++I
) 
 705       cout 
<< "I found (source):" << endl
; 
 706       for (vector
<string
>::iterator I 
= SourceList
.begin(); I 
!= SourceList
.end(); ++I
) 
 708       cout 
<< "I found (Signatures):" << endl
; 
 709       for (vector
<string
>::iterator I 
= SigList
.begin(); I 
!= SigList
.end(); ++I
) 
 713    //log->Update(_("Cleaning package lists..."), STEP_CLEAN); 
 716    DropBinaryArch(List
); 
 717    DropRepeats(List
,"Packages"); 
 718    DropRepeats(SourceList
,"Sources"); 
 719    DropRepeats(SigList
,"Release.gpg"); 
 720    DropRepeats(SigList
,"InRelease"); 
 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
);