What is a a FIFO, or “named pipe”? What is mkfifo in C?

Yet Another kind of “file” in UNIX is the “named pipe”, or “FIFO” (“First In, First Out”; i.e. a queue). The named pipe is created with the mkfifo system call. A named pipe is much like a traditional pipe, created with the pipe system call. However, while pipe provides access via two file descriptors, the named pipe is accessed via the filesystem at a path.

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * path, mode_t mode);

Here’s an example. It creates a FIFO, forks, then the parent process talks to the child via the FIFO. (This could also be achieved with “unnamed pipes”.)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char const * const FIFO_PATH = "my_pipe";

int guard(int ret, char * err) {
  if (ret == -1) { perror(err); exit(1); }
  return ret;
}

void write_all(int fd, char * bytes, size_t nbyte) {
  ssize_t written = 0;
  while(written < nbyte) {
    written += guard(write(fd, bytes+written, nbyte-written), "Could not write to pipe");
  }
}

void write_str(int fd, char * chars) { write_all(fd, chars, strlen(chars)); }

int main(void) {
  guard(mkfifo(FIFO_PATH, 0777), "Could not create pipe");
  pid_t child_pid = fork();
  if (child_pid == 0) {
    // Child
    int pipe_read_fd = guard(open(FIFO_PATH, O_RDONLY), "Could not open pipe for reading");
    char buf[4];
    for (;;) {
      ssize_t num_read = guard(read(pipe_read_fd, buf, sizeof(buf)), "Could not read from pipe");
      if (num_read == 0) {
        write_str(1, "Read EOF; closing read end\n");
        guard(close(pipe_read_fd), "Could not close pipe read end");
        break;
      } else {
        write_str(1, "Read from pipe: ");
        write_all(1, buf, num_read);
        write_str(1, "\n");
      }
    }
  } else {
    // Parent
    int pipe_write_fd = guard(open(FIFO_PATH, O_WRONLY), "Could not open pipe for writing");
    write_str(pipe_write_fd, "Hello, pipe");
    guard(close(pipe_write_fd), "Could not close pipe write end");
  }

  return 0;
}

This prints:

$ ./a.out
Read from pipe: Hell
Read from pipe: o, p
Read from pipe: ipe
Read EOF; closing read end

I wrote this because I felt like it. This post is not associated with my employer.