Re: How do a more complicated gtk_input_add call than this one???....



[ violating my own propaganda about the relationship between this
  list and general POSIX programming ... :) ]

>How do I get 2 way communication between a parent and child
>processes and use gdk_input_add as well???
>This is more than just reading from STDIO I think.

you can't do it *easily* with stdio. you can do it very easily with 
pipe(2), close(2) and dup(2). this is the kind of basic POSIX
programming that far too few people ever learn anymore.

however, to make your life even easier, i enclose working, GPL'ed code
below. You use this by first calling:

       int read_pipe[2];
       int write_pipe[2];
       char *argv[N];
       extern char *environ;

       if (pipe (pipes)) {
           ... error ..
       }

       forkexec	(argv, environ, write_pipe, read_pipe);

forkexec_cmd() can be used a bit like system(3). i had a version of
this code at some point that accepted a third "pipe" for stderr, but i
can't find it right now. stderr on the child process will still point
to the same place as in the parent. i'd probably write this a little
differently now than when i did 10 years ago ...

need i add that you just use read_pipe[READ_DESC] as the fd for
gdk_input_add(). note that you may wish to make the pipe non-blocking
as well. this is useful for a number of programs. see fcntl(2) for how
to do this.

--p

/*
    Copyright (C) 1992 Paul Davis 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>

/*
  Run a program with program name and args specified by argv, in the
  environment specified by envp.

  The exec'ed program uses inpipe[READ_DESC] and outpipe[WRITE_DESC]
  as stdin and stdout, resp.

  You can safely leave outpipe and inpipe unspecified (NULL) if you
  want the command to read/write from/to stdin/stdout. envp could just
  be the environ extern that all C/C++ programs have access to, or it
  could be some filtered version of it. This function doesn't care
  what it is, but the cmd might (it might try to use $HOME for
  example). I don't know if it can be a null pointer.  
*/

#define READ_DESC 0
#define WRITE_DESC 1
#define MAXARGS 512

/* Return codes:

   -1: dup of read-end of pipe failed
   -2: dup of write-end of pipe failed
   -3: execve failed
   -4: fork failed
*/

pid_t
forkexec (char **argv, char **envp, int outpipe[2], int inpipe[2])

{
	extern char **environ;
	pid_t pid;

	if ((pid = fork ()) == 0) {

		/* In the child process */

		if (inpipe) {
			if (inpipe[READ_DESC] != 0) {
				close (0);
				if (dup (inpipe[READ_DESC]) < 0) {
					return (-1);
				}
			}
			if (inpipe[WRITE_DESC]) {
				close (inpipe[WRITE_DESC]);
			}
		}

		if (outpipe) {
			if (outpipe[WRITE_DESC] != 1) {
				close (1);
				if (dup (outpipe[WRITE_DESC]) < 0) {
					return (-2);
				}
			}
			if (outpipe[READ_DESC]) {
				close (outpipe[READ_DESC]);
			}
		}

		/* this is stupid - it shouldn't be necessary to do this ! */
	
		environ = envp;
	
		/* do it */

		execve (argv[0], argv, envp);
		return (-3);
	
	} else if (pid == -1) {
		return (-4);

	} else {
		/* In the parent process */
	
		if (outpipe && outpipe[WRITE_DESC]) {
			close (outpipe[WRITE_DESC]);
		}
	}

	return (pid);
}

/*
  This is like system(3), only safe from all shell side effects and
  security concerns. Its also faster, and it doesn't wait for the
  forked child to return.
*/

pid_t
forkexec_cmd (char *cmd, char **envp, int outpipe[2], int inpipe[2])

{
	char *argv[MAXARGS];
	int i;
	char *cpcmd;
	char *p, *q;
	pid_t retval;
	int should_break = 0;

	cpcmd = strdup (cmd);

	for (p = cpcmd, q = cpcmd, i = 0; *p && !should_break &&
		     (i < MAXARGS); p = q , i++) {

		while ((*q) && !isspace (*q)) q++;
		if (!*q) {
			should_break = 1;
		} else {
			should_break = 0;
			*q = '\0';
		}
		argv[i] = p;
		q++;
	}

	argv[i] = 0;
	retval = forkexec (argv, envp, outpipe, inpipe);
	free (cpcmd);
	return retval;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]