/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2020. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Supplementary program for Chapter 19 */
/* Known limitations
- Pathnames longer than PATH_MAX are not handled.
*/
#define _GNU_SOURCE
#include <sys/select.h>
#include <sys/stat.h>
#include <limits.h>
#include <sys/select.h>
#include <sys/inotify.h>
#include <fcntl.h>
#include <ftw.h>
#include <signal.h>
#include <stdarg.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
/* logMessage() flags */
#define VB_BASIC 1 /* Basic messages */
#define VB_NOISY 2 /* Verbose messages */
static int verboseMask;
static int checkCache;
static int dumpCache;
static int readBufferSize = 0;
static char *stopFile;
static int abortOnCacheProblem;
static FILE *logfp = NULL;
static int inotifyReadCnt = 0; /* Counts number of read()s from
inotify file descriptor */
static const int INOTIFY_READ_BUF_LEN =
(100 * (sizeof(struct inotify_event) + NAME_MAX + 1));
static void dumpCacheToLog(void);
/* Something went badly wrong. Create a 'stop' file to signal the
'rand_dtree' processes to stop, dump a copy of the cache to the
log file, and abort. */
__attribute__ ((__noreturn__))
static void
createStopFileAndAbort(void)
{
open(stopFile, O_CREAT | O_RDWR, 0600);
dumpCacheToLog();
abort();
}
/* Write a log message. The message is sent to none, either, or both of
stderr and the log file, depending on 'vb_mask' and whether a log file
has been specified via command-line options . */
static void
logMessage(int vb_mask, const char *format, ...)
{
va_list argList;
/* Write message to stderr if 'vb_mask' is zero, or matches one
of the bits in 'verboseMask' */
if ((vb_mask == 0) || (vb_mask & verboseMask)) {
va_start(argList, format);
vfprintf(stderr, format, argList);
va_end(argList);
}
/* If we have a log file, write the message there */
if (logfp != NULL) {
va_start(argList, format);
vfprintf(logfp, format, argList);
va_end(argList);
}
}
/***********************************************************************/
/* Display some information about an inotify event. (Used when
when we are doing verbose logging.) */
static void
displayInotifyEvent(struct inotify_event *ev)
{
logMessage(VB_NOISY, "==> wd = %d; ", ev->wd);
if (ev->cookie > 0)
logMessage(VB_NOISY, "cookie = %4d; ", ev->cookie);
logMessage(VB_NOISY, "mask = ");
if (ev->mask & IN_ISDIR)
logMessage(VB_NOISY, "IN_ISDIR ");
if (ev->mask & IN_CREATE)
logMessage(VB_NOISY, "IN_CREATE ");
if (ev->mask & IN_DELETE_SELF)
logMessage(VB_NOISY, "IN_DELETE_SELF ");
if (ev->mask & IN_MOVE_SELF)
logMessage(VB_NOISY, "IN_MOVE_SELF ");
if (ev->mask & IN_MOVED_FROM)
logMessage(VB_NOISY, "IN_MOVED_FROM ");
if (ev->mask & IN_MOVED_TO)
logMessage(VB_NOISY, "IN_MOVED_TO ");
if (ev->mask & IN_IGNORED)
logMessage(VB_NOISY, "IN_IGNORED ");
if (ev->mask & IN_Q_OVERFLOW)
logMessage(VB_NOISY, "IN_Q_OVERFLOW ");
if (ev->mask & IN_UNMOUNT)
logMessage(VB_NOISY, "IN_UNMOUNT ");
logMessage(VB_NOISY, "\n");
if (ev->len > 0)
logMessage(VB_NOISY, " name = %s\n", ev->name);
}
/***********************************************************************/
/* Data structures and functions for the watch list cache */
/* We use a very simple data structure for caching watched directory
paths: a dynamically sized array that is searched linearly. Not
efficient, but our main goal is to demonstrate the use of inotify. */
struct watch {
int wd; /* Watch descriptor (-1 if slot unused) */
char path[PATH_MAX]; /* Cached pathname */
};
struct watch *wlCache = NULL; /* Array of cached items */
static int cacheSize = 0; /* Current size of the array */
/* Deallocate the watch cache */
static void
freeCache(void)
{
free(wlCache);
cacheSize = 0;
wlCache = NULL;
}
/* Check that all pathnames in the cache are valid, and refer
to directories */
static void
checkCacheConsistency(void)
{
int failures;
struct stat sb;
failures = 0;
for (int j = 0; j < cacheSize; j++) {
if (wlCache[j].wd >= 0) {
if (lstat(wlCache[j].path, &sb) == -1) {
logMessage(0,
"checkCacheConsistency: stat: "
"[slot = %d; wd = %d] %s: %s\n",
j, wlCache[j].wd, wlCache[j].path, strerror(errno));
failures++;
} else if (!S_ISDIR(sb.st_mode)) {
logMessage(0, "checkCacheConsistency: %s is not a directory\n",
wlCache[j].path);
exit(EXIT_FAILURE);
}
}
}
if (failures > 0)
logMessage(VB_NOISY, "checkCacheConsistency: %d failures\n",
failures);
}
/* Check whether the cache contains the watch descriptor 'wd'.
If found, return the slot number, otherwise return -1. */
static int
findWatch(int wd)
{
for (int j = 0; j < cacheSize; j++)
if (wlCache[j].wd == wd)
return j;
return -1;
}
/* Find and return the cache slot for the watch descriptor 'wd'.
The caller expects this watch descriptor to exist. If it does not,
there is a problem, which is signaled by the -1 return. */
static int
findWatchChecked(int wd)
{
int slot;
slot = findWatch(wd);
if (slot >= 0)
return slot;
logMessage(0, "Could not find watch %d\n", wd);
/* With multiple renamers there are still rare cases where
the cache is missing entries after a 'Could not find watch'
event. It looks as though this is because of races with nftw(),
since the cache is (occasionally) re-created with fewer
entries than there are objects in the tree(s). Returning
-1 to our caller identifies that there's a problem, and the
caller should probably trigger a cache rebuild. */
if (abortOnCacheProblem) {
createStopFileAndAbort();
} else {
return -1;
}
}
/* Mark a cache entry as unused */
static void
markCacheSlotEmpty(int slot)
{
logMessage(VB_NOISY,
" markCacheSlotEmpty: slot = %d; wd = %d; path = %s\n",
slot, wlCache[slot].wd, wlCache[slot].path);
wlCache[slot].wd = -1;
wlCache[slot].path[0] = '\0';
}
/* Find a free slot in the cache */
static int
findEmptyCacheSlot(void)
{
const int ALLOC_INCR = 200;
for (int j = 0; j < cacheSize; j++)
if (wlCache[j].wd == -1)
return j;
/* No free slot found; resize cache */
cacheSize += ALLOC_INCR;
wlCache = realloc(wlCache, cacheSize * sizeof(struct watch));
if (wlCache == NULL)
errExit("realloc");
for (int j = cacheSize - ALLOC_INCR; j < cacheSize; j++)
markCacheSlotEmpty(j);
return cacheSize - ALLOC_INCR; /* Return first slot in
newly allocated space */
}
/* Add an item to the cache */
static int
addWatchToCache(int
linux/unix系统编程手册附录代码
需积分: 0 25 浏览量
更新于2023-06-04
收藏 260KB GZ 举报
《Linux/Unix系统编程手册》是一本深受程序员和系统管理员喜爱的经典著作,它详细阐述了在Linux和Unix操作系统上进行低级编程的各种技术。附录中的代码是书中的实例,旨在帮助读者深入理解和掌握这些系统编程的核心概念。下面将详细讨论其中涉及的知识点。
1. **进程管理**:
- `fork()`: 创建新进程,是Unix/Linux编程中最基本的函数之一。
- `execve()`: 在已存在的进程中替换其执行映像,加载新的程序。
- `wait()` 和 `waitpid()`: 等待子进程结束并获取其退出状态。
- `signal()`, `raise()`: 处理和发送信号,用于进程间的通信和异常处理。
2. **文件和I/O操作**:
- `open()`, `close()`: 打开和关闭文件。
- `read()`, `write()`: 从文件或设备读取和写入数据。
- `fopen()`, `fclose()`: C标准库中的文件操作函数,与系统调用相对应。
- `pipe()`, `fifo()`: 创建管道和命名管道,实现进程间通信。
- `dup()`, `dup2()`: 复制或重定向文件描述符。
- `ioctl()`: 对I/O设备进行控制操作。
3. **网络编程**:
- `socket()`: 创建套接字,是网络通信的基础。
- `bind()`, `listen()`, `accept()`: 绑定地址,监听连接请求,接受新连接。
- `connect()`: 客户端连接服务器。
- `send()`, `recv()`: 发送和接收网络数据。
- `select()`, `poll()`: 监控多个文件描述符的状态变化,包括网络套接字。
4. **文件系统和权限**:
- `chmod()`, `chown()`: 改变文件权限和所有者。
- `mkdir()`, `rmdir()`: 创建和删除目录。
- `access()`: 检查文件访问权限。
- `stat()`, `lstat()`: 获取文件或符号链接的状态信息。
5. **信号和同步**:
- `pthread_create()`, `pthread_join()`: 创建和等待线程结束。
- `pthread_mutex_*()`: 互斥锁,用于多线程同步。
- `semaphore`: 信号量,另一种同步机制。
- `pipe()` 和 `fork()` 实现的管道通信。
6. **错误处理和调试**:
- `perror()`, `strerror()`: 输出和转换错误消息。
- `assert()`: 断言检查,用于调试代码。
7. **内存管理**:
- `malloc()`, `calloc()`, `realloc()`, `free()`: 动态内存分配和释放。
- `mmap()`: 映射文件或设备到内存,高效读写大文件。
8. **时间和日期**:
- `time()`, `ctime()`, `strftime()`: 获取当前时间,格式化时间显示。
- `sleep()`, `nanosleep()`: 延迟程序执行。
通过阅读和分析这些附录代码,读者不仅可以学习到具体的函数用法,还能理解它们在实际场景中的应用,从而提升自己的Linux/Unix系统编程能力。这些知识点涵盖了从基础操作到高级特性的方方面面,对于软件开发、系统维护、性能优化等领域都具有极高的实用价值。

0开始
- 粉丝: 14
最新资源
- flash培训实训总结.docx
- 2023年中小学教师计算机考试试题.doc
- basic_framework-Vscode配置c / c++环境资源
- advanced-go-programming-book-汇编语言资源
- lilishop 商城 小程序 uni 移动端-C语言资源
- Java程序的设计语言课程标准.doc
- austin-Java资源
- 2022Linux认证考试试题及答案.docx
- tinyflow-Python资源
- awesome-ios-Swift资源
- Spatial_Information_Support_Force_Grouping_Mode_Analysis-Matlab资源
- 第18讲第六章综合布线电缆光缆测试.pptx
- PhalApi-机器人开发资源
- CoSec-Kotlin资源
- wmproxy-Rust资源
- 智能环境助手-硬件开发资源