daemon: Map directly to gcrypt hash functions.
[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;
d0ed201e
MR
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;
36457566 868#else
2bb04905 869 if (kill(-1, SIGKILL) == 0) break;
36457566 870#endif
2bb04905
LC
871 if (errno == ESRCH) break; /* no more processes */
872 if (errno != EINTR)
873 throw SysError(format("cannot kill processes for uid `%1%'") % uid);
36457566 874 }
2bb04905 875
36457566 876 _exit(0);
2bb04905 877 });
36457566 878
36457566 879 int status = pid.wait(true);
d0ed201e
MR
880#if __GNU__
881 /* When the child killed itself, status = SIGKILL. */
882 if (status == SIGKILL) return;
883#endif
36457566
LC
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
2bb04905
LC
897pid_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 {
54c260e6
LC
906#if __linux__
907 if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
908 throw SysError("setting death signal");
909#endif
2bb04905
LC
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
322eeb87 927std::vector<char *> stringsToCharPtrs(const Strings & ss)
54c260e6 928{
322eeb87
LC
929 std::vector<char *> res;
930 for (auto & s : ss) res.push_back((char *) s.c_str());
54c260e6
LC
931 res.push_back(0);
932 return res;
933}
934
935
36457566
LC
936string runProgram(Path program, bool searchPath, const Strings & args)
937{
938 checkInterrupt();
939
36457566
LC
940 /* Create a pipe. */
941 Pipe pipe;
942 pipe.create();
943
944 /* Fork. */
2bb04905
LC
945 Pid pid = startProcess([&]() {
946 if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
947 throw SysError("dupping stdout");
36457566 948
54c260e6
LC
949 Strings args_(args);
950 args_.push_front(program);
54c260e6 951
2bb04905 952 if (searchPath)
322eeb87 953 execvp(program.c_str(), stringsToCharPtrs(args_).data());
2bb04905 954 else
322eeb87 955 execv(program.c_str(), stringsToCharPtrs(args_).data());
36457566 956
2bb04905
LC
957 throw SysError(format("executing `%1%'") % program);
958 });
36457566
LC
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))
2bb04905 967 throw ExecError(format("program `%1%' %2%")
36457566
LC
968 % program % statusToString(status));
969
970 return result;
971}
972
973
974void 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
985void 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
36457566
LC
994//////////////////////////////////////////////////////////////////////
995
996
997volatile sig_atomic_t _isInterrupted = 0;
998
999void _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
1015template<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
1029template Strings tokenizeString(const string & s, const string & separators);
1030template StringSet tokenizeString(const string & s, const string & separators);
1031template vector<string> tokenizeString(const string & s, const string & separators);
1032
1033
1034string 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
1045string 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
1056string 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
1063string 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
1083bool statusOk(int status)
1084{
1085 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
1086}
1087
1088
1089bool hasSuffix(const string & s, const string & suffix)
1090{
1091 return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix;
1092}
1093
1094
1095void 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)
15ddeff5 1100 throw FormatError(format("expected string `%1%'") % s);
36457566
LC
1101}
1102
1103
1104string 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
1122bool 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
36457566
LC
1136void ignoreException()
1137{
1138 try {
1139 throw;
1140 } catch (std::exception & e) {
1141 printMsg(lvlError, format("error (ignored): %1%") % e.what());
1142 }
1143}
1144
1145
1146}