plugins: Wire up rust plugin support for NBD_INFO_INIT_STATE
[nbdkit/ericb.git] / server / debug-flags.c
blob5b169387f9a3bdf5f0a7750204faa3f485d33293
1 /* nbdkit
2 * Copyright (C) 2013-2019 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * 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.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
39 #include <dlfcn.h>
41 #include "internal.h"
43 struct debug_flag {
44 struct debug_flag *next;
45 char *name; /* plugin or filter name */
46 char *flag; /* flag name */
47 char *symbol; /* symbol, eg. "myplugin_debug_foo" */
48 int value; /* value of flag */
49 bool used; /* if flag was successfully set */
52 /* Synthesize the name of the *_debug_* variable from the plugin name
53 * and flag.
55 static char *
56 symbol_of_debug_flag (const char *name, const char *flag)
58 char *var;
59 size_t i;
60 int len;
62 len = asprintf (&var, "%s_debug_%s", name, flag);
63 if (len == -1) {
64 perror ("asprintf");
65 exit (EXIT_FAILURE);
68 /* If there are any '.'s remaining in the name, convert them to '_'. */
69 for (i = 0; i < (size_t) len; ++i) {
70 if (var[i] == '.')
71 var[i] = '_';
74 return var; /* caller frees */
77 /* Parse and add a single -D flag from the command line.
79 * Debug Flag must be "NAME.FLAG=N".
80 * ^ ^ ^
81 * arg p q (after +1 adjustment below)
83 void
84 add_debug_flag (const char *arg)
86 struct debug_flag *flag;
87 char *p, *q;
89 p = strchr (arg, '.');
90 q = strchr (arg, '=');
91 if (p == NULL || q == NULL) {
92 bad_debug_flag:
93 fprintf (stderr,
94 "%s: -D (Debug Flag) must have the format NAME.FLAG=N\n",
95 program_name);
96 exit (EXIT_FAILURE);
98 p++; /* +1 adjustment */
99 q++;
101 if (p - arg <= 1) goto bad_debug_flag; /* NAME too short */
102 if (p > q) goto bad_debug_flag;
103 if (q - p <= 1) goto bad_debug_flag; /* FLAG too short */
104 if (*q == '\0') goto bad_debug_flag; /* N too short */
106 flag = malloc (sizeof *flag);
107 if (flag == NULL) {
108 debug_flag_perror:
109 perror ("malloc");
110 exit (EXIT_FAILURE);
113 flag->name = strndup (arg, p-arg-1);
114 if (!flag->name) goto debug_flag_perror;
115 flag->flag = strndup (p, q-p-1);
116 if (!flag->flag) goto debug_flag_perror;
117 if (nbdkit_parse_int ("flag", q, &flag->value) == -1)
118 goto bad_debug_flag;
119 flag->used = false;
120 flag->symbol = symbol_of_debug_flag (flag->name, flag->flag);
122 /* Add flag to the linked list. */
123 flag->next = debug_flags;
124 debug_flags = flag;
127 /* Apply all debug flags applicable to this backend. */
128 void
129 apply_debug_flags (void *dl, const char *name)
131 struct debug_flag *flag;
133 for (flag = debug_flags; flag != NULL; flag = flag->next) {
134 if (!flag->used && strcmp (name, flag->name) == 0) {
135 int *sym;
137 /* Find the symbol. */
138 sym = dlsym (dl, flag->symbol);
139 if (sym) {
140 /* Set the flag. */
141 *sym = flag->value;
143 else {
144 fprintf (stderr,
145 "%s: warning: -D %s.%s: %s does not contain a "
146 "global variable called %s\n",
147 program_name, name, flag->flag, name, flag->symbol);
150 /* Mark this flag as used. */
151 flag->used = true;
156 void
157 free_debug_flags (void)
159 while (debug_flags != NULL) {
160 struct debug_flag *next = debug_flags->next;
162 if (!debug_flags->used)
163 fprintf (stderr, "%s: warning: debug flag -D %s.%s was not used\n",
164 program_name, debug_flags->name, debug_flags->flag);
165 free (debug_flags->name);
166 free (debug_flags->flag);
167 free (debug_flags->symbol);
168 free (debug_flags);
169 debug_flags = next;