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