Whamcloud - gitweb
LU-17895 lnet: Validate input for lnetctl import
[fs/lustre-release.git] / lustre / tests / monitor_lustrefs.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <limits.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <libgen.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <sys/fanotify.h>
13
14
15 void usage(const char *progname)
16 {
17         const char *base, *msg;
18
19         base = strrchr(progname, '/');
20         if (base == NULL)
21                 base = progname;
22         else
23                 base++;
24
25         fprintf(stderr, "Usage:\n");
26         fprintf(stderr, "  %s LUSTRE_MOUNT_DIR\n", base);
27         fprintf(stderr, "\n");
28
29         msg =
30 "Description:\n"
31 "  Monitor some file operations on a lustre fs. Report the events as below:\n"
32 "    <events>:<lustre_file>:<pid>:[<command>]\n"
33 "\n"
34 "  <events>      is 1 event or multiple events separated by '&'. For example,\n"
35 "                'open', 'write&close'. Currently only these events are\n"
36 "                monitored:\n"
37 "                  - open\n"
38 "                  - close\n"
39 "                  - read\n"
40 "                  - write\n"
41 "  <lustre_file> is the file to be operated.\n"
42 "  <pid>         is the process id who operates the file.\n"
43 "  <command>     is the command who operates the file. It is reported only if\n"
44 "                the process is still running so it can be found from pid.\n"
45 "\n";
46         fprintf(stderr, "%s", msg);
47 }
48
49 void print_event(struct fanotify_event_metadata *metadata)
50 {
51         bool first = true;
52         char procfd_path[PATH_MAX], path[PATH_MAX], cmd_file[PATH_MAX];
53         int path_len, cmd_fd, cmd_len;
54
55         // print event type
56         if (metadata->mask & FAN_OPEN) {
57                 printf("open");
58                 first = false;
59         }
60         if (metadata->mask & FAN_ACCESS) {
61                 if (!first)
62                         printf("&");
63                 printf("read");
64                 first = false;
65         }
66         if (metadata->mask & FAN_MODIFY) {
67                 if (!first)
68                         printf("&");
69                 printf("write");
70                 first = false;
71         }
72         if (metadata->mask & FAN_CLOSE) {
73                 if (!first)
74                         printf("&");
75                 printf("close");
76                 first = false;
77         }
78         printf(":");
79
80         // print the name of the file
81         snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d",
82                  metadata->fd);
83         path_len = readlink(procfd_path, path, sizeof(path) - 1);
84         if (path_len == -1) {
85                 fprintf(stderr, "failed to read link target of %s. %d:%s\n",
86                         procfd_path, errno, strerror(errno));
87                 exit(EXIT_FAILURE);
88         }
89         path[path_len] = '\0';
90         printf("%s:", path);
91         close(metadata->fd);
92
93         // print the pid
94         printf("%d:", metadata->pid);
95
96         // try to print the cmdline of process
97         snprintf(cmd_file, sizeof(cmd_file), "/proc/%d/cmdline", metadata->pid);
98         cmd_fd = open(cmd_file, O_RDONLY);
99         if (cmd_fd >= 0) {
100                 // reuse cmd_file as buffer
101                 cmd_len = read(cmd_fd, cmd_file, sizeof(cmd_file) - 1);
102                 if (cmd_len > 0) {
103                         cmd_file[cmd_len] = '\0';
104                         printf("%s", cmd_file);
105                 }
106                 close(cmd_fd);
107         }
108         printf("\n");
109         fflush(stdout);
110 }
111
112 int main(int argc, char *argv[])
113 {
114         int fd, rc;
115         uint32_t mask;
116         struct fanotify_event_metadata buf[256], *metadata;
117         int len;
118
119         if (argc != 2) {
120                 usage(argv[0]);
121                 exit(EXIT_FAILURE);
122         }
123
124         fd = fanotify_init(FAN_CLASS_CONTENT, O_RDONLY | O_LARGEFILE);
125         if (fd < 0) {
126                 fprintf(stderr, "failed to init fanotify. %d:%s\n", errno,
127                         strerror(errno));
128                 exit(EXIT_FAILURE);
129         }
130
131         mask = FAN_OPEN | FAN_ACCESS | FAN_MODIFY | FAN_CLOSE;
132         rc = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, mask, AT_FDCWD,
133                            argv[1]);
134         if (rc < 0) {
135                 fprintf(stderr,
136                         "failed to open watch descriptor on %s. %d:%s\n",
137                         argv[1], errno, strerror(errno));
138                 exit(EXIT_FAILURE);
139         }
140
141         while (1) {
142                 len = read(fd, (void *)&buf[0], sizeof(buf));
143                 if (len < 0 && errno != EAGAIN) {
144                         fprintf(stderr,
145                                 "failed to read from fanotiify file descriptor."
146                                 " %d:%s",
147                                 errno, strerror(errno));
148                         exit(EXIT_FAILURE);
149                 }
150                 if (len < 0)
151                         break;
152
153                 metadata = &buf[0];
154                 while (FAN_EVENT_OK(metadata, len)) {
155                         /* Check run-time and compile-time structures match */
156                         if (metadata->vers != FANOTIFY_METADATA_VERSION) {
157                                 fprintf(stderr, "Mismatch of fanotify "
158                                         "metadata version.\n");
159                                 exit(EXIT_FAILURE);
160                         }
161
162                         if (metadata->fd >= 0) {
163                                 print_event(metadata);
164                                 close(metadata->fd);
165                         }
166                         metadata = FAN_EVENT_NEXT(metadata, len);
167                 }
168         }
169
170         close(fd);
171         return EXIT_SUCCESS;
172 }