pkg_parse.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /* pkg_parse.c - the opkg package management system
  2. Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com>
  3. Steven M. Ayer
  4. Copyright (C) 2002 Compaq Computer Corporation
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2, or (at
  8. your option) any later version.
  9. This program is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. General Public License for more details.
  13. */
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <unistd.h>
  17. #include "pkg.h"
  18. #include "opkg_utils.h"
  19. #include "pkg_parse.h"
  20. #include "pkg_depends.h"
  21. #include "libbb/libbb.h"
  22. #include "file_util.h"
  23. #include "parse_util.h"
  24. static void parse_status(pkg_t * pkg, const char *sstr)
  25. {
  26. char sw_str[64], sf_str[64], ss_str[64];
  27. if (sscanf(sstr, "Status: %63s %63s %63s", sw_str, sf_str, ss_str) != 3) {
  28. opkg_msg(ERROR, "Failed to parse Status line for %s\n",
  29. pkg->name);
  30. return;
  31. }
  32. pkg->state_want = pkg_state_want_from_str(sw_str);
  33. pkg->state_flag |= pkg_state_flag_from_str(sf_str);
  34. pkg->state_status = pkg_state_status_from_str(ss_str);
  35. }
  36. static void parse_conffiles(pkg_t * pkg, const char *cstr)
  37. {
  38. conffile_list_t *cl;
  39. char file_name[1024], md5sum[85];
  40. if (sscanf(cstr, "%1023s %84s", file_name, md5sum) != 2) {
  41. opkg_msg(ERROR, "Failed to parse Conffiles line for %s\n",
  42. pkg->name);
  43. return;
  44. }
  45. cl = pkg_get_ptr(pkg, PKG_CONFFILES);
  46. if (cl)
  47. conffile_list_append(cl, file_name, md5sum);
  48. }
  49. int parse_version(pkg_t * pkg, const char *vstr)
  50. {
  51. char *colon, *dup, *rev;
  52. if (strncmp(vstr, "Version:", 8) == 0)
  53. vstr += 8;
  54. while (*vstr && isspace(*vstr))
  55. vstr++;
  56. colon = strchr(vstr, ':');
  57. if (colon) {
  58. errno = 0;
  59. pkg_set_int(pkg, PKG_EPOCH, strtoul(vstr, NULL, 10));
  60. if (errno) {
  61. opkg_perror(ERROR, "%s: invalid epoch", pkg->name);
  62. }
  63. vstr = ++colon;
  64. }
  65. dup = xstrdup(vstr);
  66. rev = strrchr(dup, '-');
  67. if (rev) {
  68. *rev++ = '\0';
  69. pkg_set_string(pkg, PKG_REVISION, rev);
  70. }
  71. pkg_set_string(pkg, PKG_VERSION, dup);
  72. free(dup);
  73. return 0;
  74. }
  75. static char *parse_architecture(pkg_t *pkg, const char *str)
  76. {
  77. const char *s = str;
  78. const char *e;
  79. while (isspace(*s))
  80. s++;
  81. e = s + strlen(s);
  82. while (e > s && isspace(*e))
  83. e--;
  84. return pkg_set_architecture(pkg, s, e - s);
  85. }
  86. static void parse_alternatives(pkg_t *pkg, char *list)
  87. {
  88. char *item, *tok;
  89. struct pkg_alternatives *pkg_alts;
  90. struct pkg_alternative **alts;
  91. int nalts;
  92. pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES);
  93. if (!pkg_alts) {
  94. nalts = 0;
  95. alts = NULL;
  96. } else {
  97. nalts = pkg_alts->nalts;
  98. alts = pkg_alts->alts;
  99. }
  100. for (item = strtok_r(list, ",", &tok);
  101. item;
  102. item = strtok_r(NULL, ",", &tok)) {
  103. enum pkg_alternative_field i;
  104. char *val, *tok1;
  105. /* the assignment was intended to quash the -Wmaybe-uninitialized warnings */
  106. int prio = prio;
  107. char *path = path, *altpath = altpath;
  108. for (i = PAF_PRIO, val = strtok_r(item, ":", &tok1);
  109. val && i < __PAF_MAX;
  110. val = strtok_r(NULL, ":", &tok1), i++) {
  111. switch (i) {
  112. case PAF_PRIO:
  113. prio = atoi(val);
  114. break;
  115. case PAF_PATH:
  116. path = val;
  117. break;
  118. case PAF_ALTPATH:
  119. altpath = val;
  120. break;
  121. default:
  122. break;
  123. }
  124. }
  125. if (!val && i == __PAF_MAX) {
  126. char *_path, *_altpath;
  127. struct pkg_alternative *alt;
  128. /*
  129. * - path must be absolute
  130. * - altpath must be non-empty
  131. */
  132. if (path[0] != '/' || !altpath[0])
  133. continue;
  134. alt = calloc_a(sizeof(*alt),
  135. &_path, strlen(path) + 1,
  136. &_altpath, strlen(altpath) + 1);
  137. if (!alt)
  138. continue;
  139. strcpy(_path, path);
  140. strcpy(_altpath, altpath);
  141. alt->prio = prio;
  142. alt->path = _path;
  143. alt->altpath = _altpath;
  144. alts = xrealloc(alts, sizeof(*alts) * (nalts + 1));
  145. alts[nalts++] = alt;
  146. }
  147. }
  148. if (nalts > 0) {
  149. if (!pkg_alts)
  150. pkg_alts = xmalloc(sizeof(*pkg_alts));
  151. pkg_alts->nalts = nalts;
  152. pkg_alts->alts = alts;
  153. pkg_set_ptr(pkg, PKG_ALTERNATIVES, pkg_alts);
  154. }
  155. }
  156. int pkg_parse_line(void *ptr, char *line, uint mask)
  157. {
  158. pkg_t *pkg = (pkg_t *) ptr;
  159. abstract_pkg_t *ab_pkg = NULL;
  160. conffile_list_t *cl;
  161. /* these flags are a bit hackish... */
  162. static int reading_conffiles = 0, reading_description = 0;
  163. static char *description = NULL;
  164. int ret = 0;
  165. /* Exclude globally masked fields. */
  166. mask |= conf->pfm;
  167. /* Flip the semantics of the mask. */
  168. mask ^= PFM_ALL;
  169. switch (*line) {
  170. case 'A':
  171. if ((mask & PFM_ABIVERSION) && is_field("ABIVersion", line))
  172. pkg_set_string(pkg, PKG_ABIVERSION, line + strlen("ABIVersion") + 1);
  173. else if ((mask & PFM_ALTERNATIVES) && is_field("Alternatives", line))
  174. parse_alternatives(pkg, line + strlen("Alternatives") + 1);
  175. else if ((mask & PFM_ARCHITECTURE) && is_field("Architecture", line))
  176. parse_architecture(pkg, line + strlen("Architecture") + 1);
  177. else if ((mask & PFM_AUTO_INSTALLED)
  178. && is_field("Auto-Installed", line)) {
  179. char *tmp = parse_simple("Auto-Installed", line);
  180. if (strcmp(tmp, "yes") == 0)
  181. pkg->auto_installed = 1;
  182. free(tmp);
  183. }
  184. break;
  185. case 'C':
  186. if ((mask & PFM_CONFFILES) && is_field("Conffiles", line)) {
  187. reading_conffiles = 1;
  188. reading_description = 0;
  189. cl = xcalloc(1, sizeof(*cl));
  190. conffile_list_init(cl);
  191. pkg_set_ptr(pkg, PKG_CONFFILES, cl);
  192. goto dont_reset_flags;
  193. } else if ((mask & PFM_CONFLICTS)
  194. && is_field("Conflicts", line))
  195. parse_deplist(pkg, CONFLICTS, line + strlen("Conflicts") + 1);
  196. break;
  197. case 'D':
  198. if ((mask & PFM_DESCRIPTION) && is_field("Description", line)) {
  199. description = parse_simple("Description", line);
  200. reading_conffiles = 0;
  201. reading_description = 1;
  202. goto dont_reset_flags;
  203. } else if ((mask & PFM_DEPENDS) && is_field("Depends", line))
  204. parse_deplist(pkg, DEPEND, line + strlen("Depends") + 1);
  205. break;
  206. case 'E':
  207. if ((mask & PFM_ESSENTIAL) && is_field("Essential", line)) {
  208. char *tmp = parse_simple("Essential", line);
  209. if (strcmp(tmp, "yes") == 0)
  210. pkg->essential = 1;
  211. free(tmp);
  212. }
  213. break;
  214. case 'F':
  215. if ((mask & PFM_FILENAME) && is_field("Filename", line))
  216. pkg_set_string(pkg, PKG_FILENAME, line + strlen("Filename") + 1);
  217. break;
  218. case 'I':
  219. if ((mask & PFM_INSTALLED_SIZE)
  220. && is_field("Installed-Size", line)) {
  221. pkg_set_int(pkg, PKG_INSTALLED_SIZE, strtoul(line + strlen("Installed-Size") + 1, NULL, 0));
  222. } else if ((mask & PFM_INSTALLED_TIME)
  223. && is_field("Installed-Time", line)) {
  224. pkg_set_int(pkg, PKG_INSTALLED_TIME, strtoul(line + strlen("Installed-Time") + 1, NULL, 0));
  225. }
  226. break;
  227. case 'M':
  228. if ((mask & PFM_MD5SUM) && (is_field("MD5sum:", line) || is_field("MD5Sum:", line)))
  229. pkg_set_md5(pkg, line + strlen("MD5sum") + 1);
  230. else if ((mask & PFM_MAINTAINER)
  231. && is_field("Maintainer", line))
  232. pkg_set_string(pkg, PKG_MAINTAINER, line + strlen("Maintainer") + 1);
  233. break;
  234. case 'P':
  235. if ((mask & PFM_PACKAGE) && is_field("Package", line)) {
  236. pkg->name = parse_simple("Package", line);
  237. ab_pkg = abstract_pkg_fetch_by_name(pkg->name);
  238. if (ab_pkg && (ab_pkg->state_flag & SF_NEED_DETAIL)) {
  239. if (!(pkg->state_flag & SF_NEED_DETAIL)) {
  240. opkg_msg(DEBUG, "propagating abpkg flag to pkg %s\n", pkg->name);
  241. pkg->state_flag |= SF_NEED_DETAIL;
  242. }
  243. }
  244. }
  245. else if ((mask & PFM_PRIORITY) && is_field("Priority", line))
  246. pkg_set_string(pkg, PKG_PRIORITY, line + strlen("Priority") + 1);
  247. else if ((mask & PFM_PROVIDES) && is_field("Provides", line))
  248. parse_providelist(pkg, line + strlen("Provides") + 1);
  249. else if ((mask & PFM_PRE_DEPENDS)
  250. && is_field("Pre-Depends", line))
  251. parse_deplist(pkg, PREDEPEND, line + strlen("Pre-Depends") + 1);
  252. break;
  253. case 'R':
  254. if ((mask & PFM_RECOMMENDS) && is_field("Recommends", line))
  255. parse_deplist(pkg, RECOMMEND, line + strlen("Recommends") + 1);
  256. else if ((mask & PFM_REPLACES) && is_field("Replaces", line))
  257. parse_replacelist(pkg, line + strlen("Replaces") + 1);
  258. break;
  259. case 'S':
  260. if ((mask & PFM_SECTION) && is_field("Section", line))
  261. pkg_set_string(pkg, PKG_SECTION, line + strlen("Section") + 1);
  262. else if ((mask & PFM_SHA256SUM) && is_field("SHA256sum", line))
  263. pkg_set_sha256(pkg, line + strlen("SHA256sum") + 1);
  264. else if ((mask & PFM_SIZE) && is_field("Size", line)) {
  265. pkg_set_int(pkg, PKG_SIZE, strtoul(line + strlen("Size") + 1, NULL, 0));
  266. } else if ((mask & PFM_SOURCE) && is_field("Source", line))
  267. pkg_set_string(pkg, PKG_SOURCE, line + strlen("Source") + 1);
  268. else if ((mask & PFM_STATUS) && is_field("Status", line))
  269. parse_status(pkg, line);
  270. else if ((mask & PFM_SUGGESTS) && is_field("Suggests", line))
  271. parse_deplist(pkg, SUGGEST, line + strlen("Suggests") + 1);
  272. break;
  273. case 'T':
  274. if ((mask & PFM_TAGS) && is_field("Tags", line))
  275. pkg_set_string(pkg, PKG_TAGS, line + strlen("Tags") + 1);
  276. break;
  277. case 'V':
  278. if ((mask & PFM_VERSION) && is_field("Version", line))
  279. parse_version(pkg, line);
  280. break;
  281. case ' ':
  282. if ((mask & PFM_DESCRIPTION) && reading_description) {
  283. size_t len = (description ? strlen(description) : 0)
  284. + (isatty(1) ? 1 : 0) + strlen(line) + 1;
  285. description = description ? xrealloc(description, len)
  286. : xcalloc(len, 1);
  287. if (isatty(1))
  288. strcat(description, "\n");
  289. strcat(description, line);
  290. goto dont_reset_flags;
  291. } else if ((mask & PFM_CONFFILES) && reading_conffiles) {
  292. parse_conffiles(pkg, line);
  293. goto dont_reset_flags;
  294. }
  295. /* FALLTHROUGH */
  296. default:
  297. /* For package lists, signifies end of package. */
  298. if (line_is_blank(line)) {
  299. ret = 1;
  300. break;
  301. }
  302. }
  303. if (reading_description && description) {
  304. pkg_set_string(pkg, PKG_DESCRIPTION, description);
  305. free(description);
  306. reading_description = 0;
  307. description = NULL;
  308. }
  309. reading_conffiles = 0;
  310. dont_reset_flags:
  311. return ret;
  312. }
  313. int pkg_parse_from_stream(pkg_t * pkg, FILE * fp, uint mask)
  314. {
  315. int ret;
  316. char *buf;
  317. const size_t len = 4096;
  318. buf = xmalloc(len);
  319. ret =
  320. parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf,
  321. len);
  322. free(buf);
  323. if (pkg->name == NULL) {
  324. /* probably just a blank line */
  325. ret = 1;
  326. }
  327. return ret;
  328. }