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}