static void test_dpkg_arch_varbuf_archqual(void) { struct varbuf vb = VARBUF_INIT; varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_NONE)); varbuf_end_str(&vb); test_str(vb.buf, ==, ""); varbuf_reset(&vb); varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_EMPTY)); varbuf_end_str(&vb); test_str(vb.buf, ==, ""); varbuf_reset(&vb); varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_ALL)); varbuf_end_str(&vb); test_str(vb.buf, ==, ":all"); varbuf_reset(&vb); varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_WILDCARD)); varbuf_end_str(&vb); test_str(vb.buf, ==, ":any"); varbuf_reset(&vb); }
void extractDebPackageInfo(const struct pkginfo *pkg, QueryData &results) { Row r; struct varbuf vb; varbuf_init(&vb, 20); // Iterate over the desired fieldinfos, calling their fwritefunctions // to extract the package's information. const struct fieldinfo *fip = nullptr; for (fip = fieldinfos; fip->name; fip++) { fip->wcall(&vb, pkg, &pkg->installed, fw_printheader, fip); std::string line = vb.string(); if (!line.empty()) { size_t separator_position = line.find(':'); std::string key = line.substr(0, separator_position); std::string value = line.substr(separator_position + 1, line.length()); auto it = kFieldMappings.find(key); if (it != kFieldMappings.end()) { boost::algorithm::trim(value); r[it->second] = std::move(value); } } varbuf_reset(&vb); } varbuf_destroy(&vb); results.push_back(r); }
bool find_command(const char *prog) { struct varbuf filename = VARBUF_INIT; struct stat stab; const char *path_list; const char *path, *path_end; size_t path_len; path_list = getenv("PATH"); if (!path_list) ohshit(_("PATH is not set")); for (path = path_list; path; path = path_end ? path_end + 1 : NULL) { path_end = strchr(path, ':'); path_len = path_end ? (size_t)(path_end - path) : strlen(path); varbuf_reset(&filename); varbuf_add_buf(&filename, path, path_len); if (path_len) varbuf_add_char(&filename, '/'); varbuf_add_str(&filename, prog); varbuf_end_str(&filename); if (stat(filename.buf, &stab) == 0 && (stab.st_mode & 0111)) { varbuf_destroy(&filename); return true; } } varbuf_destroy(&filename); return false; }
void log_message(const char *fmt, ...) { static struct varbuf log; static FILE *logfd = NULL; char time_str[20]; time_t now; va_list args; if (!log_file) return; if (!logfd) { logfd = fopen(log_file, "a"); if (!logfd) { notice(_("could not open log '%s': %s"), log_file, strerror(errno)); log_file = NULL; return; } setlinebuf(logfd); setcloexec(fileno(logfd), log_file); } va_start(args, fmt); varbuf_reset(&log); varbuf_vprintf(&log, fmt, args); va_end(args); time(&now); strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&now)); fprintf(logfd, "%s %s\n", time_str, log.buf); }
void statusfd_send(const char *fmt, ...) { static struct varbuf vb; struct pipef *pipef; va_list args; if (!status_pipes) return; va_start(args, fmt); varbuf_reset(&vb); varbuf_vprintf(&vb, fmt, args); /* Sanitize string to not include new lines, as front-ends should be * doing their own word-wrapping. */ varbuf_map_char(&vb, '\n', ' '); varbuf_add_char(&vb, '\n'); va_end(args); for (pipef = status_pipes; pipef; pipef = pipef->next) { if (fd_write(pipef->fd, vb.buf, vb.used) < 0) ohshite(_("unable to write to status fd %d"), pipef->fd); } }
static void info_spew(const char *debar, const char *dir, const char *const *argv) { struct dpkg_error err; const char *component; struct varbuf controlfile = VARBUF_INIT; int fd; int re= 0; while ((component = *argv++) != NULL) { varbuf_reset(&controlfile); varbuf_printf(&controlfile, "%s/%s", dir, component); fd = open(controlfile.buf, O_RDONLY); if (fd >= 0) { if (fd_fd_copy(fd, 1, -1, &err) < 0) ohshit(_("cannot extract control file '%s' from '%s': %s"), controlfile.buf, debar, err.str); close(fd); } else if (errno == ENOENT) { notice(_("'%.255s' contains no control component '%.255s'"), debar, component); re++; } else { ohshite(_("open component `%.255s' (in %.255s) failed in an unexpected way"), component, dir); } } varbuf_destroy(&controlfile); if (re > 0) ohshit(P_("%d requested control component is missing", "%d requested control components are missing", re), re); }
/** * Read a filename from the file descriptor and create a file_info struct. * * @return A file_info struct or NULL if there is nothing to read. */ static struct file_info * file_info_get(const char *root, int fd) { static struct varbuf fn = VARBUF_INIT; struct file_info *fi; size_t root_len; varbuf_reset(&fn); root_len = varbuf_printf(&fn, "%s/", root); while (1) { int res; varbuf_grow(&fn, 1); res = fd_read(fd, (fn.buf + fn.used), 1); if (res < 0) return NULL; if (res == 0) /* EOF -> parent died. */ return NULL; if (fn.buf[fn.used] == '\0') break; varbuf_trunc(&fn, fn.used + 1); if (fn.used >= MAXFILENAME) ohshit(_("file name '%.50s...' is too long"), fn.buf + root_len); } fi = file_info_new(fn.buf + root_len); if (lstat(fn.buf, &(fi->st)) != 0) ohshite(_("unable to stat file name '%.250s'"), fn.buf); return fi; }
/** * Verify that some programs can be found in the PATH. */ void checkpath(void) { static const char *const prog_list[] = { DEFAULTSHELL, RM, TAR, FIND, BACKEND, "ldconfig", #if WITH_START_STOP_DAEMON "start-stop-daemon", #endif NULL }; const char *const *prog; const char *path_list; struct varbuf filename = VARBUF_INIT; int warned= 0; path_list = getenv("PATH"); if (!path_list) ohshit(_("PATH is not set.")); for (prog = prog_list; *prog; prog++) { struct stat stab; const char *path, *path_end; size_t path_len; for (path = path_list; path; path = path_end ? path_end + 1 : NULL) { path_end = strchr(path, ':'); path_len = path_end ? (size_t)(path_end - path) : strlen(path); varbuf_reset(&filename); varbuf_add_buf(&filename, path, path_len); if (path_len) varbuf_add_char(&filename, '/'); varbuf_add_str(&filename, *prog); varbuf_end_str(&filename); if (stat(filename.buf, &stab) == 0 && (stab.st_mode & 0111)) break; } if (!path) { warning(_("'%s' not found in PATH or not executable."), *prog); warned++; } } varbuf_destroy(&filename); if (warned) forcibleerr(fc_badpath, P_("%d expected program not found in PATH or not executable.\n%s", "%d expected programs not found in PATH or not executable.\n%s", warned), warned, _("Note: root's PATH should usually contain " "/usr/local/sbin, /usr/sbin and /sbin.")); }
/* * Does cycle checking. Doesn't mind if pkg has no triggers pending - in * that case does nothing but fix up any stale awaiters. */ void trigproc(struct pkginfo *pkg) { static struct varbuf namesarg; struct trigpend *tp; struct pkginfo *gaveup; debug(dbg_triggers, "trigproc %s", pkg_describe(pkg, pdo_foreign)); if (pkg->clientdata->trigprocdeferred) pkg->clientdata->trigprocdeferred->pkg = NULL; pkg->clientdata->trigprocdeferred = NULL; if (pkg->trigpend_head) { assert(pkg->status == stat_triggerspending || pkg->status == stat_triggersawaited); gaveup = check_trigger_cycle(pkg); if (gaveup == pkg) return; printf(_("Processing triggers for %s ...\n"), pkg_describe(pkg, pdo_foreign)); log_action("trigproc", pkg); varbuf_reset(&namesarg); for (tp = pkg->trigpend_head; tp; tp = tp->next) { varbuf_add_char(&namesarg, ' '); varbuf_add_str(&namesarg, tp->name); } varbuf_end_str(&namesarg); /* Setting the status to half-configured * causes modstatdb_note to clear pending triggers. */ pkg->status = stat_halfconfigured; modstatdb_note(pkg); if (!f_noact) { sincenothing = 0; maintainer_script_postinst(pkg, "triggered", namesarg.buf + 1, NULL); } /* This is to cope if the package triggers itself: */ pkg->status = pkg->trigaw.head ? stat_triggersawaited : pkg->trigpend_head ? stat_triggerspending : stat_installed; post_postinst_tasks_core(pkg); } else { /* In other branch is done by modstatdb_note. */ trig_clear_awaiters(pkg); } }
/** * Parse the field and value into the package being constructed. */ static void pkg_parse_field(struct parsedb_state *ps, struct field_state *fs, void *parse_obj) { struct pkg_parse_object *pkg_obj = parse_obj; const struct nickname *nick; const struct fieldinfo *fip; int *ip; for (nick = nicknames; nick->nick; nick++) if (strncasecmp(nick->nick, fs->fieldstart, fs->fieldlen) == 0 && nick->nick[fs->fieldlen] == '\0') break; if (nick->nick) { fs->fieldstart = nick->canon; fs->fieldlen = strlen(fs->fieldstart); } for (fip = fieldinfos, ip = fs->fieldencountered; fip->name; fip++, ip++) if (strncasecmp(fip->name, fs->fieldstart, fs->fieldlen) == 0) break; if (fip->name) { if ((*ip)++) parse_error(ps, _("duplicate value for `%s' field"), fip->name); varbuf_reset(&fs->value); varbuf_add_buf(&fs->value, fs->valuestart, fs->valuelen); varbuf_end_str(&fs->value); fip->rcall(pkg_obj->pkg, pkg_obj->pkgbin, ps, fs->value.buf, fip); } else { struct arbitraryfield *arp, **larpp; if (fs->fieldlen < 2) parse_error(ps, _("user-defined field name `%.*s' too short"), fs->fieldlen, fs->fieldstart); larpp = &pkg_obj->pkgbin->arbs; while ((arp = *larpp) != NULL) { if (!strncasecmp(arp->name, fs->fieldstart, fs->fieldlen)) parse_error(ps, _("duplicate value for user-defined field `%.*s'"), fs->fieldlen, fs->fieldstart); larpp = &arp->next; } arp = nfmalloc(sizeof(struct arbitraryfield)); arp->name = nfstrnsave(fs->fieldstart, fs->fieldlen); arp->value = nfstrnsave(fs->valuestart, fs->valuelen); arp->next = NULL; *larpp = arp; } }
/* * Does cycle checking. Doesn't mind if pkg has no triggers pending - in * that case does nothing but fix up any stale awaiters. */ void trigproc(struct pkginfo *pkg) { static struct varbuf namesarg; struct trigpend *tp; struct pkginfo *gaveup; debug(dbg_triggers, "trigproc %s", pkg_name(pkg, pnaw_always)); if (pkg->clientdata->trigprocdeferred) pkg->clientdata->trigprocdeferred->pkg = NULL; pkg->clientdata->trigprocdeferred = NULL; if (pkg->trigpend_head) { assert(pkg->status == stat_triggerspending || pkg->status == stat_triggersawaited); gaveup = check_trigger_cycle(pkg); if (gaveup == pkg) return; printf(_("Processing triggers for %s (%s) ...\n"), pkg_name(pkg, pnaw_nonambig), versiondescribe(&pkg->installed.version, vdew_nonambig)); log_action("trigproc", pkg, &pkg->installed); varbuf_reset(&namesarg); for (tp = pkg->trigpend_head; tp; tp = tp->next) { varbuf_add_char(&namesarg, ' '); varbuf_add_str(&namesarg, tp->name); } varbuf_end_str(&namesarg); /* Setting the status to half-configured * causes modstatdb_note to clear pending triggers. */ pkg_set_status(pkg, stat_halfconfigured); modstatdb_note(pkg); if (!f_noact) { sincenothing = 0; maintscript_postinst(pkg, "triggered", namesarg.buf + 1, NULL); } post_postinst_tasks(pkg, stat_installed); } else { /* In other branch is done by modstatdb_note(), from inside * post_postinst_tasks(). */ trig_clear_awaiters(pkg); } }
static void trk_explicit_interest_change(const char *trig, struct pkginfo *pkg, int signum, enum trig_options opts) { static struct varbuf newfn; char buf[1024]; FILE *nf; bool empty = true; trk_explicit_start(trig); varbuf_reset(&newfn); varbuf_printf(&newfn, "%s/%s.new", triggersdir, trig); nf = fopen(newfn.buf, "w"); if (!nf) ohshite(_("unable to create new trigger interest file `%.250s'"), newfn.buf); push_cleanup(cu_closestream, ~ehflag_normaltidy, NULL, 0, 1, nf); while (trk_explicit_f && trk_explicit_fgets(buf, sizeof(buf)) >= 0) { int len = strlen(pkg->name); if (strncmp(buf, pkg->name, len) == 0 && (buf[len] == '\0' || buf[len] == '/')) continue; fprintf(nf, "%s\n", buf); empty = false; } if (signum > 0) { fprintf(nf, "%s%s\n", pkg->name, (opts == trig_noawait) ? "/noawait" : ""); empty = false; } if (!empty) trk_explicit_interest_flush(newfn.buf, nf); pop_cleanup(ehflag_normaltidy); if (fclose(nf)) ohshite(_("unable to close new trigger interest file `%.250s'"), newfn.buf); if (empty) trk_explicit_interest_remove(newfn.buf); else trk_explicit_interest_commit(newfn.buf); dir_sync_path(triggersdir); }
/* * If mask is nonzero, will not write any file whose filenamenode * has any flag bits set in mask. */ void write_filelist_except(struct pkginfo *pkg, struct pkgbin *pkgbin, struct fileinlist *list, enum fnnflags mask) { static struct varbuf newvb; const char *listfile; FILE *file; listfile = pkgadminfile(pkg, pkgbin, LISTFILE); varbuf_reset(&newvb); varbuf_add_str(&newvb, listfile); varbuf_add_str(&newvb, NEWDBEXT); varbuf_end_str(&newvb); file= fopen(newvb.buf,"w+"); if (!file) ohshite(_("unable to create updated files list file for package %s"), pkg_describe(pkg, pdo_foreign)); push_cleanup(cu_closestream, ehflag_bombout, NULL, 0, 1, (void *)file); while (list) { if (!(mask && (list->namenode->flags & mask))) { fputs(list->namenode->name,file); putc('\n',file); } list= list->next; } if (ferror(file)) ohshite(_("failed to write to updated files list file for package %s"), pkg_describe(pkg, pdo_foreign)); if (fflush(file)) ohshite(_("failed to flush updated files list file for package %s"), pkg_describe(pkg, pdo_foreign)); if (fsync(fileno(file))) ohshite(_("failed to sync updated files list file for package %s"), pkg_describe(pkg, pdo_foreign)); pop_cleanup(ehflag_normaltidy); /* file = fopen() */ if (fclose(file)) ohshite(_("failed to close updated files list file for package %s"), pkg_describe(pkg, pdo_foreign)); if (rename(newvb.buf, listfile)) ohshite(_("failed to install updated files list file for package %s"), pkg_describe(pkg, pdo_foreign)); dir_sync_path(pkgadmindir()); note_must_reread_files_inpackage(pkg); }
static void trk_explicit_start(const char *trig) { trk_explicit_activate_done(); varbuf_reset(&trk_explicit_fn); varbuf_add_str(&trk_explicit_fn, triggersdir); varbuf_add_str(&trk_explicit_fn, trig); varbuf_end_str(&trk_explicit_fn); trk_explicit_f = fopen(trk_explicit_fn.buf, "r"); if (!trk_explicit_f) { if (errno != ENOENT) ohshite(_("failed to open trigger interest list file `%.250s'"), trk_explicit_fn.buf); } }
static void verify_package(struct pkginfo *pkg) { struct fsys_namenode_list *file; struct varbuf filename = VARBUF_INIT; ensure_packagefiles_available(pkg); parse_filehash(pkg, &pkg->installed); pkg_conffiles_mark_old(pkg); for (file = pkg->files; file; file = file->next) { struct verify_checks checks; struct fsys_namenode *fnn; char hash[MD5HASHLEN + 1]; int failures = 0; fnn = namenodetouse(file->namenode, pkg, &pkg->installed); if (strcmp(fnn->newhash, EMPTYHASHFLAG) == 0) { if (fnn->oldhash == NULL) continue; else fnn->newhash = fnn->oldhash; } varbuf_reset(&filename); varbuf_add_str(&filename, instdir); varbuf_add_str(&filename, fnn->name); varbuf_end_str(&filename); memset(&checks, 0, sizeof(checks)); md5hash(pkg, hash, filename.buf); if (strcmp(hash, fnn->newhash) != 0) { checks.md5sum = VERIFY_FAIL; failures++; } if (failures) verify_output(fnn, &checks); } varbuf_destroy(&filename); }
static const char * diversion_current(const char *filename) { static struct varbuf str = VARBUF_INIT; if (opt_pkgname_match_any) { varbuf_reset(&str); if (opt_divertto == NULL) varbuf_printf(&str, _("any diversion of %s"), filename); else varbuf_printf(&str, _("any diversion of %s to %s"), filename, opt_divertto); } else { return varbuf_diversion(&str, opt_pkgname, filename, opt_divertto); } return str.buf; }
const char * pkgadminfile(struct pkginfo *pkg, struct pkgbin *pkgbin, const char *filetype) { static struct varbuf vb; varbuf_reset(&vb); varbuf_add_str(&vb, infodir); varbuf_add_char(&vb, '/'); varbuf_add_str(&vb, pkg->set->name); if (pkgbin->multiarch == multiarch_same && pkg_infodb_format() >= 1) { varbuf_add_char(&vb, ':'); varbuf_add_str(&vb, pkgbin->arch->name); } varbuf_add_char(&vb, '.'); varbuf_add_str(&vb, filetype); varbuf_end_str(&vb); return vb.buf; }
const char *versiondescribe (const struct dpkg_version *version, enum versiondisplayepochwhen vdew) { static struct varbuf bufs[10]; static int bufnum=0; struct varbuf *vb; if (!dpkg_version_is_informative(version)) return C_("version", "<none>"); vb= &bufs[bufnum]; bufnum++; if (bufnum == 10) bufnum= 0; varbuf_reset(vb); varbufversion(vb,version,vdew); varbuf_end_str(vb); return vb->buf; }
static void modstatdb_note_core(struct pkginfo *pkg) { assert(cstatus >= msdbrw_write); varbuf_reset(&uvb); varbufrecord(&uvb, pkg, &pkg->installed); if (fwrite(uvb.buf, 1, uvb.used, importanttmp) != uvb.used) ohshite(_("unable to write updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (fflush(importanttmp)) ohshite(_("unable to flush updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (ftruncate(fileno(importanttmp), uvb.used)) ohshite(_("unable to truncate for updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (fsync(fileno(importanttmp))) ohshite(_("unable to fsync updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (fclose(importanttmp)) ohshite(_("unable to close updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); sprintf(updatefnrest, IMPORTANTFMT, nextupdate); if (rename(importanttmpfile, updatefnbuf)) ohshite(_("unable to install updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); dir_sync_path(updatesdir); /* Have we made a real mess? */ assert(strlen(updatefnrest) <= IMPORTANTMAXLEN); nextupdate++; if (nextupdate > MAXUPDATES) { modstatdb_checkpoint(); nextupdate = 0; } createimptmp(); }
static void test_varbuf_reset(void) { struct varbuf vb; varbuf_init(&vb, 10); varbuf_add_buf(&vb, "1234567890", 10); varbuf_reset(&vb); test_pass(vb.used == 0); test_pass(vb.size >= vb.used); varbuf_add_buf(&vb, "abcdefghijklmno", 15); test_pass(vb.used == 15); test_pass(vb.size >= vb.used); test_mem(vb.buf, ==, "abcdefghijklmno", 15); varbuf_destroy(&vb); }
static char * deb_field(const char *filename, const char *field) { pid_t pid; int p[2]; struct varbuf buf = VARBUF_INIT; char *end; m_pipe(p); pid = subproc_fork(); if (pid == 0) { /* Child writes to pipe. */ m_dup2(p[1], 1); close(p[0]); close(p[1]); execlp(BACKEND, BACKEND, "--field", filename, field, NULL); ohshite(_("unable to execute %s (%s)"), _("package field value extraction"), BACKEND); } close(p[1]); /* Parant reads from pipe. */ varbuf_reset(&buf); fd_vbuf_copy(p[0], &buf, -1, _("package field value extraction")); varbuf_end_str(&buf); close(p[0]); subproc_wait_check(pid, _("package field value extraction"), PROCPIPE); /* Trim down trailing junk. */ for (end = buf.buf + strlen(buf.buf) - 1; end - buf.buf >= 1; end--) if (isspace(*end)) *end = '\0'; else break; return varbuf_detach(&buf); }
const char * pkg_infodb_get_file(const struct pkginfo *pkg, const struct pkgbin *pkgbin, const char *filetype) { static struct varbuf vb; enum pkg_infodb_format format; /* Make sure to always read and verify the format version. */ format = pkg_infodb_get_format(); varbuf_reset(&vb); varbuf_add_str(&vb, pkg_infodb_get_dir()); varbuf_add_char(&vb, '/'); varbuf_add_str(&vb, pkg->set->name); if (pkgbin->multiarch == PKG_MULTIARCH_SAME && format == PKG_INFODB_FORMAT_MULTIARCH) varbuf_add_archqual(&vb, pkgbin->arch); varbuf_add_char(&vb, '.'); varbuf_add_str(&vb, filetype); varbuf_end_str(&vb); return vb.buf; }
static const char * varbuf_diversion(struct varbuf *str, const char *pkgname, const char *filename, const char *divertto) { varbuf_reset(str); if (pkgname == NULL) { if (divertto == NULL) varbuf_printf(str, _("local diversion of %s"), filename); else varbuf_printf(str, _("local diversion of %s to %s"), filename, divertto); } else { if (divertto == NULL) varbuf_printf(str, _("diversion of %s by %s"), filename, pkgname); else varbuf_printf(str, _("diversion of %s to %s by %s"), filename, divertto, pkgname); } return str->buf; }
/** * Check control directory and file permissions. */ static void check_file_perms(const char *ctrldir) { struct varbuf path = VARBUF_INIT; const char *const *mscriptp; struct stat mscriptstab; varbuf_printf(&path, "%s/", ctrldir); if (lstat(path.buf, &mscriptstab)) ohshite(_("unable to stat control directory")); if (!S_ISDIR(mscriptstab.st_mode)) ohshit(_("control directory is not a directory")); if ((mscriptstab.st_mode & 07757) != 0755) ohshit(_("control directory has bad permissions %03lo " "(must be >=0755 and <=0775)"), (unsigned long)(mscriptstab.st_mode & 07777)); for (mscriptp = maintainerscripts; *mscriptp; mscriptp++) { varbuf_reset(&path); varbuf_printf(&path, "%s/%s", ctrldir, *mscriptp); if (!lstat(path.buf, &mscriptstab)) { if (S_ISLNK(mscriptstab.st_mode)) continue; if (!S_ISREG(mscriptstab.st_mode)) ohshit(_("maintainer script '%.50s' is not a plain file or symlink"), *mscriptp); if ((mscriptstab.st_mode & 07557) != 0555) ohshit(_("maintainer script '%.50s' has bad permissions %03lo " "(must be >=0555 and <=0775)"), *mscriptp, (unsigned long)(mscriptstab.st_mode & 07777)); } else if (errno != ENOENT) { ohshite(_("maintainer script '%.50s' is not stattable"), *mscriptp); } } varbuf_destroy(&path); }
static void test_varbuf_printf(void) { struct varbuf vb; varbuf_init(&vb, 5); /* Test normal format printing. */ varbuf_printf(&vb, "format %s number %d", "string", 10); test_pass(vb.used == strlen("format string number 10")); test_pass(vb.size >= vb.used); test_str(vb.buf, ==, "format string number 10"); varbuf_reset(&vb); /* Test concatenated format printing. */ varbuf_printf(&vb, "format %s number %d", "string", 10); varbuf_printf(&vb, " extra %s", "string"); test_pass(vb.used == strlen("format string number 10 extra string")); test_pass(vb.size >= vb.used); test_str(vb.buf, ==, "format string number 10 extra string"); varbuf_destroy(&vb); }
/* * *whynot must already have been initialized; it need not be * empty though - it will be reset before use. * * If depisok returns false for ‘not OK’ it will contain a description, * newline-terminated BUT NOT NUL-TERMINATED, of the reason. * * If depisok returns true it will contain garbage. * allowunconfigd should be non-zero during the ‘Pre-Depends’ checking * before a package is unpacked, when it is sufficient for the package * to be unpacked provided that both the unpacked and previously-configured * versions are acceptable. * * On false return (‘not OK’), *canfixbyremove refers to a package which * if removed (dep_conflicts) or deconfigured (dep_breaks) will fix * the problem. Caller may pass NULL for canfixbyremove and need not * initialize *canfixbyremove. * * On false return (‘not OK’), *canfixbytrigaw refers to a package which * can fix the problem if all the packages listed in Triggers-Awaited have * their triggers processed. Caller may pass NULL for canfixbytrigaw and * need not initialize *canfixbytrigaw. */ bool depisok(struct dependency *dep, struct varbuf *whynot, struct pkginfo **canfixbyremove, struct pkginfo **canfixbytrigaw, bool allowunconfigd) { struct deppossi *possi; struct deppossi *provider; struct pkginfo *pkg_pos; int nconflicts; /* Use this buffer so that when internationalisation comes along we * don't have to rewrite the code completely, only redo the sprintf strings * (assuming we have the fancy argument-number-specifiers). * Allow 250x3 for package names, versions, &c, + 250 for ourselves. */ char linebuf[1024]; assert(dep->type == dep_depends || dep->type == dep_predepends || dep->type == dep_breaks || dep->type == dep_conflicts || dep->type == dep_recommends || dep->type == dep_suggests || dep->type == dep_enhances); if (canfixbyremove) *canfixbyremove = NULL; if (canfixbytrigaw) *canfixbytrigaw = NULL; /* The dependency is always OK if we're trying to remove the depend*ing* * package. */ switch (dep->up->clientdata->istobe) { case PKG_ISTOBE_REMOVE: case PKG_ISTOBE_DECONFIGURE: return true; case PKG_ISTOBE_NORMAL: /* Only installed packages can be make dependency problems. */ switch (dep->up->status) { case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: case PKG_STAT_TRIGGERSAWAITED: break; case PKG_STAT_HALFCONFIGURED: case PKG_STAT_UNPACKED: case PKG_STAT_HALFINSTALLED: if (dep->type == dep_predepends || dep->type == dep_conflicts || dep->type == dep_breaks) break; /* Fall through. */ case PKG_STAT_CONFIGFILES: case PKG_STAT_NOTINSTALLED: return true; default: internerr("unknown status depending '%d'", dep->up->status); } break; case PKG_ISTOBE_INSTALLNEW: case PKG_ISTOBE_PREINSTALL: break; default: internerr("unknown istobe depending '%d'", dep->up->clientdata->istobe); } /* Describe the dependency, in case we have to moan about it. */ varbuf_reset(whynot); varbuf_add_char(whynot, ' '); describedepcon(whynot, dep); varbuf_add_char(whynot, '\n'); /* TODO: Check dep_enhances as well. */ if (dep->type == dep_depends || dep->type == dep_predepends || dep->type == dep_recommends || dep->type == dep_suggests ) { /* Go through the alternatives. As soon as we find one that * we like, we return ‘true’ straight away. Otherwise, when we get to * the end we'll have accumulated all the reasons in whynot and * can return ‘false’. */ for (possi= dep->list; possi; possi= possi->next) { struct deppossi_pkg_iterator *possi_iter; possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe); while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) { switch (pkg_pos->clientdata->istobe) { case PKG_ISTOBE_REMOVE: sprintf(linebuf, _(" %.250s is to be removed.\n"), pkg_name(pkg_pos, pnaw_nonambig)); break; case PKG_ISTOBE_DECONFIGURE: sprintf(linebuf, _(" %.250s is to be deconfigured.\n"), pkg_name(pkg_pos, pnaw_nonambig)); break; case PKG_ISTOBE_INSTALLNEW: if (versionsatisfied(&pkg_pos->available, possi)) { deppossi_pkg_iter_free(possi_iter); return true; } sprintf(linebuf, _(" %.250s is to be installed, but is version " "%.250s.\n"), pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig), versiondescribe(&pkg_pos->available.version, vdew_nonambig)); break; case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: switch (pkg_pos->status) { case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: if (versionsatisfied(&pkg_pos->installed, possi)) { deppossi_pkg_iter_free(possi_iter); return true; } sprintf(linebuf, _(" %.250s is installed, but is version " "%.250s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->installed.version, vdew_nonambig)); break; case PKG_STAT_NOTINSTALLED: /* Don't say anything about this yet - it might be a virtual package. * Later on, if nothing has put anything in linebuf, we know that it * isn't and issue a diagnostic then. */ *linebuf = '\0'; break; case PKG_STAT_TRIGGERSAWAITED: if (canfixbytrigaw && versionsatisfied(&pkg_pos->installed, possi)) *canfixbytrigaw = pkg_pos; /* Fall through to have a chance to return OK due to * allowunconfigd and to fill the explanation */ case PKG_STAT_UNPACKED: case PKG_STAT_HALFCONFIGURED: if (allowunconfigd) { if (!dpkg_version_is_informative(&pkg_pos->configversion)) { sprintf(linebuf, _(" %.250s is unpacked, but has never been " "configured.\n"), pkg_name(pkg_pos, pnaw_nonambig)); break; } else if (!versionsatisfied(&pkg_pos->installed, possi)) { sprintf(linebuf, _(" %.250s is unpacked, but is version " "%.250s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->installed.version, vdew_nonambig)); break; } else if (!dpkg_version_relate(&pkg_pos->configversion, possi->verrel, &possi->version)) { sprintf(linebuf, _(" %.250s latest configured version is " "%.250s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->configversion, vdew_nonambig)); break; } else { deppossi_pkg_iter_free(possi_iter); return true; } } /* Fall through. */ default: sprintf(linebuf, _(" %.250s is %s.\n"), pkg_name(pkg_pos, pnaw_nonambig), gettext(statusstrings[pkg_pos->status])); break; } break; default: internerr("unknown istobe depended '%d'", pkg_pos->clientdata->istobe); } varbuf_add_str(whynot, linebuf); } deppossi_pkg_iter_free(possi_iter); /* See if the package we're about to install Provides it. */ for (provider = possi->ed->depended.available; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; if (provider->up->up->clientdata->istobe == PKG_ISTOBE_INSTALLNEW) return true; } /* Now look at the packages already on the system. */ for (provider = possi->ed->depended.installed; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; switch (provider->up->up->clientdata->istobe) { case PKG_ISTOBE_INSTALLNEW: /* Don't pay any attention to the Provides field of the * currently-installed version of the package we're trying * to install. We dealt with that by using the available * information above. */ continue; case PKG_ISTOBE_REMOVE: sprintf(linebuf, _(" %.250s provides %.250s but is to be removed.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name); break; case PKG_ISTOBE_DECONFIGURE: sprintf(linebuf, _(" %.250s provides %.250s but is to be deconfigured.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name); break; case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: if (provider->up->up->status == PKG_STAT_INSTALLED || provider->up->up->status == PKG_STAT_TRIGGERSPENDING) return true; if (provider->up->up->status == PKG_STAT_TRIGGERSAWAITED) *canfixbytrigaw = provider->up->up; sprintf(linebuf, _(" %.250s provides %.250s but is %s.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name, gettext(statusstrings[provider->up->up->status])); break; default: internerr("unknown istobe provider '%d'", provider->up->up->clientdata->istobe); } varbuf_add_str(whynot, linebuf); } if (!*linebuf) { /* If the package wasn't installed at all, and we haven't said * yet why this isn't satisfied, we should say so now. */ sprintf(linebuf, _(" %.250s is not installed.\n"), possi->ed->name); varbuf_add_str(whynot, linebuf); } } return false; } else { /* It's conflicts or breaks. There's only one main alternative, * but we also have to consider Providers. We return ‘false’ as soon * as we find something that matches the conflict, and only describe * it then. If we get to the end without finding anything we return * ‘true’. */ possi= dep->list; nconflicts= 0; if (possi->ed != possi->up->up->set) { struct deppossi_pkg_iterator *possi_iter; /* If the package conflicts with or breaks itself it must mean * other packages which provide the same virtual name. We * therefore don't look at the real package and go on to the * virtual ones. */ possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe); while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) { switch (pkg_pos->clientdata->istobe) { case PKG_ISTOBE_REMOVE: break; case PKG_ISTOBE_INSTALLNEW: if (!versionsatisfied(&pkg_pos->available, possi)) break; sprintf(linebuf, _(" %.250s (version %.250s) is to be installed.\n"), pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig), versiondescribe(&pkg_pos->available.version, vdew_nonambig)); varbuf_add_str(whynot, linebuf); if (!canfixbyremove) { deppossi_pkg_iter_free(possi_iter); return false; } nconflicts++; *canfixbyremove = pkg_pos; break; case PKG_ISTOBE_DECONFIGURE: if (dep->type == dep_breaks) break; /* Already deconfiguring this. */ /* Fall through. */ case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: switch (pkg_pos->status) { case PKG_STAT_NOTINSTALLED: case PKG_STAT_CONFIGFILES: break; case PKG_STAT_HALFINSTALLED: case PKG_STAT_UNPACKED: case PKG_STAT_HALFCONFIGURED: if (dep->type == dep_breaks) break; /* No problem. */ case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: case PKG_STAT_TRIGGERSAWAITED: if (!versionsatisfied(&pkg_pos->installed, possi)) break; sprintf(linebuf, _(" %.250s (version %.250s) is present and %s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->installed.version, vdew_nonambig), gettext(statusstrings[pkg_pos->status])); varbuf_add_str(whynot, linebuf); if (!canfixbyremove) { deppossi_pkg_iter_free(possi_iter); return false; } nconflicts++; *canfixbyremove = pkg_pos; } break; default: internerr("unknown istobe conflict '%d'", pkg_pos->clientdata->istobe); } } deppossi_pkg_iter_free(possi_iter); } /* See if the package we're about to install Provides it. */ for (provider = possi->ed->depended.available; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (provider->up->up->clientdata->istobe != PKG_ISTOBE_INSTALLNEW) continue; if (provider->up->up->set == dep->up->set) continue; /* Conflicts and provides the same. */ if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; sprintf(linebuf, _(" %.250s provides %.250s and is to be installed.\n"), pkgbin_name(provider->up->up, &provider->up->up->available, pnaw_nonambig), possi->ed->name); varbuf_add_str(whynot, linebuf); /* We can't remove the one we're about to install: */ if (canfixbyremove) *canfixbyremove = NULL; return false; } /* Now look at the packages already on the system. */ for (provider = possi->ed->depended.installed; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (provider->up->up->set == dep->up->set) continue; /* Conflicts and provides the same. */ if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; switch (provider->up->up->clientdata->istobe) { case PKG_ISTOBE_INSTALLNEW: /* Don't pay any attention to the Provides field of the * currently-installed version of the package we're trying * to install. We dealt with that package by using the * available information above. */ continue; case PKG_ISTOBE_REMOVE: continue; case PKG_ISTOBE_DECONFIGURE: if (dep->type == dep_breaks) continue; /* Already deconfiguring. */ case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: switch (provider->up->up->status) { case PKG_STAT_NOTINSTALLED: case PKG_STAT_CONFIGFILES: continue; case PKG_STAT_HALFINSTALLED: case PKG_STAT_UNPACKED: case PKG_STAT_HALFCONFIGURED: if (dep->type == dep_breaks) break; /* No problem. */ case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: case PKG_STAT_TRIGGERSAWAITED: sprintf(linebuf, _(" %.250s provides %.250s and is present and %s.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name, gettext(statusstrings[provider->up->up->status])); varbuf_add_str(whynot, linebuf); if (!canfixbyremove) return false; nconflicts++; *canfixbyremove= provider->up->up; break; } break; default: internerr("unknown istobe conflict provider '%d'", provider->up->up->clientdata->istobe); } } if (!nconflicts) return true; if (nconflicts > 1) *canfixbyremove = NULL; return false; } /* if (dependency) {...} else {...} */ }
/** * Check if conffiles contains sane information. */ static void check_conffiles(const char *ctrldir, const char *rootdir) { FILE *cf; struct varbuf controlfile = VARBUF_INIT; char conffilename[MAXCONFFILENAME + 1]; struct file_info *conffiles_head = NULL; struct file_info *conffiles_tail = NULL; varbuf_printf(&controlfile, "%s/%s", ctrldir, CONFFILESFILE); cf = fopen(controlfile.buf, "r"); if (cf == NULL) { if (errno == ENOENT) return; ohshite(_("error opening conffiles file")); } while (fgets(conffilename, MAXCONFFILENAME + 1, cf)) { struct stat controlstab; int n; n = strlen(conffilename); if (!n) ohshite(_("empty string from fgets reading conffiles")); if (conffilename[n - 1] != '\n') ohshit(_("conffile name '%s' is too long, or missing final newline"), conffilename); conffilename[n - 1] = '\0'; varbuf_reset(&controlfile); varbuf_printf(&controlfile, "%s/%s", rootdir, conffilename); if (lstat(controlfile.buf, &controlstab)) { if (errno == ENOENT) { if ((n > 1) && c_isspace(conffilename[n - 2])) warning(_("conffile filename '%s' contains trailing white spaces"), conffilename); ohshit(_("conffile '%.250s' does not appear in package"), conffilename); } else ohshite(_("conffile '%.250s' is not stattable"), conffilename); } else if (!S_ISREG(controlstab.st_mode)) { warning(_("conffile '%s' is not a plain file"), conffilename); } if (file_info_find_name(conffiles_head, conffilename)) { warning(_("conffile name '%s' is duplicated"), conffilename); } else { struct file_info *conffile; conffile = file_info_new(conffilename); file_info_list_append(&conffiles_head, &conffiles_tail, conffile); } } file_info_list_free(conffiles_head); varbuf_destroy(&controlfile); if (ferror(cf)) ohshite(_("error reading conffiles file")); fclose(cf); }
int commandfd(const char *const *argv) { struct varbuf linevb = VARBUF_INIT; const char * pipein; const char **newargs = NULL; char *ptr, *endptr; FILE *in; long infd; int ret = 0; int c, lno, i; bool skipchar; pipein = *argv++; if (pipein == NULL || *argv) badusage(_("--%s takes exactly one argument"), cipaction->olong); infd = dpkg_options_parse_arg_int(cipaction, pipein); in = fdopen(infd, "r"); if (in == NULL) ohshite(_("couldn't open '%i' for stream"), (int)infd); for (;;) { bool mode = false; int argc= 1; lno= 0; push_error_context(); do { c = getc(in); if (c == '\n') lno++; } while (c != EOF && c_isspace(c)); if (c == EOF) break; if (c == '#') { do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n'); continue; } varbuf_reset(&linevb); do { varbuf_add_char(&linevb, c); c= getc(in); if (c == '\n') lno++; /* This isn't fully accurate, but overestimating can't hurt. */ if (c_isspace(c)) argc++; } while (c != EOF && c != '\n'); if (c == EOF) ohshit(_("unexpected end of file before end of line %d"), lno); if (!argc) continue; varbuf_end_str(&linevb); newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1)); argc= 1; ptr= linevb.buf; endptr = ptr + linevb.used + 1; skipchar = false; while(ptr < endptr) { if (skipchar) { skipchar = false; } else if (*ptr == '\\') { memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1)); endptr--; skipchar = true; continue; } else if (c_isspace(*ptr)) { if (mode == true) { *ptr = '\0'; mode = false; } } else { if (mode == false) { newargs[argc]= ptr; argc++; mode = true; } } ptr++; } *ptr = '\0'; newargs[argc++] = NULL; /* We strdup() each argument, but never free it, because the * error messages contain references back to these strings. * Freeing them, and reusing the memory, would make those * error messages confusing, to say the least. */ for(i=1;i<argc;i++) if (newargs[i]) newargs[i] = m_strdup(newargs[i]); setaction(NULL, NULL); dpkg_options_parse((const char *const **)&newargs, cmdinfos, printforhelp); if (!cipaction) badusage(_("need an action option")); ret |= cipaction->action(newargs); pop_error_context(ehflag_normaltidy); } return ret; }
/* * Does cycle checking. Doesn't mind if pkg has no triggers pending - in * that case does nothing but fix up any stale awaiters. */ void trigproc(struct pkginfo *pkg, enum trigproc_type type) { static struct varbuf namesarg; struct varbuf depwhynot = VARBUF_INIT; struct trigpend *tp; struct pkginfo *gaveup; debug(dbg_triggers, "trigproc %s", pkg_name(pkg, pnaw_always)); if (pkg->clientdata->trigprocdeferred) pkg->clientdata->trigprocdeferred->pkg = NULL; pkg->clientdata->trigprocdeferred = NULL; if (pkg->trigpend_head) { enum dep_check ok; assert(pkg->status == PKG_STAT_TRIGGERSPENDING || pkg->status == PKG_STAT_TRIGGERSAWAITED); if (dependtry > 1) { gaveup = check_trigger_cycle(pkg); if (gaveup == pkg) return; if (findbreakcycle(pkg)) sincenothing = 0; } ok = dependencies_ok(pkg, NULL, &depwhynot); if (ok == DEP_CHECK_DEFER) { varbuf_destroy(&depwhynot); enqueue_package(pkg); return; } else if (ok == DEP_CHECK_HALT) { /* We cannot process this package on this dpkg run, * and we can get here repeatedly if this package is * required to make progress for other packages. So * reset the trigger cycles tracking to avoid bogus * cycle detections. */ trigproc_reset_cycle(); /* When doing opportunistic trigger processig, nothing * requires us to be able to make progress; skip the * package and silently ignore the error due to * unsatisfiable dependencies. */ if (type == TRIGPROC_TRY) { varbuf_destroy(&depwhynot); return; } sincenothing = 0; varbuf_end_str(&depwhynot); notice(_("dependency problems prevent processing " "triggers for %s:\n%s"), pkg_name(pkg, pnaw_nonambig), depwhynot.buf); varbuf_destroy(&depwhynot); ohshit(_("dependency problems - leaving triggers unprocessed")); } else if (depwhynot.used) { varbuf_end_str(&depwhynot); notice(_("%s: dependency problems, but processing " "triggers anyway as you requested:\n%s"), pkg_name(pkg, pnaw_nonambig), depwhynot.buf); varbuf_destroy(&depwhynot); } if (dependtry <= 1) { gaveup = check_trigger_cycle(pkg); if (gaveup == pkg) return; } printf(_("Processing triggers for %s (%s) ...\n"), pkg_name(pkg, pnaw_nonambig), versiondescribe(&pkg->installed.version, vdew_nonambig)); log_action("trigproc", pkg, &pkg->installed); varbuf_reset(&namesarg); for (tp = pkg->trigpend_head; tp; tp = tp->next) { varbuf_add_char(&namesarg, ' '); varbuf_add_str(&namesarg, tp->name); } varbuf_end_str(&namesarg); /* Setting the status to half-configured * causes modstatdb_note to clear pending triggers. */ pkg_set_status(pkg, PKG_STAT_HALFCONFIGURED); modstatdb_note(pkg); if (!f_noact) { sincenothing = 0; maintscript_postinst(pkg, "triggered", namesarg.buf + 1, NULL); } post_postinst_tasks(pkg, PKG_STAT_INSTALLED); } else { /* In other branch is done by modstatdb_note(), from inside * post_postinst_tasks(). */ trig_clear_awaiters(pkg); } }
/** * Print a single package which: * (a) is the target of one or more relevant predependencies. * (b) has itself no unsatisfied pre-dependencies. * * If such a package is present output is the Packages file entry, * which can be massaged as appropriate. * * Exit status: * 0 = a package printed, OK * 1 = no suitable package available * 2 = error */ int predeppackage(const char *const *argv) { static struct varbuf vb; struct pkgiterator *it; struct pkginfo *pkg = NULL, *startpkg, *trypkg; struct dependency *dep; struct deppossi *possi, *provider; if (*argv) badusage(_("--%s takes no arguments"), cipaction->olong); modstatdb_open(msdbrw_readonly | msdbrw_available_readonly); /* We use clientdata->istobe to detect loops. */ clear_istobes(); dep = NULL; it = pkg_db_iter_new(); while (!dep && (pkg = pkg_db_iter_next_pkg(it))) { /* Ignore packages user doesn't want. */ if (pkg->want != PKG_WANT_INSTALL) continue; /* Ignore packages not available. */ if (!pkg->files) continue; pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL; for (dep= pkg->available.depends; dep; dep= dep->next) { if (dep->type != dep_predepends) continue; if (depisok(dep, &vb, NULL, NULL, true)) continue; /* This will leave dep non-NULL, and so exit the loop. */ break; } pkg->clientdata->istobe = PKG_ISTOBE_NORMAL; /* If dep is NULL we go and get the next package. */ } pkg_db_iter_free(it); if (!dep) return 1; /* Not found. */ assert(pkg); startpkg= pkg; pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL; /* OK, we have found an unsatisfied predependency. * Now go and find the first thing we need to install, as a first step * towards satisfying it. */ do { /* We search for a package which would satisfy dep, and put it in pkg. */ for (possi = dep->list, pkg = NULL; !pkg && possi; possi=possi->next) { struct deppossi_pkg_iterator *possi_iter; possi_iter = deppossi_pkg_iter_new(possi, wpb_available); while (!pkg && (trypkg = deppossi_pkg_iter_next(possi_iter))) { if (trypkg->files && trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL && versionsatisfied(&trypkg->available, possi)) { pkg = trypkg; break; } for (provider = possi->ed->depended.available; !pkg && provider; provider = provider->next) { if (provider->up->type != dep_provides) continue; if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; trypkg = provider->up->up; if (!trypkg->files) continue; if (trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL) { pkg = trypkg; break; } } } deppossi_pkg_iter_free(possi_iter); } if (!pkg) { varbuf_reset(&vb); describedepcon(&vb,dep); varbuf_end_str(&vb); notice(_("cannot see how to satisfy pre-dependency:\n %s"), vb.buf); ohshit(_("cannot satisfy pre-dependencies for %.250s (wanted due to %.250s)"), pkgbin_name(dep->up, &dep->up->available, pnaw_nonambig), pkgbin_name(startpkg, &startpkg->available, pnaw_nonambig)); } pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL; for (dep= pkg->available.depends; dep; dep= dep->next) { if (dep->type != dep_predepends) continue; if (depisok(dep, &vb, NULL, NULL, true)) continue; /* This will leave dep non-NULL, and so exit the loop. */ break; } } while (dep); /* OK, we've found it - pkg has no unsatisfied pre-dependencies! */ writerecord(stdout, _("<standard output>"), pkg, &pkg->available); m_output(stdout, _("<standard output>")); return 0; }