Claude
Skills
Sign in
Back

c-systems-programming

Included with Lifetime
$97 forever

Use when c systems programming including file I/O, processes, signals, and system calls for low-level system interaction.

General

What this skill does


# C Systems Programming

Systems programming in C provides direct access to operating system resources
through system calls, enabling control over files, processes, signals, and
inter-process communication. This skill covers essential systems programming
patterns for building robust low-level applications.

## File I/O Operations

C provides both standard library I/O (buffered) and system-level I/O
(unbuffered) operations. Understanding when to use each is crucial for
performance and correctness.

### Standard I/O Functions

Standard I/O provides buffering and convenience functions for common operations.

```c
#include <stdio.h>
#include <stdlib.h>

// Reading and writing with standard I/O
int file_copy_stdio(const char *src, const char *dst) {
    FILE *source = fopen(src, "rb");
    if (!source) {
        perror("Failed to open source");
        return -1;
    }

    FILE *dest = fopen(dst, "wb");
    if (!dest) {
        perror("Failed to open destination");
        fclose(source);
        return -1;
    }

    char buffer[4096];
    size_t bytes;
    while ((bytes = fread(buffer, 1, sizeof(buffer), source)) > 0) {
        if (fwrite(buffer, 1, bytes, dest) != bytes) {
            perror("Write failed");
            fclose(source);
            fclose(dest);
            return -1;
        }
    }

    if (ferror(source)) {
        perror("Read failed");
        fclose(source);
        fclose(dest);
        return -1;
    }

    fclose(source);
    fclose(dest);
    return 0;
}
```

### System-Level I/O

System calls provide direct access to kernel I/O operations without buffering.

```c
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

// Reading and writing with system calls
int file_copy_syscall(const char *src, const char *dst) {
    int source_fd = open(src, O_RDONLY);
    if (source_fd == -1) {
        perror("Failed to open source");
        return -1;
    }

    int dest_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (dest_fd == -1) {
        perror("Failed to open destination");
        close(source_fd);
        return -1;
    }

    char buffer[4096];
    ssize_t bytes_read, bytes_written;

    while ((bytes_read = read(source_fd, buffer, sizeof(buffer))) > 0) {
        bytes_written = write(dest_fd, buffer, bytes_read);
        if (bytes_written != bytes_read) {
            perror("Write failed");
            close(source_fd);
            close(dest_fd);
            return -1;
        }
    }

    if (bytes_read == -1) {
        perror("Read failed");
        close(source_fd);
        close(dest_fd);
        return -1;
    }

    close(source_fd);
    close(dest_fd);
    return 0;
}
```

## Process Management

Creating and managing processes is fundamental to systems programming. The
`fork()` and `exec()` family of functions enable process creation and execution.

```c
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

// Create child process and execute command
int execute_command(const char *program, char *const argv[]) {
    pid_t pid = fork();

    if (pid == -1) {
        perror("fork failed");
        return -1;
    }

    if (pid == 0) {
        // Child process
        execvp(program, argv);
        // execvp only returns on error
        perror("execvp failed");
        exit(EXIT_FAILURE);
    }

    // Parent process
    int status;
    pid_t waited = waitpid(pid, &status, 0);

    if (waited == -1) {
        perror("waitpid failed");
        return -1;
    }

    if (WIFEXITED(status)) {
        return WEXITSTATUS(status);
    } else if (WIFSIGNALED(status)) {
        fprintf(stderr, "Child terminated by signal %d\n",
                WTERMSIG(status));
        return -1;
    }

    return -1;
}
```

## Signal Handling

Signals provide asynchronous event notification. Proper signal handling is
essential for graceful shutdown and error recovery.

```c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>

// Global flag for signal handling
static volatile sig_atomic_t keep_running = 1;

// Signal handler for graceful shutdown
void signal_handler(int signum) {
    if (signum == SIGINT || signum == SIGTERM) {
        keep_running = 0;
    }
}

// Setup signal handlers
int setup_signals(void) {
    struct sigaction sa;
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction SIGINT");
        return -1;
    }

    if (sigaction(SIGTERM, &sa, NULL) == -1) {
        perror("sigaction SIGTERM");
        return -1;
    }

    return 0;
}

// Main loop with signal handling
void run_with_signals(void) {
    if (setup_signals() == -1) {
        return;
    }

    while (keep_running) {
        // Do work
        sleep(1);
        printf("Working...\n");
    }

    printf("Shutting down gracefully\n");
}
```

## Inter-Process Communication

Pipes enable communication between related processes, commonly used for
command pipelines and parent-child communication.

```c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>

// Create a pipeline: ls | wc -l
int pipeline_example(void) {
    int pipefd[2];

    if (pipe(pipefd) == -1) {
        perror("pipe");
        return -1;
    }

    pid_t pid1 = fork();
    if (pid1 == -1) {
        perror("fork");
        return -1;
    }

    if (pid1 == 0) {
        // First child: ls
        close(pipefd[0]);  // Close read end
        dup2(pipefd[1], STDOUT_FILENO);
        close(pipefd[1]);
        execlp("ls", "ls", NULL);
        perror("execlp ls");
        exit(EXIT_FAILURE);
    }

    pid_t pid2 = fork();
    if (pid2 == -1) {
        perror("fork");
        return -1;
    }

    if (pid2 == 0) {
        // Second child: wc -l
        close(pipefd[1]);  // Close write end
        dup2(pipefd[0], STDIN_FILENO);
        close(pipefd[0]);
        execlp("wc", "wc", "-l", NULL);
        perror("execlp wc");
        exit(EXIT_FAILURE);
    }

    // Parent
    close(pipefd[0]);
    close(pipefd[1]);

    waitpid(pid1, NULL, 0);
    waitpid(pid2, NULL, 0);

    return 0;
}
```

## File Locking

File locking prevents concurrent access issues in multi-process environments.

```c
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

// Advisory file locking
int lock_file(int fd, int lock_type) {
    struct flock fl;
    fl.l_type = lock_type;    // F_RDLCK, F_WRLCK, F_UNLCK
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;             // Lock entire file
    fl.l_pid = getpid();

    if (fcntl(fd, F_SETLKW, &fl) == -1) {
        perror("fcntl");
        return -1;
    }

    return 0;
}

// Write to file with exclusive lock
int write_locked(const char *filename, const char *data) {
    int fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    // Acquire exclusive lock
    if (lock_file(fd, F_WRLCK) == -1) {
        close(fd);
        return -1;
    }

    // Write data
    ssize_t written = write(fd, data, strlen(data));
    if (written == -1) {
        perror("write");
        lock_file(fd, F_UNLCK);
        close(fd);
        return -1;
    }

    // Release lock
    lock_file(fd, F_UNLCK);
    close(fd);

    return 0;
}
```

## Directory Operations

Working with directories requires understanding directory streams and entry
manipulation.

```c
#include <dirent.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>

// List all files in directory recursively
void list_directory(const char *path, int indent) {
    DIR *dir = opendir(path);
    if (!dir) {
        perror("opendir");
        return;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        // Skip . and ..
        if (strcmp(entry->d_name, ".") == 0 ||
            strcmp(entry->d_name, "..") == 0) {
            conti

Related in General