v0.9.6 bug fix release
[platform/upstream/corewatcher.git] / src / coredump.c
1 #define _GNU_SOURCE
2 /*
3  * Copyright 2007, Intel Corporation
4  *
5  * This file is part of corewatcher.org
6  *
7  * This program file is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program in a file named COPYING; if not, write to the
18  * Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301 USA
21  *
22  * Authors:
23  *      Arjan van de Ven <arjan@linux.intel.com>
24  *      William Douglas <william.douglas@intel.com>
25  *      Tim Pepper <timothy.c.pepper@linux.intel.com>
26  */
27
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <fcntl.h>
34 #include <asm/unistd.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <dirent.h>
39 #include <signal.h>
40 #include <glib.h>
41 #include <errno.h>
42
43 #include "corewatcher.h"
44
45 int uid = 0;
46 int sig = 0;
47
48 const char *core_folder = "/var/lib/corewatcher/";
49 const char *processed_folder = "/var/lib/corewatcher/processed/";
50
51 /* Always pick up the processing_mtx and then the
52    processing_queue_mtx, reverse for setting down */
53 /* Always pick up the gdb_mtx and then the
54    processing_queue_mtx, reverse for setting down */
55 /* Always pick up the processing_mtx and then the
56    gdb_mtx, reverse for setting down */
57 /* so order for pick up should be:
58    processing_mtx -> gdb_mtx -> processing_queue_mtx
59    and the reverse for setting down */
60 GMutex processing_queue_mtx;
61 static char *processing_queue[MAX_PROCESSING_OOPS];
62 static int pq_tail = 0;
63 static int pq_head = 0;
64 GMutex gdb_mtx;
65
66 static char *get_release(void)
67 {
68         FILE *file = NULL;
69         char *line = NULL;
70         size_t dummy = 0;
71
72         file = fopen("/etc/os-release", "r");
73         if (!file)
74                 return NULL;
75
76         while (!feof(file)) {
77                 if (getline(&line, &dummy, file) == -1)
78                         break;
79                 if (strstr(line, "VERSION_ID=")) {
80                         char *c = NULL;
81
82                         c = strchr(line, '\n');
83                         if (c) {
84                                 *c = 0;
85                                 c = strdup(&line[11]);
86                                 fclose(file);
87                                 free(line);
88                                 return c;
89                         }
90                 }
91         }
92
93         fclose(file);
94         free(line);
95
96         return NULL;
97 }
98
99 /*
100  * Strip the directories from the path
101  * given by fullname
102  */
103 char *strip_directories(char *fullpath)
104 {
105         char *dfile = NULL, *c1 = NULL, *c2 = NULL, *r = NULL;
106         char delim[] = "/";
107
108         if (!fullpath)
109                 return NULL;
110
111         dfile = strdup(fullpath);
112         if (!dfile)
113                 return NULL;
114
115         c1 = strtok(dfile, delim);
116         while(c1) {
117                 c2 = c1;
118                 c1 = strtok(NULL, delim);
119         }
120
121         if (c2)
122                 r = strdup(c2);
123         free(dfile);
124
125         return r;
126 }
127
128 /*
129  * Move corefile from core_folder to processed_folder subdir.
130  * If this type of core has recently been seen, unlink this more recent
131  * example in order to rate limit submissions of extremely crashy
132  * applications.
133  * Add extension if given and attempt to create directories if needed.
134  */
135 int move_core(char *fullpath, char *extension)
136 {
137         char *corefilename = NULL, newpath[8192], *coreprefix = NULL;
138         char *s = NULL;
139         size_t prefix_len;
140         DIR *dir = NULL;
141         struct dirent *entry = NULL;
142
143         if (!fullpath)
144                 return -1;
145
146         if (!(corefilename = strip_directories(fullpath)))
147                 return -ENOMEM;
148
149         /* if the corefile's name minus any suffixes (such as .$PID) and
150          * minus two additional characters (ie: last two digits of
151          * timestamp assuming core_%e_%t) matches another core file in the
152          * processed_folder, simply unlink it instead of processing it for
153          * submission.  TODO: consider a (configurable) time delta greater
154          * than which the cores must be separated, stat'ing the files, etc.
155          */
156         if (!(coreprefix = strdup(corefilename)))
157                 return -ENOMEM;
158         if (!(s = strstr(coreprefix, ".")))
159                 return -1;
160         *s = '\0';
161         prefix_len = strlen(coreprefix);
162         if (prefix_len > 2) {
163                 s = strndup(coreprefix, prefix_len - 2);
164                 free(coreprefix);
165                 coreprefix = s;
166         } else {
167                 goto error;
168         }
169         dir = opendir(processed_folder);
170         if (!dir)
171                 goto error;
172         while(1) {
173                 entry = readdir(dir);
174                 if (!entry || !entry->d_name)
175                         break;
176                 if (entry->d_name[0] == '.')
177                         continue;
178                 if (!strstr(entry->d_name, coreprefix))
179                         continue;
180                 fprintf(stderr, "+ ...ignoring/unlinking %s\n", fullpath);
181                 unlink(fullpath);
182                 goto error;
183         }
184
185         if (extension)
186                 snprintf(newpath, 8192, "%s%s.%s", processed_folder, corefilename, extension);
187         else
188                 snprintf(newpath, 8192, "%s%s", processed_folder, corefilename);
189
190         free(coreprefix);
191         free(corefilename);
192         rename(fullpath, newpath);
193
194         return 0;
195 error:
196         free(coreprefix);
197         free(corefilename);
198         return -1;
199 }
200
201 /*
202  * Finds the full path for the application that crashed,
203  * and moves file to processed_folder for processing
204  */
205 static char *get_appfile(char *fullpath)
206 {
207         char *appname = NULL, *appfile = NULL;
208
209         if (!fullpath)
210                 return NULL;
211
212         appname = find_coredump(fullpath);
213         if (!appname)
214                 return NULL;
215
216         /* don't try and do anything for rpm, gdb or corewatcher crashes */
217         if (!(strcmp(appname, "rpm") && strcmp(appname, "gdb") && strcmp(appname, "corewatcher")))
218                 return NULL;
219
220         appfile = find_executable(appname);
221         /* appname no longer used, so free it as it was strdup'd */
222         free(appname);
223         if (!appfile)
224                 return NULL;
225
226         move_core(fullpath, "to-process");
227
228         return appfile;
229 }
230
231 /*
232  * Use GDB to extract backtrace information from corefile
233  */
234 static struct oops *extract_core(char *fullpath, char *appfile)
235 {
236         struct oops *oops = NULL;
237         int ret = 0;
238         char *command = NULL, *h1 = NULL, *c1 = NULL, *c2 = NULL, *line = NULL;
239         char *text = NULL, *coretime = NULL;
240         char *m1 = NULL, *m2 = NULL;
241         int bt_lines = 0, maps_lines = 0;
242         FILE *file = NULL;
243         char *badchar = NULL;
244         char *release = get_release();
245         int parsing_maps = 0;
246         struct stat stat_buf;
247         size_t size = 0;
248         ssize_t bytesread = 0;
249
250         fprintf(stderr, "+ extract_core() called for %s\n", fullpath);
251
252         if (asprintf(&command, "LANG=C gdb --batch -f %s %s -x /etc/corewatcher/gdb.command 2> /dev/null", appfile, fullpath) == -1)
253                 return NULL;
254
255         file = popen(command, "r");
256         free(command);
257         if (!file)
258                 fprintf(stderr, "+ gdb failed for %s\n", fullpath);
259
260         if (stat(fullpath, &stat_buf) != -1) {
261                 coretime = malloc(26);
262                 if (coretime)
263                         ctime_r(&stat_buf.st_mtime, coretime);
264         }
265
266         ret = asprintf(&h1,
267                        "cmdline: %s\n"
268                        "release: %s\n"
269                        "time: %s",
270                        appfile,
271                        release ? release : "Unknown",
272                        coretime ? coretime : "Unknown");
273         if (release)
274                 free(release);
275         if (coretime)
276                 free(coretime);
277         if (ret == -1)
278                 return NULL;
279
280         while (file && !feof(file)) {
281                 bytesread = getline(&line, &size, file);
282                 if (!size)
283                         break;
284                 if (bytesread == -1)
285                         break;
286
287                 /* try to figure out if we're onto the maps output yet */
288                 if (strncmp(line, "From", 4) == 0) {
289                         parsing_maps = 1;
290                 }
291                 /* maps might not be present */
292                 if (strncmp(line, "No shared libraries", 19) == 0) {
293                         break;
294                 }
295
296                 if (!parsing_maps) { /* parsing backtrace */
297                         c2 = c1;
298
299                         /* gdb's backtrace lines start with a line number */
300                         if (line[0] != '#')
301                                 continue;
302
303                         /* gdb prints some initial info which may include the
304                          * "#0" line of the backtrace, then prints the
305                          * backtrace in its entirety, leading to a
306                          * duplicate "#0" in our summary if we do do: */
307                         if ((bt_lines == 1) && (strncmp(line, "#0 ", 3) == 0))
308                                 continue;
309                         bt_lines++;
310
311                         /* gdb outputs some 0x1a's which break XML */
312                         do {
313                                 badchar = memchr(line, 0x1a, bytesread);
314                                 if (badchar)
315                                         *badchar = ' ';
316                         } while (badchar);
317
318                         if (c1) {
319                                 c1 = NULL;
320                                 if (asprintf(&c1, "%s        %s", c2, line) == -1)
321                                         continue;
322                                 free(c2);
323                         } else {
324                                 /* keep going even if asprintf has errors */
325                                 ret = asprintf(&c1, "        %s", line);
326                         }
327                 } else { /* parsing maps */
328                         m2 = m1;
329                         maps_lines++;
330                         if (m1) {
331                                 m1 = NULL;
332                                 if (asprintf(&m1, "%s        %s", m2, line) == -1)
333                                         continue;
334                                 free(m2);
335                         } else {
336                                 /* keep going even if asprintf has errors */
337                                 ret = asprintf(&m1, "        %s", line);
338                         }
339                 }
340         }
341         if (line)
342                 free(line);
343         if (file)
344                 pclose(file);
345
346         ret = asprintf(&text,
347                        "%s"
348                        "backtrace: |\n"
349                        "%s"
350                        "maps: |\n"
351                        "%s",
352                        h1,
353                        c1 ? c1 : "        Unknown",
354                        m1 ? m1 : "        Unknown");
355         free(h1);
356         if (c1)
357                 free(c1);
358         if (m1)
359                 free(m1);
360
361         if (ret == -1)
362                 return NULL;
363
364         oops = malloc(sizeof(struct oops));
365         if (!oops) {
366                 free(text);
367                 return NULL;
368         }
369         memset(oops, 0, sizeof(struct oops));
370         oops->application = appfile;
371         oops->text = text;
372         oops->filename = strdup(fullpath);
373         return oops;
374 }
375
376 /*
377  * input filename has the form: core_$APP_$TIMESTAMP[.$PID]
378  * output filename has form of: $APP_$TIMESTAMP[.ext]
379  */
380 char *get_core_filename(char *filename, char *ext)
381 {
382         char *name = NULL, *dotpid = NULL, *stamp = NULL, *detail_filename = NULL;
383
384         if (!filename)
385                 return NULL;
386
387         if (!(stamp = strstr(filename, "_")))
388                 return NULL;
389
390         if (!(++stamp))
391                 return NULL;
392
393         if (!(name = strdup(stamp)))
394                 return NULL;
395
396         /* strip trailing .PID if present */
397         dotpid = strstr(name, ".");
398         if (dotpid)
399                 *dotpid = '\0';
400
401         if (ext) {
402                 if ((asprintf(&detail_filename, "%s%s.%s", processed_folder, name, ext)) == -1) {
403                         free(name);
404                         return NULL;
405                 }
406         } else {
407                 if ((asprintf(&detail_filename, "%s%s", processed_folder, name)) == -1) {
408                         free(name);
409                         return NULL;
410                 }
411         }
412         free(name);
413
414         return detail_filename;
415 }
416
417 /*
418  * Write the backtrace from the core file into a text
419  * file named as $APP_$TIMESTAMP.txt
420  */
421 static void write_core_detail_file(char *filename, char *text)
422 {
423         int fd = 0;
424         char *detail_filename = NULL;
425
426         if (!filename || !text)
427                 return;
428
429         if (!(detail_filename = get_core_filename(filename, "txt")))
430                 return;
431
432         if ((fd = open(detail_filename, O_WRONLY | O_CREAT | O_TRUNC, 0)) != -1) {
433                 if(write(fd, text, strlen(text)) >= 0) {
434                         fchmod(fd, 0644);
435                 } else {
436                         fprintf(stderr, "+ ...ignoring/unlinking %s\n", detail_filename);
437                         unlink(detail_filename);
438                 }
439                 close(fd);
440         }
441         free(detail_filename);
442 }
443
444 /*
445  * Removes corefile (core.XXXX) from the processing_queue.
446  *
447  * Expects the processing_queue_mtx to be held.
448  */
449 static void remove_from_processing_queue(void)
450 {
451         fprintf(stderr, "+ removing processing_queue head\n");
452         free(processing_queue[pq_head]);
453         processing_queue[pq_head++] = NULL;
454
455         if (pq_head == MAX_PROCESSING_OOPS) {
456                 fprintf(stderr, "+ wrapping processing_queue head to 0 (bugs here?)\n");
457                 pq_head = 0;
458         }
459 }
460
461 /*
462  * Removes file from processing_oops hash based on core name,
463  * extracting that core name from a fullpath such as
464  * "/${processed_folder}/core_$APP_$TIMESTAMP.$PID"
465  * in order to get just "$APP_$TIMESTAMP"
466  *
467  * Expects the lock on the given hash to be held.
468  */
469 void remove_name_from_hash(char *fullpath, GHashTable *ht)
470 {
471         char *name = NULL, *corename = NULL, *shortname = NULL;
472
473         if (!(name = strip_directories(fullpath)))
474                 return;
475
476         if (!(corename = get_core_filename(name, NULL))) {
477                 free(name);
478                 return;
479         }
480         free(name);
481
482         if (!(shortname = strip_directories(corename))) {
483                 free(corename);
484                 return;
485         }
486         free(corename);
487
488         if (g_hash_table_remove(ht, shortname))
489                 fprintf(stderr, "+ core %s removed from processing_oops hash table\n", shortname);
490         else
491                 fprintf(stderr, "+ core %s not in processing_oops hash table\n", shortname);
492
493         free(shortname);
494 }
495
496 /*
497  * Common function for processing core
498  * files to generate oops structures
499  */
500 static struct oops *process_common(char *fullpath)
501 {
502         struct oops *oops = NULL;
503         char *appname = NULL, *appfile = NULL;
504
505         if(!(appname = find_coredump(fullpath))) {
506                 return NULL;
507         }
508
509         if (!(appfile = find_executable(appname))) {
510                 free(appname);
511                 return NULL;
512         }
513         free(appname);
514
515         if (!(oops = extract_core(fullpath, appfile))) {
516                 free(appfile);
517                 return NULL;
518         }
519
520         return oops;
521 }
522
523
524 /*
525  * Processes .to-process core files.
526  * Also creates the $APP_$TIMESTAMP.txt file and adds
527  * the oops struct to the submit queue
528  *
529  * Picks up and sets down the gdb_mtx and
530  * picks up and sets down the processing_queue_mtx.
531  * (held at the same time in that order)
532  */
533 static void *process_new(void __unused *vp)
534 {
535         struct oops *oops = NULL;
536         char *procfn = NULL, *corefn = NULL, *fullpath = NULL;
537
538         g_mutex_lock(&core_status.processing_mtx);
539         g_mutex_lock(&gdb_mtx);
540         g_mutex_lock(&processing_queue_mtx);
541
542         fprintf(stderr, "+ Entered process_new()\n");
543
544         if (!(fullpath = processing_queue[pq_head])) {
545                 fprintf(stderr, "+ processing_queue corruption?\n");
546                 g_mutex_unlock(&processing_queue_mtx);
547                 g_mutex_unlock(&gdb_mtx);
548                 g_mutex_unlock(&core_status.processing_mtx);
549                 return NULL;
550         }
551
552         if (!(corefn = strip_directories(fullpath))) {
553                 fprintf(stderr, "+ No corefile? (%s)\n", fullpath);
554                 goto clean_process_new;
555         }
556
557         if (!(procfn = replace_name(fullpath, ".to-process", ".processed"))) {
558                 fprintf(stderr, "+ Problems with filename manipulation for %s\n", corefn);
559                 goto clean_process_new;
560         }
561
562         if (!(oops = process_common(fullpath))) {
563                 fprintf(stderr, "+ Problems processing %s\n", procfn);
564                 goto clean_process_new;
565         }
566
567         if (!(oops->detail_filename = get_core_filename(corefn, "txt"))) {
568                 fprintf(stderr, "+ Problems with filename manipulation for %s\n", procfn);
569                 goto clean_process_new;
570         }
571
572         if (rename(fullpath, procfn)) {
573                 fprintf(stderr, "+ Unable to move %s to %s\n", fullpath, procfn);
574                 goto clean_process_new;
575         }
576
577         free(oops->filename);
578         oops->filename = procfn;
579
580         remove_from_processing_queue();
581
582         g_mutex_unlock(&processing_queue_mtx);
583         g_mutex_unlock(&gdb_mtx);
584         g_mutex_unlock(&core_status.processing_mtx);
585
586         write_core_detail_file(corefn, oops->text);
587
588         queue_backtrace(oops);
589
590         fprintf(stderr, "+ Leaving process_new() with %s queued\n", oops->detail_filename);
591
592         /* mustn't free procfn because it was hung on oops->filename */
593         free(corefn);
594         return NULL;
595
596 clean_process_new:
597         remove_name_from_hash(fullpath, core_status.processing_oops);
598         remove_from_processing_queue();
599         free(procfn);
600         free(corefn);
601         FREE_OOPS(oops);
602         g_mutex_unlock(&processing_queue_mtx);
603         g_mutex_unlock(&gdb_mtx);
604         g_mutex_unlock(&core_status.processing_mtx);
605         return NULL;
606 }
607
608 /*
609  * Reprocesses .processed core files.
610  *
611  * Picks up and sets down the gdb_mtx.
612  * Picks up and sets down the processing_queue_mtx.
613  * (held at the same time in that order)
614  */
615 static void *process_old(void __unused *vp)
616 {
617         struct oops *oops = NULL;
618         char *corefn = NULL, *fullpath = NULL;
619
620         g_mutex_lock(&gdb_mtx);
621         g_mutex_lock(&processing_queue_mtx);
622
623         fprintf(stderr, "+ Entered process_old()\n");
624
625         if (!(fullpath = processing_queue[pq_head])) {
626                 fprintf(stderr, "+ processing_queue corruption?\n");
627                 g_mutex_unlock(&processing_queue_mtx);
628                 g_mutex_unlock(&gdb_mtx);
629                 return NULL;
630         }
631         fprintf(stderr, "+ Reprocessing %s\n", fullpath);
632
633         if (!(corefn = strip_directories(fullpath))) {
634                 fprintf(stderr, "+ No corefile? (%s)\n", fullpath);
635                 goto clean_process_old;
636         }
637
638         if (!(oops = process_common(fullpath))) {
639                 fprintf(stderr, "+ Problems processing %s\n", corefn);
640                 goto clean_process_old;
641         }
642
643         if (!(oops->detail_filename = get_core_filename(corefn, "txt"))) {
644                 fprintf(stderr, "+ Problems with filename manipulation for %s\n", corefn);
645                 goto clean_process_old;
646         }
647
648         remove_from_processing_queue();
649
650         g_mutex_unlock(&processing_queue_mtx);
651         g_mutex_unlock(&gdb_mtx);
652
653         queue_backtrace(oops);
654
655         fprintf(stderr, "+ Leaving process_old() with %s queued\n", oops->detail_filename);
656
657         free(corefn);
658         return NULL;
659
660 clean_process_old:
661         remove_name_from_hash(fullpath, core_status.processing_oops);
662         remove_from_processing_queue();
663         free(corefn);
664         FREE_OOPS(oops);
665         g_mutex_unlock(&processing_queue_mtx);
666         g_mutex_unlock(&gdb_mtx);
667         return NULL;
668 }
669
670 /*
671  * Adds corefile (based on name) to the processing_oops
672  * hash table if it is not already there, then
673  * tries to add to the processing_queue.
674  *
675  * Picks up and sets down the processing_mtx.
676  * Picks up and sets down the processing_queue_mtx.
677  */
678 static int add_to_processing(char *fullpath)
679 {
680         char *c1 = NULL, *c2 = NULL, *fp = NULL;
681
682         if (!fullpath)
683                 return -1;
684
685         if (!(fp = strdup(fullpath)))
686                 goto clean_add_to_processing;
687
688         if (!(c1 = get_core_filename(fp, NULL)))
689                 goto clean_add_to_processing;
690
691         if (!(c2 = strip_directories(c1)))
692                 goto clean_add_to_processing;
693
694         free(c1);
695         c1 = NULL;
696
697         g_mutex_lock(&core_status.processing_mtx);
698         if (g_hash_table_lookup(core_status.processing_oops, c2)) {
699                 g_mutex_unlock(&core_status.processing_mtx);
700                 fprintf(stderr, "+ ...name %s already in processing_oops hash table\n", c2);
701                 goto clean_add_to_processing;
702         }
703
704         g_mutex_lock(&processing_queue_mtx);
705         if (processing_queue[pq_tail]) {
706                 g_mutex_unlock(&processing_queue_mtx);
707                 g_mutex_unlock(&core_status.processing_mtx);
708                 fprintf(stderr, "+ ...processing_queue full\n");
709                 goto clean_add_to_processing;
710         }
711
712         g_hash_table_insert(core_status.processing_oops, c2, c2);
713         processing_queue[pq_tail++] = fp;
714         if (pq_tail == MAX_PROCESSING_OOPS)
715                 pq_tail = 0;
716
717         g_mutex_unlock(&processing_queue_mtx);
718         g_mutex_unlock(&core_status.processing_mtx);
719         return 0;
720 clean_add_to_processing:
721         free(fp);
722         free(c1);
723         free(c2);
724         return -1;
725 }
726
727 /*
728  * Entry for processing new core files.
729  */
730 static void process_corefile(char *fullpath)
731 {
732         GThread *thrd = NULL;
733         int r = 1;
734
735         r = add_to_processing(fullpath);
736
737         if (r)
738                 return;
739
740         thrd = g_thread_new("process_new", process_new, NULL);
741         if (thrd == NULL)
742                 fprintf(stderr, "Couldn't start thread for process_new()\n");
743 }
744
745 /*
746  * Entry for processing already seen core files.
747  */
748 static void reprocess_corefile(char *fullpath)
749 {
750         GThread *thrd = NULL;
751         int r = 0;
752
753         r = add_to_processing(fullpath);
754
755         if (r)
756                 return;
757
758         thrd = g_thread_new("process_old", process_old, NULL);
759         if (thrd == NULL)
760                 fprintf(stderr, "Couldn't start thread for process_old()\n");
761 }
762
763 static void scan_core_folder(void __unused *unused)
764 {
765         /* scan for new crash data */
766         DIR *dir = NULL;
767         struct dirent *entry = NULL;
768         char *fullpath = NULL, *appfile = NULL;
769         int r = 0;
770
771         dir = opendir(core_folder);
772         if (!dir)
773                 return;
774         fprintf(stderr, "+ Begin scanning %s...\n", core_folder);
775         while(1) {
776                 free(fullpath);
777                 fullpath = NULL;
778
779                 entry = readdir(dir);
780                 if (!entry || !entry->d_name)
781                         break;
782                 if (entry->d_name[0] == '.')
783                         continue;
784                 if (strncmp(entry->d_name, "core_", 5))
785                         continue;
786
787                 /* matched core_#### */
788                 r = asprintf(&fullpath, "%s%s", core_folder, entry->d_name);
789                 if (r == -1) {
790                         fullpath = NULL;
791                         continue;
792                 } else if (((unsigned int)r) != strlen(core_folder) + strlen(entry->d_name)) {
793                         continue;
794                 }
795
796                 /* If one were to prompt the user before submitting, that
797                  * might happen here.  */
798
799                 fprintf(stderr, "+ Looking at %s\n", fullpath);
800                 appfile = get_appfile(fullpath);
801
802                 if (!appfile) {
803                         fprintf(stderr, "+ ...ignoring/unlinking %s\n", fullpath);
804                         unlink(fullpath);
805                 } else {
806                         free(appfile);
807                         appfile = NULL;
808                 }
809         }
810         closedir(dir);
811         fprintf(stderr, "+ End scanning %s...\n", core_folder);
812 }
813
814 static void scan_processed_folder(void __unused *unused)
815 {
816         /* scan for partially processed crash data */
817         DIR *dir = NULL;
818         struct dirent *entry = NULL;
819         char *fullpath = NULL;
820         int r = 0;
821
822         dir = opendir(processed_folder);
823         if (!dir)
824                 return;
825         fprintf(stderr, "+ Begin scanning %s...\n", processed_folder);
826         while(1) {
827                 free(fullpath);
828                 fullpath = NULL;
829
830                 entry = readdir(dir);
831                 if (!entry || !entry->d_name)
832                         break;
833                 if (entry->d_name[0] == '.')
834                         continue;
835                 if (!strstr(entry->d_name, "process"))
836                         continue;
837
838                 r = asprintf(&fullpath, "%s%s", processed_folder, entry->d_name);
839                 if (r == -1) {
840                         fullpath = NULL;
841                         continue;
842                 } else if (((unsigned int)r) != strlen(processed_folder) + strlen(entry->d_name)) {
843                         continue;
844                 }
845
846                 fprintf(stderr, "+ Looking at %s\n", fullpath);
847                 if (strstr(fullpath, "to-process"))
848                         process_corefile(fullpath);
849                 else
850                         reprocess_corefile(fullpath);
851         }
852         closedir(dir);
853         fprintf(stderr, "+ End scanning %s...\n", processed_folder);
854 }
855
856 int scan_corefolders(void __unused *unused)
857 {
858         scan_core_folder(NULL);
859         scan_processed_folder(NULL);
860
861         return 1;
862 }