1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2007 SWSoft. All Rights Reserved.
4 * Author: Andrew Vagin <avagin@sw.ru>
5 *
6 * DESCRIPTION
7 * Check that inotify work for a file
8 *
9 * ALGORITHM
10 * Execute sequence file's operation and check return events
11 */
12 #include "config.h"
13
14 #include <stdio.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/syscall.h>
21 #include "tst_test.h"
22 #include "inotify.h"
23
24 #if defined(HAVE_SYS_INOTIFY_H)
25 #include <sys/inotify.h>
26
27 #define EVENT_MAX 1024
28 /* size of the event structure, not counting name */
29 #define EVENT_SIZE (sizeof (struct inotify_event))
30 /* reasonable guess as to size of 1024 events */
31 #define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16))
32
33 #define BUF_SIZE 256
34
35 static char fname[BUF_SIZE];
36 static char buf[BUF_SIZE];
37 static int fd, fd_notify;
38 static int wd, reap_wd;
39
40 static unsigned int event_set[EVENT_MAX];
41
42 static char event_buf[EVENT_BUF_LEN];
43
verify_inotify(void)44 void verify_inotify(void)
45 {
46 int test_cnt = 0;
47
48 /*
49 * generate sequence of events
50 */
51 SAFE_CHMOD(fname, 0755);
52 event_set[test_cnt] = IN_ATTRIB;
53 test_cnt++;
54
55 fd = SAFE_OPEN(fname, O_RDONLY);
56 event_set[test_cnt] = IN_OPEN;
57 test_cnt++;
58
59 if (read(fd, buf, BUF_SIZE) == -1) {
60 tst_brk(TBROK | TERRNO,
61 "read(%d, buf, %d) failed", fd, BUF_SIZE);
62 }
63 event_set[test_cnt] = IN_ACCESS;
64 test_cnt++;
65
66 SAFE_CLOSE(fd);
67 event_set[test_cnt] = IN_CLOSE_NOWRITE;
68 test_cnt++;
69
70 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
71 event_set[test_cnt] = IN_OPEN;
72 test_cnt++;
73
74 if (write(fd, buf, BUF_SIZE) == -1) {
75 tst_brk(TBROK,
76 "write(%d, %s, 1) failed", fd, fname);
77 }
78 event_set[test_cnt] = IN_MODIFY;
79 test_cnt++;
80
81 SAFE_CLOSE(fd);
82 event_set[test_cnt] = IN_CLOSE_WRITE;
83 test_cnt++;
84
85 /*
86 * get list of events
87 */
88 int len, i = 0, test_num = 0;
89 if ((len = read(fd_notify, event_buf, EVENT_BUF_LEN)) < 0) {
90 tst_brk(TBROK,
91 "read(%d, buf, %zu) failed",
92 fd_notify, EVENT_BUF_LEN);
93
94 }
95
96 /*
97 * check events
98 */
99 while (i < len) {
100 struct inotify_event *event;
101 event = (struct inotify_event *)&event_buf[i];
102 if (test_num >= test_cnt) {
103 tst_res(TFAIL,
104 "get unnecessary event: wd=%d mask=%02x "
105 "cookie=%u len=%u",
106 event->wd, event->mask,
107 event->cookie, event->len);
108 } else if (event_set[test_num] == event->mask) {
109 if (event->cookie != 0) {
110 tst_res(TFAIL,
111 "get event: wd=%d mask=%02x "
112 "cookie=%u (expected 0) len=%u",
113 event->wd, event->mask,
114 event->cookie, event->len);
115 } else {
116 tst_res(TPASS, "get event: wd=%d "
117 "mask=%02x cookie=%u len=%u",
118 event->wd, event->mask,
119 event->cookie, event->len);
120 }
121
122 } else {
123 tst_res(TFAIL, "get event: wd=%d mask=%02x "
124 "(expected %x) cookie=%u len=%u",
125 event->wd, event->mask,
126 event_set[test_num],
127 event->cookie, event->len);
128 }
129 test_num++;
130 i += EVENT_SIZE + event->len;
131 }
132 for (; test_num < test_cnt; test_num++) {
133 tst_res(TFAIL, "didn't get event: mask=%02x",
134 event_set[test_num]);
135
136 }
137 }
138
setup(void)139 static void setup(void)
140 {
141 sprintf(fname, "tfile_%d", getpid());
142
143 SAFE_FILE_PRINTF(fname, "%s", fname);
144
145 fd_notify = SAFE_MYINOTIFY_INIT();
146
147 wd = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, fname, IN_ALL_EVENTS);
148 reap_wd = 1;
149 }
150
cleanup(void)151 static void cleanup(void)
152 {
153 if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
154 tst_res(TWARN | TERRNO, "inotify_rm_watch (%d, %d) failed",
155 fd_notify, wd);
156 }
157
158 if (fd_notify > 0)
159 SAFE_CLOSE(fd_notify);
160 }
161
162 static struct tst_test test = {
163 .needs_tmpdir = 1,
164 .setup = setup,
165 .cleanup = cleanup,
166 .test_all = verify_inotify,
167 };
168
169 #else
170 TST_TEST_TCONF("system doesn't have required inotify support");
171 #endif
172