[ccan] [PATCH 2/9] configurator: Reimplement run using popen

David Gibson david at gibson.dropbear.id.au
Tue Sep 20 15:00:23 AEST 2016


On Sun, Sep 18, 2016 at 06:51:59PM -0600, Kevin Locke wrote:
> Rather than using fork+pipe+system+waitpid, most of which are only
> available on POSIX-like systems, use popen which is also available on
> Windows (under the name _popen).

Concept looks good, one little wart.

> 
> Signed-off-by: Kevin Locke <kevin at kevinlocke.name>
> ---
>  tools/configurator/configurator.c | 77 +++++++++++++++------------------------
>  1 file changed, 29 insertions(+), 48 deletions(-)
> 
> diff --git a/tools/configurator/configurator.c b/tools/configurator/configurator.c
> index e322c76..9817fcd 100644
> --- a/tools/configurator/configurator.c
> +++ b/tools/configurator/configurator.c
> @@ -24,14 +24,14 @@
>  #include <stdio.h>
>  #include <stdbool.h>
>  #include <stdlib.h>
> -#include <unistd.h>
>  #include <err.h>
> -#include <sys/types.h>
> -#include <sys/wait.h>
> -#include <sys/stat.h>
> -#include <fcntl.h>
>  #include <string.h>
>  
> +#ifdef _MSC_VER
> +#define popen _popen
> +#define pclose _pclose
> +#endif
> +
>  #define DEFAULT_COMPILER "cc"
>  #define DEFAULT_FLAGS "-g3 -ggdb -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition"
>  
> @@ -367,20 +367,19 @@ static struct test tests[] = {
>  	},
>  };
>  
> -static char *grab_fd(int fd)
> +static char *grab_stream(FILE *file)
>  {
> -	int ret;
> -	size_t max, size = 0;
> +	size_t max, ret, size = 0;
>  	char *buffer;
>  
> -	max = 16384;
> -	buffer = malloc(max+1);
> -	while ((ret = read(fd, buffer + size, max - size)) > 0) {
> +	max = BUFSIZ;
> +	buffer = malloc(max);
> +	while ((ret = fread(buffer+size, 1, max - size, file)) == max - size) {

This assumes that fread() will never return a short read except on EOF
or error.  I expect that will be true in practice for regular files,
but I'm not sure if it's a good idea to rely on it.

>  		size += ret;
> -		if (size == max)
> -			buffer = realloc(buffer, max *= 2);
> +		buffer = realloc(buffer, max *= 2);
>  	}
> -	if (ret < 0)
> +	size += ret;
> +	if (ferror(file))
>  		err(1, "reading from command");
>  	buffer[size] = '\0';
>  	return buffer;
> @@ -388,43 +387,25 @@ static char *grab_fd(int fd)
>  
>  static char *run(const char *cmd, int *exitstatus)
>  {
> -	pid_t pid;
> -	int p[2];
> +	static const char redir[] = " 2>&1";
> +	size_t cmdlen;
> +	char *cmdredir;
> +	FILE *cmdout;
>  	char *ret;
> -	int status;
>  
> -	if (pipe(p) != 0)
> -		err(1, "creating pipe");
> -
> -	pid = fork();
> -	if (pid == -1)
> -		err(1, "forking");
> -
> -	if (pid == 0) {
> -		if (dup2(p[1], STDOUT_FILENO) != STDOUT_FILENO
> -		    || dup2(p[1], STDERR_FILENO) != STDERR_FILENO
> -		    || close(p[0]) != 0
> -		    || close(STDIN_FILENO) != 0
> -		    || open("/dev/null", O_RDONLY) != STDIN_FILENO)
> -			exit(128);
> -
> -		status = system(cmd);
> -		if (WIFEXITED(status))
> -			exit(WEXITSTATUS(status));
> -		/* Here's a hint... */
> -		exit(128 + WTERMSIG(status));
> -	}
> +	cmdlen = strlen(cmd);
> +	cmdredir = malloc(cmdlen + sizeof(redir));
> +	memcpy(cmdredir, cmd, cmdlen);
> +	memcpy(cmdredir + cmdlen, redir, sizeof(redir));
> +
> +	cmdout = popen(cmdredir, "r");
> +	if (!cmdout)
> +		err(1, "popen \"%s\"", cmdredir);
> +
> +	free(cmdredir);
>  
> -	close(p[1]);
> -	ret = grab_fd(p[0]);
> -	/* This shouldn't fail... */
> -	if (waitpid(pid, &status, 0) != pid)
> -		err(1, "Failed to wait for child");
> -	close(p[0]);
> -	if (WIFEXITED(status))
> -		*exitstatus = WEXITSTATUS(status);
> -	else
> -		*exitstatus = -WTERMSIG(status);
> +	ret = grab_stream(cmdout);
> +	*exitstatus = pclose(cmdout);
>  	return ret;
>  }
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/ccan/attachments/20160920/9e1d993a/attachment-0001.sig>


More information about the ccan mailing list