This repository has been archived on 2022-05-27. You can view files and clone it, but cannot push or open issues or pull requests.
ocaml-cgroups2/examples/cp/cp_cgroup.c
2021-12-31 11:00:37 +00:00

145 lines
2.8 KiB
C

#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define IO_BLOCK_SIZE 4096
/*
* Get size of regular file or error otherwise.
*/
off_t get_file_size(int fd) {
struct stat st;
if (fstat(fd, &st) < 0) {
perror("fstat");
return -1;
}
if (S_ISREG(st.st_mode)) {
return st.st_size;
} else {
return -1;
}
}
/*
* Move self to a leaf node of the cgroup.
*/
int leaf_self() {}
/*
* Perform the copy between the two file descriptors.
*/
int copy(int src_fd, int dst_fd) {
off_t src_len;
int passwd_fd;
if ((passwd_fd = open("/home/jake/plot", O_RDONLY)) == -1) {
perror("open 2");
return 1;
} else {
// TODO: Debug this
fprintf(stderr, "opened second file successfully\n");
}
if ((src_len = get_file_size(src_fd)) == -1) {
return 1;
}
char buf[IO_BLOCK_SIZE];
off_t blocks =
(src_len / IO_BLOCK_SIZE) + ((src_len % IO_BLOCK_SIZE) > 0 ? 1 : 0);
for (off_t i = 0; i < blocks; i++) {
off_t len;
if (i == blocks - 1 && src_len % IO_BLOCK_SIZE != 0) {
len = src_len % IO_BLOCK_SIZE;
} else {
len = IO_BLOCK_SIZE;
}
if (read(src_fd, &buf, len) == -1) {
perror("read");
return -1;
};
if (write(dst_fd, &buf, len) == -1) {
perror("write");
return -1;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "usage: %s <src> <dst>\n", argv[0]);
return 1;
}
int src_fd, dst_fd;
if ((src_fd = open(argv[1], O_RDONLY)) == -1) {
perror("open");
return 1;
}
if ((dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
perror("open");
return 1;
}
// all necessary files opened, drop filesystem
if (unshare(CLONE_FS) == -1) {
perror("unshare");
return -1;
}
// fork and copy in a second process
pid_t child_pid = fork();
if (child_pid == -1) {
perror("fork");
return -1;
} else if (child_pid == 0) {
// pause(); // await cgroup setup
raise(SIGSTOP); // await cgroup setup
return copy(src_fd, dst_fd);
}
// setup a cgroup for the child
// wait for the child to pause and restart it
int status;
if (waitpid(child_pid, &status, WUNTRACED | WSTOPPED) == -1) {
perror("waitpid");
return -1;
}
if (WIFSTOPPED(status)) {
if (kill(child_pid, SIGCONT) == -1) {
perror("kill");
return -1;
}
} else {
fprintf(stderr, "child behaved unexpectedly\n");
return -1;
}
// wait for the child process to terminate
if (waitpid(child_pid, &status, 0) == -1) {
perror("waitpid");
return -1;
}
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
return -1;
}