main shrubtools / nviz / os-posix.c
  1#define _POSIX_C_SOURCE 200809L
  2#include <errno.h>
  3#include <stdbool.h>
  4#include <stdlib.h>
  5#include <stdint.h>
  6#include <fcntl.h>
  7#include <sys/stat.h>
  8#include <unistd.h>
  9#ifndef NO_POSIX_SPAWN
 10#include <spawn.h>
 11#endif
 12#include "graph.h"
 13#include "os.h"
 14#include "util.h"
 15
 16void
 17osgetcwd(char *buf, size_t len)
 18{
 19	if (!getcwd(buf, len))
 20		fatal("getcwd:");
 21}
 22
 23void
 24oschdir(const char *dir)
 25{
 26	if (chdir(dir) < 0)
 27		fatal("chdir %s:", dir);
 28}
 29
 30int
 31osmkdirs(struct string *path, bool parent)
 32{
 33	int ret;
 34	struct stat st;
 35	char *s, *end;
 36
 37	ret = 0;
 38	end = path->s + path->n;
 39	for (s = end - parent; s > path->s; --s) {
 40		if (*s != '/' && *s)
 41			continue;
 42		*s = '\0';
 43		if (stat(path->s, &st) == 0)
 44			break;
 45		if (errno != ENOENT) {
 46			warn("stat %s:", path->s);
 47			ret = -1;
 48			break;
 49		}
 50	}
 51	if (s > path->s && s < end)
 52		*s = '/';
 53	while (++s <= end - parent) {
 54		if (*s != '\0')
 55			continue;
 56		if (ret == 0 && mkdir(path->s, 0777) < 0 && errno != EEXIST) {
 57			warn("mkdir %s:", path->s);
 58			ret = -1;
 59		}
 60		if (s < end)
 61			*s = '/';
 62	}
 63
 64	return ret;
 65}
 66
 67int64_t
 68osmtime(const char *name)
 69{
 70	struct stat st;
 71
 72	if (stat(name, &st) < 0) {
 73		if (errno != ENOENT)
 74			fatal("stat %s:", name);
 75		return MTIME_MISSING;
 76	} else {
 77#ifdef __APPLE__
 78		return (int64_t)st.st_mtime * 1000000000 + st.st_mtimensec;
 79/*
 80Illumos hides the members of st_mtim when you define _POSIX_C_SOURCE
 81since it has not been updated to support POSIX.1-2008:
 82https://www.illumos.org/issues/13327
 83*/
 84#elif defined(__sun)
 85		return (int64_t)st.st_mtim.__tv_sec * 1000000000 + st.st_mtim.__tv_nsec;
 86#else
 87		return (int64_t)st.st_mtim.tv_sec * 1000000000 + st.st_mtim.tv_nsec;
 88#endif
 89	}
 90}
 91
 92long
 93osnproc(void)
 94{
 95#ifdef _SC_NPROCESSORS_ONLN
 96	return sysconf(_SC_NPROCESSORS_ONLN);
 97#else
 98	return 1;
 99#endif
100}
101
102pid_t
103osspawn(char *const argv[], int outfd)
104{
105#ifdef NO_POSIX_SPAWN
106	pid_t pid;
107	int i, fd[3];
108
109	pid = fork();
110	switch (pid) {
111	case 0:
112		if (outfd != -1) {
113			fd[0] = open("/dev/null", O_RDONLY | O_CLOEXEC);
114			if (fd[0] == -1)
115				_exit(1);
116			fd[1] = outfd;
117			fd[2] = outfd;
118			for (i = 0; i <= 2; ++i) {
119				if (dup2(fd[i], i) == -1)
120					_exit(1);
121			}
122		}
123		execvp(argv[0], argv);
124		_exit(1);
125		/* unreachable */
126		return -1;
127	default:
128		return pid;
129	case -1:
130		warn("fork:");
131		return -1;
132	}
133#else
134	extern char **environ;
135	pid_t pid;
136	posix_spawn_file_actions_t actions;
137
138	if ((errno = posix_spawn_file_actions_init(&actions))) {
139		warn("posix_spawn_file_actions_init:");
140		goto err0;
141	}
142	if (outfd != -1) {
143		if ((errno = posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDONLY, 0))) {
144			warn("posix_spawn_file_actions_adddup2:");
145			goto err1;
146		}
147		if ((errno = posix_spawn_file_actions_adddup2(&actions, outfd, 1))) {
148			warn("posix_spawn_file_actions_adddup2:");
149			goto err1;
150		}
151		if ((errno = posix_spawn_file_actions_adddup2(&actions, outfd, 2))) {
152			warn("posix_spawn_file_actions_adddup2:");
153			goto err1;
154		}
155	}
156	if ((errno = posix_spawn(&pid, argv[0], &actions, NULL, argv, environ))) {
157		warn("posix_spawn %s:", argv[0]);
158		goto err1;
159	}
160	posix_spawn_file_actions_destroy(&actions);
161	return pid;
162
163err1:
164	posix_spawn_file_actions_destroy(&actions);
165err0:
166	return -1;
167#endif
168}