Open /var/lib/corewatcher correctly after creation
[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  */
26
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <fcntl.h>
33 #include <pthread.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 /* Always pick up the processing_mtx and then the
49    processing_queue_mtx, reverse for setting down */
50 /* Always pick up the gdb_mtx and then the
51    processing_queue_mtx, reverse for setting down */
52 /* Always pick up the processing_mtx and then the
53    gdb_mtx, reverse for setting down */
54 /* so order for pick up should be:
55    processing_mtx -> gdb_mtx -> processing_queue_mtx
56    and the reverse for setting down */
57 static pthread_mutex_t processing_queue_mtx = PTHREAD_MUTEX_INITIALIZER;
58 static char *processing_queue[MAX_PROCESSING_OOPS];
59 static pthread_mutex_t gdb_mtx = PTHREAD_MUTEX_INITIALIZER;
60 static int tail = 0;
61 static int head = 0;
62
63 static char *get_release(void)
64 {
65         FILE *file = NULL;
66         char *line = NULL;
67         size_t dummy = 0;
68
69         file = fopen("/etc/os-release", "r");
70         if (!file) {
71                 line = strdup("Unknown");
72                 return line;
73         }
74
75         while (!feof(file)) {
76                 if (getline(&line, &dummy, file) == -1)
77                         break;
78                 if (strstr(line, "VERSION_ID=")) {
79                         char *c = NULL;
80
81                         c = strchr(line, '\n');
82                         if (c) {
83                                 *c = 0;
84                                 c = strdup(&line[11]);
85                                 fclose(file);
86                                 free(line);
87                                 return c;
88                         }
89                 }
90         }
91
92         fclose(file);
93         free(line);
94
95         line = strdup("Unknown");
96
97         return line;
98 }
99
100 static char *set_wrapped_app(char *line)
101 {
102         char *dline = NULL, *app = NULL, *appfile = NULL, *abs_path = NULL;
103         char delim[] = " '";
104         char app_folder[] = "/usr/share/";
105         int r = 0;
106
107         if (!line)
108                 return NULL;
109
110         dline = strdup(line);
111
112         app = strtok(dline, delim);
113         while(app) {
114                 if (strcmp(app, "--app") == 0) {
115                         app = strtok(NULL, delim);
116                         break;
117                 }
118                 app = strtok(NULL, delim);
119         }
120         if (!app)
121                 goto cleanup_set_wrapped_app;
122         r = asprintf(&abs_path, "%s%s", app_folder, app);
123         if (r == -1) {
124                 abs_path = NULL;
125                 goto cleanup_set_wrapped_app;
126         } else if (((unsigned int)r) != strlen(app_folder) + strlen(app)) {
127                 goto cleanup_set_wrapped_app;
128         }
129
130         appfile = find_executable(abs_path);
131
132 cleanup_set_wrapped_app:
133         free(abs_path);
134         free(dline);
135         return appfile;
136 }
137
138 /*
139  * Scan core dump in case a wrapper was used
140  * to run the process and get the actual binary name
141  */
142 static char *wrapper_scan(char *command)
143 {
144         char *line = NULL, *appfile = NULL;
145         FILE *file = NULL;
146
147         file = popen(command, "r");
148         if (!file)
149                 return NULL;
150
151         while (!feof(file)) {
152                 size_t size = 0;
153                 int ret = 0;
154                 free(line);
155                 ret = getline(&line, &size, file);
156                 if (!size)
157                         break;
158                 if (ret < 0)
159                         break;
160
161                 if (strstr(line, "Core was generated by") &&
162                     strstr(line, "--app")) {
163                         /* attempt to update appfile */
164                         appfile = set_wrapped_app(line);
165                         break;
166                 }
167         }
168         if (line)
169                 free(line);
170         pclose(file);
171
172         return appfile;
173 }
174
175 /*
176  * Strip the directories from the path
177  * given by fullname
178  */
179 char *strip_directories(char *fullpath)
180 {
181         char *dfile = NULL, *c1 = NULL, *c2 = NULL, *r = NULL;
182         char delim[] = "/";
183
184         if (!fullpath)
185                 return NULL;
186
187         dfile = strdup(fullpath);
188         if (!dfile)
189                 return NULL;
190
191         c1 = strtok(dfile, delim);
192         while(c1) {
193                 c2 = c1;
194                 c1 = strtok(NULL, delim);
195         }
196
197         if (c2)
198                 r = strdup(c2);
199         free(dfile);
200
201         return r;
202 }
203
204 /*
205  * Move corefile from /tmp to core_folder.
206  * Add extension if given and attempt to create core_folder.
207  */
208 int move_core(char *fullpath, char *extension)
209 {
210         char *corefn = NULL, newpath[8192];
211
212         if (!core_folder || !fullpath)
213                 return -1;
214
215         if (!(corefn = strip_directories(fullpath))) {
216                 unlink(fullpath);
217                 return -ENOMEM;
218         }
219
220         if (!mkdir(core_folder, S_IRWXU | S_IRWXG | S_IRWXO)
221             && errno != EEXIST) {
222                 free(corefn);
223                 return -errno;
224         }
225
226         if (extension)
227                 snprintf(newpath, 8192, "%s%s.%s", core_folder, corefn, extension);
228         else
229                 snprintf(newpath, 8192, "%s%s", core_folder, corefn);
230
231         free(corefn);
232         rename(fullpath, newpath);
233
234         return 0;
235 }
236
237 /*
238  * Finds the full path for the application that crashed,
239  * and depending on what opted_in was configured as will:
240  * opted_in 2 (always submit) -> move file to core_folder
241  * to be processed further
242  * opted_in 1 (ask user) -> ask user if we should submit
243  * the crash and add to asked_oops hash so we don't get
244  * called again for this corefile
245  * opted_in 0 (don't submit) -> do nothing
246  *
247  * Picks up and sets down the asked_mtx.
248  */
249 static char *get_appfile(char *fullpath)
250 {
251         char *appname = NULL, *appfile = NULL;
252
253         if (!fullpath)
254                 return NULL;
255
256         appname = find_coredump(fullpath);
257         if (!appname)
258                 return NULL;
259
260         /* don't try and do anything for rpm, gdb or corewatcher crashes */
261         if (!(strcmp(appname, "rpm") && strcmp(appname, "gdb") && strcmp(appname, "corewatcher")))
262                 return NULL;
263
264         appfile = find_executable(appname);
265         /* appname no longer used, so free it as it was strdup'd */
266         free(appname);
267         if (!appfile)
268                 return NULL;
269
270         move_core(fullpath, "to-process");
271
272         return appfile;
273 }
274
275 /*
276  * Use GDB to extract backtrace information from corefile
277  */
278 static struct oops *extract_core(char *fullpath, char *appfile)
279 {
280         struct oops *oops = NULL;
281         int ret = 0;
282         char *command = NULL, *h1 = NULL, *c1 = NULL, *c2 = NULL, *line = NULL, *text = NULL, *at = NULL;
283         char *m1 = NULL, *m2 = NULL;
284         FILE *file = NULL;
285         char *badchar = NULL;
286         char *release = get_release();
287         int parsing_maps = 0;
288
289         if (asprintf(&command, "LANG=C gdb --batch -f %s %s -x /etc/corewatcher/gdb.command 2> /dev/null", appfile, fullpath) == -1)
290                 return NULL;
291
292         if ((at = wrapper_scan(command))) {
293                 free(appfile);
294                 appfile = at;
295         }
296
297         ret = asprintf(&h1,
298                        "cmdline: %s\n"
299                        "release: %s\n",
300                        appfile,
301                        release);
302         free(release);
303         if (ret == -1)
304                 h1 = strdup("Unknown");
305
306         file = popen(command, "r");
307
308         while (file && !feof(file)) {
309                 size_t size = 0;
310
311                 free(line);
312                 line = NULL;
313                 ret = getline(&line, &size, file);
314                 if (!size)
315                         break;
316                 if (ret == -1)
317                         break;
318
319                 if (strncmp(line, "From", 4) == 0) {
320                         parsing_maps = 1;
321                         /*continue;*/
322                 }
323
324                 if (!parsing_maps) { /* parsing backtrace */
325                         c2 = c1;
326                         if (line[0] != '#')
327                                 continue;
328 fixup:                  /* gdb outputs some 0x1a's which break XML */
329                         badchar = memchr(line, 0x1a, size);
330                         if (badchar) {
331                                 *badchar = ' ';
332                                 goto fixup;
333                         }
334
335                         if (c1) {
336                                 c1 = NULL;
337                                 if (asprintf(&c1, "%s        %s", c2, line) == -1)
338                                         continue;
339                                 free(c2);
340                         } else {
341                                 /* keep going even if asprintf has errors */
342                                 ret = asprintf(&c1, "        %s", line);
343                         }
344                 } else { /* parsing maps */
345                         m2 = m1;
346                         if (m1) {
347                                 m1 = NULL;
348                                 if (asprintf(&m1, "%s        %s", m2, line) == -1)
349                                         continue;
350                                 free(m2);
351                         } else {
352                                 /* keep going even if asprintf has errors */
353                                 ret = asprintf(&m1, "        %s", line);
354                         }
355                 }
356         }
357         if (line)
358                 free(line);
359         if (file)
360                 pclose(file);
361         free(command);
362
363         ret = asprintf(&text,
364                        "%s"
365                        "backtrace: |\n"
366                        "%s"
367                        "maps: |\n"
368                        "%s",
369                        h1, c1, m1);
370         if (ret == -1)
371                 text = NULL;
372
373         free(h1);
374         free(c1);
375
376         oops = malloc(sizeof(struct oops));
377         if (!oops) {
378                 free(text);
379                 return NULL;
380         }
381         memset(oops, 0, sizeof(struct oops));
382         oops->application = strdup(appfile);
383         oops->text = text;
384         oops->filename = strdup(fullpath);
385         return oops;
386 }
387
388 /*
389  * filename is of the form core_XXXX[.blah]
390  * we need to get the pid out as we want
391  * output of the form XXXX[.ext]
392  */
393 char *get_core_filename(char *filename, char *ext)
394 {
395         char *pid = NULL, *c = NULL, *s = NULL, *detail_filename = NULL;
396
397         if (!filename)
398                 return NULL;
399
400         if (!(s = strstr(filename, "_")))
401                 return NULL;
402
403         if (!(++s))
404                 return NULL;
405         /* causes valgrind whining because we copy from middle of a string */
406         if (!(pid = strdup(s)))
407                 return NULL;
408
409         c = strstr(pid, ".");
410
411         if (c)
412                 *c = '\0';
413
414         if (ext) {
415                 /* causes valgrind whining because we copy from middle of a string */
416                 if ((asprintf(&detail_filename, "%s%s.%s", core_folder, pid, ext)) == -1) {
417                         free(pid);
418                         return NULL;
419                 }
420         } else {
421                 /* causes valgrind whining because we copy from middle of a string */
422                 if ((asprintf(&detail_filename, "%s%s", core_folder, pid)) == -1) {
423                         free(pid);
424                         return NULL;
425                 }
426         }
427
428         free(pid);
429         return detail_filename;
430 }
431
432 /*
433  * Write the backtrace from the core file into a text
434  * file named after the pid
435  */
436 static void write_core_detail_file(char *filename, char *text)
437 {
438         int fd = 0;
439         char *detail_filename = NULL;
440
441         if (!filename || !text)
442                 return;
443
444         if (!(detail_filename = get_core_filename(filename, "txt")))
445                 return;
446
447         if ((fd = open(detail_filename, O_WRONLY | O_CREAT | O_TRUNC, 0)) != -1) {
448                 if(write(fd, text, strlen(text)) >= 0)
449                         fchmod(fd, 0644);
450                 else
451                         unlink(detail_filename);
452                 close(fd);
453         }
454         free(detail_filename);
455 }
456
457 /*
458  * Removes corefile (core.XXXX) from the processing_queue.
459  *
460  * Expects the processing_queue_mtx to be held.
461  */
462 static void remove_from_processing_queue(void)
463 {
464         free(processing_queue[head]);
465         processing_queue[head++] = NULL;
466
467         if (head == 100)
468                 head = 0;
469 }
470
471 /*
472  * Removes file from processing_oops hash based on pid.
473  * Extracts pid from the fullpath such that
474  * /home/user/core.pid will be tranformed into just the pid.
475  *
476  * Expects the lock on the given hash to be held.
477  */
478 void remove_pid_from_hash(char *fullpath, GHashTable *ht)
479 {
480         char *c1 = NULL, *c2 = NULL;
481
482         if (!(c1 = strip_directories(fullpath)))
483                 return;
484
485         if (!(c2 = get_core_filename(c1, NULL))) {
486                 free(c1);
487                 return;
488         }
489
490         free(c1);
491
492         g_hash_table_remove(ht, c2);
493
494         free(c2);
495 }
496
497 /*
498  * Common function for processing core
499  * files to generate oops structures
500  */
501 static struct oops *process_common(char *fullpath)
502 {
503         struct oops *oops = NULL;
504         char *appname = NULL, *appfile = NULL;
505
506         if(!(appname = find_coredump(fullpath))) {
507                 return NULL;
508         }
509
510         if (!(appfile = find_executable(appname))) {
511                 free(appname);
512                 return NULL;
513         }
514         free(appname);
515
516         if (!(oops = extract_core(fullpath, appfile))) {
517                 free(appfile);
518                 return NULL;
519         }
520         free(appfile);
521
522         return oops;
523 }
524
525
526 /*
527  * Processes .to-process core files.
528  * Also creates the pid.txt file and adds
529  * the oops struct to the submit queue
530  *
531  * Picks up and sets down the gdb_mtx and
532  * picks up and sets down the processing_queue_mtx.
533  * (held at the same time in that order)
534  * Also will pick up and sets down the queued_mtx.
535  */
536 static void *process_new(void __unused *vp)
537 {
538         struct oops *oops = NULL;
539         char *procfn = NULL, *corefn = NULL, *fullpath = NULL;
540
541         pthread_mutex_lock(&core_status.processing_mtx);
542         pthread_mutex_lock(&gdb_mtx);
543         pthread_mutex_lock(&processing_queue_mtx);
544
545         if (!(fullpath = processing_queue[head])) {
546                 /* something went quite wrong */
547                 pthread_mutex_unlock(&processing_queue_mtx);
548                 pthread_mutex_unlock(&gdb_mtx);
549                 pthread_mutex_unlock(&core_status.processing_mtx);
550                 return NULL;
551         }
552
553         if (!(corefn = strip_directories(fullpath)))
554                 goto clean_process_new;
555
556         if (!(procfn = replace_name(fullpath, ".to-process", ".processed")))
557                 goto clean_process_new;
558
559         if (!(oops = process_common(fullpath)))
560                 goto clean_process_new;
561
562         if (!(oops->detail_filename = get_core_filename(corefn, "txt")))
563                 goto clean_process_new;
564
565         if (rename(fullpath, procfn))
566                 goto clean_process_new;
567
568         free(oops->filename);
569         oops->filename = procfn;
570
571         remove_from_processing_queue();
572
573         pthread_mutex_unlock(&processing_queue_mtx);
574         pthread_mutex_unlock(&gdb_mtx);
575         pthread_mutex_unlock(&core_status.processing_mtx);
576
577         write_core_detail_file(corefn, oops->text);
578
579         pthread_mutex_lock(&core_status.queued_mtx);
580         queue_backtrace(oops);
581         pthread_mutex_unlock(&core_status.queued_mtx);
582
583         /* don't need to free procfn because was set to oops->filename and that gets free'd */
584         free(corefn);
585         FREE_OOPS(oops);
586         return NULL;
587
588 clean_process_new:
589         remove_pid_from_hash(fullpath, core_status.processing_oops);
590         remove_from_processing_queue();
591         free(procfn);
592         procfn = NULL; /* don't know if oops->filename == procfn so be safe */
593         free(corefn);
594         FREE_OOPS(oops);
595         pthread_mutex_unlock(&processing_queue_mtx);
596         pthread_mutex_unlock(&gdb_mtx);
597         pthread_mutex_unlock(&core_status.processing_mtx);
598         return NULL;
599 }
600
601 /*
602  * Reprocesses .processed core files.
603  *
604  * Picks up and sets down the gdb_mtx.
605  * Picks up and sets down the processing_queue_mtx.
606  * (held at the same time in that order)
607  * Also will pick up and sets down the queued_mtx.
608  */
609 static void *process_old(void __unused *vp)
610 {
611         struct oops *oops = NULL;
612         char *corefn = NULL, *fullpath = NULL;
613
614         pthread_mutex_lock(&gdb_mtx);
615         pthread_mutex_lock(&processing_queue_mtx);
616
617         if (!(fullpath = processing_queue[head])) {
618                 /* something went quite wrong */
619                 pthread_mutex_unlock(&processing_queue_mtx);
620                 pthread_mutex_unlock(&gdb_mtx);
621                 return NULL;
622         }
623
624         if (!(corefn = strip_directories(fullpath)))
625                 goto clean_process_old;
626
627         if (!(oops = process_common(fullpath)))
628                 goto clean_process_old;
629
630         if (!(oops->detail_filename = get_core_filename(corefn, "txt")))
631                 goto clean_process_old;
632
633         remove_from_processing_queue();
634
635         pthread_mutex_unlock(&processing_queue_mtx);
636         pthread_mutex_unlock(&gdb_mtx);
637
638         pthread_mutex_lock(&core_status.queued_mtx);
639         queue_backtrace(oops);
640         pthread_mutex_unlock(&core_status.queued_mtx);
641
642         free(corefn);
643         FREE_OOPS(oops);
644         return NULL;
645
646 clean_process_old:
647         remove_pid_from_hash(fullpath, core_status.processing_oops);
648         remove_from_processing_queue();
649         free(corefn);
650         FREE_OOPS(oops);
651         pthread_mutex_unlock(&processing_queue_mtx);
652         pthread_mutex_unlock(&gdb_mtx);
653         return NULL;
654 }
655
656 /*
657  * Adds corefile (based on pid) to the processing_oops
658  * hash table if it is not already there, then
659  * tries to add to the processing_queue.
660  *
661  * Picks up and sets down the processing_mtx.
662  * Picks up and sets down the processing_queue_mtx.
663  */
664 static int add_to_processing(char *fullpath)
665 {
666         char *c1 = NULL, *c2 = NULL, *fp = NULL;
667
668         if (!fullpath)
669                 return -1;
670
671         if (!(fp = strdup(fullpath)))
672                 goto clean_add_to_processing;
673
674         if (!(c1 = get_core_filename(fp, NULL)))
675                 goto clean_add_to_processing;
676
677         if (!(c2 = strip_directories(c1)))
678                 goto clean_add_to_processing;
679
680         free(c1);
681         c1 = NULL;
682
683         pthread_mutex_lock(&core_status.processing_mtx);
684         if (g_hash_table_lookup(core_status.processing_oops, c2)) {
685                 pthread_mutex_unlock(&core_status.processing_mtx);
686                 goto clean_add_to_processing;
687         }
688
689         pthread_mutex_lock(&processing_queue_mtx);
690         if (processing_queue[tail]) {
691                 pthread_mutex_unlock(&processing_queue_mtx);
692                 pthread_mutex_unlock(&core_status.processing_mtx);
693                 goto clean_add_to_processing;
694         }
695
696         g_hash_table_insert(core_status.processing_oops, c2, c2);
697         processing_queue[tail++] = fp;
698         if (tail == 100)
699                 tail = 0;
700
701         pthread_mutex_unlock(&processing_queue_mtx);
702         pthread_mutex_unlock(&core_status.processing_mtx);
703         return 0;
704 clean_add_to_processing:
705         free(fp);
706         free(c1);
707         free(c2);
708         return -1;
709 }
710
711 /*
712  * Entry for processing new core files.
713  */
714 static void process_corefile(char *fullpath)
715 {
716         pthread_t thrd;
717         int r = 1;
718
719         r = add_to_processing(fullpath);
720
721         if (r)
722                 return;
723
724         if (pthread_create(&thrd, NULL, process_new, NULL))
725                 fprintf(stderr, "Couldn't start up gdb extract core thread\n");
726 }
727
728 /*
729  * Entry for processing already seen core files.
730  */
731 static void reprocess_corefile(char *fullpath)
732 {
733         pthread_t thrd;
734         int r = 0;
735
736         r = add_to_processing(fullpath);
737
738         if (r)
739                 return;
740
741         if (pthread_create(&thrd, NULL, process_old, NULL))
742                 fprintf(stderr, "Couldn't start up gdb extract core thread\n");
743 }
744
745 int scan_corefolders(void __unused *unused)
746 {
747         DIR *dir = NULL;
748         struct dirent *entry = NULL;
749         char *fullpath = NULL, *appfile = NULL;
750         char tmp_folder[] = "/tmp/";
751         int r = 0;
752
753         pthread_mutex_init(&core_status.processing_mtx, NULL);
754         pthread_mutex_init(&core_status.queued_mtx, NULL);
755         pthread_mutex_init(&core_status.asked_mtx, NULL);
756
757         dir = opendir(tmp_folder);
758         if (!dir)
759                 return 1;
760
761         fprintf(stderr, "+ scanning %s...\n", tmp_folder);
762         while(1) {
763                 free(fullpath);
764                 fullpath = NULL;
765
766                 entry = readdir(dir);
767                 if (!entry || !entry->d_name)
768                         break;
769                 if (entry->d_name[0] == '.')
770                         continue;
771                 if (strncmp(entry->d_name, "core_", 5))
772                         continue;
773
774                 /* matched core_#### where #### is the pid of the process */
775                 r = asprintf(&fullpath, "%s%s", tmp_folder, entry->d_name);
776                 if (r == -1) {
777                         fullpath = NULL;
778                         continue;
779                 } else if (((unsigned int)r) != strlen(tmp_folder) + strlen(entry->d_name)) {
780                         continue;
781                 }
782                 /* already found, waiting for response from user */
783                 pthread_mutex_lock(&core_status.asked_mtx);
784                 if (g_hash_table_lookup(core_status.asked_oops, fullpath)) {
785                         pthread_mutex_unlock(&core_status.asked_mtx);
786                         continue;
787                 }
788                 pthread_mutex_unlock(&core_status.asked_mtx);
789                 fprintf(stderr, "+ Looking at %s\n", fullpath);
790                 appfile = get_appfile(fullpath);
791
792                 if (!appfile) {
793                         unlink(fullpath);
794                 } else {
795                         free(appfile);
796                         appfile = NULL;
797                 }
798         }
799         closedir(dir);
800
801         if (!core_folder)
802                 return 1;
803         dir = opendir(core_folder);
804         if (!dir) {
805                 if (!mkdir(core_folder, S_IRWXU | S_IRWXG | S_IRWXO)
806                         && errno != EEXIST) {
807                         return 1;
808                 }
809                 dir = opendir(core_folder);
810                 if (!dir)
811                         return 1;
812         }
813
814         fprintf(stderr, "+ scanning %s...\n", core_folder);
815         while(1) {
816                 free(fullpath);
817                 fullpath = NULL;
818
819                 entry = readdir(dir);
820                 if (!entry || !entry->d_name)
821                         break;
822                 if (entry->d_name[0] == '.')
823                         continue;
824                 if (!strstr(entry->d_name, "process"))
825                         continue;
826
827                 r = asprintf(&fullpath, "%s%s", core_folder, entry->d_name);
828                 if (r == -1) {
829                         fullpath = NULL;
830                         continue;
831                 } else if (((unsigned int)r) != strlen(core_folder) + strlen(entry->d_name)) {
832                         continue;
833                 }
834
835                 fprintf(stderr, "+ Looking at %s\n", fullpath);
836                 if (strstr(fullpath, "to-process"))
837                         process_corefile(fullpath);
838                 else
839                         reprocess_corefile(fullpath);
840         }
841         closedir(dir);
842
843         submit_queue();
844
845         return 1;
846 }