1 /*
2  * Copyright (c) 2016-2018 NLNet Labs.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29 #endif
30 #ifndef _GNU_SOURCE
31 #define __USE_GNU
32 #endif
33 
34 #include "config.h"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <unistd.h>
41 #include <signal.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/time.h>
45 #include <sys/resource.h>
46 #include <dlfcn.h>
47 #include <pthread.h>
48 #ifdef HAVE_BACKTRACE_FULL
49 #include <backtrace.h>
50 #endif
51 #ifdef HAVE_BACKTRACE
52 #include <execinfo.h>
53 #endif
54 #ifdef HAVE_LIBUNWIND
55 #include <libunwind.h>
56 #endif
57 
58 #include "janitor.h"
59 
60 static struct sigaction original_quit_action;
61 static struct sigaction original_abrt_action;
62 static struct sigaction original_segv_action;
63 static struct sigaction original_fpe_action;
64 static struct sigaction original_ill_action;
65 static struct sigaction original_bus_action;
66 static struct sigaction original_sys_action;
67 
68 static janitor_alertfn_t alert;
69 static janitor_alertfn_t report;
70 
71 struct janitor_threadclass_struct {
72     char* name;
73     int detached;
74     int autorun;
75     int blocksignals;
76     int hasattr;
77     pthread_attr_t attr;
78 };
79 
80 int
janitor_threadclass_create(janitor_threadclass_t * threadclass,const char * name)81 janitor_threadclass_create(janitor_threadclass_t* threadclass, const char* name)
82 {
83     *threadclass = malloc(sizeof(struct janitor_threadclass_struct));
84     (*threadclass)->name = strdup(name);
85     (*threadclass)->detached = 0;
86     (*threadclass)->autorun = 0;
87     (*threadclass)->blocksignals = 0;
88     (*threadclass)->hasattr = 0;
89     return 0;
90 }
91 
92 char*
janitor_threadclass_name(janitor_threadclass_t threadclass)93 janitor_threadclass_name(janitor_threadclass_t threadclass)
94 {
95     return threadclass->name;
96 }
97 
98 void
janitor_threadclass_destroy(janitor_threadclass_t threadclass)99 janitor_threadclass_destroy(janitor_threadclass_t threadclass)
100 {
101     if (threadclass->hasattr) {
102         pthread_attr_destroy(&threadclass->attr);
103     }
104     free(threadclass->name);
105     free(threadclass);
106 }
107 
108 void
janitor_threadclass_setdetached(janitor_threadclass_t threadclass)109 janitor_threadclass_setdetached(janitor_threadclass_t threadclass)
110 {
111     threadclass->detached = 1;
112     if (!threadclass->hasattr) {
113         pthread_attr_init(&threadclass->attr);
114     }
115     pthread_attr_setdetachstate(&threadclass->attr, PTHREAD_CREATE_DETACHED);
116 }
117 
118 void
janitor_threadclass_setautorun(janitor_threadclass_t threadclass)119 janitor_threadclass_setautorun(janitor_threadclass_t threadclass)
120 {
121     threadclass->autorun = 1;
122 }
123 
124 void
janitor_threadclass_setblockedsignals(janitor_threadclass_t threadclass)125 janitor_threadclass_setblockedsignals(janitor_threadclass_t threadclass)
126 {
127     threadclass->blocksignals = 1;
128 }
129 
130 void
janitor_threadclass_setminstacksize(janitor_threadclass_t threadclass,size_t minstacksize)131 janitor_threadclass_setminstacksize(janitor_threadclass_t threadclass, size_t minstacksize)
132 {
133     size_t stacksize;
134     if (!threadclass->hasattr) {
135         pthread_attr_init(&threadclass->attr);
136     }
137     pthread_attr_getstacksize(&threadclass->attr, &stacksize);
138     if (stacksize < minstacksize) {
139         pthread_attr_setstacksize(&threadclass->attr, minstacksize);
140         threadclass->hasattr = 1;
141     }
142 }
143 
144 static void fail(const char* file, int line, const char* func, const char* expr, int stat);
145 #define CHECKFAIL(EX) do { int CHECKFAIL; if((CHECKFAIL = (EX))) { fail(__FILE__,__LINE__,__func__,#EX,CHECKFAIL); goto fail; } } while(0)
146 
147 static void
fail(const char * file,int line,const char * func,const char * expr,int stat)148 fail(const char* file, int line, const char* func, const char* expr, int stat)
149 {
150     report("Failure %d in %s at %s:%d of %s\n", stat, func, file, line, expr);
151 }
152 
153 void
janitor_initialize(janitor_alertfn_t alertfn,janitor_alertfn_t reportfn)154 janitor_initialize(janitor_alertfn_t alertfn, janitor_alertfn_t reportfn)
155 {
156     report = reportfn;
157     alert = alertfn;
158 }
159 
160 struct janitor_thread_struct {
161     struct janitor_thread_struct* next;
162     struct janitor_thread_struct* prev;
163     pthread_t thread;
164     janitor_runfn_t runfunc;
165     void* rundata;
166     int isstarted;
167     int blocksignals;
168     pthread_barrier_t startbarrier;
169     janitor_threadclass_t threadclass;
170 };
171 
172 static pthread_mutex_t threadlock = PTHREAD_MUTEX_INITIALIZER;
173 static struct janitor_thread_struct *threadlist = NULL; /* running threads */
174 static struct janitor_thread_struct *finishedthreadlist = NULL; /* threads waiting to be joined */
175 static pthread_once_t threadlocatorinitializeonce = PTHREAD_ONCE_INIT;
176 static pthread_key_t threadlocator;
177 static pthread_cond_t threadblock = PTHREAD_COND_INITIALIZER;
178 
179 static void
threadlocatorinitialize(void)180 threadlocatorinitialize(void)
181 {
182     pthread_key_create(&threadlocator, NULL);
183 }
184 
185 static void
janitor_thread_unregister(janitor_thread_t info)186 janitor_thread_unregister(janitor_thread_t info)
187 {
188     int err, errcount;
189     if (info == NULL)
190         return;
191     CHECKFAIL(pthread_mutex_lock(&threadlock));
192     if (threadlist != NULL) {
193         if (threadlist == info) {
194             if (info->next == info) {
195                 threadlist = NULL;
196             } else {
197                 threadlist = info->next;
198             }
199         }
200         info->next->prev = info->prev;
201         info->prev->next = info->next;
202         info->next = info->prev = NULL;
203         /* The implementation on FreeBSD10 of pthreads is pretty brain dead.
204          * If two threads enter a barrier with count 2, then the barrier
205          * is satisfied and thus not really being waited upon.  If now one
206          * of the threads tries to destroy the thread, while the other thread
207          * did not have its turn yet on the CPU, then still the destroy call
208          * will return EBUSY.  Although valid, this is really a brain dead
209          * implementation causing pain to application developers to do the
210          * following every time:
211          */
212         errcount = 0;
213         do {
214             err = pthread_barrier_destroy(&info->startbarrier);
215             if (err == EBUSY) {
216                 ++errcount;
217                 sleep(1);
218             }
219         } while(err == EBUSY && errcount <= 3);
220         CHECKFAIL(pthread_cond_signal(&threadblock));
221     }
222     CHECKFAIL(pthread_mutex_unlock(&threadlock));
223 fail:
224     ;
225 }
226 
227 static void
janitor_thread_dispose(janitor_thread_t info)228 janitor_thread_dispose(janitor_thread_t info)
229 {
230     if (info == NULL)
231         return;
232     if (!info->threadclass || !info->threadclass->detached) {
233         pthread_mutex_lock(&threadlock);
234         if (finishedthreadlist != NULL) {
235             if (finishedthreadlist == info) {
236                 if (info->next == info) {
237                     finishedthreadlist = NULL;
238                 } else {
239                     finishedthreadlist = info->next;
240                 }
241             }
242             if(info->next && info->next->prev == info)
243                 info->next->prev = info->prev;
244             if(info->prev && info->prev->next == info)
245                 info->prev->next = info->next;
246             info->next = info->prev = NULL;
247         }
248         pthread_mutex_unlock(&threadlock);
249     }
250     free(info);
251 }
252 
253 static void
janitor_thread_register(janitor_thread_t info)254 janitor_thread_register(janitor_thread_t info)
255 {
256     pthread_mutex_lock(&threadlock);
257     pthread_once(&threadlocatorinitializeonce, threadlocatorinitialize);
258     if (threadlist != NULL) {
259         info->next = threadlist;
260         info->prev = threadlist->prev;
261         threadlist->prev->next = info;
262         threadlist->prev = info;
263     } else {
264         info->next = info->prev = info;
265     }
266     threadlist = info;
267     pthread_mutex_unlock(&threadlock);
268 }
269 
270 static void
janitor_thread_finished(janitor_thread_t info)271 janitor_thread_finished(janitor_thread_t info)
272 {
273     if (!info->threadclass->detached) {
274         pthread_mutex_lock(&threadlock);
275         if (finishedthreadlist != NULL) {
276             info->next = finishedthreadlist;
277             info->prev = finishedthreadlist->prev;
278             finishedthreadlist->prev->next = info;
279             finishedthreadlist->prev = info;
280         } else {
281             info->next = info->prev = info;
282         }
283         finishedthreadlist = info;
284         pthread_mutex_unlock(&threadlock);
285     } else {
286         pthread_detach(pthread_self());
287         janitor_thread_dispose(info);
288     }
289 }
290 
291 static void*
runthread(void * data)292 runthread(void* data)
293 {
294     int err;
295     sigset_t sigset;
296     struct janitor_thread_struct* info;
297     stack_t ss;
298     stack_t prevss;
299     info = (struct janitor_thread_struct*) data;
300     pthread_setspecific(threadlocator, info);
301     ss.ss_sp = malloc(SIGSTKSZ);
302     ss.ss_size = SIGSTKSZ;
303     ss.ss_flags = 0;
304     sigaltstack(&ss, &prevss);
305     pthread_barrier_wait(&info->startbarrier);
306     if (info->blocksignals) {
307         sigfillset(&sigset);
308         sigdelset(&sigset, SIGQUIT);
309         sigdelset(&sigset, SIGABRT);
310         sigdelset(&sigset, SIGSEGV);
311         sigdelset(&sigset, SIGFPE);
312         sigdelset(&sigset, SIGILL);
313         sigdelset(&sigset, SIGBUS);
314         sigdelset(&sigset, SIGSYS);
315         if ((err = pthread_sigmask(SIG_SETMASK, &sigset, NULL)))
316             report("pthread_sigmask: %s (%d)", strerror(err), err);
317     }
318     info->runfunc(info->rundata);
319     sigaltstack(&prevss, NULL);
320     free(ss.ss_sp); /* libxml has/had problems when freeing this as it tries to access it */
321     janitor_thread_unregister(info);
322     janitor_thread_finished(info);
323     return NULL;
324 }
325 
326 int
janitor_thread_create(janitor_thread_t * thread,janitor_threadclass_t threadclass,janitor_runfn_t func,void * data)327 janitor_thread_create(janitor_thread_t* thread, janitor_threadclass_t threadclass, janitor_runfn_t func, void*data)
328 {
329     struct janitor_thread_struct* info;
330     info = malloc(sizeof (struct janitor_thread_struct));
331     info->runfunc = func;
332     info->rundata = data;
333     info->blocksignals = 0;
334     info->isstarted = 0;
335     info->threadclass = threadclass;
336     CHECKFAIL(pthread_barrier_init(&info->startbarrier, NULL, 2));
337     CHECKFAIL(pthread_create(&info->thread, ((threadclass && threadclass->hasattr) ? &threadclass->attr : NULL), runthread, info));
338     janitor_thread_register(info);
339     *thread = info;
340     if(threadclass && threadclass->autorun) {
341         janitor_thread_start(info);
342     }
343     return 0;
344 fail:
345     return 1;
346 }
347 
janitor_thread_signal(janitor_thread_t thread)348 void janitor_thread_signal(janitor_thread_t thread)
349 {
350     pthread_kill(thread->thread, SIGHUP);
351 }
352 
353 void
janitor_thread_start(janitor_thread_t thread)354 janitor_thread_start(janitor_thread_t thread)
355 {
356     int isstarted;
357 
358     pthread_mutex_lock(&threadlock);
359     isstarted = thread->isstarted;
360     thread->isstarted = 1;
361     pthread_mutex_unlock(&threadlock);
362 
363     if (!isstarted) {
364         pthread_barrier_wait(&thread->startbarrier);
365     }
366 }
367 
368 int
janitor_thread_join(janitor_thread_t thread)369 janitor_thread_join(janitor_thread_t thread)
370 {
371     janitor_thread_t info;
372     int status;
373     status = pthread_join(thread->thread, NULL);
374     janitor_thread_dispose(thread);
375     return status;
376 }
377 
378 int
janitor_thread_tryjoinall(janitor_threadclass_t threadclass)379 janitor_thread_tryjoinall(janitor_threadclass_t threadclass)
380 {
381     struct janitor_thread_struct* thread;
382     struct janitor_thread_struct* foundthread;
383 
384     do {
385         foundthread = NULL;
386         pthread_mutex_lock(&threadlock);
387         thread = finishedthreadlist;
388         if (thread) {
389             do {
390                 if (thread->threadclass == threadclass) {
391                     foundthread = thread;
392                     break;
393                 }
394                 thread = thread->next;
395             } while (thread != finishedthreadlist);
396         }
397         pthread_mutex_unlock(&threadlock);
398         if (foundthread) {
399             janitor_thread_join(foundthread);
400         }
401     } while(foundthread);
402 
403     pthread_mutex_lock(&threadlock);
404     foundthread = NULL;
405     thread = finishedthreadlist;
406     if (thread) {
407         do {
408             if (thread->threadclass == threadclass) {
409                 foundthread = thread;
410                 break;
411             }
412             thread = thread->next;
413         } while (thread != finishedthreadlist);
414     }
415     thread = threadlist;
416     if (!foundthread && thread) {
417         do {
418             if (thread->threadclass == threadclass) {
419                 foundthread = thread;
420                 break;
421             }
422             thread = thread->next;
423         } while (thread != threadlist);
424     }
425     pthread_mutex_unlock(&threadlock);
426     if (foundthread) {
427         return 1;
428     } else {
429         return 0;
430     }
431 }
432 
433 void
janitor_thread_joinall(janitor_threadclass_t threadclass)434 janitor_thread_joinall(janitor_threadclass_t threadclass)
435 {
436     int moreleft;
437     do {
438         moreleft = janitor_thread_tryjoinall(threadclass);
439     } while(moreleft);
440 }
441 
442 static void
dumpthreads(void)443 dumpthreads(void)
444 {
445     struct janitor_thread_struct* info;
446     struct janitor_thread_struct* list;
447     pthread_mutex_lock(&threadlock);
448     info = pthread_getspecific(threadlocator);
449     list = threadlist;
450     if (list) {
451         do {
452             if (list != info) {
453                 pthread_kill(list->thread, SIGQUIT);
454                 pthread_cond_wait(&threadblock, &threadlock);
455             }
456             list = list->next;
457         } while (list != threadlist);
458     }
459     pthread_mutex_unlock(&threadlock);
460 }
461 
462 #ifdef HAVE_BACKTRACE_FULL
463 static struct backtrace_state *state  = NULL;
464 static struct backtrace_state *frames = NULL;
465 static pthread_mutex_t frameslock = PTHREAD_MUTEX_INITIALIZER;
466 
467 static int
callback(void * data,uintptr_t pc,const char * filename,int lineno,const char * function)468 callback(void* data, uintptr_t pc, const char *filename, int lineno, const char *function)
469 {
470     if (filename == NULL && lineno == 0 && function == NULL) {
471         alert("  inlined method\n");
472     } else {
473         alert("  %s:%d in %s()\n", filename, lineno, function);
474     }
475     if (function && !strcmp(function, "main"))
476         return 1;
477     else
478         return 0;
479 }
480 
481 static void
errorhandler(void * data,const char * msg,int xerrno)482 errorhandler(void* data, const char *msg, int xerrno)
483 {
484     int len = strlen(msg);
485     (void) (write(2, msg, len));
486     (void) (write(2, "\n", 1));
487 }
488 #endif
489 
490 static void
outputbacktrace(int skips,void * workaround)491 outputbacktrace(int skips, void *workaround)
492 {
493 #ifdef HAVE_BACKTRACE_FULL
494     struct backtrace_state *state = (struct backtrace_state*) workaround;
495 #else
496 #ifdef HAVE_BACKTRACE
497     Dl_info btinfo;
498     void *bt[20];
499     int count, i;
500 #else
501 #ifdef HAVE_LIBUNWIND
502     unw_context_t ctx;
503     unw_cursor_t cursor;
504     char symbol[256];
505     unw_word_t offset;
506 #endif
507 #endif
508 #endif
509 #ifdef HAVE_BACKTRACE_FULL
510     backtrace_full(state, skips, (backtrace_full_callback) callback, (backtrace_error_callback) errorhandler, NULL);
511 #else
512 #ifdef HAVE_BACKTRACE
513     count = backtrace(bt, sizeof (bt) / sizeof (void*));
514     for (i = skips; i < count; i++) {
515         dladdr(bt[i], &btinfo);
516         if (btinfo.dli_sname != NULL) {
517             alert("  %s\n", btinfo.dli_sname);
518             if (!strcmp(btinfo.dli_sname, "main"))
519                 break;
520         } else
521             alert("  unknown\n");
522     }
523 #else
524 #ifdef HAVE_LIBUNWIND
525     unw_getcontext(&ctx);
526     unw_init_local(&cursor, &ctx);
527     if (unw_step(&cursor)) {
528         /* skip the first one */
529         while (unw_step(&cursor)) {
530             unw_get_proc_name(&cursor, symbol, sizeof (symbol) - (skips-1), &offset);
531             alert("  %s\n", symbol);
532             if (!strcmp(symbol, "main"))
533                 break;
534         }
535     }
536 #endif
537 #endif
538 #endif
539 }
540 
541 static void
handlesignal(int signal,siginfo_t * info,void * data)542 handlesignal(int signal, siginfo_t* info, void* data)
543 {
544     const char* signalname;
545     Dl_info btinfo;
546     janitor_thread_t thrinfo;
547     (void) signal;
548     (void) data;
549 #ifndef HAVE_BACKTRACE_FULL
550 #ifdef HAVE_BACKTRACE
551     void *bt[20];
552     int count, i;
553 #else
554 #ifdef HAVE_LIBUNWIND
555     unw_context_t ctx;
556     unw_cursor_t cursor;
557     char symbol[256];
558     unw_word_t offset;
559 #endif
560 #endif
561 #endif
562     switch (info->si_signo) {
563         case SIGQUIT:
564             signalname = "Threaddump";
565             break;
566         case SIGABRT:
567             sigaction(info->si_signo, &original_abrt_action, NULL);
568             signalname = "Aborted";
569             break;
570         case SIGSEGV:
571             sigaction(info->si_signo, &original_segv_action, NULL);
572             signalname = "Segmentation fault";
573             break;
574         case SIGFPE:
575             sigaction(info->si_signo, &original_fpe_action, NULL);
576             signalname = "Floating point error";
577             break;
578         case SIGILL:
579             sigaction(info->si_signo, &original_ill_action, NULL);
580             signalname = "Illegal instruction";
581             break;
582         case SIGBUS:
583             sigaction(info->si_signo, &original_bus_action, NULL);
584             signalname = "Bus error";
585             break;
586         case SIGSYS:
587             sigaction(info->si_signo, &original_sys_action, NULL);
588             signalname = "System error";
589             break;
590         default:
591             signalname = "Unknown error";
592     }
593     if (dladdr(info->si_addr, &btinfo) != 0)
594         alert("%s in %s", signalname, btinfo.dli_sname);
595     else
596         alert("%s", signalname);
597 #ifdef HAVE_BACKTRACE_FULL
598     alert(":\n");
599 #else
600 #ifdef HAVE_BACKTRACE
601     alert(":\n");
602 #else
603 #ifdef HAVE_LIBUNWIND
604     alert(":\n");
605 #else
606     alert("\n");
607 #endif
608 #endif
609 #endif
610 #ifdef HAVE_BACKTRACE_FULL
611     outputbacktrace(2, state);
612 #else
613     outputbacktrace(2, NULL);
614 #endif
615     if (info->si_signo == SIGQUIT) {
616         pthread_mutex_lock(&threadlock);
617         pthread_cond_signal(&threadblock);
618         pthread_mutex_unlock(&threadlock);
619     } else {
620         dumpthreads();
621         raise(info->si_signo);
622     }
623 }
624 
625 void
janitor_backtrace(void)626 janitor_backtrace(void)
627 {
628 #ifdef HAVE_BACKTRACE_FULL
629     if(frames == NULL) {
630         frames = backtrace_create_state(NULL, 0, (backtrace_error_callback) errorhandler, NULL);
631     }
632     pthread_mutex_lock(&frameslock);
633     outputbacktrace(1, frames);
634     pthread_mutex_unlock(&frameslock);
635 #else
636     outputbacktrace(1, NULL);
637 #endif
638 }
639 
640 static int
callbackstring(void * data,uintptr_t pc,const char * filename,int lineno,const char * function)641 callbackstring(void* data, uintptr_t pc, const char *filename, int lineno, const char *function)
642 {
643     int siz, len;
644     char** ptr = data;
645     if (filename != NULL || lineno != 0 || function == NULL) {
646         siz = snprintf(NULL, 0, "  %s:%d in %s()\n", filename, lineno, function);
647         if (*ptr != NULL) {
648             len = strlen(*ptr);
649             siz += len + 1;
650             *ptr = realloc(*ptr, siz);
651         } else {
652             len = 0;
653             siz += 1;
654             *ptr = malloc(siz);
655         }
656         snprintf(&(*ptr)[len], siz-len, "  %s:%d in %s()\n", filename, lineno, function);
657     }
658     if (function && !strcmp(function, "main"))
659         return 1;
660     else
661         return 0;
662 }
663 
664 char*
janitor_backtrace_string(void)665 janitor_backtrace_string(void)
666 {
667     char* string = NULL;
668 #ifdef HAVE_BACKTRACE_FULL
669     if(frames == NULL) {
670         frames = backtrace_create_state(NULL, 0, (backtrace_error_callback) errorhandler, NULL);
671     }
672     pthread_mutex_lock(&frameslock);
673     backtrace_full(frames, 1, (backtrace_full_callback) callbackstring, (backtrace_error_callback) errorhandler, &string);
674     pthread_mutex_unlock(&frameslock);
675 #endif
676     return string;
677 }
678 
679 void
janitor_backtrace_all(void)680 janitor_backtrace_all(void)
681 {
682     dumpthreads();
683 }
684 
685 int
janitor_trapsignals(char * argv0)686 janitor_trapsignals(char* argv0)
687 {
688     sigset_t mask;
689     stack_t ss;
690     struct sigaction newsigaction;
691     static struct backtrace_state *frames;
692 
693 #ifdef HAVE_BACKTRACE_FULL
694     CHECKFAIL((state  = backtrace_create_state(argv0, 0, (backtrace_error_callback)errorhandler, NULL)) == NULL);
695     CHECKFAIL((frames = backtrace_create_state(argv0, 0, (backtrace_error_callback)errorhandler, NULL)) == NULL);
696 #else
697     (void) argv0;
698 #endif
699 
700     /*ss.ss_sp = malloc(SIGSTKSZ);
701     ss.ss_size = SIGSTKSZ;
702     ss.ss_flags = 0;
703     CHECKFAIL(sigaltstack(&ss, NULL) == -1);*/
704 
705     sigfillset(&mask);
706     sigdelset(&mask, SIGQUIT);
707     newsigaction.sa_sigaction = handlesignal;
708     newsigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
709     newsigaction.sa_mask = mask;
710     CHECKFAIL(sigaction(SIGQUIT, &newsigaction, &original_quit_action));
711     CHECKFAIL(sigaction(SIGABRT, &newsigaction, &original_abrt_action));
712     CHECKFAIL(sigaction(SIGSEGV, &newsigaction, &original_segv_action));
713     CHECKFAIL(sigaction(SIGFPE, &newsigaction, &original_fpe_action));
714     CHECKFAIL(sigaction(SIGILL, &newsigaction, &original_ill_action));
715     CHECKFAIL(sigaction(SIGBUS, &newsigaction, &original_bus_action));
716     CHECKFAIL(sigaction(SIGSYS, &newsigaction, &original_sys_action));
717     return 0;
718 fail:
719     return -1;
720 }
721 
722 int
janitor_disablecoredump(void)723 janitor_disablecoredump(void)
724 {
725     struct rlimit rlim;
726     rlim.rlim_cur = 0;
727     rlim.rlim_max = 0;
728 
729     CHECKFAIL(setrlimit(RLIMIT_CORE, &rlim));
730     return 0;
731 fail:
732     return -1;
733 }
734 
735 struct janitor_pthread_barrier_struct {
736     pthread_mutex_t mutex;
737     pthread_cond_t cond;
738     unsigned int waiting;
739     unsigned int count;
740 };
741 
742 int
janitor_pthread_barrier_init(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned int count)743 janitor_pthread_barrier_init(pthread_barrier_t* barrier, const pthread_barrierattr_t* attr, unsigned int count)
744 {
745     struct janitor_pthread_barrier_struct* b;
746     b = malloc(sizeof(struct janitor_pthread_barrier_struct));
747     if(count == 0 || attr != NULL) {
748         errno = EINVAL;
749         return -1;
750     }
751     if(pthread_mutex_init(&b->mutex, 0) < 0) {
752         free(b);
753         return -1;
754     }
755     if(pthread_cond_init(&b->cond, 0) < 0) {
756         pthread_mutex_destroy(&b->mutex);
757         free(b);
758         return -1;
759     }
760     b->count = count;
761     b->waiting = 0;
762     *(void**)barrier = b;
763     return 0;
764 }
765 
766 int
janitor_pthread_barrier_destroy(pthread_barrier_t * barrier)767 janitor_pthread_barrier_destroy(pthread_barrier_t* barrier)
768 {
769     struct janitor_pthread_barrier_struct* b = *(void**)barrier;
770     pthread_mutex_lock(&b->mutex);
771     if(b->count > 0) {
772         pthread_mutex_unlock(&b->mutex);
773         errno = EBUSY;
774         return -1;
775     }
776     *(void**)barrier = NULL;
777     pthread_mutex_unlock(&b->mutex);
778     pthread_cond_destroy(&b->cond);
779     pthread_mutex_destroy(&b->mutex);
780     free(b);
781     return 0;
782 }
783 
784 int
janitor_pthread_barrier_wait(pthread_barrier_t * barrier)785 janitor_pthread_barrier_wait(pthread_barrier_t* barrier)
786 {
787     struct janitor_pthread_barrier_struct* b = *(void**)barrier;
788     pthread_mutex_lock(&b->mutex);
789     b->waiting += 1;
790     if(b->waiting == b->count) {
791         b->count = 0;
792         pthread_cond_broadcast(&b->cond);
793         pthread_mutex_unlock(&b->mutex);
794         return PTHREAD_BARRIER_SERIAL_THREAD;
795     } else {
796         pthread_cond_wait(&b->cond, &b->mutex);
797         pthread_mutex_unlock(&b->mutex);
798         return 0;
799     }
800 }
801