12#include <sys/utsname.h>
18 struct timespec value;
19 return clock_gettime(CLOCK_MONOTONIC, &value)
21 : (int64_t)value.tv_sec * 1000000000 + value.tv_nsec;
24int ns_reap(pid_t pid,
int milliseconds) {
25 int64_t start = ns_now(), now, end = start + (int64_t)milliseconds * 1000000;
26 while (start >= 0 && (now = ns_now()) >= 0 && now < end) {
28 pid_t result = waitpid(pid, &status, WNOHANG);
30 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
31 if (result < 0 && errno != EINTR)
33 struct timespec pause = {0, 5000000};
34 nanosleep(&pause, NULL);
37 while (waitpid(pid, NULL, 0) < 0 && errno == EINTR) {
42int ns_read(
int fd,
void* buffer,
size_t length) {
43 unsigned char* bytes = buffer;
45 struct pollfd ready = {.fd = fd, .events = POLLIN};
48 result = poll(&ready, 1, 10000);
49 while (result < 0 && errno == EINTR);
52 ssize_t count = read(fd, bytes, length);
53 if (count < 0 && errno == EINTR)
63int ns_write(
int fd,
const void* buffer,
size_t length) {
64 const unsigned char* bytes = buffer;
66 ssize_t count = write(fd, bytes, length);
67 if (count < 0 && errno == EINTR)
76int ns_send(
int fd,
char value) {
77 return ns_write(fd, &value, 1);
79int ns_receive(
int fd,
char value) {
81 return ns_read(fd, &actual, 1) || actual != value ? -1 : 0;
84int ns_spawn(
struct ns_peer* peer,
int (*body)(
int,
int,
void*),
void* argument) {
85 int command[2], report[2];
98 int result = body(command[0], report[1], argument);
101 _exit(result ? 1 : 0);
110 *peer = (
struct ns_peer){pid, command[1], report[0]};
114int ns_join(
struct ns_peer* peer) {
115 int result = ns_reap(peer->pid, 10000);
117 fprintf(stderr,
"namespace child pid=%d status=%d\n", peer->pid, result);
122void ns_cleanup(
struct ns_peer* peer) {
124 kill(peer->pid, SIGKILL);
125 ns_reap(peer->pid, 1000);
127 if (peer->command >= 0)
128 close(peer->command);
129 if (peer->report >= 0)
131 *peer = (
struct ns_peer)NS_PEER_INITIALIZER;
136 if (fstat(fd, &status) || !status.st_ino)
142 int fd = open(path, O_RDONLY | O_CLOEXEC);
145 int result = ns_fd_identity(fd,
identity);
150 return left.device == right.device && left.inode == right.inode;
152int ns_set(
const char* host,
const char* domain) {
153 return sethostname(host, strlen(host)) || setdomainname(domain, strlen(domain));
155int ns_expect(
const char* host,
const char* domain) {
156 struct utsname value;
159 if (!strcmp(value.nodename, host) && !strcmp(value.domainname, domain))
161 fprintf(stderr,
"namespace names expected=%s/%s actual=%s/%s\n", host, domain, value.nodename,
166int ns_send_fd(
int socket,
int fd) {
168 struct iovec vector = {&byte, 1};
170 struct cmsghdr align;
171 char bytes[CMSG_SPACE(
sizeof(
int))];
173 struct msghdr
message = {.msg_iov = &vector,
175 .msg_control = control.bytes,
176 .msg_controllen =
sizeof(control)};
177 struct cmsghdr* header = CMSG_FIRSTHDR(&
message);
178 header->cmsg_level = SOL_SOCKET;
179 header->cmsg_type = SCM_RIGHTS;
180 header->cmsg_len = CMSG_LEN(
sizeof(
int));
181 memcpy(CMSG_DATA(header), &fd,
sizeof(fd));
182 return sendmsg(socket, &
message, 0) == 1 ? 0 : -1;
184int ns_receive_fd(
int socket) {
186 struct iovec vector = {&byte, 1};
188 struct cmsghdr align;
189 char bytes[CMSG_SPACE(
sizeof(
int))];
191 struct msghdr
message = {.msg_iov = &vector,
193 .msg_control = control.bytes,
194 .msg_controllen =
sizeof(control)};
195 if (recvmsg(socket, &
message, 0) != 1 ||
byte !=
'N' || (
message.msg_flags & MSG_CTRUNC))
197 struct cmsghdr* header = CMSG_FIRSTHDR(&
message);
198 if (!header || header->cmsg_level != SOL_SOCKET || header->cmsg_type != SCM_RIGHTS ||
199 header->cmsg_len != CMSG_LEN(
sizeof(
int)))
202 memcpy(&fd, CMSG_DATA(header),
sizeof(fd));