1 #include "common.h"
2 #include "../config.h"
3
4 #include <sys/stat.h>
5 #include <sys/types.h>
6
7 #include <errno.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include <inotifytools/inotifytools.h>
15
16 #define MAXLEN 4096
17 #define LIST_CHUNK 1024
18
resize_if_necessary(const int count,int * len,const char *** ptr)19 static void resize_if_necessary(const int count, int* len, const char*** ptr) {
20 if (count >= *len - 1) {
21 *len += LIST_CHUNK;
22 *ptr = (const char**)realloc(*ptr, sizeof(char*) * *len);
23 }
24 }
25
print_event_descriptions()26 void print_event_descriptions() {
27 printf("\taccess\t\tfile or directory contents were read\n");
28 printf("\tmodify\t\tfile or directory contents were written\n");
29 printf("\tattrib\t\tfile or directory attributes changed\n");
30 printf("\tclose_write\tfile or directory closed, after being opened in\n"
31 "\t \twritable mode\n");
32 printf("\tclose_nowrite\tfile or directory closed, after being opened in\n"
33 "\t \tread-only mode\n");
34 printf("\tclose\t\tfile or directory closed, regardless of read/write "
35 "mode\n");
36 printf("\topen\t\tfile or directory opened\n");
37 printf("\tmoved_to\tfile or directory moved to watched directory\n");
38 printf("\tmoved_from\tfile or directory moved from watched directory\n");
39 printf("\tmove\t\tfile or directory moved to or from watched directory\n");
40 printf("\tmove_self\t\tA watched file or directory was moved.\n");
41 printf("\tcreate\t\tfile or directory created within watched directory\n");
42 printf("\tdelete\t\tfile or directory deleted within watched directory\n");
43 printf("\tdelete_self\tfile or directory was deleted\n");
44 printf("\tunmount\t\tfile system containing file or directory unmounted\n");
45 }
46
isdir(char const * path)47 int isdir(char const *path) {
48 static struct stat my_stat;
49
50 if (-1 == lstat(path, &my_stat)) {
51 if (errno == ENOENT)
52 return 0;
53 fprintf(stderr, "Stat failed on %s: %s\n", path, strerror(errno));
54 return 0;
55 }
56
57 return S_ISDIR(my_stat.st_mode) && !S_ISLNK(my_stat.st_mode);
58 }
59
free_list(int argc,char ** argv,FileList * list)60 void free_list(int argc, char** argv, FileList* list) {
61 char* start_of_stack = argv[0];
62 char* end_of_stack = argv[argc - 1];
63 for (int i = 0; argv[i]; ++i) {
64 if (argv[i] < start_of_stack) {
65 start_of_stack = argv[i];
66 } else if (argv[i] > end_of_stack) {
67 end_of_stack = argv[i];
68 }
69 }
70
71 while (*end_of_stack) {
72 ++end_of_stack;
73 }
74
75 for (int i = 0; list->watch_files[i]; ++i) {
76 if (list->watch_files[i] < start_of_stack ||
77 list->watch_files[i] > end_of_stack) {
78 free((void*)list->watch_files[i]);
79 }
80 }
81
82 free(list->watch_files);
83
84 for (int i = 0; list->exclude_files[i]; ++i) {
85 if (list->exclude_files[i] < start_of_stack ||
86 list->exclude_files[i] > end_of_stack) {
87 free((void*)list->exclude_files[i]);
88 }
89 }
90
91 free(list->exclude_files);
92 }
93
construct_path_list(int argc,char ** argv,char const * filename,FileList * list)94 void construct_path_list(int argc,
95 char** argv,
96 char const* filename,
97 FileList* list) {
98 list->watch_files = 0;
99 list->exclude_files = 0;
100 FILE* file = 0;
101
102 if (filename) {
103 if (!strcmp(filename, "-")) {
104 file = stdin;
105 } else {
106 file = fopen(filename, "r");
107 }
108 }
109
110 int watch_len = LIST_CHUNK;
111 int exclude_len = LIST_CHUNK;
112 int watch_count = 0;
113 int exclude_count = 0;
114 list->watch_files = (char const**)malloc(sizeof(char*) * LIST_CHUNK);
115 list->exclude_files = (char const**)malloc(sizeof(char*) * LIST_CHUNK);
116
117 char name[MAXLEN];
118 while (file && fgets(name, MAXLEN, file)) {
119 if (name[strlen(name) - 1] == '\n')
120 name[strlen(name) - 1] = 0;
121 if (strlen(name) == 0)
122 continue;
123 if ('@' == name[0] && strlen(name) == 1)
124 continue;
125 if ('@' == name[0]) {
126 resize_if_necessary(exclude_count, &exclude_len,
127 &list->exclude_files);
128 list->exclude_files[exclude_count++] = strdup(&name[1]);
129 } else {
130 resize_if_necessary(watch_count, &watch_len,
131 &list->watch_files);
132 list->watch_files[watch_count++] = strdup(name);
133 }
134 }
135
136 if (file && file != stdin)
137 fclose(file);
138
139 for (int i = 0; i < argc; ++i) {
140 if (strlen(argv[i]) == 0)
141 continue;
142 if ('@' == argv[i][0] && strlen(argv[i]) == 1)
143 continue;
144 if ('@' == argv[i][0]) {
145 resize_if_necessary(exclude_count, &exclude_len,
146 &list->exclude_files);
147 list->exclude_files[exclude_count++] = &argv[i][1];
148 } else {
149 resize_if_necessary(watch_count, &watch_len,
150 &list->watch_files);
151 list->watch_files[watch_count++] = argv[i];
152 }
153 }
154
155 list->exclude_files[exclude_count] = 0;
156 list->watch_files[watch_count] = 0;
157 }
158
warn_inotify_init_error(int fanotify)159 void warn_inotify_init_error(int fanotify) {
160 const char* backend = fanotify ? "fanotify" : "inotify";
161 const char* resource = fanotify ? "groups" : "instances";
162 int error = inotifytools_error();
163
164 fprintf(stderr, "Couldn't initialize %s: %s\n", backend,
165 strerror(error));
166 if (error == EMFILE) {
167 fprintf(stderr,
168 "Try increasing the value of "
169 "/proc/sys/fs/%s/max_user_%s\n",
170 backend, resource);
171 }
172 if (fanotify && error == EINVAL) {
173 fprintf(stderr,
174 "fanotify support for reporting the events with "
175 "file names was added in kernel v5.9.\n");
176 }
177 if (fanotify && error == EPERM) {
178 fprintf(stderr, "fanotify watch requires admin privileges\n");
179 }
180 }
181
is_timeout_option_valid(unsigned int * timeout,char * o)182 bool is_timeout_option_valid(unsigned int* timeout, char* o) {
183 if ((o == NULL) || (*o == '\0')) {
184 fprintf(stderr,
185 "The provided value is not a valid timeout value.\n"
186 "Please specify a long int value.\n");
187 return false;
188 }
189
190 char* timeout_end = NULL;
191 errno = 0;
192 *timeout = strtol(o, &timeout_end, 10);
193
194 const int err = errno;
195 if (err != 0) {
196 fprintf(stderr,
197 "Something went wrong with the timeout "
198 "value you provided.\n");
199 fprintf(stderr, "%s\n", strerror(err));
200 return false;
201 }
202
203 if (*timeout_end != '\0') {
204 fprintf(stderr,
205 "'%s' is not a valid timeout value.\n"
206 "Please specify a long int value.\n",
207 o);
208 return false;
209 }
210
211 return true;
212 }
213