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 if ((fd = open(fname, O_RDONLY)) == -1) {
56 tst_brk(TBROK | TERRNO,
57 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
58 }
59 event_set[test_cnt] = IN_OPEN;
60 test_cnt++;
61
62 if (read(fd, buf, BUF_SIZE) == -1) {
63 tst_brk(TBROK | TERRNO,
64 "read(%d, buf, %d) failed", fd, BUF_SIZE);
65 }
66 event_set[test_cnt] = IN_ACCESS;
67 test_cnt++;
68
69 SAFE_CLOSE(fd);
70 event_set[test_cnt] = IN_CLOSE_NOWRITE;
71 test_cnt++;
72
73 if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1) {
74 tst_brk(TBROK,
75 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
76 }
77 event_set[test_cnt] = IN_OPEN;
78 test_cnt++;
79
80 if (write(fd, buf, BUF_SIZE) == -1) {
81 tst_brk(TBROK,
82 "write(%d, %s, 1) failed", fd, fname);
83 }
84 event_set[test_cnt] = IN_MODIFY;
85 test_cnt++;
86
87 SAFE_CLOSE(fd);
88 event_set[test_cnt] = IN_CLOSE_WRITE;
89 test_cnt++;
90
91 /*
92 * get list of events
93 */
94 int len, i = 0, test_num = 0;
95 if ((len = read(fd_notify, event_buf, EVENT_BUF_LEN)) < 0) {
96 tst_brk(TBROK,
97 "read(%d, buf, %zu) failed",
98 fd_notify, EVENT_BUF_LEN);
99
100 }
101
102 /*
103 * check events
104 */
105 while (i < len) {
106 struct inotify_event *event;
107 event = (struct inotify_event *)&event_buf[i];
108 if (test_num >= test_cnt) {
109 tst_res(TFAIL,
110 "get unnecessary event: wd=%d mask=%02x "
111 "cookie=%u len=%u",
112 event->wd, event->mask,
113 event->cookie, event->len);
114 } else if (event_set[test_num] == event->mask) {
115 if (event->cookie != 0) {
116 tst_res(TFAIL,
117 "get event: wd=%d mask=%02x "
118 "cookie=%u (expected 0) len=%u",
119 event->wd, event->mask,
120 event->cookie, event->len);
121 } else {
122 tst_res(TPASS, "get event: wd=%d "
123 "mask=%02x cookie=%u len=%u",
124 event->wd, event->mask,
125 event->cookie, event->len);
126 }
127
128 } else {
129 tst_res(TFAIL, "get event: wd=%d mask=%02x "
130 "(expected %x) cookie=%u len=%u",
131 event->wd, event->mask,
132 event_set[test_num],
133 event->cookie, event->len);
134 }
135 test_num++;
136 i += EVENT_SIZE + event->len;
137 }
138 for (; test_num < test_cnt; test_num++) {
139 tst_res(TFAIL, "didn't get event: mask=%02x",
140 event_set[test_num]);
141
142 }
143 }
144
setup(void)145 static void setup(void)
146 {
147 sprintf(fname, "tfile_%d", getpid());
148
149 SAFE_FILE_PRINTF(fname, "%s", fname);
150
151 fd_notify = SAFE_MYINOTIFY_INIT();
152
153 wd = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, fname, IN_ALL_EVENTS);
154 reap_wd = 1;
155 }
156
cleanup(void)157 static void cleanup(void)
158 {
159 if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
160 tst_res(TWARN | TERRNO, "inotify_rm_watch (%d, %d) failed",
161 fd_notify, wd);
162 }
163
164 if (fd_notify > 0)
165 SAFE_CLOSE(fd_notify);
166 }
167
168 static struct tst_test test = {
169 .needs_tmpdir = 1,
170 .setup = setup,
171 .cleanup = cleanup,
172 .test_all = verify_inotify,
173 };
174
175 #else
176 TST_TEST_TCONF("system doesn't have required inotify support");
177 #endif
178