gnu: surgescript: Update to 0.5.4.4.
[jackhill/guix/guix.git] / nix / libutil / util.cc
1 #include "config.h"
2
3 #include "util.hh"
4 #include "affinity.hh"
5
6 #include <iostream>
7 #include <cerrno>
8 #include <cstdio>
9 #include <cstdlib>
10 #include <sstream>
11 #include <cstring>
12
13 #include <sys/wait.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <limits.h>
17
18 #ifdef __APPLE__
19 #include <sys/syscall.h>
20 #endif
21
22 #ifdef __linux__
23 #include <sys/prctl.h>
24 #endif
25
26
27 extern char * * environ;
28
29
30 namespace nix {
31
32
33 BaseError::BaseError(const FormatOrString & fs, unsigned int status)
34 : status(status)
35 {
36 err = fs.s;
37 }
38
39
40 BaseError & BaseError::addPrefix(const FormatOrString & fs)
41 {
42 prefix_ = fs.s + prefix_;
43 return *this;
44 }
45
46
47 SysError::SysError(const FormatOrString & fs)
48 : Error(format("%1%: %2%") % fs.s % strerror(errno))
49 , errNo(errno)
50 {
51 }
52
53
54 string getEnv(const string & key, const string & def)
55 {
56 char * value = getenv(key.c_str());
57 return value ? string(value) : def;
58 }
59
60
61 Path absPath(Path path, Path dir)
62 {
63 if (path[0] != '/') {
64 if (dir == "") {
65 #ifdef __GNU__
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);
69 if (buf == NULL)
70 #else
71 char buf[PATH_MAX];
72 if (!getcwd(buf, sizeof(buf)))
73 #endif
74 throw SysError("cannot get cwd");
75 dir = buf;
76 #ifdef __GNU__
77 free(buf);
78 #endif
79 }
80 path = dir + "/" + path;
81 }
82 return canonPath(path);
83 }
84
85
86 Path canonPath(const Path & path, bool resolveSymlinks)
87 {
88 string s;
89
90 if (path[0] != '/')
91 throw Error(format("not an absolute path: `%1%'") % path);
92
93 string::const_iterator i = path.begin(), end = path.end();
94 string temp;
95
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;
99
100 while (1) {
101
102 /* Skip slashes. */
103 while (i != end && *i == '/') i++;
104 if (i == end) break;
105
106 /* Ignore `.'. */
107 if (*i == '.' && (i + 1 == end || i[1] == '/'))
108 i++;
109
110 /* If `..', delete the last component. */
111 else if (*i == '.' && i + 1 < end && i[1] == '.' &&
112 (i + 2 == end || i[2] == '/'))
113 {
114 if (!s.empty()) s.erase(s.rfind('/'));
115 i += 2;
116 }
117
118 /* Normal component; copy it. */
119 else {
120 s += '/';
121 while (i != end && *i != '/') s += *i++;
122
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))
129 + string(i, end);
130 i = temp.begin(); /* restart */
131 end = temp.end();
132 s = "";
133 }
134 }
135 }
136
137 return s.empty() ? "/" : s;
138 }
139
140
141 Path dirOf(const Path & path)
142 {
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);
147 }
148
149
150 string baseNameOf(const Path & path)
151 {
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);
156 }
157
158
159 bool isInDir(const Path & path, const Path & dir)
160 {
161 return path[0] == '/'
162 && string(path, 0, dir.size()) == dir
163 && path.size() >= dir.size() + 2
164 && path[dir.size()] == '/';
165 }
166
167
168 struct stat lstat(const Path & path)
169 {
170 struct stat st;
171 if (lstat(path.c_str(), &st))
172 throw SysError(format("getting status of `%1%'") % path);
173 return st;
174 }
175
176
177 bool pathExists(const Path & path)
178 {
179 int res;
180 #ifdef HAVE_STATX
181 struct statx st;
182 res = statx(AT_FDCWD, path.c_str(), AT_SYMLINK_NOFOLLOW, 0, &st);
183 #else
184 struct stat st;
185 res = lstat(path.c_str(), &st);
186 #endif
187 if (!res) return true;
188 if (errno != ENOENT && errno != ENOTDIR)
189 throw SysError(format("getting status of %1%") % path);
190 return false;
191 }
192
193
194 Path readLink(const Path & path)
195 {
196 checkInterrupt();
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);
202 if (rlsize == -1)
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);
208 }
209
210
211 bool isLink(const Path & path)
212 {
213 struct stat st = lstat(path);
214 return S_ISLNK(st.st_mode);
215 }
216
217
218 DirEntries readDirectory(const Path & path)
219 {
220 DirEntries entries;
221 entries.reserve(64);
222
223 AutoCloseDir dir = opendir(path.c_str());
224 if (!dir) throw SysError(format("opening directory `%1%'") % path);
225
226 struct dirent * dirent;
227 while (errno = 0, dirent = readdir(dir)) { /* sic */
228 checkInterrupt();
229 string name = dirent->d_name;
230 if (name == "." || name == "..") continue;
231 entries.emplace_back(name, dirent->d_ino, dirent->d_type);
232 }
233 if (errno) throw SysError(format("reading directory `%1%'") % path);
234
235 return entries;
236 }
237
238
239 unsigned char getFileType(const Path & path)
240 {
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;
245 return DT_UNKNOWN;
246 }
247
248
249 string readFile(int fd)
250 {
251 struct stat st;
252 if (fstat(fd, &st) == -1)
253 throw SysError("statting file");
254
255 unsigned char * buf = new unsigned char[st.st_size];
256 AutoDeleteArray<unsigned char> d(buf);
257 readFull(fd, buf, st.st_size);
258
259 return string((char *) buf, st.st_size);
260 }
261
262
263 string readFile(const Path & path, bool drain)
264 {
265 AutoCloseFD fd = open(path.c_str(), O_RDONLY);
266 if (fd == -1)
267 throw SysError(format("opening file `%1%'") % path);
268 return drain ? drainFD(fd) : readFile(fd);
269 }
270
271
272 void writeFile(const Path & path, const string & s)
273 {
274 AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
275 if (fd == -1)
276 throw SysError(format("opening file '%1%'") % path);
277 writeFull(fd, s);
278 }
279
280
281 string readLine(int fd)
282 {
283 string s;
284 while (1) {
285 checkInterrupt();
286 char ch;
287 ssize_t rd = read(fd, &ch, 1);
288 if (rd == -1) {
289 if (errno != EINTR)
290 throw SysError("reading a line");
291 } else if (rd == 0)
292 throw EndOfFile("unexpected EOF reading a line");
293 else {
294 if (ch == '\n') return s;
295 s += ch;
296 }
297 }
298 }
299
300
301 void writeLine(int fd, string s)
302 {
303 s += '\n';
304 writeFull(fd, s);
305 }
306
307
308 static void _deletePath(const Path & path, unsigned long long & bytesFreed, size_t linkThreshold)
309 {
310 checkInterrupt();
311
312 printMsg(lvlVomit, format("%1%") % path);
313
314 #ifdef HAVE_STATX
315 # define st_mode stx_mode
316 # define st_size stx_size
317 # define st_nlink stx_nlink
318 struct statx st;
319 if (statx(AT_FDCWD, path.c_str(),
320 AT_SYMLINK_NOFOLLOW,
321 STATX_SIZE | STATX_NLINK | STATX_MODE, &st) == -1)
322 throw SysError(format("getting status of `%1%'") % path);
323 #else
324 struct stat st = lstat(path);
325 #endif
326
327 if (!S_ISDIR(st.st_mode) && st.st_nlink <= linkThreshold)
328 bytesFreed += st.st_size;
329
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);
335 }
336
337 for (auto & i : readDirectory(path))
338 _deletePath(path + "/" + i.name, bytesFreed, linkThreshold);
339 }
340 #undef st_mode
341 #undef st_size
342 #undef st_nlink
343
344 if (remove(path.c_str()) == -1)
345 throw SysError(format("cannot unlink `%1%'") % path);
346 }
347
348
349 void deletePath(const Path & path)
350 {
351 unsigned long long dummy;
352 deletePath(path, dummy);
353 }
354
355
356 void deletePath(const Path & path, unsigned long long & bytesFreed, size_t linkThreshold)
357 {
358 startNest(nest, lvlDebug,
359 format("recursively deleting path `%1%'") % path);
360 bytesFreed = 0;
361 _deletePath(path, bytesFreed, linkThreshold);
362 }
363
364
365 static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
366 int & counter)
367 {
368 tmpRoot = canonPath(tmpRoot.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot, true);
369 if (includePid)
370 return (format("%1%/%2%-%3%-%4%") % tmpRoot % prefix % getpid() % counter++).str();
371 else
372 return (format("%1%/%2%-%3%") % tmpRoot % prefix % counter++).str();
373 }
374
375
376 Path createTempDir(const Path & tmpRoot, const Path & prefix,
377 bool includePid, bool useGlobalCounter, mode_t mode)
378 {
379 static int globalCounter = 0;
380 int localCounter = 0;
381 int & counter(useGlobalCounter ? globalCounter : localCounter);
382
383 while (1) {
384 checkInterrupt();
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);
397 return tmpDir;
398 }
399 if (errno != EEXIST)
400 throw SysError(format("creating directory `%1%'") % tmpDir);
401 }
402 }
403
404
405 Paths createDirs(const Path & path)
406 {
407 Paths created;
408 if (path == "/") return created;
409
410 struct stat st;
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);
415 st = lstat(path);
416 created.push_back(path);
417 }
418
419 if (S_ISLNK(st.st_mode) && stat(path.c_str(), &st) == -1)
420 throw SysError(format("statting symlink `%1%'") % path);
421
422 if (!S_ISDIR(st.st_mode)) throw Error(format("`%1%' is not a directory") % path);
423
424 return created;
425 }
426
427
428 void createSymlink(const Path & target, const Path & link)
429 {
430 if (symlink(target.c_str(), link.c_str()))
431 throw SysError(format("creating symlink from `%1%' to `%2%'") % link % target);
432 }
433
434
435 LogType logType = ltPretty;
436 Verbosity verbosity = lvlInfo;
437
438 static int nestingLevel = 0;
439
440
441 Nest::Nest()
442 {
443 nest = false;
444 }
445
446
447 Nest::~Nest()
448 {
449 close();
450 }
451
452
453 static string escVerbosity(Verbosity level)
454 {
455 return std::to_string((int) level);
456 }
457
458
459 void Nest::open(Verbosity level, const FormatOrString & fs)
460 {
461 if (level <= verbosity) {
462 if (logType == ltEscapes)
463 std::cerr << "\033[" << escVerbosity(level) << "p"
464 << fs.s << "\n";
465 else
466 printMsg_(level, fs);
467 nest = true;
468 nestingLevel++;
469 }
470 }
471
472
473 void Nest::close()
474 {
475 if (nest) {
476 nestingLevel--;
477 if (logType == ltEscapes)
478 std::cerr << "\033[q";
479 nest = false;
480 }
481 }
482
483
484 void printMsg_(Verbosity level, const FormatOrString & fs)
485 {
486 checkInterrupt();
487 if (level > verbosity) return;
488 string prefix;
489 if (logType == ltPretty)
490 for (int i = 0; i < nestingLevel; i++)
491 prefix += "| ";
492 else if (logType == ltEscapes && level != lvlInfo)
493 prefix = "\033[" + escVerbosity(level) + "s";
494 string s = (format("%1%%2%\n") % prefix % fs.s).str();
495 writeToStderr(s);
496 }
497
498
499 void warnOnce(bool & haveWarned, const FormatOrString & fs)
500 {
501 if (!haveWarned) {
502 printMsg(lvlError, format("warning: %1%") % fs.s);
503 haveWarned = true;
504 }
505 }
506
507
508 void writeToStderr(const string & s)
509 {
510 try {
511 if (_writeToStderr)
512 _writeToStderr((const unsigned char *) s.data(), s.size());
513 else
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;
522 }
523 }
524
525
526 void (*_writeToStderr) (const unsigned char * buf, size_t count) = 0;
527
528
529 void readFull(int fd, unsigned char * buf, size_t count)
530 {
531 while (count) {
532 checkInterrupt();
533 ssize_t res = read(fd, (char *) buf, count);
534 if (res == -1) {
535 if (errno == EINTR) continue;
536 throw SysError("reading from file");
537 }
538 if (res == 0) throw EndOfFile("unexpected end-of-file");
539 count -= res;
540 buf += res;
541 }
542 }
543
544
545 void writeFull(int fd, const unsigned char * buf, size_t count)
546 {
547 while (count) {
548 checkInterrupt();
549 ssize_t res = write(fd, (char *) buf, count);
550 if (res == -1) {
551 if (errno == EINTR) continue;
552 throw SysError("writing to file");
553 }
554 count -= res;
555 buf += res;
556 }
557 }
558
559
560 void writeFull(int fd, const string & s)
561 {
562 writeFull(fd, (const unsigned char *) s.data(), s.size());
563 }
564
565
566 string drainFD(int fd)
567 {
568 string result;
569 unsigned char buffer[4096];
570 while (1) {
571 checkInterrupt();
572 ssize_t rd = read(fd, buffer, sizeof buffer);
573 if (rd == -1) {
574 if (errno != EINTR)
575 throw SysError("reading from file");
576 }
577 else if (rd == 0) break;
578 else result.append((char *) buffer, rd);
579 }
580 return result;
581 }
582
583
584
585 //////////////////////////////////////////////////////////////////////
586
587
588 AutoDelete::AutoDelete(const string & p, bool recursive) : path(p)
589 {
590 del = true;
591 this->recursive = recursive;
592 }
593
594 AutoDelete::~AutoDelete()
595 {
596 try {
597 if (del) {
598 if (recursive)
599 deletePath(path);
600 else {
601 if (remove(path.c_str()) == -1)
602 throw SysError(format("cannot unlink `%1%'") % path);
603 }
604 }
605 } catch (...) {
606 ignoreException();
607 }
608 }
609
610 void AutoDelete::cancel()
611 {
612 del = false;
613 }
614
615
616
617 //////////////////////////////////////////////////////////////////////
618
619
620 AutoCloseFD::AutoCloseFD()
621 {
622 fd = -1;
623 }
624
625
626 AutoCloseFD::AutoCloseFD(int fd)
627 {
628 this->fd = fd;
629 }
630
631
632 AutoCloseFD::AutoCloseFD(const AutoCloseFD & fd)
633 {
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
639 the map yet). */
640 this->fd = fd.fd;
641 if (this->fd != -1) abort();
642 }
643
644
645 AutoCloseFD::~AutoCloseFD()
646 {
647 try {
648 close();
649 } catch (...) {
650 ignoreException();
651 }
652 }
653
654
655 void AutoCloseFD::operator =(int fd)
656 {
657 if (this->fd != fd) close();
658 this->fd = fd;
659 }
660
661
662 AutoCloseFD::operator int() const
663 {
664 return fd;
665 }
666
667
668 void AutoCloseFD::close()
669 {
670 if (fd != -1) {
671 if (::close(fd) == -1)
672 /* This should never happen. */
673 throw SysError(format("closing file descriptor %1%") % fd);
674 fd = -1;
675 }
676 }
677
678
679 bool AutoCloseFD::isOpen()
680 {
681 return fd != -1;
682 }
683
684
685 /* Pass responsibility for closing this fd to the caller. */
686 int AutoCloseFD::borrow()
687 {
688 int oldFD = fd;
689 fd = -1;
690 return oldFD;
691 }
692
693
694 void Pipe::create()
695 {
696 int fds[2];
697 if (pipe(fds) != 0) throw SysError("creating pipe");
698 readSide = fds[0];
699 writeSide = fds[1];
700 closeOnExec(readSide);
701 closeOnExec(writeSide);
702 }
703
704
705
706 //////////////////////////////////////////////////////////////////////
707
708
709 AutoCloseDir::AutoCloseDir()
710 {
711 dir = 0;
712 }
713
714
715 AutoCloseDir::AutoCloseDir(DIR * dir)
716 {
717 this->dir = dir;
718 }
719
720
721 AutoCloseDir::~AutoCloseDir()
722 {
723 close();
724 }
725
726
727 void AutoCloseDir::operator =(DIR * dir)
728 {
729 this->dir = dir;
730 }
731
732
733 AutoCloseDir::operator DIR *()
734 {
735 return dir;
736 }
737
738
739 void AutoCloseDir::close()
740 {
741 if (dir) {
742 closedir(dir);
743 dir = 0;
744 }
745 }
746
747
748 //////////////////////////////////////////////////////////////////////
749
750
751 Pid::Pid()
752 : pid(-1), separatePG(false), killSignal(SIGKILL)
753 {
754 }
755
756
757 Pid::Pid(pid_t pid)
758 : pid(pid), separatePG(false), killSignal(SIGKILL)
759 {
760 }
761
762
763 Pid::~Pid()
764 {
765 kill();
766 }
767
768
769 void Pid::operator =(pid_t pid)
770 {
771 if (this->pid != pid) kill();
772 this->pid = pid;
773 killSignal = SIGKILL; // reset signal to default
774 }
775
776
777 Pid::operator pid_t()
778 {
779 return pid;
780 }
781
782
783 void Pid::kill(bool quiet)
784 {
785 if (pid == -1 || pid == 0) return;
786
787 if (!quiet)
788 printMsg(lvlError, format("killing process %1%") % pid);
789
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()));
795
796 /* Wait until the child dies, disregarding the exit status. */
797 int status;
798 while (waitpid(pid, &status, 0) == -1) {
799 checkInterrupt();
800 if (errno != EINTR) {
801 printMsg(lvlError,
802 (SysError(format("waiting for process %1%") % pid).msg()));
803 break;
804 }
805 }
806
807 pid = -1;
808 }
809
810
811 int Pid::wait(bool block)
812 {
813 assert(pid != -1);
814 while (1) {
815 int status;
816 int res = waitpid(pid, &status, block ? 0 : WNOHANG);
817 if (res == pid) {
818 pid = -1;
819 return status;
820 }
821 if (res == 0 && !block) return -1;
822 if (errno != EINTR)
823 throw SysError("cannot get child exit status");
824 checkInterrupt();
825 }
826 }
827
828
829 void Pid::setSeparatePG(bool separatePG)
830 {
831 this->separatePG = separatePG;
832 }
833
834
835 void Pid::setKillSignal(int signal)
836 {
837 this->killSignal = signal;
838 }
839
840
841 void killUser(uid_t uid)
842 {
843 debug(format("killing all processes running under uid `%1%'") % uid);
844
845 assert(uid != 0); /* just to be safe... */
846
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. */
850
851 Pid pid = startProcess([&]() {
852
853 if (setuid(uid) == -1)
854 throw SysError("setting uid");
855
856 while (true) {
857 #ifdef __APPLE__
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
862 */
863 if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break;
864 #elif __GNU__
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;
868 #else
869 if (kill(-1, SIGKILL) == 0) break;
870 #endif
871 if (errno == ESRCH) break; /* no more processes */
872 if (errno != EINTR)
873 throw SysError(format("cannot kill processes for uid `%1%'") % uid);
874 }
875
876 _exit(0);
877 });
878
879 int status = pid.wait(true);
880 #if __GNU__
881 /* When the child killed itself, status = SIGKILL. */
882 if (status == SIGKILL) return;
883 #endif
884 if (status != 0)
885 throw Error(format("cannot kill processes for uid `%1%': %2%") % uid % statusToString(status));
886
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'. */
891 }
892
893
894 //////////////////////////////////////////////////////////////////////
895
896
897 pid_t startProcess(std::function<void()> fun,
898 bool dieWithParent, const string & errorPrefix, bool runExitHandlers)
899 {
900 pid_t pid = fork();
901 if (pid == -1) throw SysError("unable to fork");
902
903 if (pid == 0) {
904 _writeToStderr = 0;
905 try {
906 #if __linux__
907 if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
908 throw SysError("setting death signal");
909 #endif
910 restoreAffinity();
911 fun();
912 } catch (std::exception & e) {
913 try {
914 std::cerr << errorPrefix << e.what() << "\n";
915 } catch (...) { }
916 } catch (...) { }
917 if (runExitHandlers)
918 exit(1);
919 else
920 _exit(1);
921 }
922
923 return pid;
924 }
925
926
927 std::vector<char *> stringsToCharPtrs(const Strings & ss)
928 {
929 std::vector<char *> res;
930 for (auto & s : ss) res.push_back((char *) s.c_str());
931 res.push_back(0);
932 return res;
933 }
934
935
936 string runProgram(Path program, bool searchPath, const Strings & args)
937 {
938 checkInterrupt();
939
940 /* Create a pipe. */
941 Pipe pipe;
942 pipe.create();
943
944 /* Fork. */
945 Pid pid = startProcess([&]() {
946 if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
947 throw SysError("dupping stdout");
948
949 Strings args_(args);
950 args_.push_front(program);
951
952 if (searchPath)
953 execvp(program.c_str(), stringsToCharPtrs(args_).data());
954 else
955 execv(program.c_str(), stringsToCharPtrs(args_).data());
956
957 throw SysError(format("executing `%1%'") % program);
958 });
959
960 pipe.writeSide.close();
961
962 string result = drainFD(pipe.readSide);
963
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));
969
970 return result;
971 }
972
973
974 void closeMostFDs(const set<int> & exceptions)
975 {
976 int maxFD = 0;
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 */
982 }
983
984
985 void closeOnExec(int fd)
986 {
987 int prev;
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");
991 }
992
993
994 //////////////////////////////////////////////////////////////////////
995
996
997 volatile sig_atomic_t _isInterrupted = 0;
998
999 void _interrupted()
1000 {
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()) {
1005 _isInterrupted = 0;
1006 throw Interrupted("interrupted by the user");
1007 }
1008 }
1009
1010
1011
1012 //////////////////////////////////////////////////////////////////////
1013
1014
1015 template<class C> C tokenizeString(const string & s, const string & separators)
1016 {
1017 C result;
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);
1025 }
1026 return result;
1027 }
1028
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);
1032
1033
1034 string concatStringsSep(const string & sep, const Strings & ss)
1035 {
1036 string s;
1037 foreach (Strings::const_iterator, i, ss) {
1038 if (s.size() != 0) s += sep;
1039 s += *i;
1040 }
1041 return s;
1042 }
1043
1044
1045 string concatStringsSep(const string & sep, const StringSet & ss)
1046 {
1047 string s;
1048 foreach (StringSet::const_iterator, i, ss) {
1049 if (s.size() != 0) s += sep;
1050 s += *i;
1051 }
1052 return s;
1053 }
1054
1055
1056 string chomp(const string & s)
1057 {
1058 size_t i = s.find_last_not_of(" \n\r\t");
1059 return i == string::npos ? "" : string(s, 0, i + 1);
1060 }
1061
1062
1063 string statusToString(int status)
1064 {
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);
1070 #if HAVE_STRSIGNAL
1071 const char * description = strsignal(sig);
1072 return (format("failed due to signal %1% (%2%)") % sig % description).str();
1073 #else
1074 return (format("failed due to signal %1%") % sig).str();
1075 #endif
1076 }
1077 else
1078 return "died abnormally";
1079 } else return "succeeded";
1080 }
1081
1082
1083 bool statusOk(int status)
1084 {
1085 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
1086 }
1087
1088
1089 bool hasSuffix(const string & s, const string & suffix)
1090 {
1091 return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix;
1092 }
1093
1094
1095 void expect(std::istream & str, const string & s)
1096 {
1097 char s2[s.size()];
1098 str.read(s2, s.size());
1099 if (string(s2, s.size()) != s)
1100 throw FormatError(format("expected string `%1%'") % s);
1101 }
1102
1103
1104 string parseString(std::istream & str)
1105 {
1106 string res;
1107 expect(str, "\"");
1108 int c;
1109 while ((c = str.get()) != '"')
1110 if (c == '\\') {
1111 c = str.get();
1112 if (c == 'n') res += '\n';
1113 else if (c == 'r') res += '\r';
1114 else if (c == 't') res += '\t';
1115 else res += c;
1116 }
1117 else res += c;
1118 return res;
1119 }
1120
1121
1122 bool endOfList(std::istream & str)
1123 {
1124 if (str.peek() == ',') {
1125 str.get();
1126 return false;
1127 }
1128 if (str.peek() == ']') {
1129 str.get();
1130 return true;
1131 }
1132 return false;
1133 }
1134
1135
1136 void ignoreException()
1137 {
1138 try {
1139 throw;
1140 } catch (std::exception & e) {
1141 printMsg(lvlError, format("error (ignored): %1%") % e.what());
1142 }
1143 }
1144
1145 static const string pathNullDevice = "/dev/null";
1146
1147 /* Common initialisation performed in child processes. */
1148 void commonChildInit(Pipe & logPipe)
1149 {
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. */
1154 if (setsid() == -1)
1155 throw SysError(format("creating a new session"));
1156
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");
1160
1161 /* Dup stderr to stdout. */
1162 if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1)
1163 throw SysError("cannot dup stderr into stdout");
1164
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");
1171 close(fdDevNull);
1172 }
1173
1174 //////////////////////////////////////////////////////////////////////
1175
1176 Agent::Agent(const string &command, const Strings &args)
1177 {
1178 debug(format("starting agent '%1%'") % command);
1179
1180 /* Create a pipe to get the output of the child. */
1181 fromAgent.create();
1182
1183 /* Create the communication pipes. */
1184 toAgent.create();
1185
1186 /* Create a pipe to get the output of the builder. */
1187 builderOut.create();
1188
1189 /* Fork the hook. */
1190 pid = startProcess([&]() {
1191
1192 commonChildInit(fromAgent);
1193
1194 if (chdir("/") == -1) throw SysError("changing into `/");
1195
1196 /* Dup the communication pipes. */
1197 if (dup2(toAgent.readSide, STDIN_FILENO) == -1)
1198 throw SysError("dupping to-hook read side");
1199
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");
1203
1204 Strings allArgs;
1205 allArgs.push_back(command);
1206 allArgs.insert(allArgs.end(), args.begin(), args.end()); // append
1207
1208 execv(command.c_str(), stringsToCharPtrs(allArgs).data());
1209
1210 throw SysError(format("executing `%1%'") % command);
1211 });
1212
1213 pid.setSeparatePG(true);
1214 fromAgent.writeSide.close();
1215 toAgent.readSide.close();
1216 }
1217
1218
1219 Agent::~Agent()
1220 {
1221 try {
1222 toAgent.writeSide.close();
1223 pid.kill(true);
1224 } catch (...) {
1225 ignoreException();
1226 }
1227 }
1228
1229
1230 }