1 /*
2  *  TVheadend
3  *  Copyright (C) 2007 - 2010 Andreas Öman
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <pthread.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <syslog.h>
29 #include <limits.h>
30 #include <time.h>
31 #include <locale.h>
32 
33 #include <pwd.h>
34 #include <grp.h>
35 
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 
39 #include "tvheadend.h"
40 #include "api.h"
41 #include "tcp.h"
42 #include "access.h"
43 #include "http.h"
44 #include "upnp.h"
45 #include "webui/webui.h"
46 #include "epggrab.h"
47 #include "spawn.h"
48 #include "subscriptions.h"
49 #include "service_mapper.h"
50 #include "descrambler.h"
51 #include "profile.h"
52 #include "dvr/dvr.h"
53 #include "htsp_server.h"
54 #include "satip/server.h"
55 #include "avahi.h"
56 #include "bonjour.h"
57 #include "input.h"
58 #include "service.h"
59 #include "trap.h"
60 #include "settings.h"
61 #include "config.h"
62 #include "notify.h"
63 #include "idnode.h"
64 #include "imagecache.h"
65 #include "timeshift.h"
66 #include "fsmonitor.h"
67 #include "lang_codes.h"
68 #include "esfilter.h"
69 #include "intlconv.h"
70 #include "dbus.h"
71 #include "libav.h"
72 #include "bouquet.h"
73 #include "tvhtime.h"
74 #include "packet.h"
75 #include "streaming.h"
76 #include "memoryinfo.h"
77 
78 #ifdef PLATFORM_LINUX
79 #include <sys/prctl.h>
80 #endif
81 #include <sys/resource.h>
82 #include <openssl/ssl.h>
83 #include <openssl/conf.h>
84 #include <openssl/err.h>
85 #include <openssl/rand.h>
86 #include <openssl/engine.h>
87 
88 pthread_t main_tid;
89 
90 int64_t   __mdispatch_clock;
91 time_t    __gdispatch_clock;
92 
93 /* Command line option struct */
94 typedef struct {
95   const char  sopt;
96   const char *lopt;
97   const char *desc;
98   enum {
99     OPT_STR,
100     OPT_INT,
101     OPT_BOOL,
102     OPT_STR_LIST,
103   }          type;
104   void       *param;
105 } cmdline_opt_t;
106 
cmdline_opt_find(cmdline_opt_t * opts,int num,const char * arg)107 static cmdline_opt_t* cmdline_opt_find
108   ( cmdline_opt_t *opts, int num, const char *arg )
109 {
110   int i;
111   int isshort = 0;
112 
113   if (strlen(arg) < 2 || *arg != '-')
114     return NULL;
115   arg++;
116 
117   if (strlen(arg) == 1)
118     isshort = 1;
119   else if (*arg == '-')
120     arg++;
121   else
122     return NULL;
123 
124   for (i = 0; i < num; i++) {
125     if (!opts[i].lopt) continue;
126     if (isshort && opts[i].sopt == *arg)
127       return &opts[i];
128     if (!isshort && !strcmp(opts[i].lopt, arg))
129       return &opts[i];
130   }
131 
132   return NULL;
133 }
134 
135 /*
136  * Globals
137  */
138 int              tvheadend_running;
139 int              tvheadend_webui_port;
140 int              tvheadend_webui_debug;
141 int              tvheadend_htsp_port;
142 int              tvheadend_htsp_port_extra;
143 const char      *tvheadend_tsdebug;
144 const char      *tvheadend_cwd0;
145 const char      *tvheadend_cwd;
146 const char      *tvheadend_webroot;
147 const tvh_caps_t tvheadend_capabilities[] = {
148 #if ENABLE_CWC || ENABLE_CAPMT || ENABLE_CONSTCW
149   { "caclient", NULL },
150 #endif
151 #if ENABLE_LINUXDVB || ENABLE_SATIP_CLIENT || ENABLE_HDHOMERUN_CLIENT
152   { "tvadapters", NULL },
153 #endif
154 #if ENABLE_SATIP_CLIENT
155   { "satip_client", NULL },
156 #endif
157 #if ENABLE_SATIP_SERVER
158   { "satip_server", NULL },
159 #endif
160 #if ENABLE_IMAGECACHE
161   { "imagecache", (uint32_t*)&imagecache_conf.enabled },
162 #endif
163 #if ENABLE_TIMESHIFT
164   { "timeshift", (uint32_t *)&timeshift_conf.enabled },
165 #endif
166 #if ENABLE_TRACE
167   { "trace",     NULL },
168 #endif
169 #if ENABLE_LIBAV
170   { "libav",     NULL },
171 #endif
172   { NULL, NULL }
173 };
174 
175 pthread_mutex_t global_lock;
176 pthread_mutex_t tasklet_lock;
177 pthread_mutex_t fork_lock;
178 pthread_mutex_t atomic_lock;
179 
180 /*
181  * Locals
182  */
183 static LIST_HEAD(, mtimer) mtimers;
184 static tvh_cond_t mtimer_cond;
185 static int64_t mtimer_periodic;
186 static pthread_t mtimer_tid;
187 static pthread_t mtimer_tick_tid;
188 static LIST_HEAD(, gtimer) gtimers;
189 static pthread_cond_t gtimer_cond;
190 static TAILQ_HEAD(, tasklet) tasklets;
191 static tvh_cond_t tasklet_cond;
192 static pthread_t tasklet_tid;
193 static memoryinfo_t tasklet_memoryinfo = { .my_name = "Tasklet" };
194 
195 static void
handle_sigpipe(int x)196 handle_sigpipe(int x)
197 {
198   return;
199 }
200 
201 static void
handle_sigill(int x)202 handle_sigill(int x)
203 {
204   /* Note that on some platforms, the SSL library tries */
205   /* to determine the CPU capabilities with possible */
206   /* unknown instructions */
207   tvhwarn(LS_CPU, "Illegal instruction handler (might be OK)");
208   signal(SIGILL, handle_sigill);
209 }
210 
211 void
doexit(int x)212 doexit(int x)
213 {
214   if (pthread_self() != main_tid)
215     pthread_kill(main_tid, SIGTERM);
216   pthread_cond_signal(&gtimer_cond);
217   tvh_cond_signal(&mtimer_cond, 1);
218   atomic_set(&tvheadend_running, 0);
219   signal(x, doexit);
220 }
221 
222 static int
get_user_groups(const struct passwd * pw,gid_t * glist,size_t gmax)223 get_user_groups (const struct passwd *pw, gid_t* glist, size_t gmax)
224 {
225   int num = 0;
226 #if !ENABLE_ANDROID
227   struct group *gr;
228   char **mem;
229   glist[num++] = pw->pw_gid;
230   for ( gr = getgrent(); (gr != NULL) && (num < gmax); gr = getgrent() ) {
231     if (gr->gr_gid == pw->pw_gid) continue;
232     for (mem = gr->gr_mem; *mem; mem++) {
233       if(!strcmp(*mem, pw->pw_name)) glist[num++] = gr->gr_gid;
234     }
235   }
236 #endif
237   return num;
238 }
239 
240 /**
241  *
242  */
243 
244 #define safecmp(a, b) ((a) > (b) ? 1 : ((a) < (b) ? -1 : 0))
245 
246 static int
mtimercmp(mtimer_t * a,mtimer_t * b)247 mtimercmp(mtimer_t *a, mtimer_t *b)
248 {
249   return safecmp(a->mti_expire, b->mti_expire);
250 }
251 
252 /**
253  *
254  */
255 void
GTIMER_FCN(mtimer_arm_abs)256 GTIMER_FCN(mtimer_arm_abs)
257   (GTIMER_TRACEID_ mtimer_t *mti, mti_callback_t *callback, void *opaque, int64_t when)
258 {
259   lock_assert(&global_lock);
260 
261   if (mti->mti_callback != NULL)
262     LIST_REMOVE(mti, mti_link);
263 
264   mti->mti_callback = callback;
265   mti->mti_opaque   = opaque;
266   mti->mti_expire   = when;
267 #if ENABLE_GTIMER_CHECK
268   mti->mti_id       = id;
269   mti->mti_fcn      = fcn;
270 #endif
271 
272   LIST_INSERT_SORTED(&mtimers, mti, mti_link, mtimercmp);
273 
274   if (LIST_FIRST(&mtimers) == mti)
275     tvh_cond_signal(&mtimer_cond, 0); // force timer re-check
276 }
277 
278 /**
279  *
280  */
281 void
GTIMER_FCN(mtimer_arm_rel)282 GTIMER_FCN(mtimer_arm_rel)
283   (GTIMER_TRACEID_ mtimer_t *gti, mti_callback_t *callback, void *opaque, int64_t delta)
284 {
285 #if ENABLE_GTIMER_CHECK
286   GTIMER_FCN(mtimer_arm_abs)(id, fcn, gti, callback, opaque, mclk() + delta);
287 #else
288   mtimer_arm_abs(gti, callback, opaque, mclk() + delta);
289 #endif
290 }
291 
292 /**
293  *
294  */
295 void
mtimer_disarm(mtimer_t * mti)296 mtimer_disarm(mtimer_t *mti)
297 {
298   if(mti->mti_callback) {
299     LIST_REMOVE(mti, mti_link);
300     mti->mti_callback = NULL;
301   }
302 }
303 
304 /**
305  *
306  */
307 static int
gtimercmp(gtimer_t * a,gtimer_t * b)308 gtimercmp(gtimer_t *a, gtimer_t *b)
309 {
310   return safecmp(a->gti_expire, b->gti_expire);
311 }
312 
313 /**
314  *
315  */
316 void
GTIMER_FCN(gtimer_arm_absn)317 GTIMER_FCN(gtimer_arm_absn)
318   (GTIMER_TRACEID_ gtimer_t *gti, gti_callback_t *callback, void *opaque, time_t when)
319 {
320   lock_assert(&global_lock);
321 
322   if (gti->gti_callback != NULL)
323     LIST_REMOVE(gti, gti_link);
324 
325   gti->gti_callback = callback;
326   gti->gti_opaque   = opaque;
327   gti->gti_expire   = when;
328 #if ENABLE_GTIMER_CHECK
329   gti->gti_id       = id;
330   gti->gti_fcn      = fcn;
331 #endif
332 
333   LIST_INSERT_SORTED(&gtimers, gti, gti_link, gtimercmp);
334 
335   if (LIST_FIRST(&gtimers) == gti)
336     pthread_cond_signal(&gtimer_cond); // force timer re-check
337 }
338 
339 /**
340  *
341  */
342 void
GTIMER_FCN(gtimer_arm_rel)343 GTIMER_FCN(gtimer_arm_rel)
344   (GTIMER_TRACEID_ gtimer_t *gti, gti_callback_t *callback, void *opaque, time_t delta)
345 {
346 #if ENABLE_GTIMER_CHECK
347   GTIMER_FCN(gtimer_arm_absn)(id, fcn, gti, callback, opaque, gclk() + delta);
348 #else
349   gtimer_arm_absn(gti, callback, opaque, gclk() + delta);
350 #endif
351 }
352 
353 /**
354  *
355  */
356 void
gtimer_disarm(gtimer_t * gti)357 gtimer_disarm(gtimer_t *gti)
358 {
359   if(gti->gti_callback) {
360     LIST_REMOVE(gti, gti_link);
361     gti->gti_callback = NULL;
362   }
363 }
364 
365 /**
366  *
367  */
368 tasklet_t *
tasklet_arm_alloc(tsk_callback_t * callback,void * opaque)369 tasklet_arm_alloc(tsk_callback_t *callback, void *opaque)
370 {
371   tasklet_t *tsk = calloc(1, sizeof(*tsk));
372   if (tsk) {
373     memoryinfo_alloc(&tasklet_memoryinfo, sizeof(*tsk));
374     tsk->tsk_free = free;
375     tasklet_arm(tsk, callback, opaque);
376   }
377   return tsk;
378 }
379 
380 /**
381  *
382  */
383 void
tasklet_arm(tasklet_t * tsk,tsk_callback_t * callback,void * opaque)384 tasklet_arm(tasklet_t *tsk, tsk_callback_t *callback, void *opaque)
385 {
386   pthread_mutex_lock(&tasklet_lock);
387 
388   if (tsk->tsk_callback != NULL)
389     TAILQ_REMOVE(&tasklets, tsk, tsk_link);
390 
391   tsk->tsk_callback = callback;
392   tsk->tsk_opaque   = opaque;
393 
394   TAILQ_INSERT_TAIL(&tasklets, tsk, tsk_link);
395 
396   if (TAILQ_FIRST(&tasklets) == tsk)
397     tvh_cond_signal(&tasklet_cond, 0);
398 
399   pthread_mutex_unlock(&tasklet_lock);
400 }
401 
402 /**
403  *
404  */
405 void
tasklet_disarm(tasklet_t * tsk)406 tasklet_disarm(tasklet_t *tsk)
407 {
408   pthread_mutex_lock(&tasklet_lock);
409 
410   if(tsk->tsk_callback) {
411     TAILQ_REMOVE(&tasklets, tsk, tsk_link);
412     tsk->tsk_callback(tsk->tsk_opaque, 1);
413     tsk->tsk_callback = NULL;
414     if (tsk->tsk_free) tsk->tsk_free(tsk);
415   }
416 
417   pthread_mutex_unlock(&tasklet_lock);
418 }
419 
420 static void
tasklet_flush()421 tasklet_flush()
422 {
423   tasklet_t *tsk;
424 
425   pthread_mutex_lock(&tasklet_lock);
426 
427   while ((tsk = TAILQ_FIRST(&tasklets)) != NULL) {
428     TAILQ_REMOVE(&tasklets, tsk, tsk_link);
429     tsk->tsk_callback(tsk->tsk_opaque, 1);
430     tsk->tsk_callback = NULL;
431     if (tsk->tsk_free) {
432       memoryinfo_free(&tasklet_memoryinfo, sizeof(*tsk));
433       tsk->tsk_free(tsk);
434     }
435   }
436 
437   pthread_mutex_unlock(&tasklet_lock);
438 }
439 
440 /**
441  *
442  */
443 static void *
tasklet_thread(void * aux)444 tasklet_thread ( void *aux )
445 {
446   tasklet_t *tsk;
447   tsk_callback_t *tsk_cb;
448   void *opaque;
449 
450   tvhthread_renice(20);
451 
452   pthread_mutex_lock(&tasklet_lock);
453   while (tvheadend_is_running()) {
454     tsk = TAILQ_FIRST(&tasklets);
455     if (tsk == NULL) {
456       tvh_cond_wait(&tasklet_cond, &tasklet_lock);
457       continue;
458     }
459     /* the callback might re-initialize tasklet, save everything */
460     TAILQ_REMOVE(&tasklets, tsk, tsk_link);
461     tsk_cb = tsk->tsk_callback;
462     opaque = tsk->tsk_opaque;
463     tsk->tsk_callback = NULL;
464     if (tsk->tsk_free) {
465       memoryinfo_free(&tasklet_memoryinfo, sizeof(*tsk));
466       tsk->tsk_free(tsk);
467     }
468     /* now, the callback can be safely called */
469     if (tsk_cb) {
470       pthread_mutex_unlock(&tasklet_lock);
471       tsk_cb(opaque, 0);
472       pthread_mutex_lock(&tasklet_lock);
473     }
474   }
475   pthread_mutex_unlock(&tasklet_lock);
476 
477   return NULL;
478 }
479 
480 /**
481  * Show version info
482  */
483 static void
show_version(const char * argv0)484 show_version(const char *argv0)
485 {
486   printf("%s: version %s\n", argv0, tvheadend_version);
487   exit(0);
488 }
489 
490 /**
491  *
492  */
493 static void
show_usage(const char * argv0,cmdline_opt_t * opts,int num,const char * err,...)494 show_usage
495   (const char *argv0, cmdline_opt_t *opts, int num, const char *err, ...)
496 {
497   int i;
498   char buf[256];
499   printf(_("Usage: %s [OPTIONS]\n"), argv0);
500   for (i = 0; i < num; i++) {
501 
502     /* Section */
503     if (!opts[i].lopt) {
504       printf("\n%s\n\n", tvh_gettext(opts[i].desc));
505 
506     /* Option */
507     } else {
508       char sopt[4];
509       char *desc, *tok;
510       if (opts[i].sopt)
511         snprintf(sopt, sizeof(sopt), "-%c,", opts[i].sopt);
512       else
513         strcpy(sopt, "   ");
514       snprintf(buf, sizeof(buf), "  %s --%s", sopt, opts[i].lopt);
515       desc = strdup(tvh_gettext(opts[i].desc));
516       tok  = strtok(desc, "\n");
517       while (tok) {
518         printf("%-30s%s\n", buf, tok);
519         tok = buf;
520         while (*tok) {
521           *tok = ' ';
522           tok++;
523         }
524         tok = strtok(NULL, "\n");
525       }
526       free(desc);
527     }
528   }
529   printf("%s",
530          _("\n"
531            "For more information please visit the Tvheadend website:\n"
532            "https://tvheadend.org\n"));
533   exit(0);
534 }
535 
536 /**
537  * Show subsystems info
538  */
539 static void
show_subsystems(const char * argv0)540 show_subsystems(const char *argv0)
541 {
542   int i;
543   tvhlog_subsys_t *ts = tvhlog_subsystems;
544   printf("Subsystems:\n\n");
545   for (i = 1, ts++; i < LS_LAST; i++, ts++) {
546     printf("  %-15s %s\n", ts->name, _(ts->desc));
547   }
548   exit(0);
549 }
550 
551 /**
552  *
553  */
554 static inline time_t
gdispatch_clock_update(void)555 gdispatch_clock_update(void)
556 {
557   time_t now = time(NULL);
558   atomic_set_time_t(&__gdispatch_clock, now);
559   return now;
560 }
561 
562 /**
563  *
564  */
565 static int64_t
mdispatch_clock_update(void)566 mdispatch_clock_update(void)
567 {
568   int64_t mono = getmonoclock();
569 
570   if (mono > atomic_get_s64(&mtimer_periodic)) {
571     atomic_set_s64(&mtimer_periodic, mono + MONOCLOCK_RESOLUTION);
572     gdispatch_clock_update(); /* gclk() update */
573     comet_flush(); /* Flush idle comet mailboxes */
574   }
575 
576   atomic_set_s64(&__mdispatch_clock, mono);
577   return mono;
578 }
579 
580 /**
581  *
582  */
583 static void *
mtimer_tick_thread(void * aux)584 mtimer_tick_thread(void *aux)
585 {
586   while (tvheadend_is_running()) {
587     /* update clocks each 10x in one second */
588     atomic_set_s64(&__mdispatch_clock, getmonoclock());
589     tvh_safe_usleep(100000);
590   }
591   return NULL;
592 }
593 
594 /**
595  *
596  */
597 static void *
mtimer_thread(void * aux)598 mtimer_thread(void *aux)
599 {
600   mtimer_t *mti;
601   mti_callback_t *cb;
602   int64_t now, next;
603 #if ENABLE_GTIMER_CHECK
604   int64_t mtm;
605   const char *id;
606   const char *fcn;
607 #endif
608 
609   while (tvheadend_is_running()) {
610     now = mdispatch_clock_update();
611 
612     /* Global monoclock timers */
613     pthread_mutex_lock(&global_lock);
614 
615     next = now + sec2mono(3600);
616 
617     while((mti = LIST_FIRST(&mtimers)) != NULL) {
618 
619       if (mti->mti_expire > now) {
620         next = mti->mti_expire;
621         break;
622       }
623 
624 #if ENABLE_GTIMER_CHECK
625       mtm = getmonoclock();
626       id = mti->mti_id;
627       fcn = mti->mti_fcn;
628 #endif
629       cb = mti->mti_callback;
630 
631       LIST_REMOVE(mti, mti_link);
632       mti->mti_callback = NULL;
633 
634       cb(mti->mti_opaque);
635 
636 #if ENABLE_GTIMER_CHECK
637       mtm = getmonoclock() - mtm;
638       if (mtm > 10000)
639         tvhtrace(LS_MTIMER, "%s:%s duration %"PRId64"us", id, fcn, mtm);
640 #endif
641     }
642 
643     /* Periodic updates */
644     if (next > mtimer_periodic)
645       next = mtimer_periodic;
646 
647     /* Wait */
648     tvh_cond_timedwait(&mtimer_cond, &global_lock, next);
649     pthread_mutex_unlock(&global_lock);
650   }
651 
652   return NULL;
653 }
654 
655 /**
656  *
657  */
658 static void
mainloop(void)659 mainloop(void)
660 {
661   gtimer_t *gti;
662   gti_callback_t *cb;
663   time_t now;
664   struct timespec ts;
665 #if ENABLE_GTIMER_CHECK
666   int64_t mtm;
667   const char *id;
668   const char *fcn;
669 #endif
670 
671   while (tvheadend_is_running()) {
672     now = gdispatch_clock_update();
673     ts.tv_sec  = now + 3600;
674     ts.tv_nsec = 0;
675 
676     /* Global timers */
677     pthread_mutex_lock(&global_lock);
678 
679     // TODO: there is a risk that if timers re-insert themselves to
680     //       the top of the list with a 0 offset we could loop indefinitely
681 
682 #if 0
683     tvhdebug(LS_GTIMER, "now %"PRItime_t, ts.tv_sec);
684     LIST_FOREACH(gti, &gtimers, gti_link)
685       tvhdebug(LS_GTIMER, "  gti %p expire %"PRItimet, gti, gti->gti_expire.tv_sec);
686 #endif
687 
688     while((gti = LIST_FIRST(&gtimers)) != NULL) {
689 
690       if (gti->gti_expire > now) {
691         ts.tv_sec = gti->gti_expire;
692         break;
693       }
694 
695 #if ENABLE_GTIMER_CHECK
696       mtm = getmonoclock();
697       id = gti->gti_id;
698       fcn = gti->gti_fcn;
699 #endif
700       cb = gti->gti_callback;
701 
702       LIST_REMOVE(gti, gti_link);
703       gti->gti_callback = NULL;
704 
705       cb(gti->gti_opaque);
706 
707 #if ENABLE_GTIMER_CHECK
708       mtm = getmonoclock() - mtm;
709       if (mtm > 10000)
710         tvhtrace(LS_GTIMER, "%s:%s duration %"PRId64"us", id, fcn, mtm);
711 #endif
712     }
713 
714     /* Wait */
715     pthread_cond_timedwait(&gtimer_cond, &global_lock, &ts);
716     pthread_mutex_unlock(&global_lock);
717   }
718 }
719 
720 
721 /**
722  *
723  */
724 int
main(int argc,char ** argv)725 main(int argc, char **argv)
726 {
727   int i;
728   sigset_t set;
729 #if ENABLE_MPEGTS
730   uint32_t adapter_mask = 0;
731 #endif
732   int  log_level   = LOG_INFO;
733   int  log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG;
734   const char *log_debug = NULL, *log_trace = NULL;
735   gid_t gid = -1;
736   uid_t uid = -1;
737   char buf[512];
738   FILE *pidfile = NULL;
739   static struct {
740     void *thread_id;
741     struct timeval tv;
742     uint8_t ru[32];
743   } randseed;
744   struct rlimit rl;
745   extern int dvb_bouquets_parse;
746 
747   main_tid = pthread_self();
748 
749   /* Setup global mutexes */
750   pthread_mutex_init(&fork_lock, NULL);
751   pthread_mutex_init(&global_lock, NULL);
752   pthread_mutex_init(&tasklet_lock, NULL);
753   pthread_mutex_init(&atomic_lock, NULL);
754   tvh_cond_init(&mtimer_cond);
755   pthread_cond_init(&gtimer_cond, NULL);
756   tvh_cond_init(&tasklet_cond);
757   TAILQ_INIT(&tasklets);
758 
759   /* Defaults */
760   tvheadend_webui_port      = 9981;
761   tvheadend_webroot         = NULL;
762   tvheadend_htsp_port       = 9982;
763   tvheadend_htsp_port_extra = 0;
764   __mdispatch_clock = getmonoclock();
765   __gdispatch_clock = time(NULL);
766 
767   /* Command line options */
768   int         opt_help         = 0,
769               opt_version      = 0,
770               opt_fork         = 0,
771               opt_firstrun     = 0,
772               opt_stderr       = 0,
773               opt_nostderr     = 0,
774               opt_syslog       = 0,
775               opt_nosyslog     = 0,
776               opt_uidebug      = 0,
777               opt_abort        = 0,
778               opt_noacl        = 0,
779               opt_fileline     = 0,
780               opt_threadid     = 0,
781               opt_libav        = 0,
782               opt_ipv6         = 0,
783               opt_nosatip      = 0,
784               opt_satip_rtsp   = 0,
785 #if ENABLE_TSFILE
786               opt_tsfile_tuner = 0,
787 #endif
788               opt_dump         = 0,
789               opt_xspf         = 0,
790               opt_dbus         = 0,
791               opt_dbus_session = 0,
792               opt_nobackup     = 0,
793               opt_nobat        = 0,
794               opt_subsystems   = 0;
795   const char *opt_config       = NULL,
796              *opt_user         = NULL,
797              *opt_group        = NULL,
798              *opt_logpath      = NULL,
799              *opt_log_debug    = NULL,
800              *opt_log_trace    = NULL,
801              *opt_pidpath      = "/var/run/tvheadend.pid",
802 #if ENABLE_LINUXDVB
803              *opt_dvb_adapters = NULL,
804 #endif
805              *opt_bindaddr     = NULL,
806              *opt_subscribe    = NULL,
807              *opt_user_agent   = NULL,
808              *opt_satip_bindaddr = NULL;
809   static char *__opt_satip_xml[10];
810   str_list_t  opt_satip_xml    = { .max = 10, .num = 0, .str = __opt_satip_xml };
811   static char *__opt_satip_tsfile[10];
812   str_list_t  opt_tsfile       = { .max = 10, .num = 0, .str = __opt_satip_tsfile };
813   cmdline_opt_t cmdline_opts[] = {
814     {   0, NULL,        N_("Generic options"),         OPT_BOOL, NULL         },
815     { 'h', "help",      N_("Show this page"),          OPT_BOOL, &opt_help    },
816     { 'v', "version",   N_("Show version information"),OPT_BOOL, &opt_version },
817 
818     {   0, NULL,        N_("Service configuration"),   OPT_BOOL, NULL         },
819     { 'c', "config",    N_("Alternate configuration path"), OPT_STR,  &opt_config  },
820     { 'B', "nobackup",  N_("Don't backup configuration tree at upgrade"), OPT_BOOL, &opt_nobackup },
821     { 'f', "fork",      N_("Fork and run as daemon"),  OPT_BOOL, &opt_fork    },
822     { 'u', "user",      N_("Run as user"),             OPT_STR,  &opt_user    },
823     { 'g', "group",     N_("Run as group"),            OPT_STR,  &opt_group   },
824     { 'p', "pid",       N_("Alternate PID path"),      OPT_STR,  &opt_pidpath },
825     { 'C', "firstrun",  N_("If no user account exists then create one with\n"
826 	                   "no username and no password. Use with care as\n"
827 	                   "it will allow world-wide administrative access\n"
828 	                   "to your Tvheadend installation until you create or edit\n"
829 	                   "the access control from within the Tvheadend web interface."),
830       OPT_BOOL, &opt_firstrun },
831 #if ENABLE_DBUS_1
832     { 'U', "dbus",      N_("Enable DBus"),
833       OPT_BOOL, &opt_dbus },
834     { 'e', "dbus_session", N_("DBus - use the session message bus instead of the system one"),
835       OPT_BOOL, &opt_dbus_session },
836 #endif
837 #if ENABLE_LINUXDVB
838     { 'a', "adapters",  N_("Only use specified DVB adapters (comma-separated, -1 = none)"),
839       OPT_STR, &opt_dvb_adapters },
840 #endif
841 #if ENABLE_SATIP_SERVER
842     {   0, "satip_bindaddr", N_("Specify bind address for SAT>IP server"),
843       OPT_STR, &opt_satip_bindaddr },
844     {   0, "satip_rtsp", N_("SAT>IP RTSP port number for server\n"
845                             "(default: -1 = disable, 0 = webconfig, standard port is 554)"),
846       OPT_INT, &opt_satip_rtsp },
847 #endif
848 #if ENABLE_SATIP_CLIENT
849     {   0, "nosatip",    N_("Disable SAT>IP client"),
850       OPT_BOOL, &opt_nosatip },
851     {   0, "satip_xml",  N_("URL with the SAT>IP server XML location"),
852       OPT_STR_LIST, &opt_satip_xml },
853 #endif
854     {   0, NULL,         N_("Server connectivity"),    OPT_BOOL, NULL         },
855     { '6', "ipv6",       N_("Listen on IPv6"),         OPT_BOOL, &opt_ipv6    },
856     { 'b', "bindaddr",   N_("Specify bind address"),   OPT_STR,  &opt_bindaddr},
857     {   0, "http_port",  N_("Specify alternative http port"),
858       OPT_INT, &tvheadend_webui_port },
859     {   0, "http_root",  N_("Specify alternative http webroot"),
860       OPT_STR, &tvheadend_webroot },
861     {   0, "htsp_port",  N_("Specify alternative htsp port"),
862       OPT_INT, &tvheadend_htsp_port },
863     {   0, "htsp_port2", N_("Specify extra htsp port"),
864       OPT_INT, &tvheadend_htsp_port_extra },
865     {   0, "useragent",  N_("Specify User-Agent header for the http client"),
866       OPT_STR, &opt_user_agent },
867     {   0, "xspf",       N_("Use XSPF playlist instead of M3U"),
868       OPT_BOOL, &opt_xspf },
869 
870     {   0, NULL,        N_("Debug options"),           OPT_BOOL, NULL         },
871     { 'd', "stderr",    N_("Enable debug on stderr"),  OPT_BOOL, &opt_stderr  },
872     { 'n', "nostderr",  N_("Disable debug on stderr"), OPT_BOOL, &opt_nostderr },
873     { 's', "syslog",    N_("Enable debug to syslog"),  OPT_BOOL, &opt_syslog  },
874     { 'S', "nosyslog",  N_("Disable syslog (all messages)"), OPT_BOOL, &opt_nosyslog },
875     { 'l', "logfile",   N_("Enable debug to file"),    OPT_STR,  &opt_logpath },
876     {   0, "debug",     N_("Enable debug subsystems"),  OPT_STR,  &opt_log_debug },
877 #if ENABLE_TRACE
878     {   0, "trace",     N_("Enable trace subsystems"), OPT_STR,  &opt_log_trace },
879 #endif
880     {   0, "subsystems",N_("List subsystems"),         OPT_BOOL, &opt_subsystems },
881     {   0, "fileline",  N_("Add file and line numbers to debug"), OPT_BOOL, &opt_fileline },
882     {   0, "threadid",  N_("Add the thread ID to debug"), OPT_BOOL, &opt_threadid },
883 #if ENABLE_LIBAV
884     {   0, "libav",     N_("More verbose libav log"),  OPT_BOOL, &opt_libav },
885 #endif
886     {   0, "uidebug",   N_("Enable web UI debug (non-minified JS)"), OPT_BOOL, &opt_uidebug },
887     { 'A', "abort",     N_("Immediately abort"),       OPT_BOOL, &opt_abort   },
888     { 'D', "dump",      N_("Enable coredumps for daemon"), OPT_BOOL, &opt_dump },
889     {   0, "noacl",     N_("Disable all access control checks"),
890       OPT_BOOL, &opt_noacl },
891     {   0, "nobat",     N_("Disable DVB bouquets"),
892       OPT_BOOL, &opt_nobat },
893     { 'j', "join",      N_("Subscribe to a service permanently"),
894       OPT_STR, &opt_subscribe },
895 
896 
897 #if ENABLE_TSFILE || ENABLE_TSDEBUG
898     { 0, NULL, N_("Testing options"), OPT_BOOL, NULL },
899     { 0, "tsfile_tuners", N_("Number of tsfile tuners"), OPT_INT, &opt_tsfile_tuner },
900     { 0, "tsfile", N_("tsfile input (mux file)"), OPT_STR_LIST, &opt_tsfile },
901 #endif
902 #if ENABLE_TSDEBUG
903     { 0, "tsdebug", N_("Output directory for tsdebug"), OPT_STR, &tvheadend_tsdebug },
904 #endif
905 
906   };
907 
908   /* Get current directory */
909   tvheadend_cwd0 = dirname(tvh_strdupa(argv[0]));
910   tvheadend_cwd = dirname(tvh_strdupa(tvheadend_cwd0));
911 
912   /* Set locale */
913   setlocale(LC_ALL, "");
914   setlocale(LC_NUMERIC, "C");
915   tvh_gettext_init();
916 
917   /* make sure the timezone is set */
918   tzset();
919 
920   /* Process command line */
921   for (i = 1; i < argc; i++) {
922 
923     /* Find option */
924     cmdline_opt_t *opt
925       = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]);
926     if (!opt) {
927       show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
928                  _("invalid option specified [%s]"), argv[i]);
929       continue;
930     }
931 
932     /* Process */
933     if (opt->type == OPT_BOOL)
934       *((int*)opt->param) = 1;
935     else if (++i == argc)
936       show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
937                  _("option %s requires a value"), opt->lopt);
938     else if (opt->type == OPT_INT)
939       *((int*)opt->param) = atoi(argv[i]);
940     else if (opt->type == OPT_STR_LIST) {
941       str_list_t *strl = opt->param;
942       if (strl->num < strl->max)
943         strl->str[strl->num++] = argv[i];
944     }
945     else
946       *((char**)opt->param) = argv[i];
947 
948     /* Stop processing */
949     if (opt_help)
950       show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL);
951     if (opt_version)
952       show_version(argv[0]);
953     if (opt_subsystems)
954       show_subsystems(argv[0]);
955   }
956 
957   /* Additional cmdline processing */
958   if (opt_nobat)
959     dvb_bouquets_parse = 0;
960 #if ENABLE_LINUXDVB
961   if (!opt_dvb_adapters) {
962     adapter_mask = ~0;
963   } else {
964     char *p, *e;
965     char *r = NULL;
966     char *dvb_adapters = strdup(opt_dvb_adapters);
967     adapter_mask = 0x0;
968     i = 0;
969     p = strtok_r(dvb_adapters, ",", &r);
970     while (p) {
971       int a = strtol(p, &e, 10);
972       if (*e != 0 || a > 31) {
973         fprintf(stderr, _("Invalid adapter number '%s'\n"), p);
974         free(dvb_adapters);
975         return 1;
976       }
977       i = 1;
978       if (a < 0)
979         adapter_mask = 0;
980       else
981         adapter_mask |= (1 << a);
982       p = strtok_r(NULL, ",", &r);
983     }
984     free(dvb_adapters);
985     if (!i) {
986       fprintf(stderr, "%s", _("No adapters specified!\n"));
987       return 1;
988     }
989   }
990 #endif
991   if (tvheadend_webroot) {
992     char *tmp;
993     if (*tvheadend_webroot == '/')
994       tmp = strdup(tvheadend_webroot);
995     else {
996       tmp = malloc(strlen(tvheadend_webroot)+2);
997       *tmp = '/';
998       strcpy(tmp+1, tvheadend_webroot);
999     }
1000     if (tmp[strlen(tmp)-1] == '/')
1001       tmp[strlen(tmp)-1] = '\0';
1002     tvheadend_webroot = tmp;
1003   }
1004   tvheadend_webui_debug = opt_uidebug;
1005 
1006   /* Setup logging */
1007   if (isatty(2))
1008     log_options |= TVHLOG_OPT_DECORATE;
1009   if (opt_stderr || opt_syslog || opt_logpath) {
1010     if (!opt_log_trace && !opt_log_debug)
1011       log_debug      = "all";
1012     log_level      = LOG_DEBUG;
1013     if (opt_stderr)
1014       log_options   |= TVHLOG_OPT_DBG_STDERR;
1015     if (opt_syslog)
1016       log_options   |= TVHLOG_OPT_DBG_SYSLOG;
1017     if (opt_logpath)
1018       log_options   |= TVHLOG_OPT_DBG_FILE;
1019   }
1020   if (opt_nostderr)
1021     log_options &= ~(TVHLOG_OPT_DECORATE|TVHLOG_OPT_STDERR|TVHLOG_OPT_DBG_STDERR);
1022   if (opt_nosyslog)
1023     log_options &= ~(TVHLOG_OPT_SYSLOG|TVHLOG_OPT_DBG_SYSLOG);
1024   if (opt_fileline)
1025     log_options |= TVHLOG_OPT_FILELINE;
1026   if (opt_threadid)
1027     log_options |= TVHLOG_OPT_THREAD;
1028   if (opt_libav)
1029     log_options |= TVHLOG_OPT_LIBAV;
1030   if (opt_log_trace) {
1031     log_level  = LOG_TRACE;
1032     log_trace  = opt_log_trace;
1033   }
1034   if (opt_log_debug)
1035     log_debug  = opt_log_debug;
1036 
1037   tvhlog_init(log_level, log_options, opt_logpath);
1038   tvhlog_set_debug(log_debug);
1039   tvhlog_set_trace(log_trace);
1040   tvhinfo(LS_MAIN, "Log started");
1041 
1042   signal(SIGPIPE, handle_sigpipe); // will be redundant later
1043   signal(SIGILL, handle_sigill);   // see handler..
1044 
1045   /* Set priviledges */
1046   if((opt_fork && getuid() == 0) || opt_group || opt_user) {
1047     const char *homedir;
1048     struct group  *grp = getgrnam(opt_group ?: "video");
1049     struct passwd *pw  = getpwnam(opt_user ?: "daemon");
1050 
1051     if(grp != NULL) {
1052       gid = grp->gr_gid;
1053     } else {
1054       gid = 1;
1055     }
1056 
1057     if (pw != NULL) {
1058       if (getuid() != pw->pw_uid) {
1059         gid_t glist[16];
1060         int gnum;
1061         gnum = get_user_groups(pw, glist, ARRAY_SIZE(glist));
1062         if (gnum > 0 && setgroups(gnum, glist)) {
1063           char buf[256] = "";
1064           int i;
1065           for (i = 0; i < gnum; i++)
1066             snprintf(buf + strlen(buf), sizeof(buf) - 1 - strlen(buf),
1067                      ",%d", glist[i]);
1068           tvhlog(LOG_ALERT, LS_START,
1069                  "setgroups(%s) failed, do you have permission?", buf+1);
1070           return 1;
1071         }
1072       }
1073       uid     = pw->pw_uid;
1074       homedir = pw->pw_dir;
1075       setenv("HOME", homedir, 1);
1076     } else {
1077       uid = 1;
1078     }
1079   }
1080 
1081   uuid_init();
1082   idnode_boot();
1083   config_boot(opt_config, gid, uid);
1084   tcp_server_preinit(opt_ipv6);
1085   http_server_init(opt_bindaddr);    // bind to ports only
1086   htsp_init(opt_bindaddr);	     // bind to ports only
1087   satip_server_init(opt_satip_bindaddr, opt_satip_rtsp); // bind to ports only
1088 
1089   if (opt_fork)
1090     pidfile = tvh_fopen(opt_pidpath, "w+");
1091 
1092   if (gid != -1 && (getgid() != gid) && setgid(gid)) {
1093     tvhlog(LOG_ALERT, LS_START,
1094            "setgid(%d) failed, do you have permission?", gid);
1095     return 1;
1096   }
1097   if (uid != -1 && (getuid() != uid) && setuid(uid)) {
1098     tvhlog(LOG_ALERT, LS_START,
1099            "setuid(%d) failed, do you have permission?", uid);
1100     return 1;
1101   }
1102 
1103   /* Daemonise */
1104   if(opt_fork) {
1105     if(daemon(0, 0)) {
1106       exit(2);
1107     }
1108     if(pidfile != NULL) {
1109       fprintf(pidfile, "%d\n", getpid());
1110       fclose(pidfile);
1111     }
1112 
1113     /* Make dumpable */
1114     if (opt_dump) {
1115       if (chdir("/tmp"))
1116         tvhwarn(LS_START, "failed to change cwd to /tmp");
1117 #ifdef PLATFORM_LINUX
1118       prctl(PR_SET_DUMPABLE, 1);
1119 #else
1120       tvhwarn(LS_START, "Coredumps not implemented on your platform");
1121 #endif
1122     }
1123 
1124     umask(0);
1125   }
1126 
1127   memset(&rl, 0, sizeof(rl));
1128   if (getrlimit(RLIMIT_STACK, &rl) || rl.rlim_cur < 2*1024*1024) {
1129     rlim_t rl2 = rl.rlim_cur;
1130     rl.rlim_cur = 2*1024*1024;
1131     if (setrlimit(RLIMIT_STACK, &rl)) {
1132       tvhlog(LOG_ALERT, LS_START, "too small stack size - %ld", (long)rl2);
1133       return 1;
1134     }
1135   }
1136 
1137   atomic_set(&tvheadend_running, 1);
1138 
1139   /* Start log thread (must be done post fork) */
1140   tvhlog_start();
1141 
1142   /* Alter logging */
1143   if (opt_fork)
1144     tvhlog_options &= ~TVHLOG_OPT_STDERR;
1145   if (!isatty(2))
1146     tvhlog_options &= ~TVHLOG_OPT_DECORATE;
1147 
1148   /* Initialise clock */
1149   pthread_mutex_lock(&global_lock);
1150   __mdispatch_clock = getmonoclock();
1151   __gdispatch_clock = time(NULL);
1152 
1153   /* Signal handling */
1154   sigfillset(&set);
1155   sigprocmask(SIG_BLOCK, &set, NULL);
1156   trap_init(argv[0]);
1157 
1158   /* SSL library init */
1159   OPENSSL_config(NULL);
1160   SSL_load_error_strings();
1161   SSL_library_init();
1162   /* Rand seed */
1163   randseed.thread_id = (void *)main_tid;
1164   gettimeofday(&randseed.tv, NULL);
1165   uuid_random(randseed.ru, sizeof(randseed.ru));
1166   RAND_seed(&randseed, sizeof(randseed));
1167 
1168   /* Initialise configuration */
1169   tvhftrace(LS_MAIN, notify_init);
1170   tvhftrace(LS_MAIN, spawn_init);
1171   tvhftrace(LS_MAIN, idnode_init);
1172   tvhftrace(LS_MAIN, config_init, opt_nobackup == 0);
1173 
1174   /* Memoryinfo */
1175   idclass_register(&memoryinfo_class);
1176   memoryinfo_register(&tasklet_memoryinfo);
1177 #if ENABLE_SLOW_MEMORYINFO
1178   memoryinfo_register(&htsmsg_memoryinfo);
1179   memoryinfo_register(&htsmsg_field_memoryinfo);
1180 #endif
1181   memoryinfo_register(&pkt_memoryinfo);
1182   memoryinfo_register(&pktbuf_memoryinfo);
1183   memoryinfo_register(&pktref_memoryinfo);
1184 
1185   /**
1186    * Initialize subsystems
1187    */
1188 
1189   epg_in_load = 1;
1190 
1191   tvhthread_create(&mtimer_tick_tid, NULL, mtimer_tick_thread, NULL, "mtick");
1192   tvhthread_create(&tasklet_tid, NULL, tasklet_thread, NULL, "tasklet");
1193 
1194   tvhftrace(LS_MAIN, streaming_init);
1195   tvhftrace(LS_MAIN, tvh_hardware_init);
1196   tvhftrace(LS_MAIN, dbus_server_init, opt_dbus, opt_dbus_session);
1197   tvhftrace(LS_MAIN, intlconv_init);
1198   tvhftrace(LS_MAIN, api_init);
1199   tvhftrace(LS_MAIN, fsmonitor_init);
1200   tvhftrace(LS_MAIN, libav_init);
1201   tvhftrace(LS_MAIN, tvhtime_init);
1202   tvhftrace(LS_MAIN, profile_init);
1203   tvhftrace(LS_MAIN, imagecache_init);
1204   tvhftrace(LS_MAIN, http_client_init, opt_user_agent);
1205   tvhftrace(LS_MAIN, esfilter_init);
1206   tvhftrace(LS_MAIN, bouquet_init);
1207   tvhftrace(LS_MAIN, service_init);
1208   tvhftrace(LS_MAIN, dvb_init);
1209 #if ENABLE_MPEGTS
1210   tvhftrace(LS_MAIN, mpegts_init, adapter_mask, opt_nosatip, &opt_satip_xml,
1211             &opt_tsfile, opt_tsfile_tuner);
1212 #endif
1213   tvhftrace(LS_MAIN, channel_init);
1214   tvhftrace(LS_MAIN, bouquet_service_resolve);
1215   tvhftrace(LS_MAIN, subscription_init);
1216   tvhftrace(LS_MAIN, dvr_config_init);
1217   tvhftrace(LS_MAIN, access_init, opt_firstrun, opt_noacl);
1218 #if ENABLE_TIMESHIFT
1219   tvhftrace(LS_MAIN, timeshift_init);
1220 #endif
1221   tvhftrace(LS_MAIN, tcp_server_init);
1222   tvhftrace(LS_MAIN, webui_init, opt_xspf);
1223 #if ENABLE_UPNP
1224   tvhftrace(LS_MAIN, upnp_server_init, opt_bindaddr);
1225 #endif
1226   tvhftrace(LS_MAIN, service_mapper_init);
1227   tvhftrace(LS_MAIN, descrambler_init);
1228   tvhftrace(LS_MAIN, epggrab_init);
1229   tvhftrace(LS_MAIN, epg_init);
1230   tvhftrace(LS_MAIN, dvr_init);
1231   tvhftrace(LS_MAIN, dbus_server_start);
1232   tvhftrace(LS_MAIN, http_server_register);
1233   tvhftrace(LS_MAIN, satip_server_register);
1234   tvhftrace(LS_MAIN, htsp_register);
1235 
1236   if(opt_subscribe != NULL)
1237     subscription_dummy_join(opt_subscribe, 1);
1238 
1239   tvhftrace(LS_MAIN, avahi_init);
1240   tvhftrace(LS_MAIN, bonjour_init);
1241 
1242   tvhftrace(LS_MAIN, epg_updated); // cleanup now all prev ref's should have been created
1243   epg_in_load = 0;
1244 
1245   pthread_mutex_unlock(&global_lock);
1246 
1247   /**
1248    * Wait for SIGTERM / SIGINT, but only in this thread
1249    */
1250 
1251   sigemptyset(&set);
1252   sigaddset(&set, SIGTERM);
1253   sigaddset(&set, SIGINT);
1254 
1255   signal(SIGTERM, doexit);
1256   signal(SIGINT, doexit);
1257 
1258   pthread_sigmask(SIG_UNBLOCK, &set, NULL);
1259 
1260   tvhlog(LOG_NOTICE, LS_START, "HTS Tvheadend version %s started, "
1261          "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s",
1262          tvheadend_version,
1263          getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)),
1264          hts_settings_get_root());
1265 
1266   if(opt_abort)
1267     abort();
1268 
1269   tvhthread_create(&mtimer_tid, NULL, mtimer_thread, NULL, "mtimer");
1270   mainloop();
1271   pthread_mutex_lock(&global_lock);
1272   tvh_cond_signal(&mtimer_cond, 0);
1273   pthread_mutex_unlock(&global_lock);
1274   pthread_join(mtimer_tid, NULL);
1275 
1276 #if ENABLE_DBUS_1
1277   tvhftrace(LS_MAIN, dbus_server_done);
1278 #endif
1279 #if ENABLE_UPNP
1280   tvhftrace(LS_MAIN, upnp_server_done);
1281 #endif
1282   tvhftrace(LS_MAIN, satip_server_done);
1283   tvhftrace(LS_MAIN, htsp_done);
1284   tvhftrace(LS_MAIN, http_server_done);
1285   tvhftrace(LS_MAIN, webui_done);
1286   tvhftrace(LS_MAIN, fsmonitor_done);
1287   tvhftrace(LS_MAIN, http_client_done);
1288   tvhftrace(LS_MAIN, tcp_server_done);
1289 
1290   // Note: the locking is obviously a bit redundant, but without
1291   //       we need to disable the gtimer_arm call in epg_save()
1292   pthread_mutex_lock(&global_lock);
1293   tvhftrace(LS_MAIN, epg_save);
1294 
1295 #if ENABLE_TIMESHIFT
1296   tvhftrace(LS_MAIN, timeshift_term);
1297 #endif
1298   pthread_mutex_unlock(&global_lock);
1299 
1300   tvhftrace(LS_MAIN, epggrab_done);
1301 #if ENABLE_MPEGTS
1302   tvhftrace(LS_MAIN, mpegts_done);
1303 #endif
1304   tvhftrace(LS_MAIN, dvr_done);
1305   tvhftrace(LS_MAIN, descrambler_done);
1306   tvhftrace(LS_MAIN, service_mapper_done);
1307   tvhftrace(LS_MAIN, service_done);
1308   tvhftrace(LS_MAIN, channel_done);
1309   tvhftrace(LS_MAIN, bouquet_done);
1310   tvhftrace(LS_MAIN, subscription_done);
1311   tvhftrace(LS_MAIN, access_done);
1312   tvhftrace(LS_MAIN, epg_done);
1313   tvhftrace(LS_MAIN, avahi_done);
1314   tvhftrace(LS_MAIN, bonjour_done);
1315   tvhftrace(LS_MAIN, imagecache_done);
1316   tvhftrace(LS_MAIN, lang_code_done);
1317   tvhftrace(LS_MAIN, api_done);
1318 
1319   tvhtrace(LS_MAIN, "tasklet enter");
1320   tvh_cond_signal(&tasklet_cond, 0);
1321   pthread_join(tasklet_tid, NULL);
1322   tvhtrace(LS_MAIN, "tasklet thread end");
1323   tasklet_flush();
1324   tvhtrace(LS_MAIN, "tasklet leave");
1325   tvhtrace(LS_MAIN, "mtimer tick thread join enter");
1326   pthread_join(mtimer_tick_tid, NULL);
1327   tvhtrace(LS_MAIN, "mtimer tick thread join leave");
1328 
1329   tvhftrace(LS_MAIN, dvb_done);
1330   tvhftrace(LS_MAIN, lang_str_done);
1331   tvhftrace(LS_MAIN, esfilter_done);
1332   tvhftrace(LS_MAIN, profile_done);
1333   tvhftrace(LS_MAIN, intlconv_done);
1334   tvhftrace(LS_MAIN, urlparse_done);
1335   tvhftrace(LS_MAIN, streaming_done);
1336   tvhftrace(LS_MAIN, idnode_done);
1337   tvhftrace(LS_MAIN, notify_done);
1338   tvhftrace(LS_MAIN, spawn_done);
1339 
1340   tvhlog(LOG_NOTICE, LS_STOP, "Exiting HTS Tvheadend");
1341   tvhlog_end();
1342 
1343   tvhftrace(LS_MAIN, config_done);
1344   tvhftrace(LS_MAIN, hts_settings_done);
1345 
1346   if(opt_fork)
1347     unlink(opt_pidpath);
1348 
1349   /* OpenSSL - welcome to the "cleanup" hell */
1350   ENGINE_cleanup();
1351   RAND_cleanup();
1352   CRYPTO_cleanup_all_ex_data();
1353   EVP_cleanup();
1354   CONF_modules_free();
1355 #if !defined(OPENSSL_NO_COMP)
1356   COMP_zlib_cleanup();
1357 #endif
1358   ERR_remove_state(0);
1359   ERR_free_strings();
1360 #if !defined(OPENSSL_NO_COMP) && OPENSSL_VERSION_NUMBER < 0x1010006f
1361   sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
1362 #endif
1363   /* end of OpenSSL cleanup code */
1364 
1365 #if ENABLE_DBUS_1
1366   extern void dbus_shutdown(void);
1367   if (opt_dbus) dbus_shutdown();
1368 #endif
1369   tvh_gettext_done();
1370   return 0;
1371 }
1372 
1373 /**
1374  *
1375  */
1376 void
tvh_str_set(char ** strp,const char * src)1377 tvh_str_set(char **strp, const char *src)
1378 {
1379   free(*strp);
1380   *strp = src ? strdup(src) : NULL;
1381 }
1382 
1383 
1384 /**
1385  *
1386  */
1387 int
tvh_str_update(char ** strp,const char * src)1388 tvh_str_update(char **strp, const char *src)
1389 {
1390   if(src == NULL)
1391     return 0;
1392   free(*strp);
1393   *strp = strdup(src);
1394   return 1;
1395 }
1396 
1397 
1398 /**
1399  *
1400  */
1401 void
scopedunlock(pthread_mutex_t ** mtxp)1402 scopedunlock(pthread_mutex_t **mtxp)
1403 {
1404   pthread_mutex_unlock(*mtxp);
1405 }
1406 
1407 
1408 /**
1409  *
1410  */
tvheadend_capabilities_list(int check)1411 htsmsg_t *tvheadend_capabilities_list(int check)
1412 {
1413   const tvh_caps_t *tc = tvheadend_capabilities;
1414   htsmsg_t *r = htsmsg_create_list();
1415   while (tc->name) {
1416     if (!check || !tc->enabled || *tc->enabled)
1417       htsmsg_add_str(r, NULL, tc->name);
1418     tc++;
1419   }
1420   if (config.caclient_ui)
1421     htsmsg_add_str(r, NULL, "caclient_advanced");
1422   return r;
1423 }
1424 
1425 /**
1426  *
1427  */
time_t_out_of_range_notify(int64_t val)1428 void time_t_out_of_range_notify(int64_t val)
1429 {
1430   tvherror(LS_MAIN, "time value out of range (%"PRId64") of time_t", val);
1431 }
1432