/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2015. *
* *
* 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 */
/* inotify_dtree.c
This is an example application to demonstrate the robust use of the
inotify API.
The goal of the application is to maintain an internal representation
("a cache") of the directory trees named on its command line. To keep
the application shorter, just the directories are represented, not the
files, but dealing with the latter is simpler in any case.
As directories are added, removed, and renamed in the subtrees, the
resulting inotify events are used to maintain an internal representation
of the directory trees that remains consistent with the filesystem.
The program also provides a command-line interface that allows the user
to perform tasks such as dumping the current state of the cache and
running a consistency check of the cache against the current state of
the directory tree(s).
Testing of this program is ongoing, and bug reports (to mtk@man7.org)
are welcome.
The rand_dtree.c program can be used to stress test the operation
of this program.
See also the article
"Filesystem notification, part 2: A deeper investigation of inotify"
July 2014
https://lwn.net/Articles/605128/
*/
/* 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, j;
struct stat sb;
failures = 0;
for (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)
{
int j;
for (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 identifi
没有合适的资源?快使用搜索试试~ 我知道了~
《LINUX/UNIX系统编程手册》((德)Michael Kerrisk )随书代码完整版
5星 · 超过95%的资源 需积分: 49 505 下载量 62 浏览量
2016-04-21
09:36:10
上传
评论 15
收藏 230KB GZ 举报
温馨提示
《LINUX/UNIX系统编程手册》((德)Michael Kerrisk ),上下册,经典的LINUX/UNIX下C语言编程教材,这是这本书所用到的所有代码,包涵所有头文件,亲测在LINUX下完美运行
资源推荐
资源详情
资源评论
收起资源包目录
《LINUX/UNIX系统编程手册》((德)Michael Kerrisk )随书代码完整版 (491个子文件)
COPYING.agpl-v3 34KB
fork_whos_on_first.count.awk 776B
longest_line.awk 74B
BUILDING 5KB
inotify_dtree.c 46KB
acl_update.c 14KB
userns_child_exec.c 11KB
simple_init.c 8KB
i_fcntl_locking.c 8KB
rand_dtree.c 7KB
demo_clone.c 7KB
inet_sockets.c 6KB
inet_sockets.c 6KB
execlp.c 6KB
pthread_barrier_demo.c 6KB
t_mount.c 6KB
test_tty_functions.c 6KB
error_functions.c 5KB
t_sigsuspend.c 5KB
check_password_caps.c 5KB
scm_cred_recv.c 5KB
scm_cred_send.c 5KB
self_pipe.c 5KB
thread_multijoin.c 5KB
select_mq.c 5KB
is_seqnum_sv.c 5KB
daemon_SIGHUP.c 5KB
scm_rights_recv.c 5KB
ptmr_sigev_thread.c 5KB
real_timer.c 5KB
thread_lock_speed.c 4KB
ttyname.c 4KB
svmsg_file_server.c 4KB
is_echo_v2_sv.c 4KB
svsem_op.c 4KB
acct_v3_view.c 4KB
acl_view.c 4KB
script.c 4KB
pty_fork.c 4KB
pty_fork.c 4KB
catch_rtsigs.c 4KB
chiflag.c 4KB
dnotify.c 4KB
t_stat.c 4KB
epoll_input.c 4KB
mq_notify_sigwaitinfo.c 4KB
unbuffer.c 4KB
job_mon.c 4KB
userns_setns_test.c 4KB
is_echo_sv.c 4KB
seek_io.c 4KB
demo_inotify.c 4KB
scm_rights_send.c 4KB
multi_SIGCHLD.c 4KB
procfs_user_exe.c 4KB
ns_child_exec.c 4KB
svsem_good_init.c 4KB
demo_sched_fifo.c 4KB
unix_sockets.c 4KB
unix_sockets.c 4KB
orphaned_pgrp_SIGHUP.c 4KB
acct_view.c 4KB
nftw_dir_tree.c 4KB
utmpx_login.c 4KB
fifo_seqnum_server.c 4KB
ptmr_sigev_signal.c 3KB
system.c 3KB
seccomp_control_open.c 3KB
svshm_xfr_writer.c 3KB
popen_glob.c 3KB
multi_pidns.c 3KB
create_pid_file.c 3KB
create_pid_file.c 3KB
thread_cleanup.c 3KB
ns_run.c 3KB
get_num.c 3KB
t_clock_nanosleep.c 3KB
svshm_create.c 3KB
mq_notify_via_signal.c 3KB
change_case.c 3KB
svsem_create.c 3KB
prod_condvar.c 3KB
is_seqnum_v2_sv.c 3KB
svmsg_file_client.c 3KB
t_select.c 3KB
unshare.c 3KB
ignore_pending_sig.c 3KB
memlock.c 3KB
demo_uts_namespaces.c 3KB
pipe_sync.c 3KB
t_clone.c 3KB
demo_SIGFPE.c 3KB
mq_notify_sig.c 3KB
sig_receiver.c 3KB
is_seqnum_cl.c 3KB
tty_functions.c 3KB
tty_functions.c 3KB
is_echo_cl.c 3KB
seccomp_perf.c 3KB
file_type_stats.c 3KB
共 491 条
- 1
- 2
- 3
- 4
- 5
AnXT
- 粉丝: 8
- 资源: 18
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
- 3
- 4
- 5
前往页