1 /*
2 * Copyright (c) 2007 SWSoft. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 * Started by Andrew Vagin <avagin@sw.ru>
24 *
25 * DESCRIPTION
26 * Check that inotify work for a file
27 *
28 * ALGORITHM
29 * Execute sequence file's operation and check return events
30 */
31 #include "config.h"
32
33 #include <stdio.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <sys/syscall.h>
40 #include "tst_test.h"
41 #include "inotify.h"
42
43 #if defined(HAVE_SYS_INOTIFY_H)
44 #include <sys/inotify.h>
45
46 #define EVENT_MAX 1024
47 /* size of the event structure, not counting name */
48 #define EVENT_SIZE (sizeof (struct inotify_event))
49 /* reasonable guess as to size of 1024 events */
50 #define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16))
51
52 #define BUF_SIZE 256
53
54 static char fname[BUF_SIZE];
55 static char buf[BUF_SIZE];
56 static int fd, fd_notify;
57 static int wd, reap_wd;
58
59 static unsigned int event_set[EVENT_MAX];
60
61 static char event_buf[EVENT_BUF_LEN];
62
verify_inotify(void)63 void verify_inotify(void)
64 {
65 int test_cnt = 0;
66
67 /*
68 * generate sequence of events
69 */
70 SAFE_CHMOD(fname, 0755);
71 event_set[test_cnt] = IN_ATTRIB;
72 test_cnt++;
73
74 if ((fd = open(fname, O_RDONLY)) == -1) {
75 tst_brk(TBROK | TERRNO,
76 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
77 }
78 event_set[test_cnt] = IN_OPEN;
79 test_cnt++;
80
81 if (read(fd, buf, BUF_SIZE) == -1) {
82 tst_brk(TBROK | TERRNO,
83 "read(%d, buf, %d) failed", fd, BUF_SIZE);
84 }
85 event_set[test_cnt] = IN_ACCESS;
86 test_cnt++;
87
88 SAFE_CLOSE(fd);
89 event_set[test_cnt] = IN_CLOSE_NOWRITE;
90 test_cnt++;
91
92 if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1) {
93 tst_brk(TBROK,
94 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
95 }
96 event_set[test_cnt] = IN_OPEN;
97 test_cnt++;
98
99 if (write(fd, buf, BUF_SIZE) == -1) {
100 tst_brk(TBROK,
101 "write(%d, %s, 1) failed", fd, fname);
102 }
103 event_set[test_cnt] = IN_MODIFY;
104 test_cnt++;
105
106 SAFE_CLOSE(fd);
107 event_set[test_cnt] = IN_CLOSE_WRITE;
108 test_cnt++;
109
110 /*
111 * get list of events
112 */
113 int len, i = 0, test_num = 0;
114 if ((len = read(fd_notify, event_buf, EVENT_BUF_LEN)) < 0) {
115 tst_brk(TBROK,
116 "read(%d, buf, %zu) failed",
117 fd_notify, EVENT_BUF_LEN);
118
119 }
120
121 /*
122 * check events
123 */
124 while (i < len) {
125 struct inotify_event *event;
126 event = (struct inotify_event *)&event_buf[i];
127 if (test_num >= test_cnt) {
128 tst_res(TFAIL,
129 "get unnecessary event: wd=%d mask=%02x "
130 "cookie=%u len=%u",
131 event->wd, event->mask,
132 event->cookie, event->len);
133 } else if (event_set[test_num] == event->mask) {
134 if (event->cookie != 0) {
135 tst_res(TFAIL,
136 "get event: wd=%d mask=%02x "
137 "cookie=%u (expected 0) len=%u",
138 event->wd, event->mask,
139 event->cookie, event->len);
140 } else {
141 tst_res(TPASS, "get event: wd=%d "
142 "mask=%02x cookie=%u len=%u",
143 event->wd, event->mask,
144 event->cookie, event->len);
145 }
146
147 } else {
148 tst_res(TFAIL, "get event: wd=%d mask=%02x "
149 "(expected %x) cookie=%u len=%u",
150 event->wd, event->mask,
151 event_set[test_num],
152 event->cookie, event->len);
153 }
154 test_num++;
155 i += EVENT_SIZE + event->len;
156 }
157 for (; test_num < test_cnt; test_num++) {
158 tst_res(TFAIL, "didn't get event: mask=%02x",
159 event_set[test_num]);
160
161 }
162 }
163
setup(void)164 static void setup(void)
165 {
166 sprintf(fname, "tfile_%d", getpid());
167
168 SAFE_FILE_PRINTF(fname, "%s", fname);
169
170 if ((fd_notify = myinotify_init()) < 0) {
171 if (errno == ENOSYS) {
172 tst_brk(TCONF,
173 "inotify is not configured in this kernel.");
174 } else {
175 tst_brk(TBROK | TERRNO,
176 "inotify_init failed");
177 }
178 }
179
180 if ((wd = myinotify_add_watch(fd_notify, fname, IN_ALL_EVENTS)) < 0) {
181 tst_brk(TBROK | TERRNO,
182 "inotify_add_watch (%d, %s, IN_ALL_EVENTS) failed",
183 fd_notify, fname);
184 reap_wd = 1;
185 };
186
187 }
188
cleanup(void)189 static void cleanup(void)
190 {
191 if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
192 tst_res(TWARN | TERRNO, "inotify_rm_watch (%d, %d) failed",
193 fd_notify, wd);
194 }
195
196 if (fd_notify > 0)
197 SAFE_CLOSE(fd_notify);
198 }
199
200 static struct tst_test test = {
201 .needs_tmpdir = 1,
202 .setup = setup,
203 .cleanup = cleanup,
204 .test_all = verify_inotify,
205 };
206
207 #else
208 TST_TEST_TCONF("system doesn't have required inotify support");
209 #endif
210