sourcelist.cc 15 KB

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