Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
0
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);
}
Example #5
0
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);
	}
}
Example #6
0
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);
}
Example #7
0
/**
 * 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;
}
Example #8
0
File: help.c Project: pexip/os-dpkg
/**
 * 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."));
}
Example #9
0
/*
 * 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);
	}
}
Example #10
0
/**
 * 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;
  }
}
Example #11
0
/*
 * 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);
	}
}
Example #12
0
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);
}
Example #13
0
/*
 * 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);
}
Example #14
0
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);
	}
}
Example #15
0
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);
}
Example #16
0
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;
}
Example #17
0
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;
}
Example #18
0
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();
}
Example #20
0
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);
}
Example #21
0
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);
}
Example #22
0
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;
}
Example #23
0
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;
}
Example #24
0
/**
 * 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);
}
Example #25
0
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);
}
Example #26
0
/*
 * *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 {...} */
}
Example #27
0
/**
 * 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);
}
Example #28
0
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;
}
Example #29
0
/*
 * 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;
}