File Index
Files and directories
Sign in
FILE

actions.c

File preview with syntax highlighting.

linux-6.19.14/tools/tracing/rtla/src/actions.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#include <stdlib.h>
  3#include <string.h>
  4#include <signal.h>
  5#include <unistd.h>
  6
  7#include "actions.h"
  8#include "trace.h"
  9#include "utils.h"
 10
 11/*
 12 * actions_init - initialize struct actions
 13 */
 14void
 15actions_init(struct actions *self)
 16{
 17	self->size = action_default_size;
 18	self->list = calloc(self->size, sizeof(struct action));
 19	self->len = 0;
 20	self->continue_flag = false;
 21
 22	memset(&self->present, 0, sizeof(self->present));
 23
 24	/* This has to be set by the user */
 25	self->trace_output_inst = NULL;
 26}
 27
 28/*
 29 * actions_destroy - destroy struct actions
 30 */
 31void
 32actions_destroy(struct actions *self)
 33{
 34	/* Free any action-specific data */
 35	for (struct action *action = self->list; action < self->list + self->len; action++) {
 36		if (action->type == ACTION_SHELL)
 37			free(action->command);
 38		if (action->type == ACTION_TRACE_OUTPUT)
 39			free(action->trace_output);
 40	}
 41
 42	/* Free action list */
 43	free(self->list);
 44}
 45
 46/*
 47 * actions_new - Get pointer to new action
 48 */
 49static struct action *
 50actions_new(struct actions *self)
 51{
 52	if (self->len >= self->size) {
 53		self->size *= 2;
 54		self->list = realloc(self->list, self->size * sizeof(struct action));
 55	}
 56
 57	return &self->list[self->len++];
 58}
 59
 60/*
 61 * actions_add_trace_output - add an action to output trace
 62 */
 63int
 64actions_add_trace_output(struct actions *self, const char *trace_output)
 65{
 66	struct action *action = actions_new(self);
 67
 68	self->present[ACTION_TRACE_OUTPUT] = true;
 69	action->type = ACTION_TRACE_OUTPUT;
 70	action->trace_output = calloc(strlen(trace_output) + 1, sizeof(char));
 71	if (!action->trace_output)
 72		return -1;
 73	strcpy(action->trace_output, trace_output);
 74
 75	return 0;
 76}
 77
 78/*
 79 * actions_add_trace_output - add an action to send signal to a process
 80 */
 81int
 82actions_add_signal(struct actions *self, int signal, int pid)
 83{
 84	struct action *action = actions_new(self);
 85
 86	self->present[ACTION_SIGNAL] = true;
 87	action->type = ACTION_SIGNAL;
 88	action->signal = signal;
 89	action->pid = pid;
 90
 91	return 0;
 92}
 93
 94/*
 95 * actions_add_shell - add an action to execute a shell command
 96 */
 97int
 98actions_add_shell(struct actions *self, const char *command)
 99{
100	struct action *action = actions_new(self);
101
102	self->present[ACTION_SHELL] = true;
103	action->type = ACTION_SHELL;
104	action->command = calloc(strlen(command) + 1, sizeof(char));
105	if (!action->command)
106		return -1;
107	strcpy(action->command, command);
108
109	return 0;
110}
111
112/*
113 * actions_add_continue - add an action to resume measurement
114 */
115int
116actions_add_continue(struct actions *self)
117{
118	struct action *action = actions_new(self);
119
120	self->present[ACTION_CONTINUE] = true;
121	action->type = ACTION_CONTINUE;
122
123	return 0;
124}
125
126/*
127 * actions_parse - add an action based on text specification
128 */
129int
130actions_parse(struct actions *self, const char *trigger, const char *tracefn)
131{
132	enum action_type type = ACTION_NONE;
133	const char *token;
134	char trigger_c[strlen(trigger) + 1];
135
136	/* For ACTION_SIGNAL */
137	int signal = 0, pid = 0;
138
139	/* For ACTION_TRACE_OUTPUT */
140	const char *trace_output;
141
142	strcpy(trigger_c, trigger);
143	token = strtok(trigger_c, ",");
144	if (!token)
145		return -1;
146
147	if (strcmp(token, "trace") == 0)
148		type = ACTION_TRACE_OUTPUT;
149	else if (strcmp(token, "signal") == 0)
150		type = ACTION_SIGNAL;
151	else if (strcmp(token, "shell") == 0)
152		type = ACTION_SHELL;
153	else if (strcmp(token, "continue") == 0)
154		type = ACTION_CONTINUE;
155	else
156		/* Invalid trigger type */
157		return -1;
158
159	token = strtok(NULL, ",");
160
161	switch (type) {
162	case ACTION_TRACE_OUTPUT:
163		/* Takes no argument */
164		if (token == NULL)
165			trace_output = tracefn;
166		else {
167			if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) {
168				trace_output = token + 5;
169			} else {
170				/* Invalid argument */
171				return -1;
172			}
173
174			token = strtok(NULL, ",");
175			if (token != NULL)
176				/* Only one argument allowed */
177				return -1;
178		}
179		return actions_add_trace_output(self, trace_output);
180	case ACTION_SIGNAL:
181		/* Takes two arguments, num (signal) and pid */
182		while (token != NULL) {
183			if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) {
184				signal = atoi(token + 4);
185			} else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) {
186				if (strncmp(token + 4, "parent", 7) == 0)
187					pid = -1;
188				else
189					pid = atoi(token + 4);
190			} else {
191				/* Invalid argument */
192				return -1;
193			}
194
195			token = strtok(NULL, ",");
196		}
197
198		if (!signal || !pid)
199			/* Missing argument */
200			return -1;
201
202		return actions_add_signal(self, signal, pid);
203	case ACTION_SHELL:
204		if (token == NULL)
205			return -1;
206		if (strlen(token) > 8 && strncmp(token, "command=", 8) == 0)
207			return actions_add_shell(self, token + 8);
208		return -1;
209	case ACTION_CONTINUE:
210		/* Takes no argument */
211		if (token != NULL)
212			return -1;
213		return actions_add_continue(self);
214	default:
215		return -1;
216	}
217}
218
219/*
220 * actions_perform - perform all actions
221 */
222int
223actions_perform(struct actions *self)
224{
225	int pid, retval;
226	const struct action *action;
227
228	for (action = self->list; action < self->list + self->len; action++) {
229		switch (action->type) {
230		case ACTION_TRACE_OUTPUT:
231			retval = save_trace_to_file(self->trace_output_inst, action->trace_output);
232			if (retval) {
233				err_msg("Error saving trace\n");
234				return retval;
235			}
236			break;
237		case ACTION_SIGNAL:
238			if (action->pid == -1)
239				pid = getppid();
240			else
241				pid = action->pid;
242			retval = kill(pid, action->signal);
243			if (retval) {
244				err_msg("Error sending signal\n");
245				return retval;
246			}
247			break;
248		case ACTION_SHELL:
249			retval = system(action->command);
250			if (retval)
251				return retval;
252			break;
253		case ACTION_CONTINUE:
254			self->continue_flag = true;
255			return 0;
256		default:
257			break;
258		}
259	}
260
261	return 0;
262}
~/ Read-only file preview.