Advertisement

IPC problems on NetBSD

Started by March 04, 2006 06:11 AM
2 comments, last by pulpfist 18 years, 8 months ago
Hi I am working on a linux/unix filter that uses plugins to extract info from web pages. I have sucessfully compiled and run the program on the following systems: x86 Fedora Linux FC2 running Linux 2.6 kernel x86 Debian GNU/Linux 3.0 running Linux 2.4 kernel AMD64 Fedora Core release 3 running Linux 2.6 kernel The problem is when I try to run it on x86 NetBSD 1.6.1 It compiles, but when I try to run the program the child process (running the plugin) spits out an error: Unknown error [256] Here is the IPC between the parent/child:

//===============================
string& Pipe::exec_filter(const string& path, string& iobuf)
{
	pid_t pid;
	int nb, status;
	fd_set read_fds;

	// check access mode
	if(::access(path.c_str(), X_OK) == -1)
		throw general_exception("Pipe::exec_filter:" + string(strerror(errno)));
		
	if(::pipe(fds1_) < 0 || ::pipe(fds2_) < 0 || (pid = ::fork()) < 0)	
		throw general_exception("Pipe::exec_filter:" + string(strerror(errno)));
	
	else if(pid > 0) { // Parent		
		
		close(fds1_[0]);
		close(fds2_[1]);

		// write
		write(fds1_[1], iobuf.c_str(), iobuf.length());
		close(fds1_[1]);
		
		// wait for something to read
		FD_ZERO(&read_fds);
		FD_SET(fds2_[0], &read_fds);
		int e = select(fds2_[0] + 1, &read_fds, NULL, NULL, &read_timeout_);
		if(e == -1) throw general_exception("Pipe::exec_filter: parent: " + string(strerror(errno)));
		else if(!e) throw general_exception("Pipe::exec_filter: parent: " + string(strerror(errno=ETIMEDOUT)) + " [" + path + "]");
		
		// read
		char buffer[256+1];
		iobuf = "";
		while((nb = read(fds2_[0], buffer, 256)) > 0) {
			*(buffer+nb) = '\0';
			iobuf += buffer;
		}

		// Wait for child exit 
		if((e = wait(&status)) == -1)
			throw general_exception("Pipe::exec_filter: parent: " + string(strerror(errno)));

		// process any child errors
		if(status) 
			throw general_exception("Pipe::exec_filter: child: " + string(strerror(status)) + " [" + path + "]");
	}		
	else {	// Child	
		
		// dup stdin/stdout 
		close(fds1_[1]);
		close(fds2_[0]);
		if(fds1_[0] != STDIN_FILENO && dup2(fds1_[0], STDIN_FILENO) != STDIN_FILENO)
			_exit(errno);	
		if(fds2_[1] != STDOUT_FILENO && dup2(fds2_[1], STDOUT_FILENO) != STDOUT_FILENO)
			_exit(errno);

		// set nice 
		errno = 0;
		if(nice_inc_ && ::nice(nice_inc_) == -1 && errno)
			_exit(errno);			
		
		::execv(path.c_str(), NULL);
		_exit(1);
	}

	return iobuf;
}
//===============================



Anyone have an idea why this child breaks on NetBSD? I know the plugin returns 0, still it seems like the status from the wait call equals 256. Is the bahavior of wait function different on BSD?
There are two problems that I can see. Firstly, the value that wait(2) stores in status is an opaque status value, not the exit value of the child. To get at the exit status of the child, you need to use the WIFEXITED/WEXITSTATUS/etc. macros. Secondly, you need to pass a valid argv array to execv so that, at least, argv[0] is the name of the program and argv[1] is NULL. It might be easier to use execl instead and just pass path.c_str() twice, e.g. execl(path.c_str(), path.c_str(), NULL);
Advertisement
Quote:
There are two problems that I can see. Firstly, the value that wait(2) stores in status is an opaque status value, not the exit value of the child. To get at the exit status of the child, you need to use the WIFEXITED/WEXITSTATUS/etc. macros.

I noticed this mistake too. Now that Im back on linux Ill fix that and see if it helps.

Quote:
Secondly, you need to pass a valid argv array to execv so that, at least, argv[0] is the name of the program and argv[1] is NULL. It might be easier to use execl instead and just pass path.c_str() twice, e.g. execl(path.c_str(), path.c_str(), NULL);

I think that is what I am doing. The 'path' string is the full path of the plugin. Nothing more, nothing less.
If the above doesnt help Ill try the execl.

Thanks
Whow I feel stupid hehe

I changed

-if(status)
+if(WEXITSTATUS(status))

That gave me a Operation not permitted error from the child.

Then I changed

-::execv(path.c_str(), NULL);
- _exit(1);

+ ::execl(path.c_str(), path.c_str());
+ _exit(errno);

That gave me a Bad address error

Changed

-::execl(path.c_str(), path.c_str());
+::execl(path.c_str(), path.c_str(), NULL); // This is where I started feeling stupid...

and now it works =D

Thanks a lot!

This topic is closed to new replies.

Advertisement