2 * This file is part of stability-monitor
4 * Copyright © 2019 Samsung Electronics
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #include <sys/types.h>
24 #include <glib-unix.h>
40 struct data_source *ds;
42 GVariant *actual_value;
43 GVariant *allowed_value;
48 static void action_finish(struct action_data *ad)
50 char objpath[PATH_MAX];
51 char interface[PATH_MAX];
53 GVariantBuilder *builder;
54 GVariant *signal_params = NULL;
56 if (snprintf(format, 20, "(is@%s@%s@a{sv})", g_variant_get_type_string(ad->actual_value),
57 g_variant_get_type_string(ad->allowed_value)) == -1) {
58 _E("Couldn't print dbus variant format: %m");
59 goto skip_dbus_signal;
62 if (snprintf(objpath, PATH_MAX, TSM_DBUS_PATH "/%s", ad->ds->name) == -1) {
63 _E("Couldn't print dbus object path: %m");
64 goto skip_dbus_signal;
66 if (snprintf(interface, PATH_MAX, TSM_DBUS_INTERFACE ".%s", ad->ds->param_name) == -1) {
67 _E("Couldn't print dbus interface: %m");
68 goto skip_dbus_signal;
71 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
72 g_variant_builder_add(builder, "{sv}",
74 g_variant_new_string(ad->report_path ? ad->report_path : ""));
76 g_variant_builder_add(builder, "{sv}",
78 g_variant_new_boolean(ad->ds->process->kill));
80 g_variant_builder_add(builder, "{sv}",
82 g_variant_new_string(ad->ds->process->name));
84 g_variant_builder_add(builder, "{sv}",
86 g_variant_new_string(process_is_foreground(ad->ds->process) ?
87 "foreground" : "background"));
89 signal_params = g_variant_new(format,
91 limit_type_to_string(ad->lt),
94 g_variant_builder_end(builder));
96 g_variant_builder_unref(builder);
100 /* Kill the process */
101 if (ad->ds->process->kill) {
102 _D_PROC(ad->ds->process, "Killing process");
103 if (kill(ad->ds->process->pid, SIGKILL))
104 _E("Unable to kill process %s(%d): %m",
105 ad->ds->process->name,
106 ad->ds->process->pid);
111 dbus_send_signal(objpath, interface, "AbnormalityDetected", signal_params);
113 _D_PROC(ad->ds->process, "Sent D-Bus signal (%s, %s)",
114 limit_type_to_string(ad->lt),
117 _E("Skipping D-Bus signal due to errors");
120 ad->ds->action_in_progress = 0;
122 process_unref(ad->ds->process);
123 close(ad->stdout_fd);
124 close(ad->stderr_fd);
125 free(ad->report_path);
129 static void crash_manager_exit_cb(GPid pid, gint status, gpointer user_data)
131 struct action_data *ad = user_data;
137 if (!g_spawn_check_exit_status (status, NULL)) {
138 _E("Crash-manager failed with code: %d", status);
140 stream = fdopen(ad->stderr_fd, "r");
142 _E("Unable to open stderr stream: %m");
146 while ((n = getline(&line, &len, stream)) != -1)
152 stream = fdopen(ad->stdout_fd, "r");
154 _E("Unable to open stdout stream: %m");
158 /* Get report path from stdout */
159 while ((n = getline(&line, &len, stream)) != -1) {
160 if (strncmp(line, "REPORT_PATH=", 12) == 0) {
163 ad->report_path = strndup(line + 12, n - 12);
164 if (!ad->report_path)
165 _E("Unable to allocate memory");
167 _D_PROC(ad->ds->process, "Received report: %s", ad->report_path);
173 _E("Crash-worker ended without error but didn't provide report path");
176 action_finish(ad); // NB: also closes `stream` through `ad->stdout_fd`
179 g_spawn_close_pid(pid);
182 static GPid spawn_crash_manager(struct action_data *ad)
185 GError *error = NULL;
186 char *pid_str = NULL;
187 if (asprintf(&pid_str, "%d", ad->ds->process->pid) == -1)
190 char *argv[] = {CRASH_MANAGER_BIN, "-lrp", pid_str, NULL};
192 _D_PROC(ad->ds->process, "Generating report...");
195 if (!g_spawn_async_with_pipes(NULL, argv, NULL,
196 G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL,
197 NULL, &child_pid, NULL, &ad->stdout_fd, &ad->stderr_fd, &error)) {
199 _E("Unable to spawn child process: %s", error->message);
202 _D("Spawned child process pid %d", child_pid);
209 static gboolean action_run(gpointer data)
211 struct action_data *ad = data;
214 if (ad->ds->process->report) {
215 child_pid = spawn_crash_manager(ad);
216 if (child_pid != 0) {
217 g_child_watch_add(child_pid, crash_manager_exit_cb, ad);
227 int action_run_default(struct data_source *ds, enum limit_type lt)
229 struct action_data *ad;
230 struct smpl_container *sc = process_is_foreground(ds->process) ? &ds->data_fg : &ds->data_bg;
232 if (ds->action_in_progress)
234 ds->action_in_progress = 1;
236 _D_PROC(ds->process, "Running default action");
238 ad = calloc(1, sizeof(*ad));
240 _E("Unable to allocate memory");
245 ad->report_path = NULL;
248 if (lt == LIMIT_TYPE_AVG) {
249 ad->actual_value = g_variant_new_double(sc->average);
250 ad->allowed_value = g_variant_new_double(ds->limit.avg);
252 ad->actual_value = sample_to_gvariant(list_first_entry(&sc->samples, struct sample_s, node));
253 ad->allowed_value = sample_to_gvariant(&ds->limit.peak);
256 process_ref(ds->process);
257 g_timeout_add(0, action_run, ad);