parse.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * parse.c - database file parsing, main package/field loop
  4. *
  5. * Copyright (C) 1995 Ian Jackson <ian@chiark.greenend.org.uk>
  6. *
  7. * This is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2,
  10. * or (at your option) any later version.
  11. *
  12. * This is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public
  18. * License along with dpkg; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <config.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include <stdarg.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <dpkg.h>
  31. #include <dpkg-db.h>
  32. #include "parsedump.h"
  33. #ifdef HAVE_MMAP
  34. #include <sys/mman.h>
  35. #endif
  36. const struct fieldinfo fieldinfos[]= {
  37. /* NB: capitalisation of these strings is important. */
  38. { "Package", f_name, w_name },
  39. { "Essential", f_boolean, w_booleandefno, PKGIFPOFF(essential) },
  40. { "Status", f_status, w_status },
  41. { "Priority", f_priority, w_priority },
  42. { "Section", f_section, w_section },
  43. { "Installed-Size", f_charfield, w_charfield, PKGIFPOFF(installedsize) },
  44. { "Origin", f_charfield, w_charfield, PKGIFPOFF(origin) },
  45. { "Maintainer", f_charfield, w_charfield, PKGIFPOFF(maintainer) },
  46. { "Bugs", f_charfield, w_charfield, PKGIFPOFF(bugs) },
  47. { "Architecture", f_charfield, w_charfield, PKGIFPOFF(architecture) },
  48. { "Source", f_charfield, w_charfield, PKGIFPOFF(source) },
  49. { "Version", f_version, w_version, PKGIFPOFF(version) },
  50. { "Revision", f_revision, w_null },
  51. { "Config-Version", f_configversion, w_configversion },
  52. { "Replaces", f_dependency, w_dependency, dep_replaces },
  53. { "Provides", f_dependency, w_dependency, dep_provides },
  54. { "Depends", f_dependency, w_dependency, dep_depends },
  55. { "Pre-Depends", f_dependency, w_dependency, dep_predepends },
  56. { "Recommends", f_dependency, w_dependency, dep_recommends },
  57. { "Suggests", f_dependency, w_dependency, dep_suggests },
  58. { "Conflicts", f_dependency, w_dependency, dep_conflicts },
  59. { "Enhances", f_dependency, w_dependency, dep_enhances },
  60. { "Conffiles", f_conffiles, w_conffiles },
  61. { "Filename", f_filecharf, w_filecharf, FILEFOFF(name) },
  62. { "Size", f_filecharf, w_filecharf, FILEFOFF(size) },
  63. { "MD5sum", f_filecharf, w_filecharf, FILEFOFF(md5sum) },
  64. { "MSDOS-Filename", f_filecharf, w_filecharf, FILEFOFF(msdosname) },
  65. { "Description", f_charfield, w_charfield, PKGIFPOFF(description) },
  66. /* Note that aliases are added to the nicknames table in parsehelp.c. */
  67. { NULL /* sentinel - tells code that list is ended */ }
  68. };
  69. #define NFIELDS (sizeof(fieldinfos)/sizeof(struct fieldinfo))
  70. const int nfields= NFIELDS;
  71. static void cu_parsedb(int argc, void **argv) { close(*(int *)argv); }
  72. int parsedb(const char *filename, enum parsedbflags flags,
  73. struct pkginfo **donep, FILE *warnto, int *warncount) {
  74. /* warnto, warncount and donep may be null.
  75. * If donep is not null only one package's information is expected.
  76. */
  77. int fd;
  78. struct pkginfo newpig, *pigp;
  79. struct pkginfoperfile *newpifp, *pifp;
  80. struct arbitraryfield *arp, **larpp;
  81. int lno;
  82. int pdone;
  83. int fieldencountered[NFIELDS];
  84. const struct fieldinfo *fip;
  85. const struct nickname *nick;
  86. char *data, *dataptr, *endptr;
  87. const char *fieldstart, *valuestart;
  88. char *value= NULL;
  89. int fieldlen= 0, valuelen= 0;
  90. int *ip, c;
  91. struct stat stat;
  92. if (warncount) *warncount= 0;
  93. newpifp= (flags & pdb_recordavailable) ? &newpig.available : &newpig.installed;
  94. fd= open(filename, O_RDONLY);
  95. if (fd == -1) ohshite(_("failed to open package info file `%.255s' for reading"),filename);
  96. push_cleanup(cu_parsedb,~0, NULL,0, 1,&fd);
  97. if (fstat(fd, &stat) == -1)
  98. ohshite(_("can't stat package info file `%.255s'"),filename);
  99. #ifdef HAVE_MMAP
  100. if ((dataptr= (char *)mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
  101. ohshite(_("can't mmap package info file `%.255s'"),filename);
  102. #else
  103. if ((dataptr= malloc(stat.st_size)) == NULL)
  104. ohshite(_("failed to malloc for info file `%.255s'"),filename);
  105. fd_buf_copy(fd, dataptr, stat.st_size, _("copy info file `%.255s'"),filename);
  106. #endif
  107. data= dataptr;
  108. endptr= dataptr + stat.st_size;
  109. lno= 1;
  110. pdone= 0;
  111. #define EOF_mmap(dataptr, endptr) (dataptr >= endptr)
  112. #define getc_mmap(dataptr) *dataptr++;
  113. #define ungetc_mmap(c, dataptr, data) dataptr--;
  114. for (;;) { /* loop per package */
  115. memset(fieldencountered, 0, sizeof(fieldencountered));
  116. blankpackage(&newpig);
  117. blankpackageperfile(newpifp);
  118. /* Skip adjacent new lines */
  119. while(!EOF_mmap(dataptr, endptr)) {
  120. c= getc_mmap(dataptr); if (c!='\n' && c!=MSDOS_EOF_CHAR ) break;
  121. lno++;
  122. }
  123. if (EOF_mmap(dataptr, endptr)) break;
  124. for (;;) { /* loop per field */
  125. fieldstart= dataptr - 1;
  126. while (!EOF_mmap(dataptr, endptr) && !isspace(c) && c!=':' && c!=MSDOS_EOF_CHAR)
  127. c= getc_mmap(dataptr);
  128. fieldlen= dataptr - fieldstart - 1;
  129. while (!EOF_mmap(dataptr, endptr) && c != '\n' && isspace(c)) c= getc_mmap(dataptr);
  130. if (EOF_mmap(dataptr, endptr))
  131. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  132. _("EOF after field name `%.*s'"),fieldlen,fieldstart);
  133. if (c == '\n')
  134. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  135. _("newline in field name `%.*s'"),fieldlen,fieldstart);
  136. if (c == MSDOS_EOF_CHAR)
  137. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  138. _("MSDOS EOF (^Z) in field name `%.*s'"),fieldlen,fieldstart);
  139. if (c != ':')
  140. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  141. _("field name `%.*s' must be followed by colon"),fieldlen,fieldstart);
  142. /* Skip space after ':' but before value and eol */
  143. while(!EOF_mmap(dataptr, endptr)) {
  144. c= getc_mmap(dataptr);
  145. if (c == '\n' || !isspace(c)) break;
  146. }
  147. if (EOF_mmap(dataptr, endptr))
  148. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  149. _("EOF before value of field `%.*s' (missing final newline)"),
  150. fieldlen,fieldstart);
  151. if (c == MSDOS_EOF_CHAR)
  152. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  153. _("MSDOS EOF char in value of field `%.*s' (missing newline?)"),
  154. fieldlen,fieldstart);
  155. valuestart= dataptr - 1;
  156. for (;;) {
  157. if (c == '\n' || c == MSDOS_EOF_CHAR) {
  158. lno++;
  159. if (EOF_mmap(dataptr, endptr)) break;
  160. c= getc_mmap(dataptr);
  161. /* Found double eol, or start of new field */
  162. if (EOF_mmap(dataptr, endptr) || c == '\n' || !isspace(c)) break;
  163. ungetc_mmap(c,dataptr, data);
  164. c= '\n';
  165. } else if (EOF_mmap(dataptr, endptr)) {
  166. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  167. _("EOF during value of field `%.*s' (missing final newline)"),
  168. fieldlen,fieldstart);
  169. }
  170. c= getc_mmap(dataptr);
  171. }
  172. valuelen= dataptr - valuestart - 1;
  173. /* trim ending space on value */
  174. while (valuelen && isspace(*(valuestart+valuelen-1)))
  175. valuelen--;
  176. for (nick= nicknames; nick->nick && (strncasecmp(nick->nick,fieldstart, fieldlen) || nick->nick[fieldlen] != 0); nick++);
  177. if (nick->nick) {
  178. fieldstart= nick->canon;
  179. fieldlen= strlen(fieldstart);
  180. }
  181. for (fip= fieldinfos, ip= fieldencountered;
  182. fip->name && strncasecmp(fieldstart,fip->name, fieldlen);
  183. fip++, ip++);
  184. if (fip->name) {
  185. value= realloc(value,valuelen+1);
  186. memcpy(value,valuestart,valuelen);
  187. *(value+valuelen)= 0;
  188. if (*ip++)
  189. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  190. _("duplicate value for `%s' field"), fip->name);
  191. fip->rcall(&newpig,newpifp,flags,filename,lno-1,warnto,warncount,value,fip);
  192. } else {
  193. if (fieldlen<2)
  194. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  195. _("user-defined field name `%.*s' too short"), fieldlen,fieldstart);
  196. larpp= &newpifp->arbs;
  197. while ((arp= *larpp) != NULL) {
  198. if (!strncasecmp(arp->name,fieldstart,fieldlen))
  199. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  200. _("duplicate value for user-defined field `%.*s'"), fieldlen,fieldstart);
  201. larpp= &arp->next;
  202. }
  203. arp= nfmalloc(sizeof(struct arbitraryfield));
  204. arp->name= nfstrnsave(fieldstart,fieldlen);
  205. arp->value= nfstrnsave(valuestart,valuelen);
  206. arp->next= NULL;
  207. *larpp= arp;
  208. }
  209. if (EOF_mmap(dataptr, endptr) || c == '\n' || c == MSDOS_EOF_CHAR) break;
  210. } /* loop per field */
  211. if (pdone && donep)
  212. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  213. _("several package info entries found, only one allowed"));
  214. parsemustfield(NULL,filename,lno, warnto,warncount,&newpig,0,
  215. &newpig.name, "package name");
  216. if ((flags & pdb_recordavailable) || newpig.status != stat_notinstalled) {
  217. parsemustfield(NULL,filename,lno, warnto,warncount,&newpig,1,
  218. (const char **)&newpifp->description, "description");
  219. parsemustfield(NULL,filename,lno, warnto,warncount,&newpig,1,
  220. (const char **)&newpifp->maintainer, "maintainer");
  221. if (newpig.status != stat_halfinstalled)
  222. parsemustfield(NULL,filename,lno, warnto,warncount,&newpig,0,
  223. &newpifp->version.version, "version");
  224. }
  225. if (flags & pdb_recordavailable)
  226. parsemustfield(NULL,filename,lno, warnto,warncount,&newpig,1,
  227. (const char **)&newpifp->architecture, "architecture");
  228. /* Check the Config-Version information:
  229. * If there is a Config-Version it is definitely to be used, but
  230. * there shouldn't be one if the package is `installed' (in which case
  231. * the Version and/or Revision will be copied) or if the package is
  232. * `not-installed' (in which case there is no Config-Version).
  233. */
  234. if (!(flags & pdb_recordavailable)) {
  235. if (newpig.configversion.version) {
  236. if (newpig.status == stat_installed || newpig.status == stat_notinstalled)
  237. parseerr(NULL,filename,lno, warnto,warncount,&newpig,0,
  238. _("Configured-Version for package with inappropriate Status"));
  239. } else {
  240. if (newpig.status == stat_installed) newpig.configversion= newpifp->version;
  241. }
  242. }
  243. /* There was a bug that could make a not-installed package have
  244. * conffiles, so we check for them here and remove them (rather than
  245. * calling it an error, which will do at some point -- fixme).
  246. */
  247. if (!(flags & pdb_recordavailable) &&
  248. newpig.status == stat_notinstalled &&
  249. newpifp->conffiles) {
  250. parseerr(NULL,filename,lno, warnto,warncount,&newpig,1,
  251. _("Package which in state not-installed has conffiles, forgetting them"));
  252. newpifp->conffiles= NULL;
  253. }
  254. pigp= findpackage(newpig.name);
  255. pifp= (flags & pdb_recordavailable) ? &pigp->available : &pigp->installed;
  256. if (!pifp->valid) blankpackageperfile(pifp);
  257. /* Copy the priority and section across, but don't overwrite existing
  258. * values if the pdb_weakclassification flag is set.
  259. */
  260. if (newpig.section && *newpig.section &&
  261. !((flags & pdb_weakclassification) && pigp->section && *pigp->section))
  262. pigp->section= newpig.section;
  263. if (newpig.priority != pri_unknown &&
  264. !((flags & pdb_weakclassification) && pigp->priority != pri_unknown)) {
  265. pigp->priority= newpig.priority;
  266. if (newpig.priority == pri_other) pigp->otherpriority= newpig.otherpriority;
  267. }
  268. /* Sort out the dependency mess. */
  269. copy_dependency_links(pigp,&pifp->depends,newpifp->depends,
  270. (flags & pdb_recordavailable) ? 1 : 0);
  271. /* Leave the `depended' pointer alone, we've just gone to such
  272. * trouble to get it right :-). The `depends' pointer in
  273. * pifp was indeed also updated by copy_dependency_links,
  274. * but since the value was that from newpifp anyway there's
  275. * no need to copy it back.
  276. */
  277. newpifp->depended= pifp->depended;
  278. /* Copy across data */
  279. memcpy(pifp,newpifp,sizeof(struct pkginfoperfile));
  280. if (!(flags & pdb_recordavailable)) {
  281. pigp->want= newpig.want;
  282. pigp->eflag= newpig.eflag;
  283. pigp->status= newpig.status;
  284. pigp->configversion= newpig.configversion;
  285. pigp->files= NULL;
  286. } else if (!(flags & pdb_ignorefiles)) {
  287. pigp->files= newpig.files;
  288. }
  289. if (donep) *donep= pigp;
  290. pdone++;
  291. if (EOF_mmap(dataptr, endptr)) break;
  292. if (c == '\n') lno++;
  293. }
  294. pop_cleanup(0);
  295. #ifdef HAVE_MMAP
  296. munmap(data, stat.st_size);
  297. #else
  298. free(data);
  299. #endif
  300. free(value);
  301. if (close(fd)) ohshite(_("failed to close after read: `%.255s'"),filename);
  302. if (donep && !pdone) ohshit(_("no package information in `%.255s'"),filename);
  303. return pdone;
  304. }
  305. void copy_dependency_links(struct pkginfo *pkg,
  306. struct dependency **updateme,
  307. struct dependency *newdepends,
  308. int available) {
  309. /* This routine is used to update the `reverse' dependency pointers
  310. * when new `forwards' information has been constructed. It first
  311. * removes all the links based on the old information. The old
  312. * information starts in *updateme; after much brou-ha-ha
  313. * the reverse structures are created and *updateme is set
  314. * to the value from newdepends.
  315. *
  316. * Parameters are:
  317. * pkg - the package we're doing this for. This is used to
  318. * construct correct uplinks.
  319. * updateme - the forwards dependency pointer that we are to
  320. * update. This starts out containing the old forwards
  321. * info, which we use to unthread the old reverse
  322. * links. After we're done it is updated.
  323. * newdepends - the value that we ultimately want to have in
  324. * updateme.
  325. * It is likely that the backward pointer for the package in
  326. * question (`depended') will be updated by this routine,
  327. * but this will happen by the routine traversing the dependency
  328. * data structures. It doesn't need to be told where to update
  329. * that; I just mention it as something that one should be
  330. * cautious about.
  331. */
  332. struct dependency *dyp;
  333. struct deppossi *dop;
  334. struct pkginfoperfile *addtopifp;
  335. /* Delete `backward' (`depended') links from other packages to
  336. * dependencies listed in old version of this one. We do this by
  337. * going through all the dependencies in the old version of this
  338. * one and following them down to find which deppossi nodes to
  339. * remove.
  340. */
  341. for (dyp= *updateme; dyp; dyp= dyp->next) {
  342. for (dop= dyp->list; dop; dop= dop->next) {
  343. if (dop->backrev)
  344. dop->backrev->nextrev= dop->nextrev;
  345. else
  346. if (available)
  347. dop->ed->available.depended= dop->nextrev;
  348. else
  349. dop->ed->installed.depended= dop->nextrev;
  350. if (dop->nextrev)
  351. dop->nextrev->backrev= dop->backrev;
  352. }
  353. }
  354. /* Now fill in new `ed' links from other packages to dependencies listed
  355. * in new version of this one, and set our uplinks correctly.
  356. */
  357. for (dyp= newdepends; dyp; dyp= dyp->next) {
  358. dyp->up= pkg;
  359. for (dop= dyp->list; dop; dop= dop->next) {
  360. addtopifp= available ? &dop->ed->available : &dop->ed->installed;
  361. if (!addtopifp->valid) blankpackageperfile(addtopifp);
  362. dop->nextrev= addtopifp->depended;
  363. dop->backrev= NULL;
  364. if (addtopifp->depended)
  365. addtopifp->depended->backrev= dop;
  366. addtopifp->depended= dop;
  367. }
  368. }
  369. /* Finally, we fill in the new value. */
  370. *updateme= newdepends;
  371. }