]> granicus.if.org Git - strace/blob - filter_qualify.c
Hide struct number_set implementation details from users
[strace] / filter_qualify.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 "nsig.h"
31 #include "number_set.h"
32 #include "filter.h"
33
34 struct number_set *read_set;
35 struct number_set *write_set;
36 struct number_set *signal_set;
37
38 static struct number_set *abbrev_set;
39 static struct number_set *inject_set;
40 static struct number_set *raw_set;
41 static struct number_set *trace_set;
42 static struct number_set *verbose_set;
43
44 static int
45 sigstr_to_uint(const char *s)
46 {
47         int i;
48
49         if (*s >= '0' && *s <= '9')
50                 return string_to_uint_upto(s, 255);
51
52         if (strncasecmp(s, "SIG", 3) == 0)
53                 s += 3;
54
55         for (i = 0; i <= 255; ++i) {
56                 const char *name = signame(i);
57
58                 if (strncasecmp(name, "SIG", 3) != 0)
59                         continue;
60
61                 name += 3;
62
63                 if (strcasecmp(name, s) != 0)
64                         continue;
65
66                 return i;
67         }
68
69         return -1;
70 }
71
72 static int
73 find_errno_by_name(const char *name)
74 {
75         unsigned int i;
76
77         for (i = 1; i < nerrnos; ++i) {
78                 if (errnoent[i] && (strcasecmp(name, errnoent[i]) == 0))
79                         return i;
80         }
81
82         return -1;
83 }
84
85 static bool
86 parse_inject_token(const char *const token, struct inject_opts *const fopts,
87                    const bool fault_tokens_only)
88 {
89         const char *val;
90         int intval;
91
92         if ((val = STR_STRIP_PREFIX(token, "when=")) != token) {
93                 /*
94                  *      == 1+1
95                  * F    == F+0
96                  * F+   == F+1
97                  * F+S
98                  */
99                 char *end;
100                 intval = string_to_uint_ex(val, &end, 0xffff, "+");
101                 if (intval < 1)
102                         return false;
103
104                 fopts->first = intval;
105
106                 if (*end) {
107                         val = end + 1;
108                         if (*val) {
109                                 /* F+S */
110                                 intval = string_to_uint_upto(val, 0xffff);
111                                 if (intval < 1)
112                                         return false;
113                                 fopts->step = intval;
114                         } else {
115                                 /* F+ == F+1 */
116                                 fopts->step = 1;
117                         }
118                 } else {
119                         /* F == F+0 */
120                         fopts->step = 0;
121                 }
122         } else if ((val = STR_STRIP_PREFIX(token, "error=")) != token) {
123                 if (fopts->rval != INJECT_OPTS_RVAL_DEFAULT)
124                         return false;
125                 intval = string_to_uint_upto(val, MAX_ERRNO_VALUE);
126                 if (intval < 0)
127                         intval = find_errno_by_name(val);
128                 if (intval < 1)
129                         return false;
130                 fopts->rval = -intval;
131         } else if (!fault_tokens_only
132                    && (val = STR_STRIP_PREFIX(token, "retval=")) != token) {
133                 if (fopts->rval != INJECT_OPTS_RVAL_DEFAULT)
134                         return false;
135                 intval = string_to_uint(val);
136                 if (intval < 0)
137                         return false;
138                 fopts->rval = intval;
139         } else if (!fault_tokens_only
140                    && (val = STR_STRIP_PREFIX(token, "signal=")) != token) {
141                 intval = sigstr_to_uint(val);
142                 if (intval < 1 || intval > NSIG_BYTES * 8)
143                         return false;
144                 fopts->signo = intval;
145         } else {
146                 return false;
147         }
148
149         return true;
150 }
151
152 static char *
153 parse_inject_expression(const char *const s, char **buf,
154                         struct inject_opts *const fopts,
155                         const bool fault_tokens_only)
156 {
157         char *saveptr = NULL;
158         char *name = NULL;
159         char *token;
160
161         *buf = xstrdup(s);
162         for (token = strtok_r(*buf, ":", &saveptr); token;
163              token = strtok_r(NULL, ":", &saveptr)) {
164                 if (!name)
165                         name = token;
166                 else if (!parse_inject_token(token, fopts, fault_tokens_only))
167                         goto parse_error;
168         }
169
170         if (name)
171                 return name;
172
173 parse_error:
174         free(*buf);
175         return *buf = NULL;
176 }
177
178 static void
179 qualify_read(const char *const str)
180 {
181         if (!read_set)
182                 read_set = alloc_number_set_array(1);
183         qualify_tokens(str, read_set, string_to_uint, "descriptor");
184 }
185
186 static void
187 qualify_write(const char *const str)
188 {
189         if (!write_set)
190                 write_set = alloc_number_set_array(1);
191         qualify_tokens(str, write_set, string_to_uint, "descriptor");
192 }
193
194 static void
195 qualify_signals(const char *const str)
196 {
197         if (!signal_set)
198                 signal_set = alloc_number_set_array(1);
199         qualify_tokens(str, signal_set, sigstr_to_uint, "signal");
200 }
201
202 static void
203 qualify_trace(const char *const str)
204 {
205         if (!trace_set)
206                 trace_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
207         qualify_syscall_tokens(str, trace_set, "system call");
208 }
209
210 static void
211 qualify_abbrev(const char *const str)
212 {
213         if (!abbrev_set)
214                 abbrev_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
215         qualify_syscall_tokens(str, abbrev_set, "system call");
216 }
217
218 static void
219 qualify_verbose(const char *const str)
220 {
221         if (!verbose_set)
222                 verbose_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
223         qualify_syscall_tokens(str, verbose_set, "system call");
224 }
225
226 static void
227 qualify_raw(const char *const str)
228 {
229         if (!raw_set)
230                 raw_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
231         qualify_syscall_tokens(str, raw_set, "system call");
232 }
233
234 static void
235 qualify_inject_common(const char *const str,
236                       const bool fault_tokens_only,
237                       const char *const description)
238 {
239         struct inject_opts opts = {
240                 .first = 1,
241                 .step = 1,
242                 .rval = INJECT_OPTS_RVAL_DEFAULT,
243                 .signo = 0
244         };
245         char *buf = NULL;
246         char *name = parse_inject_expression(str, &buf, &opts, fault_tokens_only);
247         if (!name) {
248                 error_msg_and_die("invalid %s '%s'", description, str);
249         }
250
251         /* If neither of retval, error, or signal is specified, then ... */
252         if (opts.rval == INJECT_OPTS_RVAL_DEFAULT && !opts.signo) {
253                 if (fault_tokens_only) {
254                         /* in fault= syntax the default error code is ENOSYS. */
255                         opts.rval = -ENOSYS;
256                 } else {
257                         /* in inject= syntax this is not allowed. */
258                         error_msg_and_die("invalid %s '%s'", description, str);
259                 }
260         }
261
262         struct number_set *tmp_set =
263                 alloc_number_set_array(SUPPORTED_PERSONALITIES);
264         qualify_syscall_tokens(name, tmp_set, description);
265
266         free(buf);
267
268         /*
269          * Initialize inject_vec accourding to tmp_set.
270          * Merge tmp_set into inject_set.
271          */
272         unsigned int p;
273         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
274                 if (number_set_array_is_empty(tmp_set, p))
275                         continue;
276
277                 if (!inject_set) {
278                         inject_set =
279                                 alloc_number_set_array(SUPPORTED_PERSONALITIES);
280                 }
281                 if (!inject_vec[p]) {
282                         inject_vec[p] = xcalloc(nsyscall_vec[p],
283                                                sizeof(*inject_vec[p]));
284                 }
285
286                 unsigned int i;
287                 for (i = 0; i < nsyscall_vec[p]; ++i) {
288                         if (is_number_in_set_array(i, tmp_set, p)) {
289                                 add_number_to_set_array(i, inject_set, p);
290                                 inject_vec[p][i] = opts;
291                         }
292                 }
293         }
294
295         free_number_set_array(tmp_set, SUPPORTED_PERSONALITIES);
296 }
297
298 static void
299 qualify_fault(const char *const str)
300 {
301         qualify_inject_common(str, true, "fault argument");
302 }
303
304 static void
305 qualify_inject(const char *const str)
306 {
307         qualify_inject_common(str, false, "inject argument");
308 }
309
310 static const struct qual_options {
311         const char *name;
312         void (*qualify)(const char *);
313 } qual_options[] = {
314         { "trace",      qualify_trace   },
315         { "t",          qualify_trace   },
316         { "abbrev",     qualify_abbrev  },
317         { "a",          qualify_abbrev  },
318         { "verbose",    qualify_verbose },
319         { "v",          qualify_verbose },
320         { "raw",        qualify_raw     },
321         { "x",          qualify_raw     },
322         { "signal",     qualify_signals },
323         { "signals",    qualify_signals },
324         { "s",          qualify_signals },
325         { "read",       qualify_read    },
326         { "reads",      qualify_read    },
327         { "r",          qualify_read    },
328         { "write",      qualify_write   },
329         { "writes",     qualify_write   },
330         { "w",          qualify_write   },
331         { "fault",      qualify_fault   },
332         { "inject",     qualify_inject  },
333 };
334
335 void
336 qualify(const char *str)
337 {
338         const struct qual_options *opt = qual_options;
339         unsigned int i;
340
341         for (i = 0; i < ARRAY_SIZE(qual_options); ++i) {
342                 const char *name = qual_options[i].name;
343                 const size_t len = strlen(name);
344                 const char *val = str_strip_prefix_len(str, name, len);
345
346                 if (val == str || *val != '=')
347                         continue;
348                 str = val + 1;
349                 opt = &qual_options[i];
350                 break;
351         }
352
353         opt->qualify(str);
354 }
355
356 unsigned int
357 qual_flags(const unsigned int scno)
358 {
359         return  (is_number_in_set_array(scno, trace_set, current_personality)
360                    ? QUAL_TRACE : 0)
361                 | (is_number_in_set_array(scno, abbrev_set, current_personality)
362                    ? QUAL_ABBREV : 0)
363                 | (is_number_in_set_array(scno, verbose_set, current_personality)
364                    ? QUAL_VERBOSE : 0)
365                 | (is_number_in_set_array(scno, raw_set, current_personality)
366                    ? QUAL_RAW : 0)
367                 | (is_number_in_set_array(scno, inject_set, current_personality)
368                    ? QUAL_INJECT : 0);
369 }