~ubuntu-core-dev/update-notifier/ubuntu

« back to all changes in this revision

Viewing changes to src/crash.c

  • Committer: Balint Reczey
  • Date: 2020-06-11 18:46:02 UTC
  • Revision ID: balint.reczey@canonical.com-20200611184602-2rv1zan3xu723x2u
Moved to git at https://git.launchpad.net/update-notifier

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#ifdef HAVE_CONFIG_H
2
 
#include "config.h"
3
 
#endif
4
 
 
5
 
#include <sys/types.h>
6
 
#include <sys/stat.h>
7
 
#include <unistd.h>
8
 
 
9
 
#include <libnotify/notify.h>
10
 
 
11
 
#include "update-notifier.h"
12
 
#include "update.h"
13
 
#include "trayappletui.h"
14
 
 
15
 
static gboolean
16
 
check_system_crashes(void)
17
 
{
18
 
   int exitcode;
19
 
 
20
 
   if(!in_admin_group())
21
 
      return FALSE;
22
 
 
23
 
   // check for system crashes
24
 
   gchar *argv[] = { CRASHREPORT_HELPER, "--system", NULL };
25
 
   if(!g_spawn_sync(NULL,
26
 
                    argv,
27
 
                    NULL,
28
 
                    G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL,
29
 
                    NULL,
30
 
                    NULL,
31
 
                    NULL,
32
 
                    NULL,
33
 
                    &exitcode,
34
 
                    NULL)) {
35
 
      g_warning("Can not run %s", CRASHREPORT_HELPER);
36
 
      return FALSE;
37
 
   }
38
 
 
39
 
   return exitcode == 0;
40
 
}
41
 
 
42
 
static gboolean
43
 
ask_invoke_apport_with_pkexec(void)
44
 
{
45
 
   GtkDialog *dialog;
46
 
   gchar *msg = _("System program problem detected");
47
 
   gchar *descr = _("Do you want to report the problem "
48
 
                    "now?");
49
 
   dialog = (GtkDialog*)gtk_message_dialog_new (NULL,
50
 
                                    GTK_DIALOG_DESTROY_WITH_PARENT,
51
 
                                    GTK_MESSAGE_QUESTION,
52
 
                                    GTK_BUTTONS_NONE,
53
 
                                    "%s", msg);
54
 
   gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
55
 
                                            "%s", descr);
56
 
   gtk_dialog_add_button(dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
57
 
   gtk_dialog_add_button(dialog, _("Report problem…"), GTK_RESPONSE_ACCEPT);
58
 
   int res = gtk_dialog_run(dialog);
59
 
   gtk_widget_destroy(GTK_WIDGET(dialog));
60
 
   if (res == GTK_RESPONSE_ACCEPT)
61
 
      return TRUE;
62
 
   return FALSE;
63
 
}
64
 
 
65
 
static gboolean
66
 
run_apport(TrayApplet *ta)
67
 
{
68
 
   g_debug("fire up the crashreport tool");
69
 
   // be nice and always ask first before firing up pkexec
70
 
   if (check_system_crashes()) {
71
 
      // workaround, wayland doesn't allow pkexec use
72
 
      if (g_strcmp0 (g_getenv ("XDG_SESSION_TYPE"), "wayland") == 0)
73
 
         g_debug ("no pkexec for system reports under wayland");
74
 
      else if (ask_invoke_apport_with_pkexec())
75
 
         invoke_with_pkexec(CRASHREPORT_REPORT_APP);
76
 
   } else {
77
 
      return g_spawn_command_line_async(CRASHREPORT_REPORT_APP, NULL);
78
 
   }
79
 
   return TRUE;
80
 
}
81
 
 
82
 
static gboolean
83
 
show_notification (TrayApplet *ta)
84
 
{
85
 
   NotifyNotification *n;
86
 
 
87
 
   // check if the update-icon is still visible (in the delay time a
88
 
   // update may already have been performed)
89
 
   if(!tray_applet_ui_get_visible(ta))
90
 
      return FALSE;
91
 
 
92
 
   n = tray_applet_ui_get_data (ta, "notification");
93
 
   if (n)
94
 
      g_object_unref (n);
95
 
   tray_applet_ui_set_data (ta, "notification", NULL);
96
 
 
97
 
   // now show a notification handle
98
 
   n = notify_notification_new(
99
 
                                     _("Crash report detected"),
100
 
                                     _("An application has crashed on your "
101
 
                                       "system (now or in the past). "
102
 
                                       "Click on the notification icon to "
103
 
                                       "display details. "
104
 
                                       ),
105
 
                                     GTK_STOCK_DIALOG_INFO);
106
 
   notify_notification_set_timeout (n, 60000);
107
 
   notify_notification_show (n, NULL);
108
 
   tray_applet_ui_set_data (ta, "notification", n);
109
 
 
110
 
   return FALSE;
111
 
}
112
 
 
113
 
static void
114
 
hide_crash_applet(TrayApplet *ta)
115
 
{
116
 
   NotifyNotification *n;
117
 
 
118
 
   /* Hide any notification popup */
119
 
   n = tray_applet_ui_get_data (ta, "notification");
120
 
   if (n) {
121
 
      notify_notification_close (n, NULL);
122
 
      g_object_unref (n);
123
 
   }
124
 
   tray_applet_ui_destroy (ta);
125
 
}
126
 
 
127
 
static gboolean
128
 
button_release_cb (GtkWidget *widget,
129
 
                   TrayApplet *ta)
130
 
{
131
 
   run_apport(ta);
132
 
   hide_crash_applet(ta);
133
 
   return TRUE;
134
 
}
135
 
 
136
 
gboolean
137
 
crashreport_check (TrayApplet *ta)
138
 
{
139
 
   int crashreports_found = 0;
140
 
   gboolean system_crashes;
141
 
   g_debug("crashreport_check");
142
 
 
143
 
   // don't do anything if no apport-gtk is installed
144
 
   if(!g_file_test(CRASHREPORT_REPORT_APP, G_FILE_TEST_IS_EXECUTABLE))
145
 
      return FALSE;
146
 
 
147
 
   // don't do anything if autoreport is enabled
148
 
   if (g_file_test(CRASHREPORT_AUTOREPORT, G_FILE_TEST_EXISTS))
149
 
      return FALSE;
150
 
   
151
 
   // if whoopsie is installed, but disabled, don't do anything
152
 
   if (g_file_test(CRASHREPORT_WHOOPSIE_EXEC, G_FILE_TEST_IS_EXECUTABLE)) {
153
 
      int exitcode;
154
 
      gchar *argv[] = { "/bin/systemctl", "is-enabled", "-q", CRASHREPORT_WHOOPSIE_SERVICE, NULL };
155
 
      if (g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL,
156
 
                      NULL, NULL, NULL, NULL, &exitcode, NULL)) {
157
 
         if (exitcode != 0) {
158
 
            g_debug("whoopsie disabled, not displaying crashes");
159
 
            return FALSE;
160
 
         }
161
 
      }
162
 
   }
163
 
 
164
 
   // Check whether the user doesn't want notifications
165
 
   if (!g_settings_get_boolean (ta->un->settings,
166
 
                                SETTINGS_KEY_APPORT_NOTIFICATIONS)) {
167
 
      g_debug("apport notifications disabled, not displaying crashes");
168
 
      return FALSE;
169
 
   }
170
 
 
171
 
   // check for (new) reports by calling CRASHREPORT_HELPER
172
 
   // and checking the return code
173
 
   int exitcode;
174
 
   gchar *argv[] = { CRASHREPORT_HELPER, NULL };
175
 
   if(!g_spawn_sync(NULL,
176
 
                    argv,
177
 
                    NULL,
178
 
                    G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL,
179
 
                    NULL,
180
 
                    NULL,
181
 
                    NULL,
182
 
                    NULL,
183
 
                    &exitcode,
184
 
                    NULL)) {
185
 
      g_warning("Can not run %s", CRASHREPORT_HELPER);
186
 
      return FALSE;
187
 
   }
188
 
   // exitcode == 0: reports found, else no reports
189
 
   system_crashes = check_system_crashes();
190
 
   crashreports_found = !exitcode || system_crashes;
191
 
 
192
 
   if (crashreports_found > 0) {
193
 
      g_debug("crashreport found running apport now");
194
 
      crashreports_found=0;
195
 
      run_apport(ta);
196
 
      return TRUE;
197
 
   } else
198
 
      return FALSE;
199
 
 
200
 
   // non-autolaunch will always use the notification area
201
 
   gboolean visible = tray_applet_ui_get_visible(ta);
202
 
 
203
 
   // crashreport found
204
 
   if(crashreports_found > 0 && !visible) {
205
 
      tray_applet_ui_ensure(ta);
206
 
      tray_applet_ui_set_single_action(ta, _("Crash report detected"),
207
 
                                       G_CALLBACK(button_release_cb), ta);
208
 
      tray_applet_ui_set_visible(ta, TRUE);
209
 
      /* Show the notification, after a delay so it doesn't look ugly
210
 
       * if we've just logged in */
211
 
      g_timeout_add_seconds(5, (GSourceFunc)(show_notification), ta);
212
 
   }
213
 
 
214
 
   // no crashreports, but visible
215
 
   if((crashreports_found == 0) && visible) {
216
 
      hide_crash_applet(ta);
217
 
   }
218
 
 
219
 
   return TRUE;
220
 
}
221
 
 
222
 
static gboolean
223
 
crashreport_check_initially(TrayApplet *ta)
224
 
{
225
 
   crashreport_check(ta);
226
 
   // stop timeout handler
227
 
   return FALSE;
228
 
}
229
 
 
230
 
void
231
 
crashreport_tray_icon_init (TrayApplet *ta)
232
 
{
233
 
        /* Check for crashes for the first time */
234
 
        g_timeout_add_seconds(1, (GSourceFunc)crashreport_check_initially, ta);
235
 
}