~indicator-applet-developers/ubuntu-app-launch/trunk.17.04

« back to all changes in this revision

Viewing changes to libubuntu-app-launch/recoverable-problem.c

  • Committer: Ted Gould
  • Date: 2016-04-06 16:19:02 UTC
  • mto: This revision was merged to the branch mainline in revision 268.
  • Revision ID: ted@gould.cx-20160406161902-nti4ocrveugnhvyd
Switching to libwhoopsie for recoverable problem support

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2013 Canonical Ltd.
3
 
 *
4
 
 * This program is free software: you can redistribute it and/or modify it
5
 
 * under the terms of the GNU General Public License version 3, as published
6
 
 * by the Free Software Foundation.
7
 
 *
8
 
 * This program is distributed in the hope that it will be useful, but
9
 
 * WITHOUT ANY WARRANTY; without even the implied warranties of
10
 
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
 
 * PURPOSE.  See the GNU General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU General Public License along
14
 
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 
 *
16
 
 * Authors:
17
 
 *     Ted Gould <ted.gould@canonical.com>
18
 
 */
19
 
 
20
 
#include "recoverable-problem.h"
21
 
#include <glib/gstdio.h>
22
 
#include <string.h>
23
 
#include <errno.h>
24
 
 
25
 
/* Helpers to ensure we write nicely */
26
 
static void 
27
 
write_string (int          fd,
28
 
              const gchar *string)
29
 
{
30
 
        int res; 
31
 
        do
32
 
                res = write (fd, string, strlen (string));
33
 
        while (G_UNLIKELY (res == -1 && errno == EINTR));
34
 
}
35
 
 
36
 
/* Make NULLs fast and fun! */
37
 
static void 
38
 
write_null (int fd)
39
 
{
40
 
        int res; 
41
 
        do
42
 
                res = write (fd, "", 1);
43
 
        while (G_UNLIKELY (res == -1 && errno == EINTR));
44
 
}
45
 
 
46
 
/* Child watcher */
47
 
static gboolean
48
 
apport_child_watch (GPid pid, gint status, gpointer user_data)
49
 
{
50
 
        g_main_loop_quit((GMainLoop *)user_data);
51
 
        return FALSE;
52
 
}
53
 
 
54
 
static gboolean
55
 
apport_child_timeout (gpointer user_data)
56
 
{
57
 
        g_warning("Recoverable Error Reporter Timeout");
58
 
        g_main_loop_quit((GMainLoop *)user_data);
59
 
        return FALSE;
60
 
}
61
 
 
62
 
/* Code to report an error */
63
 
void
64
 
report_recoverable_problem (const gchar * signature, GPid report_pid, gboolean wait, const gchar * additional_properties[])
65
 
{
66
 
        GError * error = NULL;
67
 
        gint error_stdin = 0;
68
 
        GPid pid = 0;
69
 
        gchar * pid_str = NULL;
70
 
        gchar ** argv = NULL;
71
 
        gchar * argv_nopid[2] = {
72
 
                "/usr/share/apport/recoverable_problem",
73
 
                NULL
74
 
        };
75
 
        gchar * argv_pid[4] = {
76
 
                "/usr/share/apport/recoverable_problem",
77
 
                "-p",
78
 
                NULL, /* put pid_str when allocated here */
79
 
                NULL
80
 
        };
81
 
 
82
 
 
83
 
        argv = (gchar **)argv_nopid;
84
 
 
85
 
        if (report_pid != 0) {
86
 
                pid_str = g_strdup_printf("%d", report_pid);
87
 
                argv_pid[2] = pid_str;
88
 
                argv = (gchar**)argv_pid;
89
 
        }
90
 
 
91
 
        GSpawnFlags flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL;
92
 
        if (wait) {
93
 
                flags |= G_SPAWN_DO_NOT_REAP_CHILD;
94
 
        }
95
 
 
96
 
        g_spawn_async_with_pipes(NULL, /* cwd */
97
 
                argv,
98
 
                NULL, /* envp */
99
 
                flags,
100
 
                NULL, NULL, /* child setup func */
101
 
                &pid,
102
 
                &error_stdin,
103
 
                NULL, /* stdout */
104
 
                NULL, /* stderr */
105
 
                &error);
106
 
 
107
 
        if (error != NULL) {
108
 
                g_warning("Unable to report a recoverable error: %s", error->message);
109
 
                g_error_free(error);
110
 
        }
111
 
 
112
 
        gboolean first = TRUE;
113
 
 
114
 
        if (error_stdin != 0 && signature != NULL) {
115
 
                write_string(error_stdin, "DuplicateSignature");
116
 
                write_null(error_stdin);
117
 
                write_string(error_stdin, signature);
118
 
 
119
 
                first = FALSE;
120
 
        }
121
 
 
122
 
        if (error_stdin != 0 && additional_properties != NULL) {
123
 
                gint i;
124
 
                for (i = 0; additional_properties[i] != NULL; i++) {
125
 
                        if (!first) {
126
 
                                write_null(error_stdin);
127
 
                        } else {
128
 
                                first = FALSE;
129
 
                        }
130
 
 
131
 
                        write_string(error_stdin, additional_properties[i]);
132
 
                }
133
 
        }
134
 
 
135
 
        if (error_stdin != 0) {
136
 
                close(error_stdin);
137
 
        }
138
 
 
139
 
        if (wait && pid != 0) {
140
 
                GSource * child_source, * timeout_source;
141
 
                GMainContext * context = g_main_context_new();
142
 
                GMainLoop * loop = g_main_loop_new(context, FALSE);
143
 
 
144
 
                child_source = g_child_watch_source_new(pid);
145
 
                g_source_attach(child_source, context);
146
 
                g_source_set_callback(child_source, (GSourceFunc)apport_child_watch, loop, NULL);
147
 
 
148
 
                timeout_source = g_timeout_source_new_seconds(5);
149
 
                g_source_attach(timeout_source, context);
150
 
                g_source_set_callback(timeout_source, apport_child_timeout, loop, NULL);
151
 
 
152
 
                g_main_loop_run(loop);
153
 
 
154
 
                g_source_destroy(timeout_source);
155
 
                g_source_destroy(child_source);
156
 
                g_main_loop_unref(loop);
157
 
                g_main_context_unref(context);
158
 
 
159
 
                g_spawn_close_pid(pid);
160
 
        }
161
 
 
162
 
        g_free(pid_str);
163
 
 
164
 
        return;
165
 
}