Linux System Programming
System programming involves writing software that provides services to applications or interacts directly with the operating system kernel. This includes file I/O, process management, networking, and device interaction.
File I/O
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
// Low-level file operations
int fd = open("file.txt", O_RDWR | O_CREAT, 0644);
if (fd == -1) {
perror("open");
return -1;
}
char buffer[1024];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
ssize_t bytes_written = write(fd, "Hello", 5);
// Memory-mapped I/O
void* addr = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
// ... use memory directly ...
munmap(addr, file_size);
close(fd);
Process Management
#include <unistd.h>
#include <sys/wait.h>
// Fork a new process
pid_t pid = fork();
if (pid == 0) {
// Child process
execl("/bin/ls", "ls", "-la", NULL);
_exit(1); // Only reached if exec fails
} else if (pid > 0) {
// Parent process
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
printf("Child exited with code %d\n", WEXITSTATUS(status));
}
} else {
perror("fork");
}
Creating a Daemon
#include <syslog.h>
void daemonize() {
pid_t pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS); // Parent exits
// Create new session
if (setsid() < 0) exit(EXIT_FAILURE);
// Fork again to prevent controlling terminal
pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS);
// Set file permissions
umask(0);
// Change working directory
chdir("/");
// Close standard file descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// Open syslog
openlog("mydaemon", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Daemon started");
}
Systemd Service
Modern Linux uses systemd for service management:
# /etc/systemd/system/myservice.service
[Unit]
Description=My Custom Service
After=network.target
[Service]
Type=simple
User=myuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/myservice
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
# Manage the service
sudo systemctl daemon-reload
sudo systemctl start myservice
sudo systemctl enable myservice
sudo systemctl status myservice
journalctl -u myservice -f
Signals
#include <signal.h>
volatile sig_atomic_t running = 1;
void signal_handler(int sig) {
if (sig == SIGTERM || sig == SIGINT) {
running = 0;
}
}
int main() {
// Set up signal handlers
struct sigaction sa;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
while (running) {
// Main loop
sleep(1);
}
printf("Shutting down gracefully\n");
return 0;
}
IPC Mechanisms
- Pipes: Simple unidirectional communication
- Named Pipes (FIFO): File-based pipes
- Message Queues: Kernel-managed message passing
- Shared Memory: Fastest IPC for large data
- Sockets: Network and local communication