Skip to content

Instantly share code, notes, and snippets.

@sjolsen
Created June 29, 2024 03:42
Show Gist options
  • Save sjolsen/4df00bc861d9f6d960f6cb426ec58247 to your computer and use it in GitHub Desktop.
Save sjolsen/4df00bc861d9f6d960f6cb426ec58247 to your computer and use it in GitHub Desktop.
demonstrating shared file description state across fork
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int write_all(int fd, const void *buf, size_t count) {
const char *cbuf = (const char *)buf;
while (count > 0) {
ssize_t rv = write(fd, cbuf, count);
if (rv == (ssize_t)-1) {
switch (errno) {
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
case EINTR:
continue;
default:
return errno;
}
}
size_t written = (size_t)rv;
cbuf += written;
count -= written;
}
return 0;
}
int read_all(int fd, void *buf, size_t count) {
char *cbuf = (char *)buf;
while (count > 0) {
ssize_t rv = read(fd, cbuf, count);
if (rv == (ssize_t)-1) {
switch (errno) {
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
case EINTR:
continue;
default:
return errno;
}
}
size_t nread = (size_t)rv;
cbuf += nread;
count -= nread;
}
return 0;
}
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s file\n", argv[0] ? argv[0] : "fork_fd");
return EXIT_FAILURE;
}
const char *filename = argv[1];
int fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0777);
if (fd < 0) {
fprintf(stderr, "open: %s: %s\n", strerror(errno), filename);
return EXIT_FAILURE;
}
const char *data = "Hello, world!\n";
int status = write_all(fd, data, strlen(data));
if (status != 0) {
fprintf(stderr, "write: %s: %s\n", strerror(status), filename);
return EXIT_FAILURE;
}
off_t offset = lseek(fd, 0, SEEK_SET);
if (offset == (off_t)-1) {
fprintf(stderr, "lseek: %s: %s\n", strerror(errno), filename);
return EXIT_FAILURE;
}
pid_t pid = fork();
if (pid == (pid_t)-1) {
fprintf(stderr, "fork: %s\n", strerror(errno));
return EXIT_FAILURE;
}
if (pid == 0) {
// Child
char rbuf[8];
status = read_all(fd, rbuf, 7);
if (status != 0) {
fprintf(stderr, "read: %s: %s\n", strerror(status), filename);
return EXIT_FAILURE;
}
rbuf[7] = '\0';
printf("Child process: read '%s'\n", rbuf);
} else {
// Parent
int wstatus;
pid_t wait_rv = waitpid(pid, &wstatus, 0);
if (wait_rv == (pid_t)-1) {
fprintf(stderr, "wait: %s\n", strerror(errno));
return EXIT_FAILURE;
}
if (!WIFEXITED(wstatus)) {
fprintf(stderr, "wait: child process exited abnormally\n");
return EXIT_FAILURE;
}
if (WEXITSTATUS(wstatus) != 0) {
return WEXITSTATUS(wstatus);
}
char rbuf[8];
status = read_all(fd, rbuf, 7);
if (status != 0) {
fprintf(stderr, "read: %s: %s\n", strerror(status), filename);
return EXIT_FAILURE;
}
rbuf[7] = '\0';
printf("Parent process: read '%s'\n", rbuf);
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment