Change Moblin to MeeGo throughout the code
[external/corewatcher.git] / submit.c
1 /*
2  * Copyright 2007, Intel Corporation
3  *
4  * This file is part of corewatcher.org
5  *
6  * This program file is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program in a file named COPYING; if not, write to the
17  * Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301 USA
20  *
21  * Authors:
22  *      Arjan van de Ven <arjan@linux.intel.com>
23  */
24
25 #define _BSD_SOURCE
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <syslog.h>
31 #include <sys/stat.h>
32
33 #include <asm/unistd.h>
34
35 #include <curl/curl.h>
36
37 #include "corewatcher.h"
38
39
40 /*
41  * we keep track of 16 checksums of the last submitted oopses; this allows us to
42  * make sure we don't submit the same oops twice (this allows us to not have to do
43  * really expensive things during non-destructive dmesg-scanning)
44  *
45  * This also limits the number of oopses we'll submit per session;
46  * it's important that this is bounded to avoid feedback loops
47  * for the scenario where submitting an oopses causes a warning/oops
48  */
49 #define MAX_CHECKSUMS 16
50 static unsigned int checksums[MAX_CHECKSUMS];
51 static int submitted;
52
53 struct oops;
54
55 struct oops {
56         struct oops *next;
57         char *text;
58         unsigned int checksum;
59 };
60
61 /* we queue up oopses, and then submit in a batch.
62  * This is useful to be able to cancel all submissions, in case
63  * we later find our marker indicating we submitted everything so far already
64  * previously.
65  */
66 static struct oops *queued_backtraces;
67 static int newoops;
68
69 /* For communicating details to the applet, we write the
70  * details in a file, and provide the filename to the applet
71  */
72 static char *detail_filename;
73
74
75 static unsigned int checksum(char *ptr)
76 {
77         unsigned int temp = 0;
78         unsigned char *c;
79         c = (unsigned char *) ptr;
80         while (c && *c) {
81                 temp = (temp) + *c;
82                 c++;
83         }
84         return temp;
85 }
86
87 void queue_backtrace(char *oops)
88 {
89         int i;
90         unsigned int sum;
91         struct oops *new;
92
93         if (submitted >= MAX_CHECKSUMS-1)
94                 return;
95         /* first, check if we haven't already submitted the oops */
96         sum = checksum(oops);
97         for (i = 0; i < submitted; i++) {
98                 if (checksums[i] == sum) {
99                         printf("Match with oops %i (%x)\n", i, sum);
100                         return;
101                 }
102         }
103         checksums[submitted++] = sum;
104
105         new = malloc(sizeof(struct oops));
106         memset(new, 0, sizeof(struct oops));
107         new->next = queued_backtraces;
108         new->checksum = sum;
109         new->text = strdup(oops);
110         queued_backtraces = new;
111         newoops = 1;
112 }
113
114
115 void write_detail_file(void)
116 {
117         int temp_fileno;
118         FILE *tmpf;
119         struct oops *oops;
120         int count = 0;
121
122         detail_filename = strdup("/tmp/corewatcher.XXXXXX");
123         temp_fileno = mkstemp(detail_filename);
124         if (temp_fileno < 0) {
125                 free(detail_filename);
126                 detail_filename = NULL;
127                 return;
128         }
129         /* regular user must be able to read this detail file to be
130          * useful; there is nothing worth doing if fchmod fails.
131          */
132         fchmod(temp_fileno, 0644);
133         tmpf = fdopen(temp_fileno, "w");
134         oops = queued_backtraces;
135         while (oops) {
136                 count++; /* Users are not programmers, start at 1 */
137                 fprintf(tmpf, "Application failure message %d:\n", count);
138                 fprintf(tmpf, "%s", oops->text);
139                 fprintf(tmpf, "\n\n");
140                 oops = oops->next;
141         }
142         fclose(tmpf);
143         close(temp_fileno);
144 }
145
146 void unlink_detail_file(void)
147 {
148         if (detail_filename) {
149                 unlink(detail_filename);
150                 free(detail_filename);
151         }
152 }
153
154
155 static void print_queue(void)
156 {
157         struct oops *oops;
158         struct oops *queue;
159         int count = 0;
160
161         queue = queued_backtraces;
162         queued_backtraces = NULL;
163         barrier();
164         oops = queue;
165         while (oops) {
166                 struct oops *next;
167
168                 printf("Submit text is:\n---[start of oops]---\n%s\n---[end of oops]---\n", oops->text);
169                 next = oops->next;
170                 free(oops->text);
171                 free(oops);
172                 oops = next;
173                 count++;
174         }
175
176 }
177
178 static void write_logfile(int count)
179 {
180         openlog("corewatcher", 0, LOG_KERN);
181         syslog(LOG_WARNING, "Submitted %i coredump signatures to %s", count, submit_url);
182         closelog();
183 }
184
185 char result_url[4096];
186
187 size_t writefunction( void *ptr, size_t size, size_t nmemb, void __attribute((unused)) *stream)
188 {
189         char *c, *c1, *c2;
190         c = malloc(size*nmemb + 1);
191         memset(c, 0, size*nmemb + 1);
192         memcpy(c, ptr, size*nmemb);
193         printf("received %s \n", c);
194         c1 = strstr(c, "201 ");
195         if (c1) {
196                 c1+=4;
197                 c2 = strchr(c1, '\n');
198                 if (c2) *c2 = 0;
199                 strncpy(result_url, c1, 4095);
200         }
201         return size * nmemb;
202 }
203
204 void submit_queue(void)
205 {
206         int result;
207         struct oops *oops;
208         struct oops *queue;
209         int count = 0;
210
211         memset(result_url, 0, 4096);
212
213         if (testmode) {
214                 print_queue();
215                 return;
216         }
217
218         queue = queued_backtraces;
219         queued_backtraces = NULL;
220         barrier();
221         oops = queue;
222         while (oops) {
223                 CURL *handle;
224                 struct curl_httppost *post = NULL;
225                 struct curl_httppost *last = NULL;
226                 struct oops *next;
227
228                 handle = curl_easy_init();
229
230                 printf("DEBUG SUBMIT URL is %s \n", submit_url);
231                 curl_easy_setopt(handle, CURLOPT_URL, submit_url);
232
233                 /* set up the POST data */
234                 curl_formadd(&post, &last,
235                         CURLFORM_COPYNAME, "backtracedata",
236                         CURLFORM_COPYCONTENTS, oops->text, CURLFORM_END);
237
238                 if (allow_distro_to_pass_on) {
239                         curl_formadd(&post, &last,
240                                 CURLFORM_COPYNAME, "pass_on_allowed",
241                                 CURLFORM_COPYCONTENTS, "yes", CURLFORM_END);
242                 }
243
244                 curl_easy_setopt(handle, CURLOPT_HTTPPOST, post);
245                 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writefunction);
246                 result = curl_easy_perform(handle);
247
248                 curl_formfree(post);
249                 curl_easy_cleanup(handle);
250                 next = oops->next;
251                 free(oops->text);
252                 free(oops);
253                 oops = next;
254                 count++;
255         }
256
257         if (count && !testmode)
258                 write_logfile(count);
259
260         if (count)
261                 dbus_say_thanks(result_url);
262         /*
263          * If we've reached the maximum count, we'll exit the program,
264          * the program won't do any useful work anymore going forward.
265          */
266         if (submitted >= MAX_CHECKSUMS-1) {
267                 unlink_detail_file();
268                 exit(EXIT_SUCCESS);
269         }
270 }
271
272 void clear_queue(void)
273 {
274         struct oops *oops, *next;
275         struct oops *queue;
276
277         queue = queued_backtraces;
278         queued_backtraces = NULL;
279         barrier();
280         oops = queue;
281         while (oops) {
282                 next = oops->next;
283                 free(oops->text);
284                 free(oops);
285                 oops = next;
286         }
287         write_logfile(0);
288 }
289
290 void ask_permission(void)
291 {
292         if (!newoops && !pinged)
293                 return;
294         pinged = 0;
295         newoops = 0;
296         if (queued_backtraces) {
297                 write_detail_file();
298                 dbus_ask_permission(detail_filename);
299         }
300 }