Merge branch 'master' into core-updates
[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;
180 struct stat st;
181 res = lstat(path.c_str(), &st);
182 if (!res) return true;
183 if (errno != ENOENT && errno != ENOTDIR)
184 throw SysError(format("getting status of %1%") % path);
185 return false;
186}
187
188
189Path readLink(const Path & path)
190{
191 checkInterrupt();
192 struct stat st = lstat(path);
193 if (!S_ISLNK(st.st_mode))
194 throw Error(format("`%1%' is not a symlink") % path);
195 char buf[st.st_size];
54c260e6
LC
196 ssize_t rlsize = readlink(path.c_str(), buf, st.st_size);
197 if (rlsize == -1)
198 throw SysError(format("reading symbolic link '%1%'") % path);
199 else if (rlsize > st.st_size)
200 throw Error(format("symbolic link ‘%1%’ size overflow %2% > %3%")
201 % path % rlsize % st.st_size);
36457566
LC
202 return string(buf, st.st_size);
203}
204
205
206bool isLink(const Path & path)
207{
208 struct stat st = lstat(path);
209 return S_ISLNK(st.st_mode);
210}
211
212
2bb04905 213DirEntries readDirectory(const Path & path)
36457566 214{
2bb04905
LC
215 DirEntries entries;
216 entries.reserve(64);
36457566
LC
217
218 AutoCloseDir dir = opendir(path.c_str());
219 if (!dir) throw SysError(format("opening directory `%1%'") % path);
220
221 struct dirent * dirent;
222 while (errno = 0, dirent = readdir(dir)) { /* sic */
223 checkInterrupt();
224 string name = dirent->d_name;
225 if (name == "." || name == "..") continue;
2bb04905 226 entries.emplace_back(name, dirent->d_ino, dirent->d_type);
36457566
LC
227 }
228 if (errno) throw SysError(format("reading directory `%1%'") % path);
229
2bb04905
LC
230 return entries;
231}
232
233
234unsigned char getFileType(const Path & path)
235{
236 struct stat st = lstat(path);
237 if (S_ISDIR(st.st_mode)) return DT_DIR;
238 if (S_ISLNK(st.st_mode)) return DT_LNK;
239 if (S_ISREG(st.st_mode)) return DT_REG;
240 return DT_UNKNOWN;
36457566
LC
241}
242
243
244string readFile(int fd)
245{
246 struct stat st;
247 if (fstat(fd, &st) == -1)
248 throw SysError("statting file");
249
250 unsigned char * buf = new unsigned char[st.st_size];
251 AutoDeleteArray<unsigned char> d(buf);
252 readFull(fd, buf, st.st_size);
253
254 return string((char *) buf, st.st_size);
255}
256
257
258string readFile(const Path & path, bool drain)
259{
260 AutoCloseFD fd = open(path.c_str(), O_RDONLY);
261 if (fd == -1)
262 throw SysError(format("opening file `%1%'") % path);
263 return drain ? drainFD(fd) : readFile(fd);
264}
265
266
267void writeFile(const Path & path, const string & s)
268{
269 AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
270 if (fd == -1)
54c260e6
LC
271 throw SysError(format("opening file '%1%'") % path);
272 writeFull(fd, s);
36457566
LC
273}
274
275
276string readLine(int fd)
277{
278 string s;
279 while (1) {
280 checkInterrupt();
281 char ch;
282 ssize_t rd = read(fd, &ch, 1);
283 if (rd == -1) {
284 if (errno != EINTR)
285 throw SysError("reading a line");
286 } else if (rd == 0)
287 throw EndOfFile("unexpected EOF reading a line");
288 else {
289 if (ch == '\n') return s;
290 s += ch;
291 }
292 }
293}
294
295
296void writeLine(int fd, string s)
297{
298 s += '\n';
54c260e6 299 writeFull(fd, s);
36457566
LC
300}
301
302
303static void _deletePath(const Path & path, unsigned long long & bytesFreed)
304{
305 checkInterrupt();
306
307 printMsg(lvlVomit, format("%1%") % path);
308
309 struct stat st = lstat(path);
310
311 if (!S_ISDIR(st.st_mode) && st.st_nlink == 1)
312 bytesFreed += st.st_blocks * 512;
313
314 if (S_ISDIR(st.st_mode)) {
36457566
LC
315 /* Make the directory writable. */
316 if (!(st.st_mode & S_IWUSR)) {
317 if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
318 throw SysError(format("making `%1%' writable") % path);
319 }
320
2bb04905
LC
321 for (auto & i : readDirectory(path))
322 _deletePath(path + "/" + i.name, bytesFreed);
36457566
LC
323 }
324
325 if (remove(path.c_str()) == -1)
326 throw SysError(format("cannot unlink `%1%'") % path);
327}
328
329
330void deletePath(const Path & path)
331{
332 unsigned long long dummy;
333 deletePath(path, dummy);
334}
335
336
337void deletePath(const Path & path, unsigned long long & bytesFreed)
338{
339 startNest(nest, lvlDebug,
340 format("recursively deleting path `%1%'") % path);
341 bytesFreed = 0;
342 _deletePath(path, bytesFreed);
343}
344
345
346static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
347 int & counter)
348{
349 tmpRoot = canonPath(tmpRoot.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot, true);
350 if (includePid)
351 return (format("%1%/%2%-%3%-%4%") % tmpRoot % prefix % getpid() % counter++).str();
352 else
353 return (format("%1%/%2%-%3%") % tmpRoot % prefix % counter++).str();
354}
355
356
357Path createTempDir(const Path & tmpRoot, const Path & prefix,
358 bool includePid, bool useGlobalCounter, mode_t mode)
359{
360 static int globalCounter = 0;
361 int localCounter = 0;
362 int & counter(useGlobalCounter ? globalCounter : localCounter);
363
364 while (1) {
365 checkInterrupt();
366 Path tmpDir = tempName(tmpRoot, prefix, includePid, counter);
367 if (mkdir(tmpDir.c_str(), mode) == 0) {
368 /* Explicitly set the group of the directory. This is to
369 work around around problems caused by BSD's group
370 ownership semantics (directories inherit the group of
371 the parent). For instance, the group of /tmp on
372 FreeBSD is "wheel", so all directories created in /tmp
373 will be owned by "wheel"; but if the user is not in
374 "wheel", then "tar" will fail to unpack archives that
375 have the setgid bit set on directories. */
376 if (chown(tmpDir.c_str(), (uid_t) -1, getegid()) != 0)
377 throw SysError(format("setting group of directory `%1%'") % tmpDir);
378 return tmpDir;
379 }
380 if (errno != EEXIST)
381 throw SysError(format("creating directory `%1%'") % tmpDir);
382 }
383}
384
385
386Paths createDirs(const Path & path)
387{
388 Paths created;
389 if (path == "/") return created;
390
391 struct stat st;
392 if (lstat(path.c_str(), &st) == -1) {
393 created = createDirs(dirOf(path));
394 if (mkdir(path.c_str(), 0777) == -1 && errno != EEXIST)
395 throw SysError(format("creating directory `%1%'") % path);
396 st = lstat(path);
397 created.push_back(path);
398 }
399
2bb04905
LC
400 if (S_ISLNK(st.st_mode) && stat(path.c_str(), &st) == -1)
401 throw SysError(format("statting symlink `%1%'") % path);
402
36457566
LC
403 if (!S_ISDIR(st.st_mode)) throw Error(format("`%1%' is not a directory") % path);
404
405 return created;
406}
407
408
409void createSymlink(const Path & target, const Path & link)
410{
411 if (symlink(target.c_str(), link.c_str()))
412 throw SysError(format("creating symlink from `%1%' to `%2%'") % link % target);
413}
414
415
416LogType logType = ltPretty;
417Verbosity verbosity = lvlInfo;
418
419static int nestingLevel = 0;
420
421
422Nest::Nest()
423{
424 nest = false;
425}
426
427
428Nest::~Nest()
429{
430 close();
431}
432
433
434static string escVerbosity(Verbosity level)
435{
79aa1a83 436 return std::to_string((int) level);
36457566
LC
437}
438
439
440void Nest::open(Verbosity level, const FormatOrString & fs)
441{
442 if (level <= verbosity) {
443 if (logType == ltEscapes)
444 std::cerr << "\033[" << escVerbosity(level) << "p"
445 << fs.s << "\n";
446 else
447 printMsg_(level, fs);
448 nest = true;
449 nestingLevel++;
450 }
451}
452
453
454void Nest::close()
455{
456 if (nest) {
457 nestingLevel--;
458 if (logType == ltEscapes)
459 std::cerr << "\033[q";
460 nest = false;
461 }
462}
463
464
465void printMsg_(Verbosity level, const FormatOrString & fs)
466{
467 checkInterrupt();
468 if (level > verbosity) return;
469 string prefix;
470 if (logType == ltPretty)
471 for (int i = 0; i < nestingLevel; i++)
472 prefix += "| ";
473 else if (logType == ltEscapes && level != lvlInfo)
474 prefix = "\033[" + escVerbosity(level) + "s";
475 string s = (format("%1%%2%\n") % prefix % fs.s).str();
476 writeToStderr(s);
477}
478
479
480void warnOnce(bool & haveWarned, const FormatOrString & fs)
481{
482 if (!haveWarned) {
483 printMsg(lvlError, format("warning: %1%") % fs.s);
484 haveWarned = true;
485 }
486}
487
488
489void writeToStderr(const string & s)
490{
491 try {
54c260e6
LC
492 if (_writeToStderr)
493 _writeToStderr((const unsigned char *) s.data(), s.size());
494 else
495 writeFull(STDERR_FILENO, s);
36457566
LC
496 } catch (SysError & e) {
497 /* Ignore failing writes to stderr if we're in an exception
498 handler, otherwise throw an exception. We need to ignore
499 write errors in exception handlers to ensure that cleanup
500 code runs to completion if the other side of stderr has
501 been closed unexpectedly. */
502 if (!std::uncaught_exception()) throw;
503 }
504}
505
506
54c260e6 507void (*_writeToStderr) (const unsigned char * buf, size_t count) = 0;
36457566
LC
508
509
510void readFull(int fd, unsigned char * buf, size_t count)
511{
512 while (count) {
513 checkInterrupt();
514 ssize_t res = read(fd, (char *) buf, count);
515 if (res == -1) {
516 if (errno == EINTR) continue;
517 throw SysError("reading from file");
518 }
519 if (res == 0) throw EndOfFile("unexpected end-of-file");
520 count -= res;
521 buf += res;
522 }
523}
524
525
526void writeFull(int fd, const unsigned char * buf, size_t count)
527{
528 while (count) {
529 checkInterrupt();
530 ssize_t res = write(fd, (char *) buf, count);
531 if (res == -1) {
532 if (errno == EINTR) continue;
533 throw SysError("writing to file");
534 }
535 count -= res;
536 buf += res;
537 }
538}
539
540
54c260e6
LC
541void writeFull(int fd, const string & s)
542{
543 writeFull(fd, (const unsigned char *) s.data(), s.size());
544}
545
546
36457566
LC
547string drainFD(int fd)
548{
549 string result;
550 unsigned char buffer[4096];
551 while (1) {
552 checkInterrupt();
553 ssize_t rd = read(fd, buffer, sizeof buffer);
554 if (rd == -1) {
555 if (errno != EINTR)
556 throw SysError("reading from file");
557 }
558 else if (rd == 0) break;
559 else result.append((char *) buffer, rd);
560 }
561 return result;
562}
563
564
565
566//////////////////////////////////////////////////////////////////////
567
568
569AutoDelete::AutoDelete(const string & p, bool recursive) : path(p)
570{
571 del = true;
572 this->recursive = recursive;
573}
574
575AutoDelete::~AutoDelete()
576{
577 try {
578 if (del) {
579 if (recursive)
580 deletePath(path);
581 else {
582 if (remove(path.c_str()) == -1)
583 throw SysError(format("cannot unlink `%1%'") % path);
584 }
585 }
586 } catch (...) {
587 ignoreException();
588 }
589}
590
591void AutoDelete::cancel()
592{
593 del = false;
594}
595
596
597
598//////////////////////////////////////////////////////////////////////
599
600
601AutoCloseFD::AutoCloseFD()
602{
603 fd = -1;
604}
605
606
607AutoCloseFD::AutoCloseFD(int fd)
608{
609 this->fd = fd;
610}
611
612
613AutoCloseFD::AutoCloseFD(const AutoCloseFD & fd)
614{
615 /* Copying an AutoCloseFD isn't allowed (who should get to close
616 it?). But as an edge case, allow copying of closed
617 AutoCloseFDs. This is necessary due to tiresome reasons
618 involving copy constructor use on default object values in STL
619 containers (like when you do `map[value]' where value isn't in
620 the map yet). */
621 this->fd = fd.fd;
622 if (this->fd != -1) abort();
623}
624
625
626AutoCloseFD::~AutoCloseFD()
627{
628 try {
629 close();
630 } catch (...) {
631 ignoreException();
632 }
633}
634
635
636void AutoCloseFD::operator =(int fd)
637{
638 if (this->fd != fd) close();
639 this->fd = fd;
640}
641
642
643AutoCloseFD::operator int() const
644{
645 return fd;
646}
647
648
649void AutoCloseFD::close()
650{
651 if (fd != -1) {
652 if (::close(fd) == -1)
653 /* This should never happen. */
654 throw SysError(format("closing file descriptor %1%") % fd);
655 fd = -1;
656 }
657}
658
659
660bool AutoCloseFD::isOpen()
661{
662 return fd != -1;
663}
664
665
666/* Pass responsibility for closing this fd to the caller. */
667int AutoCloseFD::borrow()
668{
669 int oldFD = fd;
670 fd = -1;
671 return oldFD;
672}
673
674
675void Pipe::create()
676{
677 int fds[2];
678 if (pipe(fds) != 0) throw SysError("creating pipe");
679 readSide = fds[0];
680 writeSide = fds[1];
681 closeOnExec(readSide);
682 closeOnExec(writeSide);
683}
684
685
686
687//////////////////////////////////////////////////////////////////////
688
689
690AutoCloseDir::AutoCloseDir()
691{
692 dir = 0;
693}
694
695
696AutoCloseDir::AutoCloseDir(DIR * dir)
697{
698 this->dir = dir;
699}
700
701
702AutoCloseDir::~AutoCloseDir()
703{
704 close();
705}
706
707
708void AutoCloseDir::operator =(DIR * dir)
709{
710 this->dir = dir;
711}
712
713
714AutoCloseDir::operator DIR *()
715{
716 return dir;
717}
718
719
720void AutoCloseDir::close()
721{
722 if (dir) {
723 closedir(dir);
724 dir = 0;
725 }
726}
727
728
729//////////////////////////////////////////////////////////////////////
730
731
732Pid::Pid()
2bb04905
LC
733 : pid(-1), separatePG(false), killSignal(SIGKILL)
734{
735}
736
737
738Pid::Pid(pid_t pid)
739 : pid(pid), separatePG(false), killSignal(SIGKILL)
36457566 740{
36457566
LC
741}
742
743
744Pid::~Pid()
745{
746 kill();
747}
748
749
750void Pid::operator =(pid_t pid)
751{
752 if (this->pid != pid) kill();
753 this->pid = pid;
754 killSignal = SIGKILL; // reset signal to default
755}
756
757
758Pid::operator pid_t()
759{
760 return pid;
761}
762
763
2bb04905 764void Pid::kill(bool quiet)
36457566
LC
765{
766 if (pid == -1 || pid == 0) return;
767
2bb04905
LC
768 if (!quiet)
769 printMsg(lvlError, format("killing process %1%") % pid);
36457566
LC
770
771 /* Send the requested signal to the child. If it has its own
772 process group, send the signal to every process in the child
773 process group (which hopefully includes *all* its children). */
774 if (::kill(separatePG ? -pid : pid, killSignal) != 0)
775 printMsg(lvlError, (SysError(format("killing process %1%") % pid).msg()));
776
777 /* Wait until the child dies, disregarding the exit status. */
778 int status;
779 while (waitpid(pid, &status, 0) == -1) {
780 checkInterrupt();
781 if (errno != EINTR) {
782 printMsg(lvlError,
783 (SysError(format("waiting for process %1%") % pid).msg()));
784 break;
785 }
786 }
787
788 pid = -1;
789}
790
791
792int Pid::wait(bool block)
793{
794 assert(pid != -1);
795 while (1) {
796 int status;
797 int res = waitpid(pid, &status, block ? 0 : WNOHANG);
798 if (res == pid) {
799 pid = -1;
800 return status;
801 }
802 if (res == 0 && !block) return -1;
803 if (errno != EINTR)
804 throw SysError("cannot get child exit status");
805 checkInterrupt();
806 }
807}
808
809
810void Pid::setSeparatePG(bool separatePG)
811{
812 this->separatePG = separatePG;
813}
814
815
816void Pid::setKillSignal(int signal)
817{
818 this->killSignal = signal;
819}
820
821
822void killUser(uid_t uid)
823{
824 debug(format("killing all processes running under uid `%1%'") % uid);
825
826 assert(uid != 0); /* just to be safe... */
827
828 /* The system call kill(-1, sig) sends the signal `sig' to all
829 users to which the current process can send signals. So we
830 fork a process, switch to uid, and send a mass kill. */
831
2bb04905 832 Pid pid = startProcess([&]() {
36457566 833
2bb04905
LC
834 if (setuid(uid) == -1)
835 throw SysError("setting uid");
36457566 836
2bb04905 837 while (true) {
36457566 838#ifdef __APPLE__
2bb04905
LC
839 /* OSX's kill syscall takes a third parameter that, among
840 other things, determines if kill(-1, signo) affects the
841 calling process. In the OSX libc, it's set to true,
842 which means "follow POSIX", which we don't want here
36457566 843 */
2bb04905 844 if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break;
36457566 845#else
2bb04905 846 if (kill(-1, SIGKILL) == 0) break;
36457566 847#endif
2bb04905
LC
848 if (errno == ESRCH) break; /* no more processes */
849 if (errno != EINTR)
850 throw SysError(format("cannot kill processes for uid `%1%'") % uid);
36457566 851 }
2bb04905 852
36457566 853 _exit(0);
2bb04905 854 });
36457566 855
36457566
LC
856 int status = pid.wait(true);
857 if (status != 0)
858 throw Error(format("cannot kill processes for uid `%1%': %2%") % uid % statusToString(status));
859
860 /* !!! We should really do some check to make sure that there are
861 no processes left running under `uid', but there is no portable
862 way to do so (I think). The most reliable way may be `ps -eo
863 uid | grep -q $uid'. */
864}
865
866
867//////////////////////////////////////////////////////////////////////
868
869
2bb04905
LC
870pid_t startProcess(std::function<void()> fun,
871 bool dieWithParent, const string & errorPrefix, bool runExitHandlers)
872{
873 pid_t pid = fork();
874 if (pid == -1) throw SysError("unable to fork");
875
876 if (pid == 0) {
877 _writeToStderr = 0;
878 try {
54c260e6
LC
879#if __linux__
880 if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
881 throw SysError("setting death signal");
882#endif
2bb04905
LC
883 restoreAffinity();
884 fun();
885 } catch (std::exception & e) {
886 try {
887 std::cerr << errorPrefix << e.what() << "\n";
888 } catch (...) { }
889 } catch (...) { }
890 if (runExitHandlers)
891 exit(1);
892 else
893 _exit(1);
894 }
895
896 return pid;
897}
898
899
322eeb87 900std::vector<char *> stringsToCharPtrs(const Strings & ss)
54c260e6 901{
322eeb87
LC
902 std::vector<char *> res;
903 for (auto & s : ss) res.push_back((char *) s.c_str());
54c260e6
LC
904 res.push_back(0);
905 return res;
906}
907
908
36457566
LC
909string runProgram(Path program, bool searchPath, const Strings & args)
910{
911 checkInterrupt();
912
36457566
LC
913 /* Create a pipe. */
914 Pipe pipe;
915 pipe.create();
916
917 /* Fork. */
2bb04905
LC
918 Pid pid = startProcess([&]() {
919 if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
920 throw SysError("dupping stdout");
36457566 921
54c260e6
LC
922 Strings args_(args);
923 args_.push_front(program);
54c260e6 924
2bb04905 925 if (searchPath)
322eeb87 926 execvp(program.c_str(), stringsToCharPtrs(args_).data());
2bb04905 927 else
322eeb87 928 execv(program.c_str(), stringsToCharPtrs(args_).data());
36457566 929
2bb04905
LC
930 throw SysError(format("executing `%1%'") % program);
931 });
36457566
LC
932
933 pipe.writeSide.close();
934
935 string result = drainFD(pipe.readSide);
936
937 /* Wait for the child to finish. */
938 int status = pid.wait(true);
939 if (!statusOk(status))
2bb04905 940 throw ExecError(format("program `%1%' %2%")
36457566
LC
941 % program % statusToString(status));
942
943 return result;
944}
945
946
947void closeMostFDs(const set<int> & exceptions)
948{
949 int maxFD = 0;
950 maxFD = sysconf(_SC_OPEN_MAX);
951 for (int fd = 0; fd < maxFD; ++fd)
952 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
953 && exceptions.find(fd) == exceptions.end())
954 close(fd); /* ignore result */
955}
956
957
958void closeOnExec(int fd)
959{
960 int prev;
961 if ((prev = fcntl(fd, F_GETFD, 0)) == -1 ||
962 fcntl(fd, F_SETFD, prev | FD_CLOEXEC) == -1)
963 throw SysError("setting close-on-exec flag");
964}
965
966
36457566
LC
967//////////////////////////////////////////////////////////////////////
968
969
970volatile sig_atomic_t _isInterrupted = 0;
971
972void _interrupted()
973{
974 /* Block user interrupts while an exception is being handled.
975 Throwing an exception while another exception is being handled
976 kills the program! */
977 if (!std::uncaught_exception()) {
978 _isInterrupted = 0;
979 throw Interrupted("interrupted by the user");
980 }
981}
982
983
984
985//////////////////////////////////////////////////////////////////////
986
987
988template<class C> C tokenizeString(const string & s, const string & separators)
989{
990 C result;
991 string::size_type pos = s.find_first_not_of(separators, 0);
992 while (pos != string::npos) {
993 string::size_type end = s.find_first_of(separators, pos + 1);
994 if (end == string::npos) end = s.size();
995 string token(s, pos, end - pos);
996 result.insert(result.end(), token);
997 pos = s.find_first_not_of(separators, end);
998 }
999 return result;
1000}
1001
1002template Strings tokenizeString(const string & s, const string & separators);
1003template StringSet tokenizeString(const string & s, const string & separators);
1004template vector<string> tokenizeString(const string & s, const string & separators);
1005
1006
1007string concatStringsSep(const string & sep, const Strings & ss)
1008{
1009 string s;
1010 foreach (Strings::const_iterator, i, ss) {
1011 if (s.size() != 0) s += sep;
1012 s += *i;
1013 }
1014 return s;
1015}
1016
1017
1018string concatStringsSep(const string & sep, const StringSet & ss)
1019{
1020 string s;
1021 foreach (StringSet::const_iterator, i, ss) {
1022 if (s.size() != 0) s += sep;
1023 s += *i;
1024 }
1025 return s;
1026}
1027
1028
1029string chomp(const string & s)
1030{
1031 size_t i = s.find_last_not_of(" \n\r\t");
1032 return i == string::npos ? "" : string(s, 0, i + 1);
1033}
1034
1035
1036string statusToString(int status)
1037{
1038 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
1039 if (WIFEXITED(status))
1040 return (format("failed with exit code %1%") % WEXITSTATUS(status)).str();
1041 else if (WIFSIGNALED(status)) {
1042 int sig = WTERMSIG(status);
1043#if HAVE_STRSIGNAL
1044 const char * description = strsignal(sig);
1045 return (format("failed due to signal %1% (%2%)") % sig % description).str();
1046#else
1047 return (format("failed due to signal %1%") % sig).str();
1048#endif
1049 }
1050 else
1051 return "died abnormally";
1052 } else return "succeeded";
1053}
1054
1055
1056bool statusOk(int status)
1057{
1058 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
1059}
1060
1061
1062bool hasSuffix(const string & s, const string & suffix)
1063{
1064 return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix;
1065}
1066
1067
1068void expect(std::istream & str, const string & s)
1069{
1070 char s2[s.size()];
1071 str.read(s2, s.size());
1072 if (string(s2, s.size()) != s)
15ddeff5 1073 throw FormatError(format("expected string `%1%'") % s);
36457566
LC
1074}
1075
1076
1077string parseString(std::istream & str)
1078{
1079 string res;
1080 expect(str, "\"");
1081 int c;
1082 while ((c = str.get()) != '"')
1083 if (c == '\\') {
1084 c = str.get();
1085 if (c == 'n') res += '\n';
1086 else if (c == 'r') res += '\r';
1087 else if (c == 't') res += '\t';
1088 else res += c;
1089 }
1090 else res += c;
1091 return res;
1092}
1093
1094
1095bool endOfList(std::istream & str)
1096{
1097 if (str.peek() == ',') {
1098 str.get();
1099 return false;
1100 }
1101 if (str.peek() == ']') {
1102 str.get();
1103 return true;
1104 }
1105 return false;
1106}
1107
1108
1109string decodeOctalEscaped(const string & s)
1110{
1111 string r;
1112 for (string::const_iterator i = s.begin(); i != s.end(); ) {
1113 if (*i != '\\') { r += *i++; continue; }
1114 unsigned char c = 0;
1115 ++i;
1116 while (i != s.end() && *i >= '0' && *i < '8')
1117 c = c * 8 + (*i++ - '0');
1118 r += c;
1119 }
1120 return r;
1121}
1122
1123
1124void ignoreException()
1125{
1126 try {
1127 throw;
1128 } catch (std::exception & e) {
1129 printMsg(lvlError, format("error (ignored): %1%") % e.what());
1130 }
1131}
1132
1133
1134}