2 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 typedef unsigned int number_slot_t;
31 #define BITS_PER_SLOT (sizeof(number_slot_t) * 8)
39 struct number_set read_set;
40 struct number_set write_set;
41 struct number_set signal_set;
43 static struct number_set abbrev_set[SUPPORTED_PERSONALITIES];
44 static struct number_set fault_set[SUPPORTED_PERSONALITIES];
45 static struct number_set raw_set[SUPPORTED_PERSONALITIES];
46 static struct number_set trace_set[SUPPORTED_PERSONALITIES];
47 static struct number_set verbose_set[SUPPORTED_PERSONALITIES];
50 number_setbit(const unsigned int i, number_slot_t *const vec)
52 vec[i / BITS_PER_SLOT] |= (number_slot_t) 1 << (i % BITS_PER_SLOT);
56 number_isset(const unsigned int i, const number_slot_t *const vec)
58 return vec[i / BITS_PER_SLOT] & ((number_slot_t) 1 << (i % BITS_PER_SLOT));
62 reallocate_number_set(struct number_set *const set, const unsigned int new_nslots)
64 if (new_nslots <= set->nslots)
66 set->vec = xreallocarray(set->vec, new_nslots, sizeof(*set->vec));
67 memset(set->vec + set->nslots, 0,
68 sizeof(*set->vec) * (new_nslots - set->nslots));
69 set->nslots = new_nslots;
73 add_number_to_set(const unsigned int number, struct number_set *const set)
75 reallocate_number_set(set, number / BITS_PER_SLOT + 1);
76 number_setbit(number, set->vec);
80 is_number_in_set(const unsigned int number, const struct number_set *const set)
82 return ((number / BITS_PER_SLOT < set->nslots)
83 && number_isset(number, set->vec)) ^ set->not;
86 typedef int (*string_to_uint_func)(const char *);
89 * Add numbers to SET according to STR specification.
92 qualify_tokens(const char *const str, struct number_set *const set,
93 string_to_uint_func func, const char *const name)
97 memset(set->vec, 0, sizeof(*set->vec) * set->nslots);
101 * Each leading ! character means inversion
102 * of the remaining specification.
107 set->not = !set->not;
111 if (strcmp(s, "none") == 0) {
113 * No numbers are added to the set.
114 * Subsequent is_number_in_set invocations will return set->not.
117 } else if (strcmp(s, "all") == 0) {
119 goto handle_inversion;
123 * Split the string into comma separated tokens.
124 * For each token, find out the corresponding number
125 * by calling FUNC, and add that number to the set.
126 * The absence of tokens or a negative answer
127 * from FUNC is a fatal error.
129 char *copy = xstrdup(s);
130 char *saveptr = NULL;
134 for (token = strtok_r(copy, ",", &saveptr); token;
135 token = strtok_r(NULL, ",", &saveptr)) {
136 number = func(token);
138 error_msg_and_die("invalid %s '%s'", name, token);
141 add_number_to_set(number, set);
147 error_msg_and_die("invalid %s '%s'", name, str);
152 sigstr_to_uint(const char *s)
156 if (*s >= '0' && *s <= '9')
157 return string_to_uint_upto(s, 255);
159 if (strncasecmp(s, "SIG", 3) == 0)
162 for (i = 0; i <= 255; ++i) {
163 const char *name = signame(i);
165 if (strncasecmp(name, "SIG", 3) != 0)
170 if (strcasecmp(name, s) != 0)
180 qualify_syscall_number(const char *s, struct number_set *set)
182 int n = string_to_uint(s);
189 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
190 if ((unsigned) n >= nsyscall_vec[p]) {
193 add_number_to_set(n, &set[p]);
201 lookup_class(const char *s)
203 static const struct {
206 } syscall_class[] = {
207 { "desc", TRACE_DESC },
208 { "file", TRACE_FILE },
209 { "memory", TRACE_MEMORY },
210 { "process", TRACE_PROCESS },
211 { "signal", TRACE_SIGNAL },
212 { "ipc", TRACE_IPC },
213 { "network", TRACE_NETWORK },
217 for (i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
218 if (strcmp(s, syscall_class[i].name) == 0) {
219 return syscall_class[i].value;
227 qualify_syscall_class(const char *s, struct number_set *set)
229 const unsigned int n = lookup_class(s);
234 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
237 for (i = 0; i < nsyscall_vec[p]; ++i) {
238 if (!sysent_vec[p][i].sys_name
239 || (sysent_vec[p][i].sys_flags & n) != n) {
242 add_number_to_set(i, &set[p]);
250 qualify_syscall_name(const char *s, struct number_set *set)
255 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
258 for (i = 0; i < nsyscall_vec[p]; ++i) {
259 if (!sysent_vec[p][i].sys_name
260 || strcmp(s, sysent_vec[p][i].sys_name)) {
263 add_number_to_set(i, &set[p]);
272 qualify_syscall(const char *token, struct number_set *set)
274 if (*token >= '0' && *token <= '9')
275 return qualify_syscall_number(token, set);
276 return qualify_syscall_class(token, set)
277 || qualify_syscall_name(token, set);
281 * Add syscall numbers to SETs for each supported personality
282 * according to STR specification.
285 qualify_syscall_tokens(const char *const str, struct number_set *const set,
286 const char *const name)
288 /* Clear all sets. */
290 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
292 memset(set[p].vec, 0,
293 sizeof(*set[p].vec) * set[p].nslots);
298 * Each leading ! character means inversion
299 * of the remaining specification.
304 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
305 set[p].not = !set[p].not;
310 if (strcmp(s, "none") == 0) {
312 * No syscall numbers are added to sets.
313 * Subsequent is_number_in_set invocations
314 * will return set[p]->not.
317 } else if (strcmp(s, "all") == 0) {
319 goto handle_inversion;
323 * Split the string into comma separated tokens.
324 * For each token, call qualify_syscall that will take care
325 * if adding appropriate syscall numbers to sets.
326 * The absence of tokens or a negative return code
327 * from qualify_syscall is a fatal error.
329 char *copy = xstrdup(s);
330 char *saveptr = NULL;
334 for (token = strtok_r(copy, ",", &saveptr); token;
335 token = strtok_r(NULL, ",", &saveptr)) {
336 done = qualify_syscall(token, set);
338 error_msg_and_die("invalid %s '%s'", name, token);
345 error_msg_and_die("invalid %s '%s'", name, str);
350 * Returns NULL if STR does not start with PREFIX,
351 * or a pointer to the first char in STR after PREFIX.
354 strip_prefix(const char *prefix, const char *str)
356 size_t len = strlen(prefix);
358 return strncmp(prefix, str, len) ? NULL : str + len;
362 find_errno_by_name(const char *name)
366 for (i = 1; i < nerrnos; ++i) {
367 if (errnoent[i] && (strcmp(name, errnoent[i]) == 0))
375 parse_fault_token(const char *const token, struct fault_opts *const fopts)
380 if ((val = strip_prefix("when=", token))) {
388 intval = string_to_uint_ex(val, &end, 0xffff, "+");
392 fopts->first = intval;
398 intval = string_to_uint_upto(val, 0xffff);
401 fopts->step = intval;
410 } else if ((val = strip_prefix("error=", token))) {
411 intval = string_to_uint_upto(val, 4095);
413 intval = find_errno_by_name(val);
425 parse_fault_expression(const char *const s, char **buf,
426 struct fault_opts *const fopts)
428 char *saveptr = NULL;
433 for (token = strtok_r(*buf, ":", &saveptr); token;
434 token = strtok_r(NULL, ":", &saveptr)) {
437 else if (!parse_fault_token(token, fopts))
450 qualify_read(const char *const str)
452 qualify_tokens(str, &read_set, string_to_uint, "descriptor");
456 qualify_write(const char *const str)
458 qualify_tokens(str, &write_set, string_to_uint, "descriptor");
462 qualify_signals(const char *const str)
464 qualify_tokens(str, &signal_set, sigstr_to_uint, "signal");
468 qualify_trace(const char *const str)
470 qualify_syscall_tokens(str, trace_set, "system call");
474 qualify_abbrev(const char *const str)
476 qualify_syscall_tokens(str, abbrev_set, "system call");
480 qualify_verbose(const char *const str)
482 qualify_syscall_tokens(str, verbose_set, "system call");
486 qualify_raw(const char *const str)
488 qualify_syscall_tokens(str, raw_set, "system call");
492 qualify_fault(const char *const str)
494 struct fault_opts opts = {
500 char *name = parse_fault_expression(str, &buf, &opts);
502 error_msg_and_die("invalid %s '%s'", "fault argument", str);
506 struct number_set tmp_set[SUPPORTED_PERSONALITIES];
507 memset(tmp_set, 0, sizeof(tmp_set));
508 qualify_syscall_tokens(name, tmp_set, "fault argument");
513 * Initialize fault_vec accourding to tmp_set.
514 * Merge tmp_set into fault_set.
517 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
518 if (!tmp_set[p].nslots && !tmp_set[p].not) {
523 fault_vec[p] = xcalloc(nsyscall_vec[p],
524 sizeof(*fault_vec[p]));
528 for (i = 0; i < nsyscall_vec[p]; ++i) {
529 if (is_number_in_set(i, &tmp_set[p])) {
530 add_number_to_set(i, &fault_set[p]);
531 fault_vec[p][i] = opts;
535 free(tmp_set[p].vec);
539 static const struct qual_options {
541 void (*qualify)(const char *);
543 { "trace", qualify_trace },
544 { "t", qualify_trace },
545 { "abbrev", qualify_abbrev },
546 { "a", qualify_abbrev },
547 { "verbose", qualify_verbose },
548 { "v", qualify_verbose },
549 { "raw", qualify_raw },
550 { "x", qualify_raw },
551 { "signal", qualify_signals },
552 { "signals", qualify_signals },
553 { "s", qualify_signals },
554 { "read", qualify_read },
555 { "reads", qualify_read },
556 { "r", qualify_read },
557 { "write", qualify_write },
558 { "writes", qualify_write },
559 { "w", qualify_write },
560 { "fault", qualify_fault },
564 qualify(const char *str)
566 const struct qual_options *opt = qual_options;
569 for (i = 0; i < ARRAY_SIZE(qual_options); ++i) {
570 const char *p = qual_options[i].name;
571 unsigned int len = strlen(p);
573 if (strncmp(str, p, len) || str[len] != '=')
576 opt = &qual_options[i];
585 qual_flags(const unsigned int scno)
587 return (is_number_in_set(scno, &trace_set[current_personality])
589 | (is_number_in_set(scno, &abbrev_set[current_personality])
591 | (is_number_in_set(scno, &verbose_set[current_personality])
593 | (is_number_in_set(scno, &raw_set[current_personality])
595 | (is_number_in_set(scno, &fault_set[current_personality])