daemon: Do not use clone on the Hurd.
[jackhill/guix/guix.git] / nix / libutil / util.cc
CommitLineData
36457566
LC
1#include "config.h"
2
2bb04905
LC
3#include "util.hh"
4#include "affinity.hh"
5
36457566
LC
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
54c260e6
LC
22#ifdef __linux__
23#include <sys/prctl.h>
24#endif
25
36457566
LC
26
27extern char * * environ;
28
29
30namespace nix {
31
32
33BaseError::BaseError(const FormatOrString & fs, unsigned int status)
34 : status(status)
35{
36 err = fs.s;
37}
38
39
40BaseError & BaseError::addPrefix(const FormatOrString & fs)
41{
42 prefix_ = fs.s + prefix_;
43 return *this;
44}
45
46
47SysError::SysError(const FormatOrString & fs)
48 : Error(format("%1%: %2%") % fs.s % strerror(errno))
49 , errNo(errno)
50{
51}
52
53
54string getEnv(const string & key, const string & def)
55{
56 char * value = getenv(key.c_str());
57 return value ? string(value) : def;
58}
59
60
61Path 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
86Path 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 = "";
36457566
LC
133 }
134 }
135 }
136
137 return s.empty() ? "/" : s;
138}
139
140
141Path 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
150string 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
159bool 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
168struct 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
177bool pathExists(const Path & path)
178{
179 int res;
b6b014bf
LC
180#ifdef HAVE_STATX
181 struct statx st;
182 res = statx(AT_FDCWD, path.c_str(), AT_SYMLINK_NOFOLLOW, 0, &st);
183#else
36457566
LC
184 struct stat st;
185 res = lstat(path.c_str(), &st);
b6b014bf 186#endif
36457566
LC
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
194Path 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];
54c260e6
LC
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);
36457566
LC
207 return string(buf, st.st_size);
208}
209
210
211bool isLink(const Path & path)
212{
213 struct stat st = lstat(path);
214 return S_ISLNK(st.st_mode);
215}
216
217
2bb04905 218DirEntries readDirectory(const Path & path)
36457566 219{
2bb04905
LC
220 DirEntries entries;
221 entries.reserve(64);
36457566
LC
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;
2bb04905 231 entries.emplace_back(name, dirent->d_ino, dirent->d_type);
36457566
LC
232 }
233 if (errno) throw SysError(format("reading directory `%1%'") % path);
234
2bb04905
LC
235 return entries;
236}
237
238
239unsigned 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;
36457566
LC
246}
247
248
249string 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
263string 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
272void 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)
54c260e6
LC
276 throw SysError(format("opening file '%1%'") % path);
277 writeFull(fd, s);
36457566
LC
278}
279
280
281string 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
301void writeLine(int fd, string s)
302{
303 s += '\n';
54c260e6 304 writeFull(fd, s);
36457566
LC
305}
306
307
7033c769 308static void _deletePath(const Path & path, unsigned long long & bytesFreed, size_t linkThreshold)
36457566
LC
309{
310 checkInterrupt();
311
312 printMsg(lvlVomit, format("%1%") % path);
313
fbecb5cd
LC
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
36457566 324 struct stat st = lstat(path);
fbecb5cd 325#endif
36457566 326
7033c769 327 if (!S_ISDIR(st.st_mode) && st.st_nlink <= linkThreshold)
546a709f 328 bytesFreed += st.st_size;
36457566
LC
329
330 if (S_ISDIR(st.st_mode)) {
36457566
LC
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
2bb04905 337 for (auto & i : readDirectory(path))
7033c769 338 _deletePath(path + "/" + i.name, bytesFreed, linkThreshold);
36457566 339 }
fbecb5cd
LC
340#undef st_mode
341#undef st_size
342#undef st_nlink
36457566
LC
343
344 if (remove(path.c_str()) == -1)
345 throw SysError(format("cannot unlink `%1%'") % path);
346}
347
348
349void deletePath(const Path & path)
350{
351 unsigned long long dummy;
352 deletePath(path, dummy);
353}
354
355
7033c769 356void deletePath(const Path & path, unsigned long long & bytesFreed, size_t linkThreshold)
36457566
LC
357{
358 startNest(nest, lvlDebug,
359 format("recursively deleting path `%1%'") % path);
360 bytesFreed = 0;
7033c769 361 _deletePath(path, bytesFreed, linkThreshold);
36457566
LC
362}
363
364
365static 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
376Path 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
405Paths 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
2bb04905
LC
419 if (S_ISLNK(st.st_mode) && stat(path.c_str(), &st) == -1)
420 throw SysError(format("statting symlink `%1%'") % path);
421
36457566
LC
422 if (!S_ISDIR(st.st_mode)) throw Error(format("`%1%' is not a directory") % path);
423
424 return created;
425}
426
427
428void 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
435LogType logType = ltPretty;
436Verbosity verbosity = lvlInfo;
437
438static int nestingLevel = 0;
439
440
441Nest::Nest()
442{
443 nest = false;
444}
445
446
447Nest::~Nest()
448{
449 close();
450}
451
452
453static string escVerbosity(Verbosity level)
454{
79aa1a83 455 return std::to_string((int) level);
36457566
LC
456}
457
458
459void 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
473void Nest::close()
474{
475 if (nest) {
476 nestingLevel--;
477 if (logType == ltEscapes)
478 std::cerr << "\033[q";
479 nest = false;
480 }
481}
482
483
484void 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
499void 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
508void writeToStderr(const string & s)
509{
510 try {
54c260e6
LC
511 if (_writeToStderr)
512 _writeToStderr((const unsigned char *) s.data(), s.size());
513 else
514 writeFull(STDERR_FILENO, s);
36457566
LC
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
54c260e6 526void (*_writeToStderr) (const unsigned char * buf, size_t count) = 0;
36457566
LC
527
528
529void 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
545void 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
54c260e6
LC
560void writeFull(int fd, const string & s)
561{
562 writeFull(fd, (const unsigned char *) s.data(), s.size());
563}
564
565
36457566
LC
566string 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
588AutoDelete::AutoDelete(const string & p, bool recursive) : path(p)
589{
590 del = true;
591 this->recursive = recursive;
592}
593
594AutoDelete::~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
610void AutoDelete::cancel()
611{
612 del = false;
613}
614
615
616
617//////////////////////////////////////////////////////////////////////
618
619
620AutoCloseFD::AutoCloseFD()
621{
622 fd = -1;
623}
624
625
626AutoCloseFD::AutoCloseFD(int fd)
627{
628 this->fd = fd;
629}
630
631
632AutoCloseFD::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
645AutoCloseFD::~AutoCloseFD()
646{
647 try {
648 close();
649 } catch (...) {
650 ignoreException();
651 }
652}
653
654
655void AutoCloseFD::operator =(int fd)
656{
657 if (this->fd != fd) close();
658 this->fd = fd;
659}
660
661
662AutoCloseFD::operator int() const
663{
664 return fd;
665}
666
667
668void 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
679bool AutoCloseFD::isOpen()
680{
681 return fd != -1;
682}
683
684
685/* Pass responsibility for closing this fd to the caller. */
686int AutoCloseFD::borrow()
687{
688 int oldFD = fd;
689 fd = -1;
690 return oldFD;
691}
692
693
694void 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
709AutoCloseDir::AutoCloseDir()
710{
711 dir = 0;
712}
713
714
715AutoCloseDir::AutoCloseDir(DIR * dir)
716{
717 this->dir = dir;
718}
719
720
721AutoCloseDir::~AutoCloseDir()
722{
723 close();
724}
725
726
727void AutoCloseDir::operator =(DIR * dir)
728{
729 this->dir = dir;
730}
731
732
733AutoCloseDir::operator DIR *()
734{
735 return dir;
736}
737
738
739void AutoCloseDir::close()
740{
741 if (dir) {
742 closedir(dir);
743 dir = 0;
744 }
745}
746
747
748//////////////////////////////////////////////////////////////////////
749
750
751Pid::Pid()
2bb04905
LC
752 : pid(-1), separatePG(false), killSignal(SIGKILL)
753{
754}
755
756
757Pid::Pid(pid_t pid)
758 : pid(pid), separatePG(false), killSignal(SIGKILL)
36457566 759{
36457566
LC
760}
761
762
763Pid::~Pid()
764{
765 kill();
766}
767
768
769void 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
777Pid::operator pid_t()
778{
779 return pid;
780}
781
782
2bb04905 783void Pid::kill(bool quiet)
36457566
LC
784{
785 if (pid == -1 || pid == 0) return;
786
2bb04905
LC
787 if (!quiet)
788 printMsg(lvlError, format("killing process %1%") % pid);
36457566
LC
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
811int 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
829void Pid::setSeparatePG(bool separatePG)
830{
831 this->separatePG = separatePG;
832}
833
834
835void Pid::setKillSignal(int signal)
836{
837 this->killSignal = signal;
838}
839
840
841void 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
2bb04905 851 Pid pid = startProcess([&]() {
36457566 852
2bb04905
LC
853 if (setuid(uid) == -1)
854 throw SysError("setting uid");
36457566 855
2bb04905 856 while (true) {
36457566 857#ifdef __APPLE__
2bb04905
LC
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
36457566 862 */
2bb04905 863 if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break;
36457566 864#else
2bb04905 865 if (kill(-1, SIGKILL) == 0) break;
36457566 866#endif
2bb04905
LC
867 if (errno == ESRCH) break; /* no more processes */
868 if (errno != EINTR)
869 throw SysError(format("cannot kill processes for uid `%1%'") % uid);
36457566 870 }
2bb04905 871
36457566 872 _exit(0);
2bb04905 873 });
36457566 874
36457566
LC
875 int status = pid.wait(true);
876 if (status != 0)
877 throw Error(format("cannot kill processes for uid `%1%': %2%") % uid % statusToString(status));
878
879 /* !!! We should really do some check to make sure that there are
880 no processes left running under `uid', but there is no portable
881 way to do so (I think). The most reliable way may be `ps -eo
882 uid | grep -q $uid'. */
883}
884
885
886//////////////////////////////////////////////////////////////////////
887
888
2bb04905
LC
889pid_t startProcess(std::function<void()> fun,
890 bool dieWithParent, const string & errorPrefix, bool runExitHandlers)
891{
892 pid_t pid = fork();
893 if (pid == -1) throw SysError("unable to fork");
894
895 if (pid == 0) {
896 _writeToStderr = 0;
897 try {
54c260e6
LC
898#if __linux__
899 if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
900 throw SysError("setting death signal");
901#endif
2bb04905
LC
902 restoreAffinity();
903 fun();
904 } catch (std::exception & e) {
905 try {
906 std::cerr << errorPrefix << e.what() << "\n";
907 } catch (...) { }
908 } catch (...) { }
909 if (runExitHandlers)
910 exit(1);
911 else
912 _exit(1);
913 }
914
915 return pid;
916}
917
918
322eeb87 919std::vector<char *> stringsToCharPtrs(const Strings & ss)
54c260e6 920{
322eeb87
LC
921 std::vector<char *> res;
922 for (auto & s : ss) res.push_back((char *) s.c_str());
54c260e6
LC
923 res.push_back(0);
924 return res;
925}
926
927
36457566
LC
928string runProgram(Path program, bool searchPath, const Strings & args)
929{
930 checkInterrupt();
931
36457566
LC
932 /* Create a pipe. */
933 Pipe pipe;
934 pipe.create();
935
936 /* Fork. */
2bb04905
LC
937 Pid pid = startProcess([&]() {
938 if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
939 throw SysError("dupping stdout");
36457566 940
54c260e6
LC
941 Strings args_(args);
942 args_.push_front(program);
54c260e6 943
2bb04905 944 if (searchPath)
322eeb87 945 execvp(program.c_str(), stringsToCharPtrs(args_).data());
2bb04905 946 else
322eeb87 947 execv(program.c_str(), stringsToCharPtrs(args_).data());
36457566 948
2bb04905
LC
949 throw SysError(format("executing `%1%'") % program);
950 });
36457566
LC
951
952 pipe.writeSide.close();
953
954 string result = drainFD(pipe.readSide);
955
956 /* Wait for the child to finish. */
957 int status = pid.wait(true);
958 if (!statusOk(status))
2bb04905 959 throw ExecError(format("program `%1%' %2%")
36457566
LC
960 % program % statusToString(status));
961
962 return result;
963}
964
965
966void closeMostFDs(const set<int> & exceptions)
967{
968 int maxFD = 0;
969 maxFD = sysconf(_SC_OPEN_MAX);
970 for (int fd = 0; fd < maxFD; ++fd)
971 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
972 && exceptions.find(fd) == exceptions.end())
973 close(fd); /* ignore result */
974}
975
976
977void closeOnExec(int fd)
978{
979 int prev;
980 if ((prev = fcntl(fd, F_GETFD, 0)) == -1 ||
981 fcntl(fd, F_SETFD, prev | FD_CLOEXEC) == -1)
982 throw SysError("setting close-on-exec flag");
983}
984
985
36457566
LC
986//////////////////////////////////////////////////////////////////////
987
988
989volatile sig_atomic_t _isInterrupted = 0;
990
991void _interrupted()
992{
993 /* Block user interrupts while an exception is being handled.
994 Throwing an exception while another exception is being handled
995 kills the program! */
996 if (!std::uncaught_exception()) {
997 _isInterrupted = 0;
998 throw Interrupted("interrupted by the user");
999 }
1000}
1001
1002
1003
1004//////////////////////////////////////////////////////////////////////
1005
1006
1007template<class C> C tokenizeString(const string & s, const string & separators)
1008{
1009 C result;
1010 string::size_type pos = s.find_first_not_of(separators, 0);
1011 while (pos != string::npos) {
1012 string::size_type end = s.find_first_of(separators, pos + 1);
1013 if (end == string::npos) end = s.size();
1014 string token(s, pos, end - pos);
1015 result.insert(result.end(), token);
1016 pos = s.find_first_not_of(separators, end);
1017 }
1018 return result;
1019}
1020
1021template Strings tokenizeString(const string & s, const string & separators);
1022template StringSet tokenizeString(const string & s, const string & separators);
1023template vector<string> tokenizeString(const string & s, const string & separators);
1024
1025
1026string concatStringsSep(const string & sep, const Strings & ss)
1027{
1028 string s;
1029 foreach (Strings::const_iterator, i, ss) {
1030 if (s.size() != 0) s += sep;
1031 s += *i;
1032 }
1033 return s;
1034}
1035
1036
1037string concatStringsSep(const string & sep, const StringSet & ss)
1038{
1039 string s;
1040 foreach (StringSet::const_iterator, i, ss) {
1041 if (s.size() != 0) s += sep;
1042 s += *i;
1043 }
1044 return s;
1045}
1046
1047
1048string chomp(const string & s)
1049{
1050 size_t i = s.find_last_not_of(" \n\r\t");
1051 return i == string::npos ? "" : string(s, 0, i + 1);
1052}
1053
1054
1055string statusToString(int status)
1056{
1057 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
1058 if (WIFEXITED(status))
1059 return (format("failed with exit code %1%") % WEXITSTATUS(status)).str();
1060 else if (WIFSIGNALED(status)) {
1061 int sig = WTERMSIG(status);
1062#if HAVE_STRSIGNAL
1063 const char * description = strsignal(sig);
1064 return (format("failed due to signal %1% (%2%)") % sig % description).str();
1065#else
1066 return (format("failed due to signal %1%") % sig).str();
1067#endif
1068 }
1069 else
1070 return "died abnormally";
1071 } else return "succeeded";
1072}
1073
1074
1075bool statusOk(int status)
1076{
1077 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
1078}
1079
1080
1081bool hasSuffix(const string & s, const string & suffix)
1082{
1083 return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix;
1084}
1085
1086
1087void expect(std::istream & str, const string & s)
1088{
1089 char s2[s.size()];
1090 str.read(s2, s.size());
1091 if (string(s2, s.size()) != s)
15ddeff5 1092 throw FormatError(format("expected string `%1%'") % s);
36457566
LC
1093}
1094
1095
1096string parseString(std::istream & str)
1097{
1098 string res;
1099 expect(str, "\"");
1100 int c;
1101 while ((c = str.get()) != '"')
1102 if (c == '\\') {
1103 c = str.get();
1104 if (c == 'n') res += '\n';
1105 else if (c == 'r') res += '\r';
1106 else if (c == 't') res += '\t';
1107 else res += c;
1108 }
1109 else res += c;
1110 return res;
1111}
1112
1113
1114bool endOfList(std::istream & str)
1115{
1116 if (str.peek() == ',') {
1117 str.get();
1118 return false;
1119 }
1120 if (str.peek() == ']') {
1121 str.get();
1122 return true;
1123 }
1124 return false;
1125}
1126
1127
36457566
LC
1128void ignoreException()
1129{
1130 try {
1131 throw;
1132 } catch (std::exception & e) {
1133 printMsg(lvlError, format("error (ignored): %1%") % e.what());
1134 }
1135}
1136
1137
1138}