Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Avoid using of popen for bi-directional pipes.
Vsevolod Stakhov committed 12 years ago
commit c1be57ad058acf1ecf82deb327a5092228951f13
parent 20a77eb
3 files changed +88 -12
modified libpkg/pkg_jobs.c
@@ -30,6 +30,7 @@

#include <sys/param.h>
#include <sys/mount.h>
+
#include <sys/types.h>

#include <assert.h>
#include <errno.h>
@@ -37,6 +38,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+
#include <sys/wait.h>

#include "pkg.h"
#include "private/event.h"
@@ -943,10 +945,11 @@ int
pkg_jobs_solve(struct pkg_jobs *j)
{
	bool dry_run = false;
-
	int ret;
+
	int ret, pstatus;
	struct pkg_solve_problem *problem;
	const char *solver;
-
	FILE *spipe;
+
	FILE *spipe[2];
+
	pid_t pchild;

	if ((j->flags & PKG_FLAG_DRY_RUN) == PKG_FLAG_DRY_RUN)
		dry_run = true;
@@ -978,27 +981,34 @@ pkg_jobs_solve(struct pkg_jobs *j)
	if (ret == EPKG_OK) {
		if (pkg_config_string(PKG_CONFIG_CUDF_SOLVER, &solver) == EPKG_OK
				&& solver != NULL) {
-
			/* XXX: whether can we use r+ on all supported platforms ? */
-
			spipe = popen(solver, "r+");
-
			ret = pkg_jobs_cudf_emit_file(j, j->type, spipe);
+
			pchild = process_spawn_pipe(spipe, solver);
+
			if (pchild == -1) {
+
				return (EPKG_FATAL);
+
			}
+
			ret = pkg_jobs_cudf_emit_file(j, j->type, spipe[1]);
			if (ret == EPKG_OK) {
-
				fflush(spipe);
-
				ret = pkg_jobs_cudf_parse_output(j, spipe);
+
				ret = pkg_jobs_cudf_parse_output(j, spipe[0]);
			}
-
			pclose(spipe);
+
			waitpid(pchild, &pstatus, WNOHANG);
+
			fclose(spipe[0]);
+
			fclose(spipe[1]);
		}
		else {
			problem = pkg_solve_jobs_to_sat(j);
			if (problem != NULL) {
				if (pkg_config_string(PKG_CONFIG_SAT_SOLVER, &solver) == EPKG_OK
						&& solver != NULL) {
-
					/* XXX: whether can we use r+ on all supported platforms ? */
-
					spipe = popen(solver, "r+");
-
					ret = pkg_solve_dimacs_export(problem, spipe);;
+
					pchild = process_spawn_pipe(spipe, solver);
+
					if (pchild == -1)
+
						return (EPKG_FATAL);
+

+
					ret = pkg_solve_dimacs_export(problem, spipe[1]);
					if (ret == EPKG_OK) {
						/* XXX: add sat solver output parser */
					}
-
					pclose(spipe);
+
					waitpid(pchild, &pstatus, WNOHANG);
+
					fclose(spipe[0]);
+
					fclose(spipe[1]);
				}
			}
			else {
modified libpkg/private/utils.h
@@ -101,5 +101,6 @@ struct dns_srvinfo *

int set_nameserver(const char *nsname);

+
pid_t process_spawn_pipe(FILE *inout[2], const char *command);

#endif
modified libpkg/utils.c
@@ -1,6 +1,7 @@
/*-
 * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
+
 * Copyright (c) 2013 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
@@ -35,6 +36,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+
#include <paths.h>

#include "pkg.h"
#include "private/event.h"
@@ -445,3 +447,66 @@ is_hardlink(struct hardlinks *hl, struct stat *st)

	return (true);
}
+

+
/* Spawn a process from pfunc, returning it's pid. The fds array passed will
+
 * be filled with two descriptors: fds[0] will read from the child process,
+
 * and fds[1] will write to it.
+
 * Similarly, the child process will receive a reading/writing fd set (in
+
 * that same order) as arguments.
+
*/
+
extern char **environ;
+
pid_t
+
process_spawn_pipe(FILE *inout[2], const char *command)
+
{
+
	pid_t pid;
+
	int pipes[4];
+
	char *argv[4];
+

+
	/* Parent read/child write pipe */
+
	if (pipe(&pipes[0]) == -1)
+
		return (-1);
+

+
	/* Child read/parent write pipe */
+
	if (pipe(&pipes[2]) == -1) {
+
		close(pipes[0]);
+
		close(pipes[1]);
+
		return (-1);
+
	}
+

+
	argv[0] = __DECONST(char *, "sh");
+
	argv[1] = __DECONST(char *, "-c");
+
	argv[2] = __DECONST(char *, command);
+
	argv[3] = NULL;
+

+
	pid = fork();
+
	if (pid > 0) {
+
		/* Parent process */
+
		inout[0] = fdopen(pipes[0], "r");
+
		inout[1] = fdopen(pipes[3], "w");
+

+
		close(pipes[1]);
+
		close(pipes[2]);
+

+
		return (pid);
+

+
	} else if (pid == 0) {
+
		close(pipes[0]);
+
		close(pipes[3]);
+

+
		if (pipes[1] != STDOUT_FILENO) {
+
			dup2(pipes[1], STDOUT_FILENO);
+
			close(pipes[1]);
+
		}
+
		if (pipes[2] != STDIN_FILENO) {
+
			dup2(pipes[2], STDIN_FILENO);
+
			close(pipes[2]);
+
		}
+
		closefrom(STDERR_FILENO + 1);
+

+
		execve(_PATH_BSHELL, argv, environ);
+

+
		exit(127);
+
	}
+

+
	return (-1); /* ? */
+
}