UP | HOME

Using Files
Systems Programming
COP-3402

Table of Contents

What is systems software?

The bridge between kernel and applications

applications.jpeg

Applications
Systems software
Kernel
Hardware

hardware_named.jpeg

Kernel design

Kernel virtualizes hardware

  • Abstract away hardware difference
  • Share hardware resources
  • Protect hardware from users

Kernel-/user-space boundary

(Diagram)

  • User-space application opens a file
  • Kernel-space function implement file abstraction
  • Hardware stores file contents

Kernel provides library of functions to manage kernel abstractions.

User applications call kernel to interface to hardware and maintain abstractions on its behalf.

For example, calling open is a kernel library function which handles paths, the file abstraction, and interfacing with storage hardware

This is the case for so-called monolithic kernels, where kernel abstractions are largely managed in kernel space.

https://en.wikipedia.org/wiki/Tanenbaum%E2%80%93Torvalds_debate

Kernel interface: syscalls

  • System calls (syscalls)
  • Functions that operate on kernel abstractions
    • Processes, memory, files, etc.

Implementation: protected mode

  • LPI Figure 3-1
  • Hardware interrupt to enter kernel space

How do we enforce kernel protections?

Learn more about kernel design in operating systems.

System Calls (syscalls)

Making syscalls

  • Just like a C function
  • The C library handles
    • Setting up parameters
    • Triggering interrupt
    • Collecting return values and error states

You can add your own syscall to Linux!

What syscalls are available?

man syscalls

manpage sections

man man
  • Section 2: system calls
  • Section 3: library calls

C library calls

man 3 fopen
man 3 fprintf
man 3 fscanf

Operates on FILE data structures, a C library abstraction. Adds additional features, like buffering, formatting, etc.

Diagram showing the difference w.r.t. to the kernel boundary.

syscalls

man 2 open
man 2 write
man 2 read

Operates directly on kernel files, references by file descriptors. Work with raw bytes.

Error handling

The UNIX way

  • DIY error handling
  • Check syscall return value
  • Inspect error state

Example: open()

int fd = open(path, O_RDONLY);
if (-1 == fd) {
  fprintf(stderr, "open failed with error %d\n", errno);
  exit(EXIT_FAILURE);
}

Check return value for error.

Look at errno for type of error.

Documentation

man 2 open
  • RETURN VALUE
  • ERRORS

Error helper: perror()

int fd = open(path, O_RDONLY);
if (-1 == fd) {
  // fprintf(stderr, "open() failed with error %d\n", errno);
  perror("open")  # perror will interpret errno for you
  exit(EXIT_FAILURE);
}

Full example of errno.c

#include <fcntl.h>     // O_RDONLY, open
#include <unistd.h>    // read, close
#include <errno.h>     // errno
#include <stdio.h>     // perror, fprintf
#include <stdlib.h>    // exit

int main(int argc, char **argv) {
  if (argc < 2) {
    fprintf(stderr, "USAGE: %s file\n", argv[0]);
    exit(1);
  }
  char *path = argv[1];
  int fd = open(path, O_RDONLY);
  if (-1 == fd) {
    perror("open");
    exit(1);
  }

  if (-1 == close(fd)) {
    perror("close");
  }
}
strace ./errno missingfile |& egrep "^(open|exit|close|perror)"
strace ./errno files.c |& egrep "^(open|exit|close|perror)"

Notice that exit and perror are not in strace, because these are C library calls. exit wraps a call to exit_group and perror is a user-space function that interprets the errno. Also note that open is implemented by calling the openat syscall, which is another variant of open.

Using file syscalls

Reading Files

Symbol Reference Reading
open() man 2 open LPI 4.1
read() man 2 read  
close() man 2 close  

Full example of files.c

#include <fcntl.h>     // O_RDONLY, open
#include <unistd.h>    // read, close
#include <errno.h>     // errno
#include <stdio.h>     // perror, fprintf
#include <stdlib.h>    // exit

int main(int argc, char **argv) {
  if (argc < 2) {
    fprintf(stderr, "USAGE: %s file\n", argv[0]);
    exit(1);
  }
  char *path = argv[1];
  int fd = open(path, O_RDONLY);
  if (-1 == fd) {
    perror("open");
    exit(1);
  }

  const int BUFSIZE = 10;
  char buf[BUFSIZE];
  int bytes = read(fd, buf, BUFSIZE);
  if (-1 == bytes) {
    perror("read");
    exit(1);
  }

  for (int i = 0; i < bytes; i++) {
    printf("%c", buf[i]);
  }

  if (-1 == close(fd)) {
    perror("close");
  }
}

Directory Operations

Symbol Reference Reading
opendir() man 3 opendir LPI 18.8
readdir() man 3 readdir  
closedir() man 3 closedir  

Full example of dir.c

#include <fcntl.h>     // O_RDONLY, open
#include <unistd.h>    // read, close
#include <errno.h>     // errno
#include <stdio.h>     // perror, fprintf
#include <stdlib.h>    // exit
#include <dirent.h>    // opendir, readdir, DIR, struct dirent

int main(int argc, char **argv) {
  if (argc < 2) {
    fprintf(stderr, "USAGE: %s path\n", argv[0]);
    exit(1);
  }

  char *path = argv[1];
  DIR *dirp = opendir(path);
  if (NULL == dirp) {
    perror("opendir");
    exit(EXIT_FAILURE);
  }

  struct dirent *curdir;
  // ls -f should be the same order
  // why not same order as ls?
  while ((curdir = readdir(dirp)) != NULL) {
    printf("%s\n", curdir->d_name);

    // concatenating path names?

  }
  if (-1 == closedir(dirp)) {
    perror("closedir");
    exit(1);
  }
}

File Status

Symbol Reference Reading
stat() man 2 stat LPI 15.1
struct stat man 3 stat  
st_mode man 7 inode  

Use the stat command to see what kind of info is stored in the stat struct.

Full example of stat.c

#include <errno.h>     // errno
#include <stdio.h>     // perror, fprintf
#include <stdlib.h>    // exit
#include <inttypes.h>  // PRIdMAX
#include <sys/stat.h>  // stat

int main(int argc, char **argv) {
  if (argc < 2) {
    fprintf(stderr, "USAGE: %s path\n", argv[0]);
    exit(1);
  }

  char *path = argv[1];

  struct stat statbuf;
  if (stat(path, &statbuf) == -1) {
    perror("stat");
    exit(EXIT_FAILURE);
  }
  printf("links: %" PRIdMAX "\n", statbuf.st_nlink);
  printf("size: %" PRIdMAX "\n", statbuf.st_size);
  switch (statbuf.st_mode & S_IFMT) {
  case S_IFREG:
    printf("REG\n");
    break;
  case S_IFDIR:
    printf("DIR\n");
    break;
  case S_IFSOCK:
    printf("SOCK\n");
    break;
  case S_IFLNK:
    printf("LNK\n");
    break;
  case S_IFBLK:
    printf("BLK\n");
    break;
  case S_IFCHR:
    printf("CHR\n");
    break;
  case S_IFIFO:
    printf("FIFO\n");
    break;
  default:
    // should never happen
    printf("UNKNOWN\n");
    break;
  }
}

If hard links to directories can't be created by the user, where are these hard links from?

From the .. parent directories and subdirectories.

myls Project Overview

Motivating questions

  • How to find the number of files in a directory?
  • How to tell whether a file is regular or a directory?
  • How to check the file mode?

Author: Paul Gazzillo

Created: 2024-09-24 Tue 22:32

Validate