// pipestream.cpp -*- C++ -*- socket library // Copyright (C) 2002 Herbert Straub // // 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. // // pipestream.C -*- C++ -*- socket library // Copyright (C) 1992-1996 Gnanasekaran Swaminathan // // Permission is granted to use at your own risk and distribute this software // in source and binary forms provided the above copyright notice and this // paragraph are preserved on all copies. This software is provided "as is" // with no express or implied warranty. // // Version: 12Jan97 1.11 // 2002-07-28 Version 1.2 (C) Herbert Straub // Eliminating sorry_about_global_temp inititialisation. This don't work // in combination with NewsCache. My idea is: initializing the classes with (0) // and in the second step call ios::init (sockbuf *) and iosockstream::init ... // The constructors of ipipestream, opipestream and iopipestream are changed. using namespace std; #include #include #include #include // environ is not given a declaration in sun's extern char** environ; // child closes s2 and uses s1 // parent closes s1 and uses s2 enum domain { af_unix = 1 }; iopipestream* iopipestream::head = 0; static sockbuf* createpipestream (const char* cmd, int mode) { int sockets[2]; if (::socketpair (af_unix, sockbuf::sock_stream, 0, sockets) == -1) throw sockerr (errno); pid_t pid = ::vfork (); if (pid == -1) throw sockerr (errno); if (pid == 0) { // child process if (::close (sockets[1]) == -1) throw sockerr (errno); if ((mode & ios::in) && ::dup2 (sockets[0], 1) == -1) throw sockerr (errno); if ((mode & ios::out) && ::dup2 (sockets[0], 0) == -1) throw sockerr (errno); if (::close (sockets[0]) == -1) throw sockerr (errno); const char* argv[4]; argv[0] = "/bin/sh"; argv[1] = "-c"; argv[2] = cmd; argv[3] = 0; execve ("/bin/sh", (char**) argv, environ); throw sockerr (errno); } // parent process if (::close (sockets[0]) == -1) throw sockerr (errno); sockbuf* s = new sockbuf (sockbuf::sockdesc(sockets[1])); if (!(mode & ios::out)) s->shutdown (sockbuf::shut_write); if (!(mode & ios::in)) s->shutdown (sockbuf::shut_read); return s; } ipipestream::ipipestream (const char* cmd) : ios (0), isockstream(0) { sockbuf *t = createpipestream (cmd, ios::in); ios::init (t); isockstream::init (t); } opipestream::opipestream (const char* cmd) : ios (0), osockstream(0) { sockbuf *t = createpipestream (cmd, ios::out); ios::init (t); osockstream::init (t); } iopipestream::iopipestream (const char* cmd) : ios (0), iosockstream(0), cpid (-1), next (0) { sockbuf *t = createpipestream (cmd, ios::in|ios::out); ios::init (t); iosockstream::init (t); } iopipestream::iopipestream(sockbuf::type ty, int proto) : ios (0), iosockstream(NULL), cpid (-1), next (head) // probably NULL is not a good idea //LN { if (::socketpair(af_unix, ty, proto, sp) == -1) throw sockerr (errno); head = this; } pid_t iopipestream::fork () { pid_t pid = ::fork (); // donot use vfork here if (pid == -1) throw sockerr (errno); if (pid > 0) { // parent process while (head) { if (::close (head->sp[1]) == -1) throw sockerr (errno); head->cpid = pid; head->init (new sockbuf (sockbuf::sockdesc(head->sp[0]))); head = head->next; } } else { // child process while (head) { if (::close (head->sp[0]) == -1) throw sockerr (errno); head->cpid = 0; head->init (new sockbuf (sockbuf::sockdesc(head->sp[1]))); head = head->next; } } return pid; }