]> granicus.if.org Git - strace/blob - basic_filters.c
btrfs: use uint32_t instead of __u32
[strace] / basic_filters.c
1 /*
2  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2016-2017 The strace developers.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "defs.h"
30 #include "number_set.h"
31 #include "filter.h"
32 #include <regex.h>
33
34 static bool
35 qualify_syscall_number(const char *s, struct number_set *set)
36 {
37         int n = string_to_uint(s);
38         if (n < 0)
39                 return false;
40
41         bool done = false;
42
43         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
44                 if ((unsigned) n >= nsyscall_vec[p])
45                         continue;
46                 add_number_to_set_array(n, set, p);
47                 done = true;
48         }
49
50         return done;
51 }
52
53 static void
54 regerror_msg_and_die(int errcode, const regex_t *preg,
55                      const char *str, const char *pattern)
56 {
57         char buf[512];
58
59         regerror(errcode, preg, buf, sizeof(buf));
60         error_msg_and_die("%s: %s: %s", str, pattern, buf);
61 }
62
63 static bool
64 qualify_syscall_regex(const char *s, struct number_set *set)
65 {
66         regex_t preg;
67         int rc;
68
69         if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
70                 regerror_msg_and_die(rc, &preg, "regcomp", s);
71
72         bool found = false;
73
74         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
75                 for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
76                         if (!sysent_vec[p][i].sys_name)
77                                 continue;
78                         rc = regexec(&preg, sysent_vec[p][i].sys_name,
79                                      0, NULL, 0);
80                         if (rc == REG_NOMATCH)
81                                 continue;
82                         else if (rc)
83                                 regerror_msg_and_die(rc, &preg, "regexec", s);
84                         add_number_to_set_array(i, set, p);
85                         found = true;
86                 }
87         }
88
89         regfree(&preg);
90         return found;
91 }
92
93 static unsigned int
94 lookup_class(const char *s)
95 {
96         static const struct {
97                 const char *name;
98                 unsigned int value;
99         } syscall_class[] = {
100                 { "%desc",      TRACE_DESC      },
101                 { "%file",      TRACE_FILE      },
102                 { "%memory",    TRACE_MEMORY    },
103                 { "%process",   TRACE_PROCESS   },
104                 { "%signal",    TRACE_SIGNAL    },
105                 { "%ipc",       TRACE_IPC       },
106                 { "%network",   TRACE_NETWORK   },
107                 { "%stat",      TRACE_STAT      },
108                 { "%lstat",     TRACE_LSTAT     },
109                 { "%fstat",     TRACE_FSTAT     },
110                 { "%%stat",     TRACE_STAT_LIKE },
111                 { "%statfs",    TRACE_STATFS    },
112                 { "%fstatfs",   TRACE_FSTATFS   },
113                 { "%%statfs",   TRACE_STATFS_LIKE       },
114                 /* legacy class names */
115                 { "desc",       TRACE_DESC      },
116                 { "file",       TRACE_FILE      },
117                 { "memory",     TRACE_MEMORY    },
118                 { "process",    TRACE_PROCESS   },
119                 { "signal",     TRACE_SIGNAL    },
120                 { "ipc",        TRACE_IPC       },
121                 { "network",    TRACE_NETWORK   },
122         };
123
124         for (unsigned int i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
125                 if (strcmp(s, syscall_class[i].name) == 0)
126                         return syscall_class[i].value;
127         }
128
129         return 0;
130 }
131
132 static bool
133 qualify_syscall_class(const char *s, struct number_set *set)
134 {
135         const unsigned int n = lookup_class(s);
136         if (!n)
137                 return false;
138
139         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
140                 for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
141                         if (sysent_vec[p][i].sys_name &&
142                             (sysent_vec[p][i].sys_flags & n) == n)
143                                 add_number_to_set_array(i, set, p);
144                 }
145         }
146
147         return true;
148 }
149
150 static bool
151 qualify_syscall_name(const char *s, struct number_set *set)
152 {
153         bool found = false;
154
155         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
156                 for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
157                         if (sysent_vec[p][i].sys_name &&
158                             strcmp(s, sysent_vec[p][i].sys_name) == 0) {
159                                 add_number_to_set_array(i, set, p);
160                                 found = true;
161                         }
162                 }
163         }
164
165         return found;
166 }
167
168 static bool
169 qualify_syscall(const char *token, struct number_set *set)
170 {
171         bool ignore_fail = false;
172
173         while (*token == '?') {
174                 token++;
175                 ignore_fail = true;
176         }
177         if (*token >= '0' && *token <= '9')
178                 return qualify_syscall_number(token, set) || ignore_fail;
179         if (*token == '/')
180                 return qualify_syscall_regex(token + 1, set) || ignore_fail;
181         return qualify_syscall_class(token, set)
182                || qualify_syscall_name(token, set)
183                || ignore_fail;
184 }
185
186 /*
187  * Add syscall numbers to SETs for each supported personality
188  * according to STR specification.
189  */
190 void
191 qualify_syscall_tokens(const char *const str, struct number_set *const set)
192 {
193         /* Clear all sets. */
194         clear_number_set_array(set, SUPPORTED_PERSONALITIES);
195
196         /*
197          * Each leading ! character means inversion
198          * of the remaining specification.
199          */
200         const char *s = str;
201         while (*s == '!') {
202                 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
203                 ++s;
204         }
205
206         if (strcmp(s, "none") == 0) {
207                 /*
208                  * No syscall numbers are added to sets.
209                  * Subsequent is_number_in_set* invocations
210                  * will return set[p]->not.
211                  */
212                 return;
213         } else if (strcmp(s, "all") == 0) {
214                 /* "all" == "!none" */
215                 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
216                 return;
217         }
218
219         /*
220          * Split the string into comma separated tokens.
221          * For each token, call qualify_syscall that will take care
222          * if adding appropriate syscall numbers to sets.
223          * The absence of tokens or a negative return code
224          * from qualify_syscall is a fatal error.
225          */
226         char *copy = xstrdup(s);
227         char *saveptr = NULL;
228         bool done = false;
229
230         for (const char *token = strtok_r(copy, ",", &saveptr);
231              token; token = strtok_r(NULL, ",", &saveptr)) {
232                 done = qualify_syscall(token, set);
233                 if (!done)
234                         error_msg_and_die("invalid system call '%s'", token);
235         }
236
237         free(copy);
238
239         if (!done)
240                 error_msg_and_die("invalid system call '%s'", str);
241 }
242
243 /*
244  * Add numbers to SET according to STR specification.
245  */
246 void
247 qualify_tokens(const char *const str, struct number_set *const set,
248                string_to_uint_func func, const char *const name)
249 {
250         /* Clear the set. */
251         clear_number_set_array(set, 1);
252
253         /*
254          * Each leading ! character means inversion
255          * of the remaining specification.
256          */
257         const char *s = str;
258         while (*s == '!') {
259                 invert_number_set_array(set, 1);
260                 ++s;
261         }
262
263         if (strcmp(s, "none") == 0) {
264                 /*
265                  * No numbers are added to the set.
266                  * Subsequent is_number_in_set* invocations
267                  * will return set->not.
268                  */
269                 return;
270         } else if (strcmp(s, "all") == 0) {
271                 /* "all" == "!none" */
272                 invert_number_set_array(set, 1);
273                 return;
274         }
275
276         /*
277          * Split the string into comma separated tokens.
278          * For each token, find out the corresponding number
279          * by calling FUNC, and add that number to the set.
280          * The absence of tokens or a negative answer
281          * from FUNC is a fatal error.
282          */
283         char *copy = xstrdup(s);
284         char *saveptr = NULL;
285         int number = -1;
286
287         for (const char *token = strtok_r(copy, ",", &saveptr);
288              token; token = strtok_r(NULL, ",", &saveptr)) {
289                 number = func(token);
290                 if (number < 0)
291                         error_msg_and_die("invalid %s '%s'", name, token);
292
293                 add_number_to_set(number, set);
294         }
295
296         free(copy);
297
298         if (number < 0)
299                 error_msg_and_die("invalid %s '%s'", name, str);
300 }