sourcelist.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: sourcelist.cc,v 1.3 2002/08/15 20:51:37 niemeyer Exp $
  4. /* ######################################################################
  5. List of Sources
  6. ##################################################################### */
  7. /*}}}*/
  8. // Include Files /*{{{*/
  9. #include<config.h>
  10. #include <apt-pkg/sourcelist.h>
  11. #include <apt-pkg/error.h>
  12. #include <apt-pkg/fileutl.h>
  13. #include <apt-pkg/strutl.h>
  14. #include <apt-pkg/configuration.h>
  15. #include <apt-pkg/metaindex.h>
  16. #include <apt-pkg/indexfile.h>
  17. #include <apt-pkg/tagfile.h>
  18. #include <fstream>
  19. #include <apti18n.h>
  20. /*}}}*/
  21. using namespace std;
  22. // Global list of Items supported
  23. static pkgSourceList::Type *ItmList[10];
  24. pkgSourceList::Type **pkgSourceList::Type::GlobalList = ItmList;
  25. unsigned long pkgSourceList::Type::GlobalListLen = 0;
  26. // Type::Type - Constructor /*{{{*/
  27. // ---------------------------------------------------------------------
  28. /* Link this to the global list of items*/
  29. pkgSourceList::Type::Type() : Name(NULL), Label(NULL)
  30. {
  31. ItmList[GlobalListLen] = this;
  32. GlobalListLen++;
  33. }
  34. /*}}}*/
  35. // Type::GetType - Get a specific meta for a given type /*{{{*/
  36. // ---------------------------------------------------------------------
  37. /* */
  38. pkgSourceList::Type *pkgSourceList::Type::GetType(const char *Type)
  39. {
  40. for (unsigned I = 0; I != GlobalListLen; I++)
  41. if (strcmp(GlobalList[I]->Name,Type) == 0)
  42. return GlobalList[I];
  43. return 0;
  44. }
  45. /*}}}*/
  46. // Type::FixupURI - Normalize the URI and check it.. /*{{{*/
  47. // ---------------------------------------------------------------------
  48. /* */
  49. bool pkgSourceList::Type::FixupURI(string &URI) const
  50. {
  51. if (URI.empty() == true)
  52. return false;
  53. if (URI.find(':') == string::npos)
  54. return false;
  55. URI = SubstVar(URI,"$(ARCH)",_config->Find("APT::Architecture"));
  56. // Make sure that the URI is / postfixed
  57. if (URI[URI.size() - 1] != '/')
  58. URI += '/';
  59. return true;
  60. }
  61. /*}}}*/
  62. bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List,
  63. pkgTagSection &Tags,
  64. int i,
  65. FileFd &Fd)
  66. {
  67. map<string, string> Options;
  68. string URI = Tags.FindS("URI");
  69. if (!FixupURI(URI))
  70. {
  71. _error->Error(_("Malformed stanza %u in source list %s (URI parse)"),i,Fd.Name().c_str());
  72. return false;
  73. }
  74. string Enabled = Tags.FindS("Enabled");
  75. if (Enabled.size() > 0 && StringToBool(Enabled) == false)
  76. return true;
  77. // Define external/internal options
  78. const char* option_deb822[] = {
  79. "Architectures", "Architectures-Add", "Architectures-Remove", "Trusted",
  80. };
  81. const char* option_internal[] = {
  82. "arch", "arch+", "arch-", "trusted",
  83. };
  84. for (unsigned int j=0; j < sizeof(option_deb822)/sizeof(char*); j++)
  85. if (Tags.Exists(option_deb822[j]))
  86. Options[option_internal[j]] = Tags.FindS(option_deb822[j]);
  87. // now create one item per suite/section
  88. string Suite = Tags.FindS("Suites");
  89. Suite = SubstVar(Suite,"$(ARCH)",_config->Find("APT::Architecture"));
  90. string const Section = Tags.FindS("Sections");
  91. std::vector<std::string> list_dist = StringSplit(Suite, " ");
  92. std::vector<std::string> list_section = StringSplit(Section, " ");
  93. for (std::vector<std::string>::const_iterator I = list_dist.begin();
  94. I != list_dist.end(); I++)
  95. {
  96. for (std::vector<std::string>::const_iterator J = list_section.begin();
  97. J != list_section.end(); J++)
  98. {
  99. if (CreateItem(List, URI, (*I), (*J), Options) == false)
  100. {
  101. return false;
  102. }
  103. }
  104. }
  105. return true;
  106. }
  107. // Type::ParseLine - Parse a single line /*{{{*/
  108. // ---------------------------------------------------------------------
  109. /* This is a generic one that is the 'usual' format for sources.list
  110. Weird types may override this. */
  111. bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
  112. const char *Buffer,
  113. unsigned long const &CurLine,
  114. string const &File) const
  115. {
  116. for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
  117. // Parse option field if it exists
  118. // e.g.: [ option1=value1 option2=value2 ]
  119. map<string, string> Options;
  120. if (Buffer != 0 && Buffer[0] == '[')
  121. {
  122. ++Buffer; // ignore the [
  123. for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
  124. while (*Buffer != ']')
  125. {
  126. // get one option, e.g. option1=value1
  127. string option;
  128. if (ParseQuoteWord(Buffer,option) == false)
  129. return _error->Error(_("Malformed line %lu in source list %s ([option] unparseable)"),CurLine,File.c_str());
  130. if (option.length() < 3)
  131. return _error->Error(_("Malformed line %lu in source list %s ([option] too short)"),CurLine,File.c_str());
  132. // accept options even if the last has no space before the ]-end marker
  133. if (option.at(option.length()-1) == ']')
  134. {
  135. for (; *Buffer != ']'; --Buffer);
  136. option.resize(option.length()-1);
  137. }
  138. size_t const needle = option.find('=');
  139. if (needle == string::npos)
  140. return _error->Error(_("Malformed line %lu in source list %s ([%s] is not an assignment)"),CurLine,File.c_str(), option.c_str());
  141. string const key = string(option, 0, needle);
  142. string const value = string(option, needle + 1, option.length());
  143. if (key.empty() == true)
  144. return _error->Error(_("Malformed line %lu in source list %s ([%s] has no key)"),CurLine,File.c_str(), option.c_str());
  145. if (value.empty() == true)
  146. return _error->Error(_("Malformed line %lu in source list %s ([%s] key %s has no value)"),CurLine,File.c_str(),option.c_str(),key.c_str());
  147. Options[key] = value;
  148. }
  149. ++Buffer; // ignore the ]
  150. for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
  151. }
  152. string URI;
  153. string Dist;
  154. string Section;
  155. if (ParseQuoteWord(Buffer,URI) == false)
  156. return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
  157. if (ParseQuoteWord(Buffer,Dist) == false)
  158. return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
  159. if (FixupURI(URI) == false)
  160. return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
  161. // Check for an absolute dists specification.
  162. if (Dist.empty() == false && Dist[Dist.size() - 1] == '/')
  163. {
  164. if (ParseQuoteWord(Buffer,Section) == true)
  165. return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str());
  166. Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
  167. return CreateItem(List, URI, Dist, Section, Options);
  168. }
  169. // Grab the rest of the dists
  170. if (ParseQuoteWord(Buffer,Section) == false)
  171. return _error->Error(_("Malformed line %lu in source list %s (dist parse)"),CurLine,File.c_str());
  172. do
  173. {
  174. if (CreateItem(List, URI, Dist, Section, Options) == false)
  175. return false;
  176. }
  177. while (ParseQuoteWord(Buffer,Section) == true);
  178. return true;
  179. }
  180. /*}}}*/
  181. // SourceList::pkgSourceList - Constructors /*{{{*/
  182. // ---------------------------------------------------------------------
  183. /* */
  184. pkgSourceList::pkgSourceList()
  185. {
  186. }
  187. pkgSourceList::pkgSourceList(string File)
  188. {
  189. Read(File);
  190. }
  191. /*}}}*/
  192. // SourceList::~pkgSourceList - Destructor /*{{{*/
  193. // ---------------------------------------------------------------------
  194. /* */
  195. pkgSourceList::~pkgSourceList()
  196. {
  197. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  198. delete *I;
  199. }
  200. /*}}}*/
  201. // SourceList::ReadMainList - Read the main source list from etc /*{{{*/
  202. // ---------------------------------------------------------------------
  203. /* */
  204. bool pkgSourceList::ReadMainList()
  205. {
  206. // CNC:2003-03-03 - Multiple sources list support.
  207. bool Res = true;
  208. #if 0
  209. Res = ReadVendors();
  210. if (Res == false)
  211. return false;
  212. #endif
  213. Reset();
  214. // CNC:2003-11-28 - Entries in sources.list have priority over
  215. // entries in sources.list.d.
  216. string Main = _config->FindFile("Dir::Etc::sourcelist");
  217. string Parts = _config->FindDir("Dir::Etc::sourceparts");
  218. if (RealFileExists(Main) == true)
  219. Res &= ReadAppend(Main);
  220. else if (DirectoryExists(Parts) == false)
  221. // Only warn if there are no sources.list.d.
  222. _error->WarningE("DirectoryExists", _("Unable to read %s"), Parts.c_str());
  223. if (DirectoryExists(Parts) == true)
  224. Res &= ReadSourceDir(Parts);
  225. else if (RealFileExists(Main) == false)
  226. // Only warn if there is no sources.list file.
  227. _error->WarningE("RealFileExists", _("Unable to read %s"), Main.c_str());
  228. return Res;
  229. }
  230. /*}}}*/
  231. // SourceList::Reset - Clear the sourcelist contents /*{{{*/
  232. // ---------------------------------------------------------------------
  233. /* */
  234. void pkgSourceList::Reset()
  235. {
  236. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  237. delete *I;
  238. SrcList.erase(SrcList.begin(),SrcList.end());
  239. }
  240. /*}}}*/
  241. // SourceList::Read - Parse the sourcelist file /*{{{*/
  242. // ---------------------------------------------------------------------
  243. /* */
  244. bool pkgSourceList::Read(string File)
  245. {
  246. Reset();
  247. return ReadAppend(File);
  248. }
  249. /*}}}*/
  250. // SourceList::ReadAppend - Parse a sourcelist file /*{{{*/
  251. // ---------------------------------------------------------------------
  252. /* */
  253. bool pkgSourceList::ReadAppend(string File)
  254. {
  255. if (_config->FindB("APT::Sources::Use-Deb822", true) == true)
  256. {
  257. int lines_parsed =ParseFileDeb822(File);
  258. if (lines_parsed < 0)
  259. return false;
  260. else if (lines_parsed > 0)
  261. return true;
  262. // no lines parsed ... fall through and use old style parser
  263. }
  264. return ParseFileOldStyle(File);
  265. }
  266. // SourceList::ReadFileOldStyle - Read Traditional style sources.list /*{{{*/
  267. // ---------------------------------------------------------------------
  268. /* */
  269. bool pkgSourceList::ParseFileOldStyle(string File)
  270. {
  271. // Open the stream for reading
  272. ifstream F(File.c_str(),ios::in /*| ios::nocreate*/);
  273. if (!F != 0)
  274. return _error->Errno("ifstream::ifstream",_("Opening %s"),File.c_str());
  275. // CNC:2003-12-10 - 300 is too short.
  276. char Buffer[1024];
  277. int CurLine = 0;
  278. while (F.eof() == false)
  279. {
  280. F.getline(Buffer,sizeof(Buffer));
  281. CurLine++;
  282. _strtabexpand(Buffer,sizeof(Buffer));
  283. if (F.fail() && !F.eof())
  284. return _error->Error(_("Line %u too long in source list %s."),
  285. CurLine,File.c_str());
  286. char *I;
  287. // CNC:2003-02-20 - Do not break if '#' is inside [].
  288. for (I = Buffer; *I != 0 && *I != '#'; I++)
  289. if (*I == '[')
  290. {
  291. char *b_end = strchr(I + 1, ']');
  292. if (b_end != NULL)
  293. I = b_end;
  294. }
  295. *I = 0;
  296. const char *C = _strstrip(Buffer);
  297. // Comment or blank
  298. if (C[0] == '#' || C[0] == 0)
  299. continue;
  300. // Grok it
  301. string LineType;
  302. if (ParseQuoteWord(C,LineType) == false)
  303. return _error->Error(_("Malformed line %u in source list %s (type)"),CurLine,File.c_str());
  304. Type *Parse = Type::GetType(LineType.c_str());
  305. if (Parse == 0)
  306. return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
  307. if (Parse->ParseLine(SrcList, C, CurLine, File) == false)
  308. return false;
  309. }
  310. return true;
  311. }
  312. /*}}}*/
  313. // SourceList::ParseFileDeb822 - Parse deb822 style sources.list /*{{{*/
  314. // ---------------------------------------------------------------------
  315. /* Returns: the number of stanzas parsed*/
  316. int pkgSourceList::ParseFileDeb822(string File)
  317. {
  318. pkgTagSection Tags;
  319. unsigned int i=0;
  320. // see if we can read the file
  321. _error->PushToStack();
  322. FileFd Fd(File, FileFd::ReadOnly);
  323. pkgTagFile Sources(&Fd);
  324. if (_error->PendingError() == true)
  325. {
  326. _error->RevertToStack();
  327. return 0;
  328. }
  329. _error->MergeWithStack();
  330. // read step by step
  331. while (Sources.Step(Tags) == true)
  332. {
  333. if(!Tags.Exists("Type"))
  334. continue;
  335. string const type = Tags.FindS("Type");
  336. Type *Parse = Type::GetType(type.c_str());
  337. if (Parse == 0)
  338. {
  339. _error->Error(_("Type '%s' is not known on stanza %u in source list %s"),type.c_str(),i,Fd.Name().c_str());
  340. return -1;
  341. }
  342. if (!Parse->ParseStanza(SrcList, Tags, i, Fd))
  343. return -1;
  344. i++;
  345. }
  346. // we are done, return the number of stanzas read
  347. return i;
  348. }
  349. /*}}}*/
  350. // SourceList::FindIndex - Get the index associated with a file /*{{{*/
  351. // ---------------------------------------------------------------------
  352. /* */
  353. bool pkgSourceList::FindIndex(pkgCache::PkgFileIterator File,
  354. pkgIndexFile *&Found) const
  355. {
  356. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  357. {
  358. vector<pkgIndexFile *> *Indexes = (*I)->GetIndexFiles();
  359. for (vector<pkgIndexFile *>::const_iterator J = Indexes->begin();
  360. J != Indexes->end(); ++J)
  361. {
  362. if ((*J)->FindInCache(*File.Cache()) == File)
  363. {
  364. Found = (*J);
  365. return true;
  366. }
  367. }
  368. }
  369. return false;
  370. }
  371. /*}}}*/
  372. // SourceList::GetIndexes - Load the index files into the downloader /*{{{*/
  373. // ---------------------------------------------------------------------
  374. /* */
  375. bool pkgSourceList::GetIndexes(pkgAcquire *Owner, bool GetAll) const
  376. {
  377. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  378. if ((*I)->GetIndexes(Owner,GetAll) == false)
  379. return false;
  380. return true;
  381. }
  382. /*}}}*/
  383. // CNC:2003-03-03 - By Anton V. Denisov <avd@altlinux.org>.
  384. // SourceList::ReadSourceDir - Read a directory with sources files
  385. // Based on ReadConfigDir() /*{{{*/
  386. // ---------------------------------------------------------------------
  387. /* */
  388. bool pkgSourceList::ReadSourceDir(string Dir)
  389. {
  390. vector<string> const List = GetListOfFilesInDir(Dir, "list", true);
  391. // Read the files
  392. for (vector<string>::const_iterator I = List.begin(); I != List.end(); ++I)
  393. if (ReadAppend(*I) == false)
  394. return false;
  395. return true;
  396. }
  397. /*}}}*/
  398. // GetLastModified() /*{{{*/
  399. // ---------------------------------------------------------------------
  400. /* */
  401. time_t pkgSourceList::GetLastModifiedTime()
  402. {
  403. vector<string> List;
  404. string Main = _config->FindFile("Dir::Etc::sourcelist");
  405. string Parts = _config->FindDir("Dir::Etc::sourceparts");
  406. // go over the parts
  407. if (DirectoryExists(Parts) == true)
  408. List = GetListOfFilesInDir(Parts, "list", true);
  409. // calculate the time
  410. time_t mtime_sources = GetModificationTime(Main);
  411. for (vector<string>::const_iterator I = List.begin(); I != List.end(); ++I)
  412. mtime_sources = std::max(mtime_sources, GetModificationTime(*I));
  413. return mtime_sources;
  414. }
  415. /*}}}*/