struct pkginfo *findpackage(const char *inname) { struct pkginfo **pointerp, *newpkg; char *name = strdup(inname), *p; if (name == NULL) ohshite(_("couldn't allocate memory for strdup in findpackage(%s)"),inname); p= name; while(*p) { *p= tolower(*p); p++; } pointerp= bins + (hash(name) % (BINS)); while (*pointerp && strcasecmp((*pointerp)->name,name)) pointerp= &(*pointerp)->next; if (*pointerp) { free(name); return *pointerp; } newpkg= nfmalloc(sizeof(struct pkginfo)); blankpackage(newpkg); newpkg->name= nfstrsave(name); newpkg->next= NULL; *pointerp= newpkg; npackages++; free(name); return newpkg; }
static int do_register(psys_pkg_t pkg, psys_err_t *err, jmp_buf *buf) { int ret; char *dpkgname = NULL; const char *dpkgarch; struct pkginfo *dpkg; psys_flist_t flist = NULL; char *filelist_path = NULL; char *md5list_path = NULL; set_error_handler(err, *buf, out); dpkgname = dpkg_name(psys_pkg_vendor(pkg), psys_pkg_name(pkg)); dpkg = findpackage(dpkgname); if (ensure_not_installed(dpkg, err)) { ret = -1; goto out; } if (ensure_dependencies_met(pkg, err)) { ret = -1; goto out; } blankpackage(dpkg); blankpackageperfile(&dpkg->installed); /* Name, Version */ dpkg->name = dpkgname; parseversion(&dpkg->installed.version, psys_pkg_version(pkg)); /* Architecture */ dpkgarch = dpkg_arch(psys_pkg_arch(pkg), err); if (!dpkgarch) { ret = -1; goto out; } dpkg->installed.architecture = dpkgarch; /* Description */ set_description(dpkg, pkg); /* * Maintainer * * FIXME: Our Maintainer value does not conform to the format * mandated by the Debian Policy Manual (which is "Name <E-Mail>"), * but this is better than not specifying a Maintainer at all * (which is a mandatory field) */ dpkg->installed.maintainer = nfstrsave(psys_pkg_vendor(pkg)); /* Priority */ dpkg->priority = pri_optional; /* Dependencies */ add_dependencies(dpkg, pkg); flist = psys_pkg_flist(pkg, err); if (!flist) { ret = -1; goto out; } /* Installed Size */ set_installed_size(dpkg, flist); /* File List */ filelist_path = create_file_list(dpkg, flist, err); if (!filelist_path) { ret = -1; goto out; } /* MD5SUMS List */ md5list_path = create_md5sums_list(dpkg, flist, err); if (!md5list_path) { ret = -1; goto out; } dpkg->want = want_install; dpkg->status = stat_installed; modstatdb_note(dpkg); ret = 0; out: if (md5list_path) { if (ret == -1) remove(md5list_path); free(md5list_path); } if (filelist_path) { if (ret == -1) remove(filelist_path); free(filelist_path); } if (flist) psys_flist_free(flist); return ret; }
int parsedb(const char *filename, enum parsedbflags flags, struct pkginfo **donep, FILE *warnto, int *warncount) { /* warnto, warncount and donep may be null. * If donep is not null only one package's information is expected. */ static int fd; struct pkginfo newpig, *pigp; struct pkginfoperfile *newpifp, *pifp; struct arbitraryfield *arp, **larpp; struct trigaw *ta; int pdone; int fieldencountered[array_count(fieldinfos)]; const struct fieldinfo *fip; const struct nickname *nick; char *data, *dataptr, *endptr; const char *fieldstart, *valuestart; char *value= NULL; int fieldlen= 0, valuelen= 0; int *ip, c; struct stat st; struct parsedb_state ps; ps.filename = filename; ps.flags = flags; ps.lno = 0; ps.warnto = warnto; ps.warncount = 0; newpifp= (flags & pdb_recordavailable) ? &newpig.available : &newpig.installed; fd= open(filename, O_RDONLY); if (fd == -1) ohshite(_("failed to open package info file `%.255s' for reading"),filename); push_cleanup(cu_closefd, ~ehflag_normaltidy, NULL, 0, 1, &fd); if (fstat(fd, &st) == -1) ohshite(_("can't stat package info file `%.255s'"),filename); if (st.st_size > 0) { #ifdef USE_MMAP dataptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (dataptr == MAP_FAILED) ohshite(_("can't mmap package info file `%.255s'"),filename); #else dataptr = m_malloc(st.st_size); fd_buf_copy(fd, dataptr, st.st_size, _("copy info file `%.255s'"), filename); #endif data= dataptr; endptr = dataptr + st.st_size; } else { data= dataptr= endptr= NULL; } pdone= 0; #define EOF_mmap(dataptr, endptr) (dataptr >= endptr) #define getc_mmap(dataptr) *dataptr++; #define ungetc_mmap(c, dataptr, data) dataptr--; for (;;) { /* loop per package */ memset(fieldencountered, 0, sizeof(fieldencountered)); blankpackage(&newpig); /* Skip adjacent new lines */ while(!EOF_mmap(dataptr, endptr)) { c= getc_mmap(dataptr); if (c!='\n' && c!=MSDOS_EOF_CHAR ) break; ps.lno++; } if (EOF_mmap(dataptr, endptr)) break; for (;;) { /* loop per field */ fieldstart= dataptr - 1; while (!EOF_mmap(dataptr, endptr) && !isspace(c) && c!=':' && c!=MSDOS_EOF_CHAR) c= getc_mmap(dataptr); fieldlen= dataptr - fieldstart - 1; while (!EOF_mmap(dataptr, endptr) && c != '\n' && isspace(c)) c= getc_mmap(dataptr); if (EOF_mmap(dataptr, endptr)) parse_error(&ps, &newpig, _("EOF after field name `%.*s'"), fieldlen, fieldstart); if (c == '\n') parse_error(&ps, &newpig, _("newline in field name `%.*s'"), fieldlen, fieldstart); if (c == MSDOS_EOF_CHAR) parse_error(&ps, &newpig, _("MSDOS EOF (^Z) in field name `%.*s'"), fieldlen, fieldstart); if (c != ':') parse_error(&ps, &newpig, _("field name `%.*s' must be followed by colon"), fieldlen, fieldstart); /* Skip space after ':' but before value and eol */ while(!EOF_mmap(dataptr, endptr)) { c= getc_mmap(dataptr); if (c == '\n' || !isspace(c)) break; } if (EOF_mmap(dataptr, endptr)) parse_error(&ps, &newpig, _("EOF before value of field `%.*s' (missing final newline)"), fieldlen,fieldstart); if (c == MSDOS_EOF_CHAR) parse_error(&ps, &newpig, _("MSDOS EOF char in value of field `%.*s' (missing newline?)"), fieldlen,fieldstart); valuestart= dataptr - 1; for (;;) { if (c == '\n' || c == MSDOS_EOF_CHAR) { ps.lno++; if (EOF_mmap(dataptr, endptr)) break; c= getc_mmap(dataptr); /* Found double eol, or start of new field */ if (EOF_mmap(dataptr, endptr) || c == '\n' || !isspace(c)) break; ungetc_mmap(c,dataptr, data); c= '\n'; } else if (EOF_mmap(dataptr, endptr)) { parse_error(&ps, &newpig, _("EOF during value of field `%.*s' (missing final newline)"), fieldlen,fieldstart); } c= getc_mmap(dataptr); } valuelen= dataptr - valuestart - 1; /* trim ending space on value */ while (valuelen && isspace(*(valuestart+valuelen-1))) valuelen--; for (nick = nicknames; nick->nick && (strncasecmp(nick->nick, fieldstart, fieldlen) || nick->nick[fieldlen] != '\0'); nick++) ; if (nick->nick) { fieldstart= nick->canon; fieldlen= strlen(fieldstart); } for (fip= fieldinfos, ip= fieldencountered; fip->name && strncasecmp(fieldstart,fip->name, fieldlen); fip++, ip++); if (fip->name) { value = m_realloc(value, valuelen + 1); memcpy(value,valuestart,valuelen); *(value + valuelen) = '\0'; if ((*ip)++) parse_error(&ps, &newpig, _("duplicate value for `%s' field"), fip->name); fip->rcall(&newpig, newpifp, &ps, value, fip); } else { if (fieldlen<2) parse_error(&ps, &newpig, _("user-defined field name `%.*s' too short"), fieldlen, fieldstart); larpp= &newpifp->arbs; while ((arp= *larpp) != NULL) { if (!strncasecmp(arp->name,fieldstart,fieldlen)) parse_error(&ps, &newpig, _("duplicate value for user-defined field `%.*s'"), fieldlen, fieldstart); larpp= &arp->next; } arp= nfmalloc(sizeof(struct arbitraryfield)); arp->name= nfstrnsave(fieldstart,fieldlen); arp->value= nfstrnsave(valuestart,valuelen); arp->next= NULL; *larpp= arp; } if (EOF_mmap(dataptr, endptr) || c == '\n' || c == MSDOS_EOF_CHAR) break; } /* loop per field */ if (pdone && donep) parse_error(&ps, &newpig, _("several package info entries found, only one allowed")); parse_must_have_field(&ps, &newpig, newpig.name, "package name"); if ((flags & pdb_recordavailable) || newpig.status != stat_notinstalled) { parse_ensure_have_field(&ps, &newpig, &newpifp->description, "description"); parse_ensure_have_field(&ps, &newpig, &newpifp->maintainer, "maintainer"); if (newpig.status != stat_halfinstalled) parse_must_have_field(&ps, &newpig, newpifp->version.version, "version"); } if (flags & pdb_recordavailable) parse_ensure_have_field(&ps, &newpig, &newpifp->architecture, "architecture"); /* Check the Config-Version information: * If there is a Config-Version it is definitely to be used, but * there shouldn't be one if the package is `installed' (in which case * the Version and/or Revision will be copied) or if the package is * `not-installed' (in which case there is no Config-Version). */ if (!(flags & pdb_recordavailable)) { if (newpig.configversion.version) { if (newpig.status == stat_installed || newpig.status == stat_notinstalled) parse_error(&ps, &newpig, _("Configured-Version for package with inappropriate Status")); } else { if (newpig.status == stat_installed) newpig.configversion= newpifp->version; } } if (newpig.trigaw.head && (newpig.status <= stat_configfiles || newpig.status >= stat_triggerspending)) parse_error(&ps, &newpig, _("package has status %s but triggers are awaited"), statusinfos[newpig.status].name); else if (newpig.status == stat_triggersawaited && !newpig.trigaw.head) parse_error(&ps, &newpig, _("package has status triggers-awaited but no triggers " "awaited")); if (!(newpig.status == stat_triggerspending || newpig.status == stat_triggersawaited) && newpig.trigpend_head) parse_error(&ps, &newpig, _("package has status %s but triggers are pending"), statusinfos[newpig.status].name); else if (newpig.status == stat_triggerspending && !newpig.trigpend_head) parse_error(&ps, &newpig, _("package has status triggers-pending but no triggers " "pending")); /* FIXME: There was a bug that could make a not-installed package have * conffiles, so we check for them here and remove them (rather than * calling it an error, which will do at some point). */ if (!(flags & pdb_recordavailable) && newpig.status == stat_notinstalled && newpifp->conffiles) { parse_warn(&ps, &newpig, _("Package which in state not-installed has conffiles, " "forgetting them")); newpifp->conffiles= NULL; } /* XXX: Mark not-installed leftover packages for automatic removal on * next database dump. This code can be removed after dpkg 1.16.x, when * there's guarantee that no leftover is found on the status file on * major distributions. */ if (!(flags & pdb_recordavailable) && newpig.status == stat_notinstalled && newpig.eflag == eflag_ok && (newpig.want == want_purge || newpig.want == want_deinstall || newpig.want == want_hold)) { newpig.want = want_unknown; } pigp= findpackage(newpig.name); pifp= (flags & pdb_recordavailable) ? &pigp->available : &pigp->installed; if ((flags & pdb_ignoreolder) && versioncompare(&newpifp->version, &pifp->version) < 0) continue; /* Copy the priority and section across, but don't overwrite existing * values if the pdb_weakclassification flag is set. */ if (newpig.section && *newpig.section && !((flags & pdb_weakclassification) && pigp->section && *pigp->section)) pigp->section= newpig.section; if (newpig.priority != pri_unknown && !((flags & pdb_weakclassification) && pigp->priority != pri_unknown)) { pigp->priority= newpig.priority; if (newpig.priority == pri_other) pigp->otherpriority= newpig.otherpriority; } /* Sort out the dependency mess. */ copy_dependency_links(pigp,&pifp->depends,newpifp->depends, (flags & pdb_recordavailable) ? 1 : 0); /* Leave the `depended' pointer alone, we've just gone to such * trouble to get it right :-). The `depends' pointer in * pifp was indeed also updated by copy_dependency_links, * but since the value was that from newpifp anyway there's * no need to copy it back. */ newpifp->depended= pifp->depended; /* Copy across data */ memcpy(pifp,newpifp,sizeof(struct pkginfoperfile)); if (!(flags & pdb_recordavailable)) { pigp->want= newpig.want; pigp->eflag= newpig.eflag; pigp->status= newpig.status; pigp->configversion= newpig.configversion; pigp->files= NULL; pigp->trigpend_head = newpig.trigpend_head; pigp->trigaw = newpig.trigaw; for (ta = pigp->trigaw.head; ta; ta = ta->sameaw.next) { assert(ta->aw == &newpig); ta->aw = pigp; /* ->othertrigaw_head is updated by trig_note_aw in *(findpackage()) * rather than in newpig */ } } else if (!(flags & pdb_ignorefiles)) { pigp->files= newpig.files; } if (donep) *donep= pigp; pdone++; if (EOF_mmap(dataptr, endptr)) break; if (c == '\n') ps.lno++; } if (data != NULL) { #ifdef USE_MMAP munmap(data, st.st_size); #else free(data); #endif } free(value); pop_cleanup(ehflag_normaltidy); if (close(fd)) ohshite(_("failed to close after read: `%.255s'"),filename); if (donep && !pdone) ohshit(_("no package information in `%.255s'"),filename); if (warncount) *warncount = ps.warncount; return pdone; }