// ssystem.cxx #include "dataset_util/ssystem.h" #include "dataset_util/Environment.h" #include "dataset_util/FileStatus.h" #include "dataset_util/WorkingDirectory.h" #include "dataset_util/Text.h" #include "dataset_util/TempDir.h" #include #include #include #include #include #include #include using std::string; using std::cerr; using std::endl; //********************************************************************** // Local definitions. //********************************************************************** namespace { int block_sigchld() { // Mask SIGCHLD now and forever. sigset_t blkset; sigemptyset(&blkset); sigaddset(&blkset, SIGCHLD); pthread_sigmask(SIG_BLOCK, &blkset, 0); return 0; } // Block sigchld early in C_++ startup so nono-main threads // won't intercept signals. int sigchld_blocked = block_sigchld(); } // end unnamed namespace //********************************************************************** // Functions. //********************************************************************** /* int ssystem(string com) { sigset_t blkset; sigemptyset(&blkset); sigaddset(&blkset, SIGCHLD); pthread_sigmask(SIG_UNBLOCK, &blkset, 0); return system(com.c_str()); } */ //********************************************************************** // Function. // Much of implementation copied from www.opengroup.org. int ssystem(string scmd, bool passenv) { if ( scmd.size() == 0 ) { return -3; } // Lock the working directory so no other thread can change it. WorkingDirectory wd; bool dbg = false; if ( FileStatus("DEBUG_ssystem").exists() ) { dbg = true; } const char* cmd = scmd.c_str(); int rstat; pid_t pid; struct sigaction sa, savintr, savequit; sigset_t saveblock; sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigemptyset(&savintr.sa_mask); sigemptyset(&savequit.sa_mask); sigaction(SIGINT, &sa, &savintr); sigaction(SIGQUIT, &sa, &savequit); // Fix action for SIGCHLD // April 2005 -- DIAL needs this in a few places. struct sigaction sa_chld, savechld; sigemptyset(&sa_chld.sa_mask); sa_chld.sa_flags = 0; sa_chld.sa_handler = SIG_DFL; sigemptyset(&savechld.sa_mask); sigaction(SIGCHLD, &sa_chld, &savechld); // End of fix sigaddset(&sa.sa_mask, SIGCHLD); sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock); if ((pid = fork()) == 0) { if ( dbg ) sleep(30); sigaction(SIGINT, &savintr, (struct sigaction *)0); sigaction(SIGQUIT, &savequit, (struct sigaction *)0); sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0); string newcmd; if ( passenv ) { newcmd = cmd; execl("/bin/sh", "sh", "-c", cmd, (char *)0); } else { const Environment& env = Environment::posix(); execle("/bin/sh", "sh", "-c", cmd, (char *)0, env.unsafe_env()); } cerr << "ssystem: exec call failed with error " << errno << endl; cerr << " " << strerror(14) << endl; cerr << " " << newcmd << endl; _exit(127); } if (pid == -1) { rstat = -1; /* errno comes from fork() */ } else { while (waitpid(pid, &rstat, 0) == -1) { int syserr = errno; if ( syserr == 0 ) { break; } if (syserr != EINTR){ rstat = -1; break; } } } sigaction(SIGINT, &savintr, (struct sigaction *)0); sigaction(SIGQUIT, &savequit, (struct sigaction *)0); // Restore SIGCHLD action. sigaction(SIGCHLD, &savechld, (struct sigaction *)0); sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0); if ( rstat != -1 ) { if ( WIFEXITED(rstat) ) { rstat = WEXITSTATUS(rstat); } else { rstat = -2; } } return rstat; } //********************************************************************** // Mutex. PThreadMutex& ssystem_mutex() { static PThreadMutex mtx; return mtx; } //**********************************************************************