/* Copyright 2008 Nathan Phillip Brink, Ethan Zonca This file is a part of DistRen. DistRen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. DistRen 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with DistRen. If not, see . */ #include "remoteio.h" #include #include #include #include #include #include int remoteio_open(const char *spec, struct remoteio **rem) { /* pipe used to write to child */ int pipe_write[2]; /* pipe used to read from child */ int pipe_read[2]; pid_t child; /* for wait(2) if needed */ int childstatus; int counter; /* create two pipes to facilitate communication with child */ if(pipe(pipe_write)) return 1; if(pipe(pipe_read)); { close(pipe_write[0]); close(pipe_write[1]); return 1; } /* parent */ child = fork(); if(child == -1) { close(pipe_write[0]); close(pipe_write[1]); close(pipe_read[0]); close(pipe_read[1]); return 1; } if(child) { /* close sides of pipe we won't use */ close(pipe_write[0]); close(pipe_read[1]); /* setup remoteio struct */ (*rem) = malloc(sizeof(struct remoteio)); if(!(*rem)) { /* we should tell the child we're dead - use wait and close our end of the pipes! */ close(pipe_write[1]); close(pipe_read[0]); /* we should probably pass of the wait() call to a thread that just does boring things like that. Especially for when the server tries to connect to other servers... */ /* maybe we should just kill the child */ kill(child, SIGTERM); /* the waitpid(2) seems to indicate that only when the child is terminated will this wait return. */ waitpid(child, &childstatus, 0); } (*rem)->pipe_write = pipe_write[1]; (*rem)->pipe_read = pipe_read[0]; (*rem)->child = child; return 0; } /* child */ else { /* close unused pipes */ close(pipe_write[1]); close(pipe_read[0]); /* reset stdin, stdout, and stderr to the appropriate files. OK, not stderr :-) */ dup2(pipe_read[1], 0); dup2(pipe_write[0], 1); /* close all other file descriptors. We want to keep 0, 1, and 2 open. We don't know that the last open() or pipe() always gives the highest fd number. However, I will assume that it does. Maybe this is a bad idea: */ counter = pipe_write[0]; if(counter < pipe_write[1]) counter = pipe_write[1]; if(counter < pipe_read[0]) counter = pipe_read[0]; if(counter < pipe_read[1]) counter = pipe_read[1]; while(counter > 2) { close(counter); counter --; } /* now exec */ return 1; /* this line should never be reached because we exec*/ } } size_t remoteio_read(struct remoteio *rem, void *buf, size_t len) { return 0; } size_t remoteio_write(struct remoteio *rem, void *buf, size_t len) { return 0; } int remoteio_close(struct remoteio *rem) { return 0; }