apt-cdrom.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: apt-cdrom.cc,v 1.42 2002/02/15 03:40:00 jgg Exp $
  4. /* ######################################################################
  5. APT CDROM - Tool for handling APT's CDROM database.
  6. Currently the only option is 'add' which will take the current CD
  7. in the drive and add it into the database.
  8. ##################################################################### */
  9. /*}}}*/
  10. // Include Files /*{{{*/
  11. #include <apt-pkg/cmndline.h>
  12. #include <apt-pkg/error.h>
  13. #include <apt-pkg/init.h>
  14. #include <apt-pkg/fileutl.h>
  15. #include <apt-pkg/progress.h>
  16. #include <apt-pkg/cdromutl.h>
  17. #include <apt-pkg/strutl.h>
  18. #include <config.h>
  19. #include <apti18n.h>
  20. #include "indexcopy.h"
  21. #include <locale.h>
  22. #include <iostream>
  23. #include <fstream>
  24. #include <vector>
  25. #include <algorithm>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. #include <dirent.h>
  29. #include <unistd.h>
  30. #include <stdio.h>
  31. /*}}}*/
  32. using namespace std;
  33. // FindPackages - Find the package files on the CDROM /*{{{*/
  34. // ---------------------------------------------------------------------
  35. /* We look over the cdrom for package files. This is a recursive
  36. search that short circuits when it his a package file in the dir.
  37. This speeds it up greatly as the majority of the size is in the
  38. binary-* sub dirs. */
  39. bool FindPackages(string CD,vector<string> &List,vector<string> &SList,
  40. string &InfoDir,unsigned int Depth = 0)
  41. {
  42. static ino_t Inodes[9];
  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. struct stat Buf;
  51. if (stat(".disk",&Buf) == 0)
  52. {
  53. if (InfoDir.empty() == true)
  54. InfoDir = CD + ".disk/";
  55. }
  56. // Don't look into directories that have been marked to ingore.
  57. if (stat(".aptignr",&Buf) == 0)
  58. return true;
  59. /* Aha! We found some package files. We assume that everything under
  60. this dir is controlled by those package files so we don't look down
  61. anymore */
  62. if (stat("Packages",&Buf) == 0 || stat("Packages.gz",&Buf) == 0)
  63. {
  64. List.push_back(CD);
  65. // Continue down if thorough is given
  66. if (_config->FindB("APT::CDROM::Thorough",false) == false)
  67. return true;
  68. }
  69. if (stat("Sources.gz",&Buf) == 0 || stat("Sources",&Buf) == 0)
  70. {
  71. SList.push_back(CD);
  72. // Continue down if thorough is given
  73. if (_config->FindB("APT::CDROM::Thorough",false) == false)
  74. return true;
  75. }
  76. DIR *D = opendir(".");
  77. if (D == 0)
  78. return _error->Errno("opendir","Unable to read %s",CD.c_str());
  79. // Run over the directory
  80. for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
  81. {
  82. // Skip some files..
  83. if (strcmp(Dir->d_name,".") == 0 ||
  84. strcmp(Dir->d_name,"..") == 0 ||
  85. //strcmp(Dir->d_name,"source") == 0 ||
  86. strcmp(Dir->d_name,".disk") == 0 ||
  87. strcmp(Dir->d_name,"experimental") == 0 ||
  88. strcmp(Dir->d_name,"binary-all") == 0)
  89. continue;
  90. // See if the name is a sub directory
  91. struct stat Buf;
  92. if (stat(Dir->d_name,&Buf) != 0)
  93. continue;
  94. if (S_ISDIR(Buf.st_mode) == 0)
  95. continue;
  96. unsigned int I;
  97. for (I = 0; I != Depth; I++)
  98. if (Inodes[I] == Buf.st_ino)
  99. break;
  100. if (I != Depth)
  101. continue;
  102. // Store the inodes weve seen
  103. Inodes[Depth] = Buf.st_ino;
  104. // Descend
  105. if (FindPackages(CD + Dir->d_name,List,SList,InfoDir,Depth+1) == false)
  106. break;
  107. if (chdir(CD.c_str()) != 0)
  108. return _error->Errno("chdir","Unable to change to %s",CD.c_str());
  109. };
  110. closedir(D);
  111. return !_error->PendingError();
  112. }
  113. /*}}}*/
  114. // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
  115. // ---------------------------------------------------------------------
  116. /* Here we drop everything that is not this machines arch */
  117. bool DropBinaryArch(vector<string> &List)
  118. {
  119. char S[300];
  120. snprintf(S,sizeof(S),"/binary-%s/",
  121. _config->Find("Apt::Architecture").c_str());
  122. for (unsigned int I = 0; I < List.size(); I++)
  123. {
  124. const char *Str = List[I].c_str();
  125. const char *Res;
  126. if ((Res = strstr(Str,"/binary-")) == 0)
  127. continue;
  128. // Weird, remove it.
  129. if (strlen(Res) < strlen(S))
  130. {
  131. List.erase(List.begin() + I);
  132. I--;
  133. continue;
  134. }
  135. // See if it is our arch
  136. if (stringcmp(Res,Res + strlen(S),S) == 0)
  137. continue;
  138. // Erase it
  139. List.erase(List.begin() + I);
  140. I--;
  141. }
  142. return true;
  143. }
  144. /*}}}*/
  145. // Score - We compute a 'score' for a path /*{{{*/
  146. // ---------------------------------------------------------------------
  147. /* Paths are scored based on how close they come to what I consider
  148. normal. That is ones that have 'dist' 'stable' 'frozen' will score
  149. higher than ones without. */
  150. int Score(string Path)
  151. {
  152. int Res = 0;
  153. if (Path.find("stable/") != string::npos)
  154. Res += 29;
  155. if (Path.find("/binary-") != string::npos)
  156. Res += 20;
  157. if (Path.find("frozen/") != string::npos)
  158. Res += 28;
  159. if (Path.find("unstable/") != string::npos)
  160. Res += 27;
  161. if (Path.find("/dists/") != string::npos)
  162. Res += 40;
  163. if (Path.find("/main/") != string::npos)
  164. Res += 20;
  165. if (Path.find("/contrib/") != string::npos)
  166. Res += 20;
  167. if (Path.find("/non-free/") != string::npos)
  168. Res += 20;
  169. if (Path.find("/non-US/") != string::npos)
  170. Res += 20;
  171. if (Path.find("/source/") != string::npos)
  172. Res += 10;
  173. if (Path.find("/debian/") != string::npos)
  174. Res -= 10;
  175. return Res;
  176. }
  177. /*}}}*/
  178. // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
  179. // ---------------------------------------------------------------------
  180. /* Here we go and stat every file that we found and strip dup inodes. */
  181. bool DropRepeats(vector<string> &List,const char *Name)
  182. {
  183. // Get a list of all the inodes
  184. ino_t *Inodes = new ino_t[List.size()];
  185. for (unsigned int I = 0; I != List.size(); I++)
  186. {
  187. struct stat Buf;
  188. if (stat((List[I] + Name).c_str(),&Buf) != 0 &&
  189. stat((List[I] + Name + ".gz").c_str(),&Buf) != 0)
  190. _error->Errno("stat","Failed to stat %s%s",List[I].c_str(),
  191. Name);
  192. Inodes[I] = Buf.st_ino;
  193. }
  194. if (_error->PendingError() == true)
  195. return false;
  196. // Look for dups
  197. for (unsigned int I = 0; I != List.size(); I++)
  198. {
  199. for (unsigned int J = I+1; J < List.size(); J++)
  200. {
  201. // No match
  202. if (Inodes[J] != Inodes[I])
  203. continue;
  204. // We score the two paths.. and erase one
  205. int ScoreA = Score(List[I]);
  206. int ScoreB = Score(List[J]);
  207. if (ScoreA < ScoreB)
  208. {
  209. List[I] = string();
  210. break;
  211. }
  212. List[J] = string();
  213. }
  214. }
  215. // Wipe erased entries
  216. for (unsigned int I = 0; I < List.size();)
  217. {
  218. if (List[I].empty() == false)
  219. I++;
  220. else
  221. List.erase(List.begin()+I);
  222. }
  223. return true;
  224. }
  225. /*}}}*/
  226. // ReduceSourceList - Takes the path list and reduces it /*{{{*/
  227. // ---------------------------------------------------------------------
  228. /* This takes the list of source list expressed entires and collects
  229. similar ones to form a single entry for each dist */
  230. void ReduceSourcelist(string CD,vector<string> &List)
  231. {
  232. sort(List.begin(),List.end());
  233. // Collect similar entries
  234. for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
  235. {
  236. // Find a space..
  237. string::size_type Space = (*I).find(' ');
  238. if (Space == string::npos)
  239. continue;
  240. string::size_type SSpace = (*I).find(' ',Space + 1);
  241. if (SSpace == string::npos)
  242. continue;
  243. string Word1 = string(*I,Space,SSpace-Space);
  244. string Prefix = string(*I,0,Space);
  245. for (vector<string>::iterator J = List.begin(); J != I; J++)
  246. {
  247. // Find a space..
  248. string::size_type Space2 = (*J).find(' ');
  249. if (Space2 == string::npos)
  250. continue;
  251. string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
  252. if (SSpace2 == string::npos)
  253. continue;
  254. if (string(*J,0,Space2) != Prefix)
  255. continue;
  256. if (string(*J,Space2,SSpace2-Space2) != Word1)
  257. continue;
  258. *J += string(*I,SSpace);
  259. *I = string();
  260. }
  261. }
  262. // Wipe erased entries
  263. for (unsigned int I = 0; I < List.size();)
  264. {
  265. if (List[I].empty() == false)
  266. I++;
  267. else
  268. List.erase(List.begin()+I);
  269. }
  270. }
  271. /*}}}*/
  272. // WriteDatabase - Write the CDROM Database file /*{{{*/
  273. // ---------------------------------------------------------------------
  274. /* We rewrite the configuration class associated with the cdrom database. */
  275. bool WriteDatabase(Configuration &Cnf)
  276. {
  277. string DFile = _config->FindFile("Dir::State::cdroms");
  278. string NewFile = DFile + ".new";
  279. unlink(NewFile.c_str());
  280. ofstream Out(NewFile.c_str());
  281. if (!Out)
  282. return _error->Errno("ofstream::ofstream",
  283. "Failed to open %s.new",DFile.c_str());
  284. /* Write out all of the configuration directives by walking the
  285. configuration tree */
  286. const Configuration::Item *Top = Cnf.Tree(0);
  287. for (; Top != 0;)
  288. {
  289. // Print the config entry
  290. if (Top->Value.empty() == false)
  291. Out << Top->FullTag() + " \"" << Top->Value << "\";" << endl;
  292. if (Top->Child != 0)
  293. {
  294. Top = Top->Child;
  295. continue;
  296. }
  297. while (Top != 0 && Top->Next == 0)
  298. Top = Top->Parent;
  299. if (Top != 0)
  300. Top = Top->Next;
  301. }
  302. Out.close();
  303. rename(DFile.c_str(),string(DFile + '~').c_str());
  304. if (rename(NewFile.c_str(),DFile.c_str()) != 0)
  305. return _error->Errno("rename","Failed to rename %s.new to %s",
  306. DFile.c_str(),DFile.c_str());
  307. return true;
  308. }
  309. /*}}}*/
  310. // WriteSourceList - Write an updated sourcelist /*{{{*/
  311. // ---------------------------------------------------------------------
  312. /* This reads the old source list and copies it into the new one. It
  313. appends the new CDROM entires just after the first block of comments.
  314. This places them first in the file. It also removes any old entries
  315. that were the same. */
  316. bool WriteSourceList(string Name,vector<string> &List,bool Source)
  317. {
  318. if (List.size() == 0)
  319. return true;
  320. string File = _config->FindFile("Dir::Etc::sourcelist");
  321. // Open the stream for reading
  322. ifstream F((FileExists(File)?File.c_str():"/dev/null"),
  323. ios::in );
  324. if (!F != 0)
  325. return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
  326. string NewFile = File + ".new";
  327. unlink(NewFile.c_str());
  328. ofstream Out(NewFile.c_str());
  329. if (!Out)
  330. return _error->Errno("ofstream::ofstream",
  331. "Failed to open %s.new",File.c_str());
  332. // Create a short uri without the path
  333. string ShortURI = "cdrom:[" + Name + "]/";
  334. string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
  335. const char *Type;
  336. if (Source == true)
  337. Type = "deb-src";
  338. else
  339. Type = "deb";
  340. char Buffer[300];
  341. int CurLine = 0;
  342. bool First = true;
  343. while (F.eof() == false)
  344. {
  345. F.getline(Buffer,sizeof(Buffer));
  346. CurLine++;
  347. _strtabexpand(Buffer,sizeof(Buffer));
  348. _strstrip(Buffer);
  349. // Comment or blank
  350. if (Buffer[0] == '#' || Buffer[0] == 0)
  351. {
  352. Out << Buffer << endl;
  353. continue;
  354. }
  355. if (First == true)
  356. {
  357. for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
  358. {
  359. string::size_type Space = (*I).find(' ');
  360. if (Space == string::npos)
  361. return _error->Error("Internal error");
  362. Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  363. " " << string(*I,Space+1) << endl;
  364. }
  365. }
  366. First = false;
  367. // Grok it
  368. string cType;
  369. string URI;
  370. const char *C = Buffer;
  371. if (ParseQuoteWord(C,cType) == false ||
  372. ParseQuoteWord(C,URI) == false)
  373. {
  374. Out << Buffer << endl;
  375. continue;
  376. }
  377. // Emit lines like this one
  378. if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
  379. string(URI,0,ShortURI.length()) != ShortURI2))
  380. {
  381. Out << Buffer << endl;
  382. continue;
  383. }
  384. }
  385. // Just in case the file was empty
  386. if (First == true)
  387. {
  388. for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
  389. {
  390. string::size_type Space = (*I).find(' ');
  391. if (Space == string::npos)
  392. return _error->Error("Internal error");
  393. Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  394. " " << string(*I,Space+1) << endl;
  395. }
  396. }
  397. Out.close();
  398. rename(File.c_str(),string(File + '~').c_str());
  399. if (rename(NewFile.c_str(),File.c_str()) != 0)
  400. return _error->Errno("rename","Failed to rename %s.new to %s",
  401. File.c_str(),File.c_str());
  402. return true;
  403. }
  404. /*}}}*/
  405. // Prompt - Simple prompt /*{{{*/
  406. // ---------------------------------------------------------------------
  407. /* */
  408. void Prompt(const char *Text)
  409. {
  410. char C;
  411. cout << Text << ' ' << flush;
  412. read(STDIN_FILENO,&C,1);
  413. if (C != '\n')
  414. cout << endl;
  415. }
  416. /*}}}*/
  417. // PromptLine - Prompt for an input line /*{{{*/
  418. // ---------------------------------------------------------------------
  419. /* */
  420. string PromptLine(const char *Text)
  421. {
  422. cout << Text << ':' << endl;
  423. string Res;
  424. getline(cin,Res);
  425. return Res;
  426. }
  427. /*}}}*/
  428. // DoAdd - Add a new CDROM /*{{{*/
  429. // ---------------------------------------------------------------------
  430. /* This does the main add bit.. We show some status and things. The
  431. sequence is to mount/umount the CD, Ident it then scan it for package
  432. files and reduce that list. Then we copy over the package files and
  433. verify them. Then rewrite the database files */
  434. bool DoAdd(CommandLine &)
  435. {
  436. // Startup
  437. string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
  438. if (CDROM[0] == '.')
  439. CDROM= SafeGetCWD() + '/' + CDROM;
  440. cout << "Using CD-ROM mount point " << CDROM << endl;
  441. // Read the database
  442. Configuration Database;
  443. string DFile = _config->FindFile("Dir::State::cdroms");
  444. if (FileExists(DFile) == true)
  445. {
  446. if (ReadConfigFile(Database,DFile) == false)
  447. return _error->Error("Unable to read the cdrom database %s",
  448. DFile.c_str());
  449. }
  450. // Unmount the CD and get the user to put in the one they want
  451. if (_config->FindB("APT::CDROM::NoMount",false) == false)
  452. {
  453. cout << "Unmounting CD-ROM" << endl;
  454. UnmountCdrom(CDROM);
  455. // Mount the new CDROM
  456. Prompt("Please insert a Disc in the drive and press enter");
  457. cout << "Mounting CD-ROM" << endl;
  458. if (MountCdrom(CDROM) == false)
  459. return _error->Error("Failed to mount the cdrom.");
  460. }
  461. // Hash the CD to get an ID
  462. cout << "Identifying.. " << flush;
  463. string ID;
  464. if (IdentCdrom(CDROM,ID) == false)
  465. {
  466. cout << endl;
  467. return false;
  468. }
  469. cout << '[' << ID << ']' << endl;
  470. cout << "Scanning Disc for index files.. " << flush;
  471. // Get the CD structure
  472. vector<string> List;
  473. vector<string> sList;
  474. string StartDir = SafeGetCWD();
  475. string InfoDir;
  476. if (FindPackages(CDROM,List,sList,InfoDir) == false)
  477. {
  478. cout << endl;
  479. return false;
  480. }
  481. chdir(StartDir.c_str());
  482. if (_config->FindB("Debug::aptcdrom",false) == true)
  483. {
  484. cout << "I found (binary):" << endl;
  485. for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
  486. cout << *I << endl;
  487. cout << "I found (source):" << endl;
  488. for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++)
  489. cout << *I << endl;
  490. }
  491. // Fix up the list
  492. DropBinaryArch(List);
  493. DropRepeats(List,"Packages");
  494. DropRepeats(sList,"Sources");
  495. cout << "Found " << List.size() << " package indexes and " << sList.size() <<
  496. " source indexes." << endl;
  497. if (List.size() == 0 && sList.size() == 0)
  498. return _error->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
  499. // Check if the CD is in the database
  500. string Name;
  501. if (Database.Exists("CD::" + ID) == false ||
  502. _config->FindB("APT::CDROM::Rename",false) == true)
  503. {
  504. // Try to use the CDs label if at all possible
  505. if (InfoDir.empty() == false &&
  506. FileExists(InfoDir + "/info") == true)
  507. {
  508. ifstream F(string(InfoDir + "/info").c_str());
  509. if (!F == 0)
  510. getline(F,Name);
  511. if (Name.empty() == false)
  512. {
  513. // Escape special characters
  514. string::iterator J = Name.begin();
  515. for (; J != Name.end(); J++)
  516. if (*J == '"' || *J == ']' || *J == '[')
  517. *J = '_';
  518. cout << "Found label '" << Name << "'" << endl;
  519. Database.Set("CD::" + ID + "::Label",Name);
  520. }
  521. }
  522. if (_config->FindB("APT::CDROM::Rename",false) == true ||
  523. Name.empty() == true)
  524. {
  525. cout << "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
  526. while (1)
  527. {
  528. Name = PromptLine("");
  529. if (Name.empty() == false &&
  530. Name.find('"') == string::npos &&
  531. Name.find('[') == string::npos &&
  532. Name.find(']') == string::npos)
  533. break;
  534. cout << "That is not a valid name, try again " << endl;
  535. }
  536. }
  537. }
  538. else
  539. Name = Database.Find("CD::" + ID);
  540. // Escape special characters
  541. string::iterator J = Name.begin();
  542. for (; J != Name.end(); J++)
  543. if (*J == '"' || *J == ']' || *J == '[')
  544. *J = '_';
  545. Database.Set("CD::" + ID,Name);
  546. cout << "This Disc is called:" << endl << " '" << Name << "'" << endl;
  547. // Copy the package files to the state directory
  548. PackageCopy Copy;
  549. SourceCopy SrcCopy;
  550. if (Copy.CopyPackages(CDROM,Name,List) == false ||
  551. SrcCopy.CopyPackages(CDROM,Name,sList) == false)
  552. return false;
  553. ReduceSourcelist(CDROM,List);
  554. ReduceSourcelist(CDROM,sList);
  555. // Write the database and sourcelist
  556. if (_config->FindB("APT::cdrom::NoAct",false) == false)
  557. {
  558. if (WriteDatabase(Database) == false)
  559. return false;
  560. cout << "Writing new source list" << endl;
  561. if (WriteSourceList(Name,List,false) == false ||
  562. WriteSourceList(Name,sList,true) == false)
  563. return false;
  564. }
  565. // Print the sourcelist entries
  566. cout << "Source List entries for this Disc are:" << endl;
  567. for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
  568. {
  569. string::size_type Space = (*I).find(' ');
  570. if (Space == string::npos)
  571. return _error->Error("Internal error");
  572. cout << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  573. " " << string(*I,Space+1) << endl;
  574. }
  575. for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++)
  576. {
  577. string::size_type Space = (*I).find(' ');
  578. if (Space == string::npos)
  579. return _error->Error("Internal error");
  580. cout << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
  581. " " << string(*I,Space+1) << endl;
  582. }
  583. cout << "Repeat this process for the rest of the CDs in your set." << endl;
  584. // Unmount and finish
  585. if (_config->FindB("APT::CDROM::NoMount",false) == false)
  586. UnmountCdrom(CDROM);
  587. return true;
  588. }
  589. /*}}}*/
  590. // DoIdent - Ident a CDROM /*{{{*/
  591. // ---------------------------------------------------------------------
  592. /* */
  593. bool DoIdent(CommandLine &)
  594. {
  595. // Startup
  596. string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
  597. if (CDROM[0] == '.')
  598. CDROM= SafeGetCWD() + '/' + CDROM;
  599. cout << "Using CD-ROM mount point " << CDROM << endl;
  600. cout << "Mounting CD-ROM" << endl;
  601. if (MountCdrom(CDROM) == false)
  602. return _error->Error("Failed to mount the cdrom.");
  603. // Hash the CD to get an ID
  604. cout << "Identifying.. " << flush;
  605. string ID;
  606. if (IdentCdrom(CDROM,ID) == false)
  607. {
  608. cout << endl;
  609. return false;
  610. }
  611. cout << '[' << ID << ']' << endl;
  612. // Read the database
  613. Configuration Database;
  614. string DFile = _config->FindFile("Dir::State::cdroms");
  615. if (FileExists(DFile) == true)
  616. {
  617. if (ReadConfigFile(Database,DFile) == false)
  618. return _error->Error("Unable to read the cdrom database %s",
  619. DFile.c_str());
  620. }
  621. cout << "Stored Label: '" << Database.Find("CD::" + ID) << "'" << endl;
  622. return true;
  623. }
  624. /*}}}*/
  625. // ShowHelp - Show the help screen /*{{{*/
  626. // ---------------------------------------------------------------------
  627. /* */
  628. int ShowHelp()
  629. {
  630. ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
  631. COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
  632. if (_config->FindB("version") == true)
  633. return 0;
  634. cout <<
  635. "Usage: apt-cdrom [options] command\n"
  636. "\n"
  637. "apt-cdrom is a tool to add CDROM's to APT's source list. The\n"
  638. "CDROM mount point and device information is taken from apt.conf\n"
  639. "and /etc/fstab.\n"
  640. "\n"
  641. "Commands:\n"
  642. " add - Add a CDROM\n"
  643. " ident - Report the identity of a CDROM\n"
  644. "\n"
  645. "Options:\n"
  646. " -h This help text\n"
  647. " -d CD-ROM mount point\n"
  648. " -r Rename a recognized CD-ROM\n"
  649. " -m No mounting\n"
  650. " -f Fast mode, don't check package files\n"
  651. " -a Thorough scan mode\n"
  652. " -c=? Read this configuration file\n"
  653. " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
  654. "See fstab(5)\n";
  655. return 0;
  656. }
  657. /*}}}*/
  658. int main(int argc,const char *argv[])
  659. {
  660. CommandLine::Args Args[] = {
  661. {'h',"help","help",0},
  662. {'v',"version","version",0},
  663. {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg},
  664. {'r',"rename","APT::CDROM::Rename",0},
  665. {'m',"no-mount","APT::CDROM::NoMount",0},
  666. {'f',"fast","APT::CDROM::Fast",0},
  667. {'n',"just-print","APT::CDROM::NoAct",0},
  668. {'n',"recon","APT::CDROM::NoAct",0},
  669. {'n',"no-act","APT::CDROM::NoAct",0},
  670. {'a',"thorough","APT::CDROM::Thorough",0},
  671. {'c',"config-file",0,CommandLine::ConfigFile},
  672. {'o',"option",0,CommandLine::ArbItem},
  673. {0,0,0,0}};
  674. CommandLine::Dispatch Cmds[] = {
  675. {"add",&DoAdd},
  676. {"ident",&DoIdent},
  677. {0,0}};
  678. // Set up gettext support
  679. setlocale(LC_ALL,"");
  680. textdomain(PACKAGE);
  681. // Parse the command line and initialize the package library
  682. CommandLine CmdL(Args,_config);
  683. if (pkgInitConfig(*_config) == false ||
  684. CmdL.Parse(argc,argv) == false ||
  685. pkgInitSystem(*_config,_system) == false)
  686. {
  687. _error->DumpErrors();
  688. return 100;
  689. }
  690. // See if the help should be shown
  691. if (_config->FindB("help") == true || _config->FindB("version") == true ||
  692. CmdL.FileSize() == 0)
  693. return ShowHelp();
  694. // Deal with stdout not being a tty
  695. if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
  696. _config->Set("quiet","1");
  697. // Match the operation
  698. CmdL.DispatchArg(Cmds);
  699. // Print any errors or warnings found during parsing
  700. if (_error->empty() == false)
  701. {
  702. bool Errors = _error->PendingError();
  703. _error->DumpErrors();
  704. return Errors == true?100:0;
  705. }
  706. return 0;
  707. }