You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1002 lines
29 KiB

  1. /*
  2. */
  3. #include<config.h>
  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>
  10. #include<apt-pkg/configuration.h>
  11. #include<apt-pkg/fileutl.h>
  12. #include<sstream>
  13. #include<fstream>
  14. #include <sys/stat.h>
  15. #include <fcntl.h>
  16. #include <dirent.h>
  17. #include <unistd.h>
  18. #include <stdio.h>
  19. #include <algorithm>
  20. #include <dlfcn.h>
  21. #include "indexcopy.h"
  22. #include<apti18n.h>
  23. using namespace std;
  24. // FindPackages - Find the package files on the CDROM /*{{{*/
  25. // ---------------------------------------------------------------------
  26. /* We look over the cdrom for package files. This is a recursive
  27. search that short circuits when it his a package file in the dir.
  28. This speeds it up greatly as the majority of the size is in the
  29. binary-* sub dirs. */
  30. bool pkgCdrom::FindPackages(string CD,
  31. vector<string> &List,
  32. vector<string> &SList,
  33. vector<string> &SigList,
  34. vector<string> &TransList,
  35. string &InfoDir, pkgCdromStatus *log,
  36. unsigned int Depth)
  37. {
  38. static ino_t Inodes[9];
  39. DIR *D;
  40. // if we have a look we "pulse" now
  41. if(log)
  42. log->Update();
  43. if (Depth >= 7)
  44. return true;
  45. if (CD[CD.length()-1] != '/')
  46. CD += '/';
  47. if (chdir(CD.c_str()) != 0)
  48. return _error->Errno("chdir","Unable to change to %s",CD.c_str());
  49. // Look for a .disk subdirectory
  50. if (DirectoryExists(".disk") == true)
  51. {
  52. if (InfoDir.empty() == true)
  53. InfoDir = CD + ".disk/";
  54. }
  55. // Don't look into directories that have been marked to ingore.
  56. if (RealFileExists(".aptignr") == true)
  57. return true;
  58. /* Check _first_ for a signature file as apt-cdrom assumes that all files
  59. under a Packages/Source file are in control of that file and stops
  60. the scanning
  61. */
  62. if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
  63. {
  64. SigList.push_back(CD);
  65. }
  66. /* Aha! We found some package files. We assume that everything under
  67. this dir is controlled by those package files so we don't look down
  68. anymore */
  69. std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
  70. for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
  71. c != compressor.end(); ++c)
  72. {
  73. if (RealFileExists(std::string("Packages").append(c->Extension).c_str()) == false)
  74. continue;
  75. if (_config->FindB("Debug::aptcdrom",false) == true)
  76. std::clog << "Found Packages in " << CD << std::endl;
  77. List.push_back(CD);
  78. // Continue down if thorough is given
  79. if (_config->FindB("APT::CDROM::Thorough",false) == false)
  80. return true;
  81. break;
  82. }
  83. for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
  84. c != compressor.end(); ++c)
  85. {
  86. if (RealFileExists(std::string("Sources").append(c->Extension).c_str()) == false)
  87. continue;
  88. if (_config->FindB("Debug::aptcdrom",false) == true)
  89. std::clog << "Found Sources in " << CD << std::endl;
  90. SList.push_back(CD);
  91. // Continue down if thorough is given
  92. if (_config->FindB("APT::CDROM::Thorough",false) == false)
  93. return true;
  94. break;
  95. }
  96. // see if we find translation indices
  97. if (DirectoryExists("i18n") == true)
  98. {
  99. D = opendir("i18n");
  100. for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
  101. {
  102. if(strncmp(Dir->d_name, "Translation-", strlen("Translation-")) != 0)
  103. continue;
  104. string file = Dir->d_name;
  105. for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
  106. c != compressor.end(); ++c)
  107. {
  108. string fileext = flExtension(file);
  109. if (file == fileext)
  110. fileext.clear();
  111. else if (fileext.empty() == false)
  112. fileext = "." + fileext;
  113. if (c->Extension == fileext)
  114. {
  115. if (_config->FindB("Debug::aptcdrom",false) == true)
  116. std::clog << "Found translation " << Dir->d_name << " in " << CD << "i18n/" << std::endl;
  117. file.erase(file.size() - fileext.size());
  118. TransList.push_back(CD + "i18n/" + file);
  119. break;
  120. }
  121. }
  122. }
  123. closedir(D);
  124. }
  125. D = opendir(".");
  126. if (D == 0)
  127. return _error->Errno("opendir","Unable to read %s",CD.c_str());
  128. // Run over the directory
  129. for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
  130. {
  131. // Skip some files..
  132. if (strcmp(Dir->d_name,".") == 0 ||
  133. strcmp(Dir->d_name,"..") == 0 ||
  134. //strcmp(Dir->d_name,"source") == 0 ||
  135. strcmp(Dir->d_name,".disk") == 0 ||
  136. strcmp(Dir->d_name,"experimental") == 0 ||
  137. strcmp(Dir->d_name,"binary-all") == 0 ||
  138. strcmp(Dir->d_name,"debian-installer") == 0)
  139. continue;
  140. // See if the name is a sub directory
  141. struct stat Buf;
  142. if (stat(Dir->d_name,&Buf) != 0)
  143. continue;
  144. if (S_ISDIR(Buf.st_mode) == 0)
  145. continue;
  146. unsigned int I;
  147. for (I = 0; I != Depth; I++)
  148. if (Inodes[I] == Buf.st_ino)
  149. break;
  150. if (I != Depth)
  151. continue;
  152. // Store the inodes weve seen
  153. Inodes[Depth] = Buf.st_ino;
  154. // Descend
  155. if (FindPackages(CD + Dir->d_name,List,SList,SigList,TransList,InfoDir,log,Depth+1) == false)
  156. break;
  157. if (chdir(CD.c_str()) != 0)
  158. {
  159. _error->Errno("chdir","Unable to change to %s", CD.c_str());
  160. closedir(D);
  161. return false;
  162. }
  163. };
  164. closedir(D);
  165. return !_error->PendingError();
  166. }
  167. /*}}}*/
  168. // Score - We compute a 'score' for a path /*{{{*/
  169. // ---------------------------------------------------------------------
  170. /* Paths are scored based on how close they come to what I consider
  171. normal. That is ones that have 'dist' 'stable' 'testing' will score
  172. higher than ones without. */
  173. int pkgCdrom::Score(string Path)
  174. {
  175. int Res = 0;
  176. if (Path.find("stable/") != string::npos)
  177. Res += 29;
  178. if (Path.find("/binary-") != string::npos)
  179. Res += 20;
  180. if (Path.find("testing/") != string::npos)
  181. Res += 28;
  182. if (Path.find("unstable/") != string::npos)
  183. Res += 27;
  184. if (Path.find("/dists/") != string::npos)
  185. Res += 40;
  186. if (Path.find("/main/") != string::npos)
  187. Res += 20;
  188. if (Path.find("/contrib/") != string::npos)
  189. Res += 20;
  190. if (Path.find("/non-free/") != string::npos)
  191. Res += 20;
  192. if (Path.find("/non-US/") != string::npos)
  193. Res += 20;
  194. if (Path.find("/source/") != string::npos)
  195. Res += 10;
  196. if (Path.find("/debian/") != string::npos)
  197. Res -= 10;
  198. // check for symlinks in the patch leading to the actual file
  199. // a symlink gets a big penalty
  200. struct stat Buf;
  201. string statPath = flNotFile(Path);
  202. string cdromPath = _config->FindDir("Acquire::cdrom::mount");
  203. while(statPath != cdromPath && statPath != "./") {
  204. statPath.resize(statPath.size()-1); // remove the trailing '/'
  205. if (lstat(statPath.c_str(),&Buf) == 0) {
  206. if(S_ISLNK(Buf.st_mode)) {
  207. Res -= 60;
  208. break;
  209. }
  210. }
  211. statPath = flNotFile(statPath); // descent
  212. }
  213. return Res;
  214. }
  215. /*}}}*/
  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)
  220. {
  221. for (unsigned int I = 0; I < List.size(); I++)
  222. {
  223. const char *Str = List[I].c_str();
  224. const char *Start, *End;
  225. if ((Start = strstr(Str,"/binary-")) == 0)
  226. continue;
  227. // Between Start and End is the architecture
  228. Start += 8;
  229. if ((End = strstr(Start,"/")) != 0 && Start != End &&
  230. APT::Configuration::checkArchitecture(string(Start, End)) == true)
  231. continue; // okay, architecture is accepted
  232. // not accepted -> Erase it
  233. List.erase(List.begin() + I);
  234. --I; // the next entry is at the same index after the erase
  235. }
  236. return true;
  237. }
  238. /*}}}*/
  239. // DropTranslation - Dump unwanted Translation-<lang> files /*{{{*/
  240. // ---------------------------------------------------------------------
  241. /* Here we drop everything that is not configured in Acquire::Languages */
  242. bool pkgCdrom::DropTranslation(vector<string> &List)
  243. {
  244. for (unsigned int I = 0; I < List.size(); I++)
  245. {
  246. const char *Start;
  247. if ((Start = strstr(List[I].c_str(), "/Translation-")) == NULL)
  248. continue;
  249. Start += strlen("/Translation-");
  250. if (APT::Configuration::checkLanguage(Start, true) == true)
  251. continue;
  252. // not accepted -> Erase it
  253. List.erase(List.begin() + I);
  254. --I; // the next entry is at the same index after the erase
  255. }
  256. return true;
  257. }
  258. /*}}}*/
  259. // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
  260. // ---------------------------------------------------------------------
  261. /* Here we go and stat every file that we found and strip dup inodes. */
  262. bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
  263. {
  264. bool couldFindAllFiles = true;
  265. // Get a list of all the inodes
  266. ino_t *Inodes = new ino_t[List.size()];
  267. for (unsigned int I = 0; I != List.size(); ++I)
  268. {
  269. struct stat Buf;
  270. bool found = false;
  271. std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
  272. for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
  273. c != compressor.end(); ++c)
  274. {
  275. std::string filename = std::string(List[I]).append(Name).append(c->Extension);
  276. if (stat(filename.c_str(), &Buf) != 0)
  277. continue;
  278. Inodes[I] = Buf.st_ino;
  279. found = true;
  280. break;
  281. }
  282. if (found == false)
  283. {
  284. _error->Errno("stat","Failed to stat %s%s",List[I].c_str(), Name);
  285. couldFindAllFiles = false;
  286. Inodes[I] = 0;
  287. }
  288. }
  289. // Look for dups
  290. for (unsigned int I = 0; I != List.size(); I++)
  291. {
  292. if (Inodes[I] == 0)
  293. continue;
  294. for (unsigned int J = I+1; J < List.size(); J++)
  295. {
  296. // No match
  297. if (Inodes[J] == 0 || Inodes[J] != Inodes[I])
  298. continue;
  299. // We score the two paths.. and erase one
  300. int ScoreA = Score(List[I]);
  301. int ScoreB = Score(List[J]);
  302. if (ScoreA < ScoreB)
  303. {
  304. List[I] = string();
  305. break;
  306. }
  307. List[J] = string();
  308. }
  309. }
  310. delete[] Inodes;
  311. // Wipe erased entries
  312. for (unsigned int I = 0; I < List.size();)
  313. {
  314. if (List[I].empty() == false)
  315. I++;
  316. else
  317. List.erase(List.begin()+I);
  318. }
  319. return couldFindAllFiles;
  320. }
  321. /*}}}*/
  322. // ReduceSourceList - Takes the path list and reduces it /*{{{*/
  323. // ---------------------------------------------------------------------
  324. /* This takes the list of source list expressed entires and collects
  325. similar ones to form a single entry for each dist */
  326. void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
  327. {
  328. sort(List.begin(),List.end());
  329. // Collect similar entries
  330. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  331. {
  332. // Find a space..
  333. string::size_type Space = (*I).find(' ');
  334. if (Space == string::npos)
  335. continue;
  336. string::size_type SSpace = (*I).find(' ',Space + 1);
  337. if (SSpace == string::npos)
  338. continue;
  339. string Word1 = string(*I,Space,SSpace-Space);
  340. string Prefix = string(*I,0,Space);
  341. string Component = string(*I,SSpace);
  342. for (vector<string>::iterator J = List.begin(); J != I; ++J)
  343. {
  344. // Find a space..
  345. string::size_type Space2 = (*J).find(' ');
  346. if (Space2 == string::npos)
  347. continue;
  348. string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
  349. if (SSpace2 == string::npos)
  350. continue;
  351. if (string(*J,0,Space2) != Prefix)
  352. continue;
  353. if (string(*J,Space2,SSpace2-Space2) != Word1)
  354. continue;
  355. string Component2 = string(*J, SSpace2) + " ";
  356. if (Component2.find(Component + " ") == std::string::npos)
  357. *J += Component;
  358. I->clear();
  359. }
  360. }
  361. // Wipe erased entries
  362. for (unsigned int I = 0; I < List.size();)
  363. {
  364. if (List[I].empty() == false)
  365. I++;
  366. else
  367. List.erase(List.begin()+I);
  368. }
  369. }
  370. /*}}}*/
  371. // WriteDatabase - Write the CDROM Database file /*{{{*/
  372. // ---------------------------------------------------------------------
  373. /* We rewrite the configuration class associated with the cdrom database. */
  374. bool pkgCdrom::WriteDatabase(Configuration &Cnf)
  375. {
  376. string DFile = _config->FindFile("Dir::State::cdroms");
  377. string NewFile = DFile + ".new";
  378. unlink(NewFile.c_str());
  379. ofstream Out(NewFile.c_str());
  380. if (!Out)
  381. return _error->Errno("ofstream::ofstream",
  382. "Failed to open %s.new",DFile.c_str());
  383. /* Write out all of the configuration directives by walking the
  384. configuration tree */
  385. Cnf.Dump(Out, NULL, "%f \"%v\";\n", false);
  386. Out.close();
  387. if (FileExists(DFile) == true)
  388. rename(DFile.c_str(), (DFile + '~').c_str());
  389. if (rename(NewFile.c_str(),DFile.c_str()) != 0)
  390. return _error->Errno("rename","Failed to rename %s.new to %s",
  391. DFile.c_str(),DFile.c_str());
  392. return true;
  393. }
  394. /*}}}*/
  395. // WriteSourceList - Write an updated sourcelist /*{{{*/
  396. // ---------------------------------------------------------------------
  397. /* This reads the old source list and copies it into the new one. It
  398. appends the new CDROM entires just after the first block of comments.
  399. This places them first in the file. It also removes any old entries
  400. that were the same. */
  401. bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
  402. {
  403. if (List.empty() == true)
  404. return true;
  405. string File = _config->FindFile("Dir::Etc::sourcelist");
  406. // Open the stream for reading
  407. ifstream F((FileExists(File)?File.c_str():"/dev/null"),
  408. ios::in );
  409. if (!F != 0)
  410. return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
  411. string NewFile = File + ".new";
  412. unlink(NewFile.c_str());
  413. ofstream Out(NewFile.c_str());
  414. if (!Out)
  415. return _error->Errno("ofstream::ofstream",
  416. "Failed to open %s.new",File.c_str());
  417. // Create a short uri without the path
  418. string ShortURI = "cdrom:[" + Name + "]/";
  419. string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
  420. string Type;
  421. if (Source == true)
  422. Type = "deb-src";
  423. else
  424. Type = "deb";
  425. char Buffer[300];
  426. int CurLine = 0;
  427. bool First = true;
  428. while (F.eof() == false)
  429. {
  430. F.getline(Buffer,sizeof(Buffer));
  431. CurLine++;
  432. if (F.fail() && !F.eof())
  433. return _error->Error(_("Line %u too long in source list %s."),
  434. CurLine,File.c_str());
  435. _strtabexpand(Buffer,sizeof(Buffer));
  436. _strstrip(Buffer);
  437. // Comment or blank
  438. if (Buffer[0] == '#' || Buffer[0] == 0)
  439. {
  440. Out << Buffer << endl;
  441. continue;
  442. }
  443. if (First == true)
  444. {
  445. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  446. {
  447. string::size_type Space = (*I).find(' ');
  448. if (Space == string::npos)
  449. return _error->Error("Internal error");
  450. Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  451. " " << string(*I,Space+1) << endl;
  452. }
  453. }
  454. First = false;
  455. // Grok it
  456. string cType;
  457. string URI;
  458. const char *C = Buffer;
  459. if (ParseQuoteWord(C,cType) == false ||
  460. ParseQuoteWord(C,URI) == false)
  461. {
  462. Out << Buffer << endl;
  463. continue;
  464. }
  465. // Emit lines like this one
  466. if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
  467. string(URI,0,ShortURI.length()) != ShortURI2))
  468. {
  469. Out << Buffer << endl;
  470. continue;
  471. }
  472. }
  473. // Just in case the file was empty
  474. if (First == true)
  475. {
  476. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  477. {
  478. string::size_type Space = (*I).find(' ');
  479. if (Space == string::npos)
  480. return _error->Error("Internal error");
  481. Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  482. " " << string(*I,Space+1) << endl;
  483. }
  484. }
  485. Out.close();
  486. rename(File.c_str(), (File + '~').c_str());
  487. if (rename(NewFile.c_str(),File.c_str()) != 0)
  488. return _error->Errno("rename","Failed to rename %s.new to %s",
  489. File.c_str(),File.c_str());
  490. return true;
  491. }
  492. /*}}}*/
  493. bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, std::string &ident, pkgCdromStatus * const log)/*{{{*/
  494. {
  495. // Startup
  496. CDROM = _config->FindDir("Acquire::cdrom::mount");
  497. if (CDROM[0] == '.')
  498. CDROM= SafeGetCWD() + '/' + CDROM;
  499. if (log != NULL)
  500. {
  501. string msg;
  502. log->SetTotal(STEP_LAST);
  503. strprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
  504. log->Update(msg, STEP_PREPARE);
  505. }
  506. // Unmount the CD and get the user to put in the one they want
  507. if (_config->FindB("APT::CDROM::NoMount", false) == false)
  508. {
  509. if(log != NULL)
  510. log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
  511. UnmountCdrom(CDROM);
  512. if(log != NULL)
  513. {
  514. log->Update(_("Waiting for disc...\n"), STEP_WAIT);
  515. if(!log->ChangeCdrom()) {
  516. // user aborted
  517. return false;
  518. }
  519. }
  520. // Mount the new CDROM
  521. if(log != NULL)
  522. log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
  523. if (MountCdrom(CDROM) == false)
  524. return _error->Error("Failed to mount the cdrom.");
  525. }
  526. // Hash the CD to get an ID
  527. if (log != NULL)
  528. log->Update(_("Identifying.. "), STEP_IDENT);
  529. if (IdentCdrom(CDROM,ident) == false)
  530. {
  531. ident = "";
  532. if (log != NULL)
  533. log->Update("\n");
  534. return false;
  535. }
  536. if (log != NULL)
  537. {
  538. string msg;
  539. strprintf(msg, "[%s]\n", ident.c_str());
  540. log->Update(msg);
  541. }
  542. // Read the database
  543. string DFile = _config->FindFile("Dir::State::cdroms");
  544. if (FileExists(DFile) == true)
  545. {
  546. if (ReadConfigFile(Database,DFile) == false)
  547. return _error->Error("Unable to read the cdrom database %s",
  548. DFile.c_str());
  549. }
  550. return true;
  551. }
  552. /*}}}*/
  553. bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
  554. {
  555. Configuration Database;
  556. std::string CDROM;
  557. if (MountAndIdentCDROM(Database, CDROM, ident, log) == false)
  558. return false;
  559. if (log != NULL)
  560. {
  561. string msg;
  562. strprintf(msg, _("Stored label: %s\n"),
  563. Database.Find("CD::"+ident).c_str());
  564. log->Update(msg);
  565. }
  566. // Unmount and finish
  567. if (_config->FindB("APT::CDROM::NoMount",false) == false)
  568. {
  569. if (log != NULL)
  570. log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
  571. UnmountCdrom(CDROM);
  572. }
  573. return true;
  574. }
  575. /*}}}*/
  576. bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
  577. {
  578. Configuration Database;
  579. std::string ID, CDROM;
  580. if (MountAndIdentCDROM(Database, CDROM, ID, log) == false)
  581. return false;
  582. if(log != NULL)
  583. log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
  584. // Get the CD structure
  585. vector<string> List;
  586. vector<string> SourceList;
  587. vector<string> SigList;
  588. vector<string> TransList;
  589. string StartDir = SafeGetCWD();
  590. string InfoDir;
  591. if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
  592. {
  593. if (log != NULL)
  594. log->Update("\n");
  595. return false;
  596. }
  597. if (chdir(StartDir.c_str()) != 0)
  598. return _error->Errno("chdir","Unable to change to %s", StartDir.c_str());
  599. if (_config->FindB("Debug::aptcdrom",false) == true)
  600. {
  601. cout << "I found (binary):" << endl;
  602. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  603. cout << *I << endl;
  604. cout << "I found (source):" << endl;
  605. for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
  606. cout << *I << endl;
  607. cout << "I found (Signatures):" << endl;
  608. for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
  609. cout << *I << endl;
  610. }
  611. //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
  612. // Fix up the list
  613. DropBinaryArch(List);
  614. DropRepeats(List,"Packages");
  615. DropRepeats(SourceList,"Sources");
  616. // FIXME: We ignore stat() errors here as we usually have only one of those in use
  617. // This has little potencial to drop 'valid' stat() errors as we know that one of these
  618. // files need to exist, but it would be better if we would check it here
  619. _error->PushToStack();
  620. DropRepeats(SigList,"Release.gpg");
  621. DropRepeats(SigList,"InRelease");
  622. _error->RevertToStack();
  623. DropRepeats(TransList,"");
  624. if (_config->FindB("APT::CDROM::DropTranslation", true) == true)
  625. DropTranslation(TransList);
  626. if(log != NULL) {
  627. string msg;
  628. strprintf(msg, _("Found %zu package indexes, %zu source indexes, "
  629. "%zu translation indexes and %zu signatures\n"),
  630. List.size(), SourceList.size(), TransList.size(),
  631. SigList.size());
  632. log->Update(msg, STEP_SCAN);
  633. }
  634. if (List.empty() == true && SourceList.empty() == true)
  635. {
  636. if (_config->FindB("APT::CDROM::NoMount",false) == false)
  637. UnmountCdrom(CDROM);
  638. return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
  639. }
  640. // Check if the CD is in the database
  641. string Name;
  642. if (Database.Exists("CD::" + ID) == false ||
  643. _config->FindB("APT::CDROM::Rename",false) == true)
  644. {
  645. // Try to use the CDs label if at all possible
  646. if (InfoDir.empty() == false &&
  647. FileExists(InfoDir + "/info") == true)
  648. {
  649. ifstream F((InfoDir + "/info").c_str());
  650. if (!F == 0)
  651. getline(F,Name);
  652. if (Name.empty() == false)
  653. {
  654. // Escape special characters
  655. string::iterator J = Name.begin();
  656. for (; J != Name.end(); ++J)
  657. if (*J == '"' || *J == ']' || *J == '[')
  658. *J = '_';
  659. if(log != NULL)
  660. {
  661. string msg;
  662. strprintf(msg, _("Found label '%s'\n"), Name.c_str());
  663. log->Update(msg);
  664. }
  665. Database.Set("CD::" + ID + "::Label",Name);
  666. }
  667. }
  668. if (_config->FindB("APT::CDROM::Rename",false) == true ||
  669. Name.empty() == true)
  670. {
  671. if(log == NULL)
  672. {
  673. if (_config->FindB("APT::CDROM::NoMount",false) == false)
  674. UnmountCdrom(CDROM);
  675. return _error->Error("No disc name found and no way to ask for it");
  676. }
  677. while(true) {
  678. if(!log->AskCdromName(Name)) {
  679. // user canceld
  680. return false;
  681. }
  682. cout << "Name: '" << Name << "'" << endl;
  683. if (Name.empty() == false &&
  684. Name.find('"') == string::npos &&
  685. Name.find('[') == string::npos &&
  686. Name.find(']') == string::npos)
  687. break;
  688. log->Update(_("That is not a valid name, try again.\n"));
  689. }
  690. }
  691. }
  692. else
  693. Name = Database.Find("CD::" + ID);
  694. // Escape special characters
  695. string::iterator J = Name.begin();
  696. for (; J != Name.end(); ++J)
  697. if (*J == '"' || *J == ']' || *J == '[')
  698. *J = '_';
  699. Database.Set("CD::" + ID,Name);
  700. if(log != NULL)
  701. {
  702. string msg;
  703. strprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
  704. log->Update(msg);
  705. log->Update(_("Copying package lists..."), STEP_COPY);
  706. }
  707. // check for existence and possibly create state directory for copying
  708. string const listDir = _config->FindDir("Dir::State::lists");
  709. string const partialListDir = listDir + "partial/";
  710. if (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false &&
  711. CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false)
  712. return _error->Errno("cdrom", _("List directory %spartial is missing."), listDir.c_str());
  713. // take care of the signatures and copy them if they are ok
  714. // (we do this before PackageCopy as it modifies "List" and "SourceList")
  715. SigVerify SignVerify;
  716. SignVerify.CopyAndVerify(CDROM, Name, SigList, List, SourceList);
  717. // Copy the package files to the state directory
  718. PackageCopy Copy;
  719. SourceCopy SrcCopy;
  720. TranslationsCopy TransCopy;
  721. if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
  722. SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
  723. TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
  724. return false;
  725. // reduce the List so that it takes less space in sources.list
  726. ReduceSourcelist(CDROM,List);
  727. ReduceSourcelist(CDROM,SourceList);
  728. // Write the database and sourcelist
  729. if (_config->FindB("APT::cdrom::NoAct",false) == false)
  730. {
  731. if (WriteDatabase(Database) == false)
  732. return false;
  733. if(log != NULL)
  734. log->Update(_("Writing new source list\n"), STEP_WRITE);
  735. if (WriteSourceList(Name,List,false) == false ||
  736. WriteSourceList(Name,SourceList,true) == false)
  737. return false;
  738. }
  739. // Print the sourcelist entries
  740. if(log != NULL)
  741. log->Update(_("Source list entries for this disc are:\n"));
  742. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  743. {
  744. string::size_type Space = (*I).find(' ');
  745. if (Space == string::npos)
  746. {
  747. if (_config->FindB("APT::CDROM::NoMount",false) == false)
  748. UnmountCdrom(CDROM);
  749. return _error->Error("Internal error");
  750. }
  751. if(log != NULL)
  752. {
  753. stringstream msg;
  754. msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  755. " " << string(*I,Space+1) << endl;
  756. log->Update(msg.str());
  757. }
  758. }
  759. for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
  760. {
  761. string::size_type Space = (*I).find(' ');
  762. if (Space == string::npos)
  763. {
  764. if (_config->FindB("APT::CDROM::NoMount",false) == false)
  765. UnmountCdrom(CDROM);
  766. return _error->Error("Internal error");
  767. }
  768. if(log != NULL) {
  769. stringstream msg;
  770. msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  771. " " << string(*I,Space+1) << endl;
  772. log->Update(msg.str());
  773. }
  774. }
  775. // Unmount and finish
  776. if (_config->FindB("APT::CDROM::NoMount",false) == false) {
  777. if (log != NULL)
  778. log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
  779. UnmountCdrom(CDROM);
  780. }
  781. return true;
  782. }
  783. /*}}}*/
  784. pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/
  785. : libudev_handle(NULL)
  786. {
  787. }
  788. /*}}}*/
  789. bool
  790. pkgUdevCdromDevices::Dlopen() /*{{{*/
  791. {
  792. // alread open
  793. if(libudev_handle != NULL)
  794. return true;
  795. // see if we can get libudev
  796. void *h = ::dlopen("libudev.so.0", RTLD_LAZY);
  797. if(h == NULL)
  798. return false;
  799. // get the pointers to the udev structs
  800. libudev_handle = h;
  801. udev_new = (udev* (*)(void)) dlsym(h, "udev_new");
  802. udev_enumerate_add_match_property = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_property");
  803. udev_enumerate_add_match_sysattr = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_sysattr");
  804. udev_enumerate_scan_devices = (int (*)(udev_enumerate*))dlsym(h, "udev_enumerate_scan_devices");
  805. udev_enumerate_get_list_entry = (udev_list_entry* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_list_entry");
  806. udev_device_new_from_syspath = (udev_device* (*)(udev*, const char*))dlsym(h, "udev_device_new_from_syspath");
  807. udev_enumerate_get_udev = (udev* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_udev");
  808. udev_list_entry_get_name = (const char* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_name");
  809. udev_device_get_devnode = (const char* (*)(udev_device*))dlsym(h, "udev_device_get_devnode");
  810. udev_enumerate_new = (udev_enumerate* (*)(udev*))dlsym(h, "udev_enumerate_new");
  811. udev_list_entry_get_next = (udev_list_entry* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_next");
  812. udev_device_get_property_value = (const char* (*)(udev_device *, const char *))dlsym(h, "udev_device_get_property_value");
  813. return true;
  814. }
  815. /*}}}*/
  816. /*{{{*/
  817. // convenience interface, this will just call ScanForRemovable
  818. vector<CdromDevice>
  819. pkgUdevCdromDevices::Scan()
  820. {
  821. bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true);
  822. return ScanForRemovable(CdromOnly);
  823. }
  824. /*}}}*/
  825. /*{{{*/
  826. vector<CdromDevice>
  827. pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
  828. {
  829. vector<CdromDevice> cdrom_devices;
  830. struct udev_enumerate *enumerate;
  831. struct udev_list_entry *l, *devices;
  832. struct udev *udev_ctx;
  833. if(libudev_handle == NULL)
  834. return cdrom_devices;
  835. udev_ctx = udev_new();
  836. enumerate = udev_enumerate_new (udev_ctx);
  837. if (CdromOnly)
  838. udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
  839. else {
  840. udev_enumerate_add_match_sysattr(enumerate, "removable", "1");
  841. }
  842. udev_enumerate_scan_devices (enumerate);
  843. devices = udev_enumerate_get_list_entry (enumerate);
  844. for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
  845. {
  846. CdromDevice cdrom;
  847. struct udev_device *udevice;
  848. udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), udev_list_entry_get_name (l));
  849. if (udevice == NULL)
  850. continue;
  851. const char* devnode = udev_device_get_devnode(udevice);
  852. // try fstab_dir first
  853. string mountpath;
  854. const char* mp = udev_device_get_property_value(udevice, "FSTAB_DIR");
  855. if (mp)
  856. mountpath = string(mp);
  857. else
  858. mountpath = FindMountPointForDevice(devnode);
  859. // fill in the struct
  860. cdrom.DeviceName = string(devnode);
  861. if (mountpath != "") {
  862. cdrom.MountPath = mountpath;
  863. string s = mountpath;
  864. cdrom.Mounted = IsMounted(s);
  865. } else {
  866. cdrom.Mounted = false;
  867. cdrom.MountPath = "";
  868. }
  869. cdrom_devices.push_back(cdrom);
  870. }
  871. return cdrom_devices;
  872. }
  873. /*}}}*/
  874. pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/
  875. {
  876. if (libudev_handle != NULL)
  877. dlclose(libudev_handle);
  878. }
  879. /*}}}*/