blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Quest Software, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Quest Software, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00038 #include "blocxx/BLOCXX_config.h" 00039 00040 #if !defined(BLOCXX_WIN32) 00041 00042 #include "blocxx/PosixExec.hpp" 00043 #include "blocxx/Format.hpp" 00044 #include "blocxx/SafeCString.hpp" 00045 #include "blocxx/Assertion.hpp" 00046 #include "blocxx/PosixUnnamedPipe.hpp" 00047 #include "blocxx/Paths.hpp" 00048 #include "blocxx/TimeoutTimer.hpp" 00049 #include "blocxx/Select.hpp" 00050 00051 extern "C" 00052 { 00053 #ifdef BLOCXX_HAVE_SYS_RESOURCE_H 00054 #include <sys/resource.h> 00055 #endif 00056 #ifdef BLOCXX_HAVE_SYS_TYPES_H 00057 #include <sys/types.h> 00058 #endif 00059 #ifdef BLOCXX_HAVE_UNISTD_H 00060 #include <unistd.h> 00061 #endif 00062 00063 #include <sys/wait.h> 00064 #include <fcntl.h> 00065 #include <errno.h> 00066 #include <stdio.h> // for perror 00067 #include <signal.h> 00068 } 00069 00070 // NSIG may be defined by signal.h, otherwise 64 should be plenty. 00071 #ifndef NSIG 00072 #define NSIG 64 00073 #endif 00074 00075 #if defined(sigemptyset) 00076 // We want to use the function instead of the macro (for scoping reasons). 00077 #undef sigemptyset 00078 #endif // sigemptyset 00079 00080 #ifdef BLOCXX_NCR 00081 #if defined(sigaction) 00082 #undef sigaction 00083 #endif 00084 #undef SIG_DFL 00085 #define SIG_DFL (void(*)())0 00086 #endif 00087 00088 namespace BLOCXX_NAMESPACE 00089 { 00090 00091 namespace // anonymous 00092 { 00093 00094 void throw_child_error(Exec::PreExec::Error const & err, const String& process_path) 00095 { 00096 Format msg("Exec::spawn(%1): child startup failed: %2", process_path, err.message); 00097 if (err.error_num != 0) 00098 { 00099 BLOCXX_THROW_ERRNO_MSG1( 00100 ExecErrorException, msg.c_str(), err.error_num); 00101 } 00102 else 00103 { 00104 BLOCXX_THROW(ExecErrorException, msg.c_str()); 00105 } 00106 } 00107 00108 void check(bool b, char const * message, bool use_errno = true) 00109 { 00110 if (!b) 00111 { 00112 Exec::PreExec::Error x; 00113 SafeCString::strcpy_trunc(x.message, message); 00114 x.error_num = use_errno ? errno : 0; 00115 throw x; 00116 } 00117 } 00118 00119 void parent_check(bool b, char const * msg) 00120 { 00121 if (!b) 00122 { 00123 BLOCXX_THROW(ExecErrorException, msg); 00124 } 00125 } 00126 00127 void close_on_exec(Descriptor descr, bool may_be_bad) 00128 { 00129 int e = ::fcntl(descr, F_SETFD, FD_CLOEXEC); 00130 check(e == 0 || may_be_bad && errno == EBADF, "fcntl"); 00131 } 00132 00133 void handle_child_error(int rc, Exec::PreExec::Error const & ce, Process & proc, const String& process_path) 00134 { 00135 if (rc < 0) // read of error status from child failed 00136 { 00137 int errnum = errno; 00138 // For some reason child initialization failed; kill it. 00139 proc.waitCloseTerm(Timeout::relative(0.0), Timeout::relative(0.0), Timeout::relative(0.0)); 00140 if (errnum == ETIMEDOUT) 00141 { 00142 BLOCXX_THROW(ExecErrorException, 00143 Format("Exec::spawn(%1): timed out waiting for child to exec()",process_path).c_str()); 00144 } 00145 BLOCXX_THROW_ERRNO_MSG1(ExecErrorException, 00146 Format("Exec::spawn(%1): error reading init status from child",process_path).c_str(), errnum); 00147 } 00148 if (rc > 0) // child sent an initialization error message 00149 { 00150 throw_child_error(ce, process_path); 00151 } 00152 // If rc == 0, initialization succeeded 00153 } 00154 00155 long getMaxOpenFiles() 00156 { 00157 long sysconfValue = sysconf(_SC_OPEN_MAX); 00158 long maxOpen = sysconfValue; 00159 rlimit rl; 00160 rl.rlim_cur = rlim_t(0); 00161 if( getrlimit(RLIMIT_NOFILE, &rl) != -1 ) 00162 { 00163 if( sysconfValue < 0 ) 00164 { 00165 maxOpen = rl.rlim_cur; 00166 } 00167 else 00168 { 00169 maxOpen = std::min<rlim_t>(rl.rlim_cur, sysconfValue); 00170 } 00171 } 00172 // Check for a value of maxOpen that really is reasonable. 00173 // This checks the maximum value to make sure it will fit in an int 00174 // (required for close). 00175 BLOCXX_ASSERT( (maxOpen > 2) && (maxOpen <= long(std::numeric_limits<int>::max())) ); 00176 return maxOpen; 00177 } 00178 00179 void init_child(char const * exec_path, 00180 char const * const argv[], char const * const envp[], 00181 Exec::PreExec & pre_exec, UnnamedPipe* ppipe[Exec::Impl::BLOCXX_NPIPE]) 00182 { 00183 // This code must be careful not to allocate memory, as this can 00184 // cause a deadlock on some platforms when there are multiple 00185 // threads running at the time of the fork(). 00186 00187 int exec_err_desc = -1; 00188 Exec::PreExec::Error err; 00189 err.error_num = 0; // should be unnecessary, but just in case... 00190 err.message[0] = '\0'; // should be unnecessary, but just in case... 00191 try 00192 { 00193 int rc; 00194 exec_err_desc = ppipe[Exec::Impl::BLOCXX_EXEC_ERR]->getOutputDescriptor(); 00195 pre_exec.call(ppipe); 00196 00197 int rval = 0; 00198 char * const * cc_argv = const_cast<char * const *>(argv); 00199 char * const * cc_envp = const_cast<char * const *>(envp); 00200 if (envp) 00201 { 00202 check(::execve(exec_path, cc_argv, cc_envp) != -1, "execve"); 00203 } 00204 else 00205 { 00206 check(::execv(exec_path, cc_argv) != -1, "execv"); 00207 } 00208 } 00209 catch (Exec::PreExec::Error & e) 00210 { 00211 err = e; 00212 } 00213 catch (std::exception & e) 00214 { 00215 SafeCString::strcpy_trunc(err.message, e.what()); 00216 err.error_num = 0; 00217 } 00218 catch (Exec::PreExec::DontCatch & e) 00219 { 00220 throw; 00221 } 00222 catch (...) 00223 { 00224 SafeCString::strcpy_trunc(err.message, "unknown exception"); 00225 err.error_num = 0; 00226 } 00227 ssize_t rv = ::write(exec_err_desc, &err, sizeof(err)); 00228 ::_exit(127); 00229 } 00230 00231 } // end anonymous namespace 00232 00233 namespace Exec 00234 { 00235 00236 using namespace Impl; 00237 00239 // PreExec methods 00240 // 00241 void PreExec::resetSignals() 00242 { 00243 /* 00244 according to susv3: 00245 00246 This volume of IEEE Std 1003.1-2001 specifies that signals set to 00247 SIG_IGN remain set to SIG_IGN, and that the process signal mask be 00248 unchanged across an exec. This is consistent with historical implemen- 00249 tations, and it permits some useful functionality, such as the nohup 00250 command. However, it should be noted that many existing applications 00251 wrongly assume that they start with certain signals set to the default 00252 action and/or unblocked. In particular, applications written with a 00253 simpler signal model that does not include blocking of signals, such as 00254 the one in the ISO C standard, may not behave properly if invoked with 00255 some signals blocked. Therefore, it is best not to block or ignore sig- 00256 nals across execs without explicit reason to do so, and especially not 00257 to block signals across execs of arbitrary (not closely co-operating) 00258 programs. 00259 00260 so we'll reset the signal mask and all signal handlers to SIG_DFL. 00261 We set them all just in case the current handlers may misbehave now 00262 that we've fork()ed. 00263 */ 00264 int rc; 00265 ::sigset_t emptymask; 00266 check(::sigemptyset(&emptymask) == 0, "sigemptyset"); 00267 check(::sigprocmask(SIG_SETMASK, &emptymask, 0) == 0, "sigprocmask"); 00268 00269 for (std::size_t sig = 1; sig <= NSIG; ++sig) 00270 { 00271 if (sig == SIGKILL || sig == SIGSTOP) 00272 { 00273 continue; 00274 } 00275 struct sigaction temp; 00276 int e = ::sigaction(sig, 0, &temp); 00277 check(e == 0 || errno == EINVAL, "sigaction [1]"); 00278 if (e == 0 && temp.sa_handler != SIG_DFL) // valid signal 00279 { 00280 temp.sa_handler = SIG_DFL; 00281 // note that we don't check the return value because there are signals 00282 // (e.g. SIGGFAULT on HP-UX), which are gettable, but not settable. 00283 ::sigaction(sig, &temp, 0); 00284 } 00285 } 00286 } 00287 00288 void PreExec::closeDescriptorsOnExec(std::vector<bool> const & keep) 00289 { 00290 long numd = m_max_descriptors ? m_max_descriptors : getMaxOpenFiles(); 00291 for (int d = 3; d < int(numd); ++d) // Don't close standard descriptors 00292 { 00293 if (size_t(d) >= keep.size() || !keep[d]) 00294 { 00295 close_on_exec(d, true); 00296 } 00297 } 00298 } 00299 00300 void PreExec::setupStandardDescriptors(pipe_pointer_t const ppipe[]) 00301 { 00302 int nulld = 0; 00303 if (!(ppipe[0] && ppipe[1] && ppipe[2])) 00304 { 00305 nulld = ::open(_PATH_DEVNULL, O_RDWR); 00306 check(nulld >= 0, "open"); 00307 close_on_exec(nulld, false); 00308 } 00309 for (unsigned d = 0; d < 3; ++d) 00310 { 00311 PosixUnnamedPipe * p = dynamic_cast<PosixUnnamedPipe*>(ppipe[d]); 00312 int ddup = 00313 !p ? nulld : d==BLOCXX_IN ? p->getInputHandle() : p->getOutputHandle(); 00314 check(::dup2(ddup, d) != -1, "dup2"); 00315 } 00316 } 00317 00318 void PreExec::closePipesOnExec(pipe_pointer_t const ppipe[]) 00319 { 00320 for (unsigned d = 0; d < BLOCXX_NPIPE; ++d) 00321 { 00322 UnnamedPipe* p = ppipe[d]; 00323 if (p) 00324 { 00325 close_on_exec(p->getInputDescriptor(), false); 00326 close_on_exec(p->getOutputDescriptor(), false); 00327 } 00328 } 00329 } 00330 00331 void PreExec::setNewProcessGroup() 00332 { 00333 int pgidrv = setpgid(0, 0); 00334 BLOCXX_ASSERT(pgidrv == 0); 00335 } 00336 00337 PreExec::PreExec(bool precompute_max_descriptors) 00338 : m_max_descriptors(precompute_max_descriptors ? getMaxOpenFiles() : 0) 00339 { 00340 } 00341 00342 PreExec::~PreExec() 00343 { 00344 } 00345 00346 PreExec::DontCatch::~DontCatch() 00347 { 00348 } 00349 00350 } // end Exec namespace 00351 00352 namespace PosixExec 00353 { 00354 //----------- Standard PreExec ------------- 00355 //------------------------------------------ 00356 StandardPreExec::StandardPreExec() : PreExec(true) 00357 { 00358 } 00359 00360 bool StandardPreExec::keepStd(int) const 00361 { 00362 return true; 00363 } 00364 00365 void StandardPreExec::call(pipe_pointer_t const pparr[]) 00366 { 00367 std::vector<bool> empty; 00368 PreExec::resetSignals(); 00369 PreExec::setNewProcessGroup(); 00370 PreExec::setupStandardDescriptors(pparr); 00371 PreExec::closeDescriptorsOnExec(empty); 00372 } 00373 00374 //----------- System PreExec --------------- 00375 //------------------------------------------ 00376 SystemPreExec::SystemPreExec() : PreExec(true) 00377 { 00378 } 00379 00380 bool SystemPreExec::keepStd(int d) const 00381 { 00382 return true; // want them all unchanged 00383 } 00384 00385 void SystemPreExec::call(pipe_pointer_t const pparr[]) 00386 { 00387 std::vector<bool> empty; 00388 PreExec::resetSignals(); 00389 PreExec::setNewProcessGroup(); 00390 PreExec::closeDescriptorsOnExec(empty); 00391 } 00392 00393 ProcessRef spawnImpl(char const * exec_path, char const * const argv[], char const * const envp[], 00394 Exec::PreExec & pre_exec) 00395 { 00396 // It's important that this code be exception-safe (proper release 00397 // of resources when exception thrown), as at least one caller 00398 // (the monitor code) relies on being able to throw a DontCatch-derived 00399 // exception from pre_exec.call() in the child process and have 00400 // it propagate out of the spawn call. 00401 // 00402 parent_check(exec_path, "Exec::spawn: null exec_path"); 00403 char const * default_argv[2] = { exec_path, 0 }; 00404 if (!argv || !*argv) 00405 { 00406 argv = default_argv; 00407 } 00408 00409 // Check this here so that any exceptions or core files caused by it can 00410 // be traced to a real problem instead of the child processes just 00411 // failing for an unreportable reason. 00412 getMaxOpenFiles(); 00413 00414 UnnamedPipeRef upipe[Exec::BLOCXX_NPIPE]; 00415 UnnamedPipe* ppipe[Exec::BLOCXX_NPIPE] = {0}; 00416 00417 for (unsigned i = 0; i < Exec::BLOCXX_NPIPE; ++i) 00418 { 00419 if (i == Exec::BLOCXX_EXEC_ERR || pre_exec.keepStd(i)) 00420 { 00421 upipe[i] = UnnamedPipe::createUnnamedPipe(); 00422 ppipe[i] = upipe[i].getPtr(); 00423 } 00424 } 00425 00426 00427 ::pid_t child_pid = ::fork(); 00428 if (child_pid == 0) // child process 00429 { 00430 init_child(exec_path, argv, envp, pre_exec, ppipe); // never returns 00431 } 00432 00433 parent_check(child_pid >= 0, Format("Exec::spawn(%1): fork() failed", exec_path).c_str()); 00434 00435 Exec::close_child_ends(upipe); 00436 00437 // 10 seconds should be plenty for the child to go from fork() to execv() 00438 const Timeout SECONDS_TO_WAIT_FOR_CHILD_TO_EXEC = Timeout::relative(10); 00439 upipe[Exec::BLOCXX_EXEC_ERR]->setReadTimeout(SECONDS_TO_WAIT_FOR_CHILD_TO_EXEC); 00440 00441 ProcessRef retval(new Process(upipe[0], upipe[1], upipe[2], child_pid)); 00442 00443 00444 Exec::PreExec::Error child_error; 00445 int nread = upipe[Exec::BLOCXX_EXEC_ERR]->read(&child_error, sizeof(child_error)); 00446 handle_child_error(nread, child_error, *retval, exec_path); 00447 00448 return retval; 00449 } 00450 00451 } // end PosixExec namespace 00452 00453 } // end BLOCXX_NAMESPACE 00454 00455 #endif