Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/tracing/rtla/src/actions.c
26285 views
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
*/
14
void
15
actions_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
*/
31
void
32
actions_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
*/
49
static struct action *
50
actions_new(struct actions *self)
51
{
52
if (self->size >= self->len) {
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
*/
63
int
64
actions_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
*/
81
int
82
actions_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
*/
97
int
98
actions_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
*/
115
int
116
actions_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
*/
129
int
130
actions_parse(struct actions *self, const char *trigger)
131
{
132
enum action_type type = ACTION_NONE;
133
char *token;
134
char trigger_c[strlen(trigger)];
135
136
/* For ACTION_SIGNAL */
137
int signal = 0, pid = 0;
138
139
/* For ACTION_TRACE_OUTPUT */
140
char *trace_output;
141
142
strcpy(trigger_c, trigger);
143
token = strtok(trigger_c, ",");
144
145
if (strcmp(token, "trace") == 0)
146
type = ACTION_TRACE_OUTPUT;
147
else if (strcmp(token, "signal") == 0)
148
type = ACTION_SIGNAL;
149
else if (strcmp(token, "shell") == 0)
150
type = ACTION_SHELL;
151
else if (strcmp(token, "continue") == 0)
152
type = ACTION_CONTINUE;
153
else
154
/* Invalid trigger type */
155
return -1;
156
157
token = strtok(NULL, ",");
158
159
switch (type) {
160
case ACTION_TRACE_OUTPUT:
161
/* Takes no argument */
162
if (token == NULL)
163
trace_output = "timerlat_trace.txt";
164
else {
165
if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) {
166
trace_output = token + 5;
167
} else {
168
/* Invalid argument */
169
return -1;
170
}
171
172
token = strtok(NULL, ",");
173
if (token != NULL)
174
/* Only one argument allowed */
175
return -1;
176
}
177
return actions_add_trace_output(self, trace_output);
178
case ACTION_SIGNAL:
179
/* Takes two arguments, num (signal) and pid */
180
while (token != NULL) {
181
if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) {
182
signal = atoi(token + 4);
183
} else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) {
184
if (strncmp(token + 4, "parent", 7) == 0)
185
pid = -1;
186
else
187
pid = atoi(token + 4);
188
} else {
189
/* Invalid argument */
190
return -1;
191
}
192
193
token = strtok(NULL, ",");
194
}
195
196
if (!signal || !pid)
197
/* Missing argument */
198
return -1;
199
200
return actions_add_signal(self, signal, pid);
201
case ACTION_SHELL:
202
if (token == NULL)
203
return -1;
204
if (strlen(token) > 8 && strncmp(token, "command=", 8) == 0)
205
return actions_add_shell(self, token + 8);
206
return -1;
207
case ACTION_CONTINUE:
208
/* Takes no argument */
209
if (token != NULL)
210
return -1;
211
return actions_add_continue(self);
212
default:
213
return -1;
214
}
215
}
216
217
/*
218
* actions_perform - perform all actions
219
*/
220
int
221
actions_perform(struct actions *self)
222
{
223
int pid, retval;
224
const struct action *action;
225
226
for (action = self->list; action < self->list + self->len; action++) {
227
switch (action->type) {
228
case ACTION_TRACE_OUTPUT:
229
retval = save_trace_to_file(self->trace_output_inst, action->trace_output);
230
if (retval) {
231
err_msg("Error saving trace\n");
232
return retval;
233
}
234
break;
235
case ACTION_SIGNAL:
236
if (action->pid == -1)
237
pid = getppid();
238
else
239
pid = action->pid;
240
retval = kill(pid, action->signal);
241
if (retval) {
242
err_msg("Error sending signal\n");
243
return retval;
244
}
245
break;
246
case ACTION_SHELL:
247
retval = system(action->command);
248
if (retval)
249
return retval;
250
break;
251
case ACTION_CONTINUE:
252
self->continue_flag = true;
253
return 0;
254
default:
255
break;
256
}
257
}
258
259
return 0;
260
}
261
262