19 #include <sys/syscall.h>
23 #include <sys/prctl.h>
27 extern char * * environ
;
33 BaseError::BaseError(const FormatOrString
& fs
, unsigned int status
)
40 BaseError
& BaseError::addPrefix(const FormatOrString
& fs
)
42 prefix_
= fs
.s
+ prefix_
;
47 SysError::SysError(const FormatOrString
& fs
)
48 : Error(format("%1%: %2%") % fs
.s
% strerror(errno
))
54 string
getEnv(const string
& key
, const string
& def
)
56 char * value
= getenv(key
.c_str());
57 return value
? string(value
) : def
;
61 Path
absPath(Path path
, Path dir
)
66 /* GNU (aka. GNU/Hurd) doesn't have any limitation on path
67 lengths and doesn't define `PATH_MAX'. */
68 char *buf
= getcwd(NULL
, 0);
72 if (!getcwd(buf
, sizeof(buf
)))
74 throw SysError("cannot get cwd");
80 path
= dir
+ "/" + path
;
82 return canonPath(path
);
86 Path
canonPath(const Path
& path
, bool resolveSymlinks
)
91 throw Error(format("not an absolute path: `%1%'") % path
);
93 string::const_iterator i
= path
.begin(), end
= path
.end();
96 /* Count the number of times we follow a symlink and stop at some
97 arbitrary (but high) limit to prevent infinite loops. */
98 unsigned int followCount
= 0, maxFollow
= 1024;
103 while (i
!= end
&& *i
== '/') i
++;
107 if (*i
== '.' && (i
+ 1 == end
|| i
[1] == '/'))
110 /* If `..', delete the last component. */
111 else if (*i
== '.' && i
+ 1 < end
&& i
[1] == '.' &&
112 (i
+ 2 == end
|| i
[2] == '/'))
114 if (!s
.empty()) s
.erase(s
.rfind('/'));
118 /* Normal component; copy it. */
121 while (i
!= end
&& *i
!= '/') s
+= *i
++;
123 /* If s points to a symlink, resolve it and restart (since
124 the symlink target might contain new symlinks). */
125 if (resolveSymlinks
&& isLink(s
)) {
126 if (++followCount
>= maxFollow
)
127 throw Error(format("infinite symlink recursion in path `%1%'") % path
);
128 temp
= absPath(readLink(s
), dirOf(s
))
130 i
= temp
.begin(); /* restart */
137 return s
.empty() ? "/" : s
;
141 Path
dirOf(const Path
& path
)
143 Path::size_type pos
= path
.rfind('/');
144 if (pos
== string::npos
)
145 throw Error(format("invalid file name `%1%'") % path
);
146 return pos
== 0 ? "/" : Path(path
, 0, pos
);
150 string
baseNameOf(const Path
& path
)
152 Path::size_type pos
= path
.rfind('/');
153 if (pos
== string::npos
)
154 throw Error(format("invalid file name `%1%'") % path
);
155 return string(path
, pos
+ 1);
159 bool isInDir(const Path
& path
, const Path
& dir
)
161 return path
[0] == '/'
162 && string(path
, 0, dir
.size()) == dir
163 && path
.size() >= dir
.size() + 2
164 && path
[dir
.size()] == '/';
168 struct stat
lstat(const Path
& path
)
171 if (lstat(path
.c_str(), &st
))
172 throw SysError(format("getting status of `%1%'") % path
);
177 bool pathExists(const Path
& path
)
182 res
= statx(AT_FDCWD
, path
.c_str(), AT_SYMLINK_NOFOLLOW
, 0, &st
);
185 res
= lstat(path
.c_str(), &st
);
187 if (!res
) return true;
188 if (errno
!= ENOENT
&& errno
!= ENOTDIR
)
189 throw SysError(format("getting status of %1%") % path
);
194 Path
readLink(const Path
& path
)
197 struct stat st
= lstat(path
);
198 if (!S_ISLNK(st
.st_mode
))
199 throw Error(format("`%1%' is not a symlink") % path
);
200 char buf
[st
.st_size
];
201 ssize_t rlsize
= readlink(path
.c_str(), buf
, st
.st_size
);
203 throw SysError(format("reading symbolic link '%1%'") % path
);
204 else if (rlsize
> st
.st_size
)
205 throw Error(format("symbolic link ‘%1%’ size overflow %2% > %3%")
206 % path
% rlsize
% st
.st_size
);
207 return string(buf
, st
.st_size
);
211 bool isLink(const Path
& path
)
213 struct stat st
= lstat(path
);
214 return S_ISLNK(st
.st_mode
);
218 DirEntries
readDirectory(const Path
& path
)
223 AutoCloseDir dir
= opendir(path
.c_str());
224 if (!dir
) throw SysError(format("opening directory `%1%'") % path
);
226 struct dirent
* dirent
;
227 while (errno
= 0, dirent
= readdir(dir
)) { /* sic */
229 string name
= dirent
->d_name
;
230 if (name
== "." || name
== "..") continue;
231 entries
.emplace_back(name
, dirent
->d_ino
, dirent
->d_type
);
233 if (errno
) throw SysError(format("reading directory `%1%'") % path
);
239 unsigned char getFileType(const Path
& path
)
241 struct stat st
= lstat(path
);
242 if (S_ISDIR(st
.st_mode
)) return DT_DIR
;
243 if (S_ISLNK(st
.st_mode
)) return DT_LNK
;
244 if (S_ISREG(st
.st_mode
)) return DT_REG
;
249 string
readFile(int fd
)
252 if (fstat(fd
, &st
) == -1)
253 throw SysError("statting file");
255 unsigned char * buf
= new unsigned char[st
.st_size
];
256 AutoDeleteArray
<unsigned char> d(buf
);
257 readFull(fd
, buf
, st
.st_size
);
259 return string((char *) buf
, st
.st_size
);
263 string
readFile(const Path
& path
, bool drain
)
265 AutoCloseFD fd
= open(path
.c_str(), O_RDONLY
);
267 throw SysError(format("opening file `%1%'") % path
);
268 return drain
? drainFD(fd
) : readFile(fd
);
272 void writeFile(const Path
& path
, const string
& s
)
274 AutoCloseFD fd
= open(path
.c_str(), O_WRONLY
| O_TRUNC
| O_CREAT
, 0666);
276 throw SysError(format("opening file '%1%'") % path
);
281 string
readLine(int fd
)
287 ssize_t rd
= read(fd
, &ch
, 1);
290 throw SysError("reading a line");
292 throw EndOfFile("unexpected EOF reading a line");
294 if (ch
== '\n') return s
;
301 void writeLine(int fd
, string s
)
308 static void _deletePath(const Path
& path
, unsigned long long & bytesFreed
, size_t linkThreshold
)
312 printMsg(lvlVomit
, format("%1%") % path
);
315 # define st_mode stx_mode
316 # define st_size stx_size
317 # define st_nlink stx_nlink
319 if (statx(AT_FDCWD
, path
.c_str(),
321 STATX_SIZE
| STATX_NLINK
| STATX_MODE
, &st
) == -1)
322 throw SysError(format("getting status of `%1%'") % path
);
324 struct stat st
= lstat(path
);
327 if (!S_ISDIR(st
.st_mode
) && st
.st_nlink
<= linkThreshold
)
328 bytesFreed
+= st
.st_size
;
330 if (S_ISDIR(st
.st_mode
)) {
331 /* Make the directory writable. */
332 if (!(st
.st_mode
& S_IWUSR
)) {
333 if (chmod(path
.c_str(), st
.st_mode
| S_IWUSR
) == -1)
334 throw SysError(format("making `%1%' writable") % path
);
337 for (auto & i
: readDirectory(path
))
338 _deletePath(path
+ "/" + i
.name
, bytesFreed
, linkThreshold
);
344 if (remove(path
.c_str()) == -1)
345 throw SysError(format("cannot unlink `%1%'") % path
);
349 void deletePath(const Path
& path
)
351 unsigned long long dummy
;
352 deletePath(path
, dummy
);
356 void deletePath(const Path
& path
, unsigned long long & bytesFreed
, size_t linkThreshold
)
358 startNest(nest
, lvlDebug
,
359 format("recursively deleting path `%1%'") % path
);
361 _deletePath(path
, bytesFreed
, linkThreshold
);
365 static Path
tempName(Path tmpRoot
, const Path
& prefix
, bool includePid
,
368 tmpRoot
= canonPath(tmpRoot
.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot
, true);
370 return (format("%1%/%2%-%3%-%4%") % tmpRoot
% prefix
% getpid() % counter
++).str();
372 return (format("%1%/%2%-%3%") % tmpRoot
% prefix
% counter
++).str();
376 Path
createTempDir(const Path
& tmpRoot
, const Path
& prefix
,
377 bool includePid
, bool useGlobalCounter
, mode_t mode
)
379 static int globalCounter
= 0;
380 int localCounter
= 0;
381 int & counter(useGlobalCounter
? globalCounter
: localCounter
);
385 Path tmpDir
= tempName(tmpRoot
, prefix
, includePid
, counter
);
386 if (mkdir(tmpDir
.c_str(), mode
) == 0) {
387 /* Explicitly set the group of the directory. This is to
388 work around around problems caused by BSD's group
389 ownership semantics (directories inherit the group of
390 the parent). For instance, the group of /tmp on
391 FreeBSD is "wheel", so all directories created in /tmp
392 will be owned by "wheel"; but if the user is not in
393 "wheel", then "tar" will fail to unpack archives that
394 have the setgid bit set on directories. */
395 if (chown(tmpDir
.c_str(), (uid_t
) -1, getegid()) != 0)
396 throw SysError(format("setting group of directory `%1%'") % tmpDir
);
400 throw SysError(format("creating directory `%1%'") % tmpDir
);
405 Paths
createDirs(const Path
& path
)
408 if (path
== "/") return created
;
411 if (lstat(path
.c_str(), &st
) == -1) {
412 created
= createDirs(dirOf(path
));
413 if (mkdir(path
.c_str(), 0777) == -1 && errno
!= EEXIST
)
414 throw SysError(format("creating directory `%1%'") % path
);
416 created
.push_back(path
);
419 if (S_ISLNK(st
.st_mode
) && stat(path
.c_str(), &st
) == -1)
420 throw SysError(format("statting symlink `%1%'") % path
);
422 if (!S_ISDIR(st
.st_mode
)) throw Error(format("`%1%' is not a directory") % path
);
428 void createSymlink(const Path
& target
, const Path
& link
)
430 if (symlink(target
.c_str(), link
.c_str()))
431 throw SysError(format("creating symlink from `%1%' to `%2%'") % link
% target
);
435 LogType logType
= ltPretty
;
436 Verbosity verbosity
= lvlInfo
;
438 static int nestingLevel
= 0;
453 static string
escVerbosity(Verbosity level
)
455 return std::to_string((int) level
);
459 void Nest::open(Verbosity level
, const FormatOrString
& fs
)
461 if (level
<= verbosity
) {
462 if (logType
== ltEscapes
)
463 std::cerr
<< "\033[" << escVerbosity(level
) << "p"
466 printMsg_(level
, fs
);
477 if (logType
== ltEscapes
)
478 std::cerr
<< "\033[q";
484 void printMsg_(Verbosity level
, const FormatOrString
& fs
)
487 if (level
> verbosity
) return;
489 if (logType
== ltPretty
)
490 for (int i
= 0; i
< nestingLevel
; i
++)
492 else if (logType
== ltEscapes
&& level
!= lvlInfo
)
493 prefix
= "\033[" + escVerbosity(level
) + "s";
494 string s
= (format("%1%%2%\n") % prefix
% fs
.s
).str();
499 void warnOnce(bool & haveWarned
, const FormatOrString
& fs
)
502 printMsg(lvlError
, format("warning: %1%") % fs
.s
);
508 void writeToStderr(const string
& s
)
512 _writeToStderr((const unsigned char *) s
.data(), s
.size());
514 writeFull(STDERR_FILENO
, s
);
515 } catch (SysError
& e
) {
516 /* Ignore failing writes to stderr if we're in an exception
517 handler, otherwise throw an exception. We need to ignore
518 write errors in exception handlers to ensure that cleanup
519 code runs to completion if the other side of stderr has
520 been closed unexpectedly. */
521 if (!std::uncaught_exception()) throw;
526 void (*_writeToStderr
) (const unsigned char * buf
, size_t count
) = 0;
529 void readFull(int fd
, unsigned char * buf
, size_t count
)
533 ssize_t res
= read(fd
, (char *) buf
, count
);
535 if (errno
== EINTR
) continue;
536 throw SysError("reading from file");
538 if (res
== 0) throw EndOfFile("unexpected end-of-file");
545 void writeFull(int fd
, const unsigned char * buf
, size_t count
)
549 ssize_t res
= write(fd
, (char *) buf
, count
);
551 if (errno
== EINTR
) continue;
552 throw SysError("writing to file");
560 void writeFull(int fd
, const string
& s
)
562 writeFull(fd
, (const unsigned char *) s
.data(), s
.size());
566 string
drainFD(int fd
)
569 unsigned char buffer
[4096];
572 ssize_t rd
= read(fd
, buffer
, sizeof buffer
);
575 throw SysError("reading from file");
577 else if (rd
== 0) break;
578 else result
.append((char *) buffer
, rd
);
585 //////////////////////////////////////////////////////////////////////
588 AutoDelete::AutoDelete(const string
& p
, bool recursive
) : path(p
)
591 this->recursive
= recursive
;
594 AutoDelete::~AutoDelete()
601 if (remove(path
.c_str()) == -1)
602 throw SysError(format("cannot unlink `%1%'") % path
);
610 void AutoDelete::cancel()
617 //////////////////////////////////////////////////////////////////////
620 AutoCloseFD::AutoCloseFD()
626 AutoCloseFD::AutoCloseFD(int fd
)
632 AutoCloseFD::AutoCloseFD(const AutoCloseFD
& fd
)
634 /* Copying an AutoCloseFD isn't allowed (who should get to close
635 it?). But as an edge case, allow copying of closed
636 AutoCloseFDs. This is necessary due to tiresome reasons
637 involving copy constructor use on default object values in STL
638 containers (like when you do `map[value]' where value isn't in
641 if (this->fd
!= -1) abort();
645 AutoCloseFD::~AutoCloseFD()
655 void AutoCloseFD::operator =(int fd
)
657 if (this->fd
!= fd
) close();
662 AutoCloseFD::operator int() const
668 void AutoCloseFD::close()
671 if (::close(fd
) == -1)
672 /* This should never happen. */
673 throw SysError(format("closing file descriptor %1%") % fd
);
679 bool AutoCloseFD::isOpen()
685 /* Pass responsibility for closing this fd to the caller. */
686 int AutoCloseFD::borrow()
697 if (pipe(fds
) != 0) throw SysError("creating pipe");
700 closeOnExec(readSide
);
701 closeOnExec(writeSide
);
706 //////////////////////////////////////////////////////////////////////
709 AutoCloseDir::AutoCloseDir()
715 AutoCloseDir::AutoCloseDir(DIR * dir
)
721 AutoCloseDir::~AutoCloseDir()
727 void AutoCloseDir::operator =(DIR * dir
)
733 AutoCloseDir::operator DIR *()
739 void AutoCloseDir::close()
748 //////////////////////////////////////////////////////////////////////
752 : pid(-1), separatePG(false), killSignal(SIGKILL
)
758 : pid(pid
), separatePG(false), killSignal(SIGKILL
)
769 void Pid::operator =(pid_t pid
)
771 if (this->pid
!= pid
) kill();
773 killSignal
= SIGKILL
; // reset signal to default
777 Pid::operator pid_t()
783 void Pid::kill(bool quiet
)
785 if (pid
== -1 || pid
== 0) return;
788 printMsg(lvlError
, format("killing process %1%") % pid
);
790 /* Send the requested signal to the child. If it has its own
791 process group, send the signal to every process in the child
792 process group (which hopefully includes *all* its children). */
793 if (::kill(separatePG
? -pid
: pid
, killSignal
) != 0)
794 printMsg(lvlError
, (SysError(format("killing process %1%") % pid
).msg()));
796 /* Wait until the child dies, disregarding the exit status. */
798 while (waitpid(pid
, &status
, 0) == -1) {
800 if (errno
!= EINTR
) {
802 (SysError(format("waiting for process %1%") % pid
).msg()));
811 int Pid::wait(bool block
)
816 int res
= waitpid(pid
, &status
, block
? 0 : WNOHANG
);
821 if (res
== 0 && !block
) return -1;
823 throw SysError("cannot get child exit status");
829 void Pid::setSeparatePG(bool separatePG
)
831 this->separatePG
= separatePG
;
835 void Pid::setKillSignal(int signal
)
837 this->killSignal
= signal
;
841 void killUser(uid_t uid
)
843 debug(format("killing all processes running under uid `%1%'") % uid
);
845 assert(uid
!= 0); /* just to be safe... */
847 /* The system call kill(-1, sig) sends the signal `sig' to all
848 users to which the current process can send signals. So we
849 fork a process, switch to uid, and send a mass kill. */
851 Pid pid
= startProcess([&]() {
853 if (setuid(uid
) == -1)
854 throw SysError("setting uid");
858 /* OSX's kill syscall takes a third parameter that, among
859 other things, determines if kill(-1, signo) affects the
860 calling process. In the OSX libc, it's set to true,
861 which means "follow POSIX", which we don't want here
863 if (syscall(SYS_kill
, -1, SIGKILL
, false) == 0) break;
865 /* Killing all a user's processes using PID=-1 does currently
866 not work on the Hurd. */
867 if (kill(getpid(), SIGKILL
) == 0) break;
869 if (kill(-1, SIGKILL
) == 0) break;
871 if (errno
== ESRCH
) break; /* no more processes */
873 throw SysError(format("cannot kill processes for uid `%1%'") % uid
);
879 int status
= pid
.wait(true);
881 /* When the child killed itself, status = SIGKILL. */
882 if (status
== SIGKILL
) return;
885 throw Error(format("cannot kill processes for uid `%1%': %2%") % uid
% statusToString(status
));
887 /* !!! We should really do some check to make sure that there are
888 no processes left running under `uid', but there is no portable
889 way to do so (I think). The most reliable way may be `ps -eo
890 uid | grep -q $uid'. */
894 //////////////////////////////////////////////////////////////////////
897 pid_t
startProcess(std::function
<void()> fun
,
898 bool dieWithParent
, const string
& errorPrefix
, bool runExitHandlers
)
901 if (pid
== -1) throw SysError("unable to fork");
907 if (dieWithParent
&& prctl(PR_SET_PDEATHSIG
, SIGKILL
) == -1)
908 throw SysError("setting death signal");
912 } catch (std::exception
& e
) {
914 std::cerr
<< errorPrefix
<< e
.what() << "\n";
927 std::vector
<char *> stringsToCharPtrs(const Strings
& ss
)
929 std::vector
<char *> res
;
930 for (auto & s
: ss
) res
.push_back((char *) s
.c_str());
936 string
runProgram(Path program
, bool searchPath
, const Strings
& args
)
945 Pid pid
= startProcess([&]() {
946 if (dup2(pipe
.writeSide
, STDOUT_FILENO
) == -1)
947 throw SysError("dupping stdout");
950 args_
.push_front(program
);
953 execvp(program
.c_str(), stringsToCharPtrs(args_
).data());
955 execv(program
.c_str(), stringsToCharPtrs(args_
).data());
957 throw SysError(format("executing `%1%'") % program
);
960 pipe
.writeSide
.close();
962 string result
= drainFD(pipe
.readSide
);
964 /* Wait for the child to finish. */
965 int status
= pid
.wait(true);
966 if (!statusOk(status
))
967 throw ExecError(format("program `%1%' %2%")
968 % program
% statusToString(status
));
974 void closeMostFDs(const set
<int> & exceptions
)
977 maxFD
= sysconf(_SC_OPEN_MAX
);
978 for (int fd
= 0; fd
< maxFD
; ++fd
)
979 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
980 && exceptions
.find(fd
) == exceptions
.end())
981 close(fd
); /* ignore result */
985 void closeOnExec(int fd
)
988 if ((prev
= fcntl(fd
, F_GETFD
, 0)) == -1 ||
989 fcntl(fd
, F_SETFD
, prev
| FD_CLOEXEC
) == -1)
990 throw SysError("setting close-on-exec flag");
994 //////////////////////////////////////////////////////////////////////
997 volatile sig_atomic_t _isInterrupted
= 0;
1001 /* Block user interrupts while an exception is being handled.
1002 Throwing an exception while another exception is being handled
1003 kills the program! */
1004 if (!std::uncaught_exception()) {
1006 throw Interrupted("interrupted by the user");
1012 //////////////////////////////////////////////////////////////////////
1015 template<class C
> C
tokenizeString(const string
& s
, const string
& separators
)
1018 string::size_type pos
= s
.find_first_not_of(separators
, 0);
1019 while (pos
!= string::npos
) {
1020 string::size_type end
= s
.find_first_of(separators
, pos
+ 1);
1021 if (end
== string::npos
) end
= s
.size();
1022 string
token(s
, pos
, end
- pos
);
1023 result
.insert(result
.end(), token
);
1024 pos
= s
.find_first_not_of(separators
, end
);
1029 template Strings
tokenizeString(const string
& s
, const string
& separators
);
1030 template StringSet
tokenizeString(const string
& s
, const string
& separators
);
1031 template vector
<string
> tokenizeString(const string
& s
, const string
& separators
);
1034 string
concatStringsSep(const string
& sep
, const Strings
& ss
)
1037 foreach (Strings::const_iterator
, i
, ss
) {
1038 if (s
.size() != 0) s
+= sep
;
1045 string
concatStringsSep(const string
& sep
, const StringSet
& ss
)
1048 foreach (StringSet::const_iterator
, i
, ss
) {
1049 if (s
.size() != 0) s
+= sep
;
1056 string
chomp(const string
& s
)
1058 size_t i
= s
.find_last_not_of(" \n\r\t");
1059 return i
== string::npos
? "" : string(s
, 0, i
+ 1);
1063 string
statusToString(int status
)
1065 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0) {
1066 if (WIFEXITED(status
))
1067 return (format("failed with exit code %1%") % WEXITSTATUS(status
)).str();
1068 else if (WIFSIGNALED(status
)) {
1069 int sig
= WTERMSIG(status
);
1071 const char * description
= strsignal(sig
);
1072 return (format("failed due to signal %1% (%2%)") % sig
% description
).str();
1074 return (format("failed due to signal %1%") % sig
).str();
1078 return "died abnormally";
1079 } else return "succeeded";
1083 bool statusOk(int status
)
1085 return WIFEXITED(status
) && WEXITSTATUS(status
) == 0;
1089 bool hasSuffix(const string
& s
, const string
& suffix
)
1091 return s
.size() >= suffix
.size() && string(s
, s
.size() - suffix
.size()) == suffix
;
1095 void expect(std::istream
& str
, const string
& s
)
1098 str
.read(s2
, s
.size());
1099 if (string(s2
, s
.size()) != s
)
1100 throw FormatError(format("expected string `%1%'") % s
);
1104 string
parseString(std::istream
& str
)
1109 while ((c
= str
.get()) != '"')
1112 if (c
== 'n') res
+= '\n';
1113 else if (c
== 'r') res
+= '\r';
1114 else if (c
== 't') res
+= '\t';
1122 bool endOfList(std::istream
& str
)
1124 if (str
.peek() == ',') {
1128 if (str
.peek() == ']') {
1136 void ignoreException()
1140 } catch (std::exception
& e
) {
1141 printMsg(lvlError
, format("error (ignored): %1%") % e
.what());
1145 static const string pathNullDevice
= "/dev/null";
1147 /* Common initialisation performed in child processes. */
1148 void commonChildInit(Pipe
& logPipe
)
1150 /* Put the child in a separate session (and thus a separate
1151 process group) so that it has no controlling terminal (meaning
1152 that e.g. ssh cannot open /dev/tty) and it doesn't receive
1153 terminal signals. */
1155 throw SysError(format("creating a new session"));
1157 /* Dup the write side of the logger pipe into stderr. */
1158 if (dup2(logPipe
.writeSide
, STDERR_FILENO
) == -1)
1159 throw SysError("cannot pipe standard error into log file");
1161 /* Dup stderr to stdout. */
1162 if (dup2(STDERR_FILENO
, STDOUT_FILENO
) == -1)
1163 throw SysError("cannot dup stderr into stdout");
1165 /* Reroute stdin to /dev/null. */
1166 int fdDevNull
= open(pathNullDevice
.c_str(), O_RDWR
);
1167 if (fdDevNull
== -1)
1168 throw SysError(format("cannot open `%1%'") % pathNullDevice
);
1169 if (dup2(fdDevNull
, STDIN_FILENO
) == -1)
1170 throw SysError("cannot dup null device into stdin");
1174 //////////////////////////////////////////////////////////////////////
1176 Agent::Agent(const string
&command
, const Strings
&args
)
1178 debug(format("starting agent '%1%'") % command
);
1180 /* Create a pipe to get the output of the child. */
1183 /* Create the communication pipes. */
1186 /* Create a pipe to get the output of the builder. */
1187 builderOut
.create();
1189 /* Fork the hook. */
1190 pid
= startProcess([&]() {
1192 commonChildInit(fromAgent
);
1194 if (chdir("/") == -1) throw SysError("changing into `/");
1196 /* Dup the communication pipes. */
1197 if (dup2(toAgent
.readSide
, STDIN_FILENO
) == -1)
1198 throw SysError("dupping to-hook read side");
1200 /* Use fd 4 for the builder's stdout/stderr. */
1201 if (dup2(builderOut
.writeSide
, 4) == -1)
1202 throw SysError("dupping builder's stdout/stderr");
1205 allArgs
.push_back(command
);
1206 allArgs
.insert(allArgs
.end(), args
.begin(), args
.end()); // append
1208 execv(command
.c_str(), stringsToCharPtrs(allArgs
).data());
1210 throw SysError(format("executing `%1%'") % command
);
1213 pid
.setSeparatePG(true);
1214 fromAgent
.writeSide
.close();
1215 toAgent
.readSide
.close();
1222 toAgent
.writeSide
.close();