xref: /OK3568_Linux_fs/kernel/tools/lib/traceevent/event-plugin.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: LGPL-2.1
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <ctype.h>
8*4882a593Smuzhiyun #include <stdio.h>
9*4882a593Smuzhiyun #include <string.h>
10*4882a593Smuzhiyun #include <dlfcn.h>
11*4882a593Smuzhiyun #include <stdlib.h>
12*4882a593Smuzhiyun #include <sys/types.h>
13*4882a593Smuzhiyun #include <sys/stat.h>
14*4882a593Smuzhiyun #include <unistd.h>
15*4882a593Smuzhiyun #include <dirent.h>
16*4882a593Smuzhiyun #include <errno.h>
17*4882a593Smuzhiyun #include "event-parse.h"
18*4882a593Smuzhiyun #include "event-parse-local.h"
19*4882a593Smuzhiyun #include "event-utils.h"
20*4882a593Smuzhiyun #include "trace-seq.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static struct registered_plugin_options {
25*4882a593Smuzhiyun 	struct registered_plugin_options	*next;
26*4882a593Smuzhiyun 	struct tep_plugin_option		*options;
27*4882a593Smuzhiyun } *registered_options;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun static struct trace_plugin_options {
30*4882a593Smuzhiyun 	struct trace_plugin_options	*next;
31*4882a593Smuzhiyun 	char				*plugin;
32*4882a593Smuzhiyun 	char				*option;
33*4882a593Smuzhiyun 	char				*value;
34*4882a593Smuzhiyun } *trace_plugin_options;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun struct tep_plugin_list {
37*4882a593Smuzhiyun 	struct tep_plugin_list	*next;
38*4882a593Smuzhiyun 	char			*name;
39*4882a593Smuzhiyun 	void			*handle;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct tep_plugins_dir {
43*4882a593Smuzhiyun 	struct tep_plugins_dir		*next;
44*4882a593Smuzhiyun 	char				*path;
45*4882a593Smuzhiyun 	enum tep_plugin_load_priority	prio;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
lower_case(char * str)48*4882a593Smuzhiyun static void lower_case(char *str)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	if (!str)
51*4882a593Smuzhiyun 		return;
52*4882a593Smuzhiyun 	for (; *str; str++)
53*4882a593Smuzhiyun 		*str = tolower(*str);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
update_option_value(struct tep_plugin_option * op,const char * val)56*4882a593Smuzhiyun static int update_option_value(struct tep_plugin_option *op, const char *val)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	char *op_val;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	if (!val) {
61*4882a593Smuzhiyun 		/* toggle, only if option is boolean */
62*4882a593Smuzhiyun 		if (op->value)
63*4882a593Smuzhiyun 			/* Warn? */
64*4882a593Smuzhiyun 			return 0;
65*4882a593Smuzhiyun 		op->set ^= 1;
66*4882a593Smuzhiyun 		return 0;
67*4882a593Smuzhiyun 	}
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	/*
70*4882a593Smuzhiyun 	 * If the option has a value then it takes a string
71*4882a593Smuzhiyun 	 * otherwise the option is a boolean.
72*4882a593Smuzhiyun 	 */
73*4882a593Smuzhiyun 	if (op->value) {
74*4882a593Smuzhiyun 		op->value = val;
75*4882a593Smuzhiyun 		return 0;
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* Option is boolean, must be either "1", "0", "true" or "false" */
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	op_val = strdup(val);
81*4882a593Smuzhiyun 	if (!op_val)
82*4882a593Smuzhiyun 		return -1;
83*4882a593Smuzhiyun 	lower_case(op_val);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
86*4882a593Smuzhiyun 		op->set = 1;
87*4882a593Smuzhiyun 	else if (strcmp(val, "0") == 0 || strcmp(val, "false") == 0)
88*4882a593Smuzhiyun 		op->set = 0;
89*4882a593Smuzhiyun 	free(op_val);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return 0;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun /**
95*4882a593Smuzhiyun  * tep_plugin_list_options - get list of plugin options
96*4882a593Smuzhiyun  *
97*4882a593Smuzhiyun  * Returns an array of char strings that list the currently registered
98*4882a593Smuzhiyun  * plugin options in the format of <plugin>:<option>. This list can be
99*4882a593Smuzhiyun  * used by toggling the option.
100*4882a593Smuzhiyun  *
101*4882a593Smuzhiyun  * Returns NULL if there's no options registered. On error it returns
102*4882a593Smuzhiyun  * INVALID_PLUGIN_LIST_OPTION
103*4882a593Smuzhiyun  *
104*4882a593Smuzhiyun  * Must be freed with tep_plugin_free_options_list().
105*4882a593Smuzhiyun  */
tep_plugin_list_options(void)106*4882a593Smuzhiyun char **tep_plugin_list_options(void)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct registered_plugin_options *reg;
109*4882a593Smuzhiyun 	struct tep_plugin_option *op;
110*4882a593Smuzhiyun 	char **list = NULL;
111*4882a593Smuzhiyun 	char *name;
112*4882a593Smuzhiyun 	int count = 0;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	for (reg = registered_options; reg; reg = reg->next) {
115*4882a593Smuzhiyun 		for (op = reg->options; op->name; op++) {
116*4882a593Smuzhiyun 			char *alias = op->plugin_alias ? op->plugin_alias : op->file;
117*4882a593Smuzhiyun 			char **temp = list;
118*4882a593Smuzhiyun 			int ret;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 			ret = asprintf(&name, "%s:%s", alias, op->name);
121*4882a593Smuzhiyun 			if (ret < 0)
122*4882a593Smuzhiyun 				goto err;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 			list = realloc(list, count + 2);
125*4882a593Smuzhiyun 			if (!list) {
126*4882a593Smuzhiyun 				list = temp;
127*4882a593Smuzhiyun 				free(name);
128*4882a593Smuzhiyun 				goto err;
129*4882a593Smuzhiyun 			}
130*4882a593Smuzhiyun 			list[count++] = name;
131*4882a593Smuzhiyun 			list[count] = NULL;
132*4882a593Smuzhiyun 		}
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 	return list;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun  err:
137*4882a593Smuzhiyun 	while (--count >= 0)
138*4882a593Smuzhiyun 		free(list[count]);
139*4882a593Smuzhiyun 	free(list);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return INVALID_PLUGIN_LIST_OPTION;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
tep_plugin_free_options_list(char ** list)144*4882a593Smuzhiyun void tep_plugin_free_options_list(char **list)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	int i;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (!list)
149*4882a593Smuzhiyun 		return;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	if (list == INVALID_PLUGIN_LIST_OPTION)
152*4882a593Smuzhiyun 		return;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	for (i = 0; list[i]; i++)
155*4882a593Smuzhiyun 		free(list[i]);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	free(list);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun static int
update_option(const char * file,struct tep_plugin_option * option)161*4882a593Smuzhiyun update_option(const char *file, struct tep_plugin_option *option)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	struct trace_plugin_options *op;
164*4882a593Smuzhiyun 	char *plugin;
165*4882a593Smuzhiyun 	int ret = 0;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	if (option->plugin_alias) {
168*4882a593Smuzhiyun 		plugin = strdup(option->plugin_alias);
169*4882a593Smuzhiyun 		if (!plugin)
170*4882a593Smuzhiyun 			return -1;
171*4882a593Smuzhiyun 	} else {
172*4882a593Smuzhiyun 		char *p;
173*4882a593Smuzhiyun 		plugin = strdup(file);
174*4882a593Smuzhiyun 		if (!plugin)
175*4882a593Smuzhiyun 			return -1;
176*4882a593Smuzhiyun 		p = strstr(plugin, ".");
177*4882a593Smuzhiyun 		if (p)
178*4882a593Smuzhiyun 			*p = '\0';
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	/* first look for named options */
182*4882a593Smuzhiyun 	for (op = trace_plugin_options; op; op = op->next) {
183*4882a593Smuzhiyun 		if (!op->plugin)
184*4882a593Smuzhiyun 			continue;
185*4882a593Smuzhiyun 		if (strcmp(op->plugin, plugin) != 0)
186*4882a593Smuzhiyun 			continue;
187*4882a593Smuzhiyun 		if (strcmp(op->option, option->name) != 0)
188*4882a593Smuzhiyun 			continue;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 		ret = update_option_value(option, op->value);
191*4882a593Smuzhiyun 		if (ret)
192*4882a593Smuzhiyun 			goto out;
193*4882a593Smuzhiyun 		break;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/* first look for unnamed options */
197*4882a593Smuzhiyun 	for (op = trace_plugin_options; op; op = op->next) {
198*4882a593Smuzhiyun 		if (op->plugin)
199*4882a593Smuzhiyun 			continue;
200*4882a593Smuzhiyun 		if (strcmp(op->option, option->name) != 0)
201*4882a593Smuzhiyun 			continue;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 		ret = update_option_value(option, op->value);
204*4882a593Smuzhiyun 		break;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun  out:
208*4882a593Smuzhiyun 	free(plugin);
209*4882a593Smuzhiyun 	return ret;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun  * tep_plugin_add_options - Add a set of options by a plugin
214*4882a593Smuzhiyun  * @name: The name of the plugin adding the options
215*4882a593Smuzhiyun  * @options: The set of options being loaded
216*4882a593Smuzhiyun  *
217*4882a593Smuzhiyun  * Sets the options with the values that have been added by user.
218*4882a593Smuzhiyun  */
tep_plugin_add_options(const char * name,struct tep_plugin_option * options)219*4882a593Smuzhiyun int tep_plugin_add_options(const char *name,
220*4882a593Smuzhiyun 			   struct tep_plugin_option *options)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct registered_plugin_options *reg;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	reg = malloc(sizeof(*reg));
225*4882a593Smuzhiyun 	if (!reg)
226*4882a593Smuzhiyun 		return -1;
227*4882a593Smuzhiyun 	reg->next = registered_options;
228*4882a593Smuzhiyun 	reg->options = options;
229*4882a593Smuzhiyun 	registered_options = reg;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	while (options->name) {
232*4882a593Smuzhiyun 		update_option(name, options);
233*4882a593Smuzhiyun 		options++;
234*4882a593Smuzhiyun 	}
235*4882a593Smuzhiyun 	return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun /**
239*4882a593Smuzhiyun  * tep_plugin_remove_options - remove plugin options that were registered
240*4882a593Smuzhiyun  * @options: Options to removed that were registered with tep_plugin_add_options
241*4882a593Smuzhiyun  */
tep_plugin_remove_options(struct tep_plugin_option * options)242*4882a593Smuzhiyun void tep_plugin_remove_options(struct tep_plugin_option *options)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	struct registered_plugin_options **last;
245*4882a593Smuzhiyun 	struct registered_plugin_options *reg;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	for (last = &registered_options; *last; last = &(*last)->next) {
248*4882a593Smuzhiyun 		if ((*last)->options == options) {
249*4882a593Smuzhiyun 			reg = *last;
250*4882a593Smuzhiyun 			*last = reg->next;
251*4882a593Smuzhiyun 			free(reg);
252*4882a593Smuzhiyun 			return;
253*4882a593Smuzhiyun 		}
254*4882a593Smuzhiyun 	}
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
parse_option_name(char ** option,char ** plugin)257*4882a593Smuzhiyun static int parse_option_name(char **option, char **plugin)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	char *p;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	*plugin = NULL;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if ((p = strstr(*option, ":"))) {
264*4882a593Smuzhiyun 		*plugin = *option;
265*4882a593Smuzhiyun 		*p = '\0';
266*4882a593Smuzhiyun 		*option = strdup(p + 1);
267*4882a593Smuzhiyun 		if (!*option)
268*4882a593Smuzhiyun 			return -1;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 	return 0;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun static struct tep_plugin_option *
find_registered_option(const char * plugin,const char * option)274*4882a593Smuzhiyun find_registered_option(const char *plugin, const char *option)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	struct registered_plugin_options *reg;
277*4882a593Smuzhiyun 	struct tep_plugin_option *op;
278*4882a593Smuzhiyun 	const char *op_plugin;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	for (reg = registered_options; reg; reg = reg->next) {
281*4882a593Smuzhiyun 		for (op = reg->options; op->name; op++) {
282*4882a593Smuzhiyun 			if (op->plugin_alias)
283*4882a593Smuzhiyun 				op_plugin = op->plugin_alias;
284*4882a593Smuzhiyun 			else
285*4882a593Smuzhiyun 				op_plugin = op->file;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 			if (plugin && strcmp(plugin, op_plugin) != 0)
288*4882a593Smuzhiyun 				continue;
289*4882a593Smuzhiyun 			if (strcmp(option, op->name) != 0)
290*4882a593Smuzhiyun 				continue;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 			return op;
293*4882a593Smuzhiyun 		}
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	return NULL;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun 
process_option(const char * plugin,const char * option,const char * val)299*4882a593Smuzhiyun static int process_option(const char *plugin, const char *option, const char *val)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	struct tep_plugin_option *op;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	op = find_registered_option(plugin, option);
304*4882a593Smuzhiyun 	if (!op)
305*4882a593Smuzhiyun 		return 0;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	return update_option_value(op, val);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun /**
311*4882a593Smuzhiyun  * tep_plugin_add_option - add an option/val pair to set plugin options
312*4882a593Smuzhiyun  * @name: The name of the option (format: <plugin>:<option> or just <option>)
313*4882a593Smuzhiyun  * @val: (optional) the value for the option
314*4882a593Smuzhiyun  *
315*4882a593Smuzhiyun  * Modify a plugin option. If @val is given than the value of the option
316*4882a593Smuzhiyun  * is set (note, some options just take a boolean, so @val must be either
317*4882a593Smuzhiyun  * "1" or "0" or "true" or "false").
318*4882a593Smuzhiyun  */
tep_plugin_add_option(const char * name,const char * val)319*4882a593Smuzhiyun int tep_plugin_add_option(const char *name, const char *val)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	struct trace_plugin_options *op;
322*4882a593Smuzhiyun 	char *option_str;
323*4882a593Smuzhiyun 	char *plugin;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	option_str = strdup(name);
326*4882a593Smuzhiyun 	if (!option_str)
327*4882a593Smuzhiyun 		return -ENOMEM;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	if (parse_option_name(&option_str, &plugin) < 0)
330*4882a593Smuzhiyun 		return -ENOMEM;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* If the option exists, update the val */
333*4882a593Smuzhiyun 	for (op = trace_plugin_options; op; op = op->next) {
334*4882a593Smuzhiyun 		/* Both must be NULL or not NULL */
335*4882a593Smuzhiyun 		if ((!plugin || !op->plugin) && plugin != op->plugin)
336*4882a593Smuzhiyun 			continue;
337*4882a593Smuzhiyun 		if (plugin && strcmp(plugin, op->plugin) != 0)
338*4882a593Smuzhiyun 			continue;
339*4882a593Smuzhiyun 		if (strcmp(op->option, option_str) != 0)
340*4882a593Smuzhiyun 			continue;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		/* update option */
343*4882a593Smuzhiyun 		free(op->value);
344*4882a593Smuzhiyun 		if (val) {
345*4882a593Smuzhiyun 			op->value = strdup(val);
346*4882a593Smuzhiyun 			if (!op->value)
347*4882a593Smuzhiyun 				goto out_free;
348*4882a593Smuzhiyun 		} else
349*4882a593Smuzhiyun 			op->value = NULL;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 		/* plugin and option_str don't get freed at the end */
352*4882a593Smuzhiyun 		free(plugin);
353*4882a593Smuzhiyun 		free(option_str);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 		plugin = op->plugin;
356*4882a593Smuzhiyun 		option_str = op->option;
357*4882a593Smuzhiyun 		break;
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	/* If not found, create */
361*4882a593Smuzhiyun 	if (!op) {
362*4882a593Smuzhiyun 		op = malloc(sizeof(*op));
363*4882a593Smuzhiyun 		if (!op)
364*4882a593Smuzhiyun 			goto out_free;
365*4882a593Smuzhiyun 		memset(op, 0, sizeof(*op));
366*4882a593Smuzhiyun 		op->plugin = plugin;
367*4882a593Smuzhiyun 		op->option = option_str;
368*4882a593Smuzhiyun 		if (val) {
369*4882a593Smuzhiyun 			op->value = strdup(val);
370*4882a593Smuzhiyun 			if (!op->value) {
371*4882a593Smuzhiyun 				free(op);
372*4882a593Smuzhiyun 				goto out_free;
373*4882a593Smuzhiyun 			}
374*4882a593Smuzhiyun 		}
375*4882a593Smuzhiyun 		op->next = trace_plugin_options;
376*4882a593Smuzhiyun 		trace_plugin_options = op;
377*4882a593Smuzhiyun 	}
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	return process_option(plugin, option_str, val);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun out_free:
382*4882a593Smuzhiyun 	free(plugin);
383*4882a593Smuzhiyun 	free(option_str);
384*4882a593Smuzhiyun 	return -ENOMEM;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
print_op_data(struct trace_seq * s,const char * name,const char * op)387*4882a593Smuzhiyun static void print_op_data(struct trace_seq *s, const char *name,
388*4882a593Smuzhiyun 			  const char *op)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	if (op)
391*4882a593Smuzhiyun 		trace_seq_printf(s, "%8s:\t%s\n", name, op);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun /**
395*4882a593Smuzhiyun  * tep_plugin_print_options - print out the registered plugin options
396*4882a593Smuzhiyun  * @s: The trace_seq descriptor to write the plugin options into
397*4882a593Smuzhiyun  *
398*4882a593Smuzhiyun  * Writes a list of options into trace_seq @s.
399*4882a593Smuzhiyun  */
tep_plugin_print_options(struct trace_seq * s)400*4882a593Smuzhiyun void tep_plugin_print_options(struct trace_seq *s)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	struct registered_plugin_options *reg;
403*4882a593Smuzhiyun 	struct tep_plugin_option *op;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	for (reg = registered_options; reg; reg = reg->next) {
406*4882a593Smuzhiyun 		if (reg != registered_options)
407*4882a593Smuzhiyun 			trace_seq_printf(s, "============\n");
408*4882a593Smuzhiyun 		for (op = reg->options; op->name; op++) {
409*4882a593Smuzhiyun 			if (op != reg->options)
410*4882a593Smuzhiyun 				trace_seq_printf(s, "------------\n");
411*4882a593Smuzhiyun 			print_op_data(s, "file", op->file);
412*4882a593Smuzhiyun 			print_op_data(s, "plugin", op->plugin_alias);
413*4882a593Smuzhiyun 			print_op_data(s, "option", op->name);
414*4882a593Smuzhiyun 			print_op_data(s, "desc", op->description);
415*4882a593Smuzhiyun 			print_op_data(s, "value", op->value);
416*4882a593Smuzhiyun 			trace_seq_printf(s, "%8s:\t%d\n", "set", op->set);
417*4882a593Smuzhiyun 		}
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun /**
422*4882a593Smuzhiyun  * tep_print_plugins - print out the list of plugins loaded
423*4882a593Smuzhiyun  * @s: the trace_seq descripter to write to
424*4882a593Smuzhiyun  * @prefix: The prefix string to add before listing the option name
425*4882a593Smuzhiyun  * @suffix: The suffix string ot append after the option name
426*4882a593Smuzhiyun  * @list: The list of plugins (usually returned by tep_load_plugins()
427*4882a593Smuzhiyun  *
428*4882a593Smuzhiyun  * Writes to the trace_seq @s the list of plugins (files) that is
429*4882a593Smuzhiyun  * returned by tep_load_plugins(). Use @prefix and @suffix for formating:
430*4882a593Smuzhiyun  * @prefix = "  ", @suffix = "\n".
431*4882a593Smuzhiyun  */
tep_print_plugins(struct trace_seq * s,const char * prefix,const char * suffix,const struct tep_plugin_list * list)432*4882a593Smuzhiyun void tep_print_plugins(struct trace_seq *s,
433*4882a593Smuzhiyun 		       const char *prefix, const char *suffix,
434*4882a593Smuzhiyun 		       const struct tep_plugin_list *list)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	while (list) {
437*4882a593Smuzhiyun 		trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
438*4882a593Smuzhiyun 		list = list->next;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun static void
load_plugin(struct tep_handle * tep,const char * path,const char * file,void * data)443*4882a593Smuzhiyun load_plugin(struct tep_handle *tep, const char *path,
444*4882a593Smuzhiyun 	    const char *file, void *data)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	struct tep_plugin_list **plugin_list = data;
447*4882a593Smuzhiyun 	struct tep_plugin_option *options;
448*4882a593Smuzhiyun 	tep_plugin_load_func func;
449*4882a593Smuzhiyun 	struct tep_plugin_list *list;
450*4882a593Smuzhiyun 	const char *alias;
451*4882a593Smuzhiyun 	char *plugin;
452*4882a593Smuzhiyun 	void *handle;
453*4882a593Smuzhiyun 	int ret;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	ret = asprintf(&plugin, "%s/%s", path, file);
456*4882a593Smuzhiyun 	if (ret < 0) {
457*4882a593Smuzhiyun 		warning("could not allocate plugin memory\n");
458*4882a593Smuzhiyun 		return;
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
462*4882a593Smuzhiyun 	if (!handle) {
463*4882a593Smuzhiyun 		warning("could not load plugin '%s'\n%s\n",
464*4882a593Smuzhiyun 			plugin, dlerror());
465*4882a593Smuzhiyun 		goto out_free;
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
469*4882a593Smuzhiyun 	if (!alias)
470*4882a593Smuzhiyun 		alias = file;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME);
473*4882a593Smuzhiyun 	if (options) {
474*4882a593Smuzhiyun 		while (options->name) {
475*4882a593Smuzhiyun 			ret = update_option(alias, options);
476*4882a593Smuzhiyun 			if (ret < 0)
477*4882a593Smuzhiyun 				goto out_free;
478*4882a593Smuzhiyun 			options++;
479*4882a593Smuzhiyun 		}
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
483*4882a593Smuzhiyun 	if (!func) {
484*4882a593Smuzhiyun 		warning("could not find func '%s' in plugin '%s'\n%s\n",
485*4882a593Smuzhiyun 			TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
486*4882a593Smuzhiyun 		goto out_free;
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	list = malloc(sizeof(*list));
490*4882a593Smuzhiyun 	if (!list) {
491*4882a593Smuzhiyun 		warning("could not allocate plugin memory\n");
492*4882a593Smuzhiyun 		goto out_free;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	list->next = *plugin_list;
496*4882a593Smuzhiyun 	list->handle = handle;
497*4882a593Smuzhiyun 	list->name = plugin;
498*4882a593Smuzhiyun 	*plugin_list = list;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	pr_stat("registering plugin: %s", plugin);
501*4882a593Smuzhiyun 	func(tep);
502*4882a593Smuzhiyun 	return;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun  out_free:
505*4882a593Smuzhiyun 	free(plugin);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun static void
load_plugins_dir(struct tep_handle * tep,const char * suffix,const char * path,void (* load_plugin)(struct tep_handle * tep,const char * path,const char * name,void * data),void * data)509*4882a593Smuzhiyun load_plugins_dir(struct tep_handle *tep, const char *suffix,
510*4882a593Smuzhiyun 		 const char *path,
511*4882a593Smuzhiyun 		 void (*load_plugin)(struct tep_handle *tep,
512*4882a593Smuzhiyun 				     const char *path,
513*4882a593Smuzhiyun 				     const char *name,
514*4882a593Smuzhiyun 				     void *data),
515*4882a593Smuzhiyun 		 void *data)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	struct dirent *dent;
518*4882a593Smuzhiyun 	struct stat st;
519*4882a593Smuzhiyun 	DIR *dir;
520*4882a593Smuzhiyun 	int ret;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	ret = stat(path, &st);
523*4882a593Smuzhiyun 	if (ret < 0)
524*4882a593Smuzhiyun 		return;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if (!S_ISDIR(st.st_mode))
527*4882a593Smuzhiyun 		return;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	dir = opendir(path);
530*4882a593Smuzhiyun 	if (!dir)
531*4882a593Smuzhiyun 		return;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	while ((dent = readdir(dir))) {
534*4882a593Smuzhiyun 		const char *name = dent->d_name;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 		if (strcmp(name, ".") == 0 ||
537*4882a593Smuzhiyun 		    strcmp(name, "..") == 0)
538*4882a593Smuzhiyun 			continue;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 		/* Only load plugins that end in suffix */
541*4882a593Smuzhiyun 		if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
542*4882a593Smuzhiyun 			continue;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 		load_plugin(tep, path, name, data);
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	closedir(dir);
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun /**
551*4882a593Smuzhiyun  * tep_load_plugins_hook - call a user specified callback to load a plugin
552*4882a593Smuzhiyun  * @tep: handler to traceevent context
553*4882a593Smuzhiyun  * @suffix: filter only plugin files with given suffix
554*4882a593Smuzhiyun  * @load_plugin: user specified callback, called for each plugin file
555*4882a593Smuzhiyun  * @data: custom context, passed to @load_plugin
556*4882a593Smuzhiyun  *
557*4882a593Smuzhiyun  * Searches for traceevent plugin files and calls @load_plugin for each
558*4882a593Smuzhiyun  * The order of plugins search is:
559*4882a593Smuzhiyun  *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_FIRST
560*4882a593Smuzhiyun  *  - Directory, specified at compile time with PLUGIN_TRACEEVENT_DIR
561*4882a593Smuzhiyun  *  - Directory, specified by environment variable TRACEEVENT_PLUGIN_DIR
562*4882a593Smuzhiyun  *  - In user's home: ~/.local/lib/traceevent/plugins/
563*4882a593Smuzhiyun  *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_LAST
564*4882a593Smuzhiyun  *
565*4882a593Smuzhiyun  */
tep_load_plugins_hook(struct tep_handle * tep,const char * suffix,void (* load_plugin)(struct tep_handle * tep,const char * path,const char * name,void * data),void * data)566*4882a593Smuzhiyun void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix,
567*4882a593Smuzhiyun 			   void (*load_plugin)(struct tep_handle *tep,
568*4882a593Smuzhiyun 					       const char *path,
569*4882a593Smuzhiyun 					       const char *name,
570*4882a593Smuzhiyun 					       void *data),
571*4882a593Smuzhiyun 			   void *data)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	struct tep_plugins_dir *dir = NULL;
574*4882a593Smuzhiyun 	char *home;
575*4882a593Smuzhiyun 	char *path;
576*4882a593Smuzhiyun 	char *envdir;
577*4882a593Smuzhiyun 	int ret;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	if (tep && tep->flags & TEP_DISABLE_PLUGINS)
580*4882a593Smuzhiyun 		return;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	if (tep)
583*4882a593Smuzhiyun 		dir = tep->plugins_dir;
584*4882a593Smuzhiyun 	while (dir) {
585*4882a593Smuzhiyun 		if (dir->prio == TEP_PLUGIN_FIRST)
586*4882a593Smuzhiyun 			load_plugins_dir(tep, suffix, dir->path,
587*4882a593Smuzhiyun 					 load_plugin, data);
588*4882a593Smuzhiyun 		dir = dir->next;
589*4882a593Smuzhiyun 	}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	/*
592*4882a593Smuzhiyun 	 * If a system plugin directory was defined,
593*4882a593Smuzhiyun 	 * check that first.
594*4882a593Smuzhiyun 	 */
595*4882a593Smuzhiyun #ifdef PLUGIN_DIR
596*4882a593Smuzhiyun 	if (!tep || !(tep->flags & TEP_DISABLE_SYS_PLUGINS))
597*4882a593Smuzhiyun 		load_plugins_dir(tep, suffix, PLUGIN_DIR,
598*4882a593Smuzhiyun 				 load_plugin, data);
599*4882a593Smuzhiyun #endif
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	/*
602*4882a593Smuzhiyun 	 * Next let the environment-set plugin directory
603*4882a593Smuzhiyun 	 * override the system defaults.
604*4882a593Smuzhiyun 	 */
605*4882a593Smuzhiyun 	envdir = getenv("TRACEEVENT_PLUGIN_DIR");
606*4882a593Smuzhiyun 	if (envdir)
607*4882a593Smuzhiyun 		load_plugins_dir(tep, suffix, envdir, load_plugin, data);
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	/*
610*4882a593Smuzhiyun 	 * Now let the home directory override the environment
611*4882a593Smuzhiyun 	 * or system defaults.
612*4882a593Smuzhiyun 	 */
613*4882a593Smuzhiyun 	home = getenv("HOME");
614*4882a593Smuzhiyun 	if (!home)
615*4882a593Smuzhiyun 		return;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
618*4882a593Smuzhiyun 	if (ret < 0) {
619*4882a593Smuzhiyun 		warning("could not allocate plugin memory\n");
620*4882a593Smuzhiyun 		return;
621*4882a593Smuzhiyun 	}
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	load_plugins_dir(tep, suffix, path, load_plugin, data);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (tep)
626*4882a593Smuzhiyun 		dir = tep->plugins_dir;
627*4882a593Smuzhiyun 	while (dir) {
628*4882a593Smuzhiyun 		if (dir->prio == TEP_PLUGIN_LAST)
629*4882a593Smuzhiyun 			load_plugins_dir(tep, suffix, dir->path,
630*4882a593Smuzhiyun 					 load_plugin, data);
631*4882a593Smuzhiyun 		dir = dir->next;
632*4882a593Smuzhiyun 	}
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	free(path);
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun struct tep_plugin_list*
tep_load_plugins(struct tep_handle * tep)638*4882a593Smuzhiyun tep_load_plugins(struct tep_handle *tep)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun 	struct tep_plugin_list *list = NULL;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	tep_load_plugins_hook(tep, ".so", load_plugin, &list);
643*4882a593Smuzhiyun 	return list;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun /**
647*4882a593Smuzhiyun  * tep_add_plugin_path - Add a new plugin directory.
648*4882a593Smuzhiyun  * @tep: Trace event handler.
649*4882a593Smuzhiyun  * @path: Path to a directory. All plugin files in that
650*4882a593Smuzhiyun  *	  directory will be loaded.
651*4882a593Smuzhiyun  *@prio: Load priority of the plugins in that directory.
652*4882a593Smuzhiyun  *
653*4882a593Smuzhiyun  * Returns -1 in case of an error, 0 otherwise.
654*4882a593Smuzhiyun  */
tep_add_plugin_path(struct tep_handle * tep,char * path,enum tep_plugin_load_priority prio)655*4882a593Smuzhiyun int tep_add_plugin_path(struct tep_handle *tep, char *path,
656*4882a593Smuzhiyun 			enum tep_plugin_load_priority prio)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	struct tep_plugins_dir *dir;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	if (!tep || !path)
661*4882a593Smuzhiyun 		return -1;
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	dir = calloc(1, sizeof(*dir));
664*4882a593Smuzhiyun 	if (!dir)
665*4882a593Smuzhiyun 		return -1;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	dir->path = strdup(path);
668*4882a593Smuzhiyun 	if (!dir->path) {
669*4882a593Smuzhiyun 		free(dir);
670*4882a593Smuzhiyun 		return -1;
671*4882a593Smuzhiyun 	}
672*4882a593Smuzhiyun 	dir->prio = prio;
673*4882a593Smuzhiyun 	dir->next = tep->plugins_dir;
674*4882a593Smuzhiyun 	tep->plugins_dir = dir;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	return 0;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
free_tep_plugin_paths(struct tep_handle * tep)679*4882a593Smuzhiyun __hidden void free_tep_plugin_paths(struct tep_handle *tep)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun 	struct tep_plugins_dir *dir;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	if (!tep)
684*4882a593Smuzhiyun 		return;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	dir = tep->plugins_dir;
687*4882a593Smuzhiyun 	while (dir) {
688*4882a593Smuzhiyun 		tep->plugins_dir = tep->plugins_dir->next;
689*4882a593Smuzhiyun 		free(dir->path);
690*4882a593Smuzhiyun 		free(dir);
691*4882a593Smuzhiyun 		dir = tep->plugins_dir;
692*4882a593Smuzhiyun 	}
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun void
tep_unload_plugins(struct tep_plugin_list * plugin_list,struct tep_handle * tep)696*4882a593Smuzhiyun tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun 	tep_plugin_unload_func func;
699*4882a593Smuzhiyun 	struct tep_plugin_list *list;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	while (plugin_list) {
702*4882a593Smuzhiyun 		list = plugin_list;
703*4882a593Smuzhiyun 		plugin_list = list->next;
704*4882a593Smuzhiyun 		func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
705*4882a593Smuzhiyun 		if (func)
706*4882a593Smuzhiyun 			func(tep);
707*4882a593Smuzhiyun 		dlclose(list->handle);
708*4882a593Smuzhiyun 		free(list->name);
709*4882a593Smuzhiyun 		free(list);
710*4882a593Smuzhiyun 	}
711*4882a593Smuzhiyun }
712