Esempio n. 1
0
int
main(int argc, char **argv)
{
  int c;
  int forkaway = 0;
  FILE *pidfile;
  const char *pidpath = "/var/run/tvheadend.pid";
  struct group *grp;
  struct passwd *pw;
  char *webroot;
  const char *usernam = NULL;
  const char *groupnam = NULL;
  int logfacility = LOG_DAEMON;
  int createdefault = 0;
  sigset_t set;
  const char *homedir;
  const char *rawts_input = NULL;
#if ENABLE_LINUXDVB
  const char *dvb_rawts_input = NULL;
#endif
  const char *join_transport = NULL;
  const char *confpath = NULL;
  char *p, *endp;
  uint32_t adapter_mask = 0xffffffff;
  int crash = 0;
  webui_port = 9981;
  htsp_port = 9982;
  gid_t gid;
  uid_t uid;

  /* Get current directory */
  tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0])));

  /* Set locale */
  setlocale(LC_ALL, "");

  // make sure the timezone is set
  tzset();

  while((c = getopt(argc, argv, "Aa:fp:u:g:c:Chdr:j:sw:e:E:R:W:")) != -1) {
    switch(c) {
    case 'a':
      adapter_mask = 0x0;
      p = strtok(optarg, ",");
      if (p != NULL) {
        do {
          int adapter = strtol(p, &endp, 10);
          if (*endp != 0 || adapter < 0 || adapter > 31) {
              fprintf(stderr, "Invalid adapter number '%s'\n", p);
              return 1;
          }
          adapter_mask |= (1 << adapter);
        } while ((p = strtok(NULL, ",")) != NULL);
        if (adapter_mask == 0x0) {
          fprintf(stderr, "No adapters specified!\n");
          return 1;
        }
      } else {
        usage(argv[0]);
      }
      break;
    case 'A':
      crash = 1;
      break;
    case 'f':
      forkaway = 1;
      break;
    case 'p':
      pidpath = optarg;
      break;
    case 'w':
      webui_port = atoi(optarg);
      break;
    case 'e':
      htsp_port = atoi(optarg);
      break;
    case 'E':
      htsp_port_extra = atoi(optarg);
      break;
    case 'u':
      usernam = optarg;
      break;
    case 'g':
      groupnam = optarg;
      break;
    case 'c':
      confpath = optarg;
      break;
    case 'd':
      log_debug_to_console = 1;
      break;
    case 's':
      log_debug_to_syslog = 1;
      break;
    case 'C':
      createdefault = 1;
      break;
    case 'r':
      rawts_input = optarg;
      break;
#if ENABLE_LINUXDVB
    case 'R':
      dvb_rawts_input = optarg;
      break;
#endif
    case 'j':
      join_transport = optarg;
      break;
    case 'W':
      webroot = malloc(strlen(optarg) + (*optarg == '/' ? 0 : 1));
      if (*optarg != '/') {
        *webroot = '/';
        strcpy(webroot+1, optarg);
      } else {
        strcpy(webroot, optarg);
      }
      if (webroot[strlen(webroot)-1] == '/')
        webroot[strlen(webroot)-1] = '\0';
      tvheadend_webroot = webroot;
      break;
    default:
      usage(argv[0]);
    }
  }

  signal(SIGPIPE, handle_sigpipe);

  log_stderr   = 1;
  log_decorate = isatty(2);

  if(forkaway) {
    grp  = getgrnam(groupnam ?: "video");
    pw   = usernam ? getpwnam(usernam) : NULL;

    pidfile = fopen(pidpath, "w+");

    if(grp != NULL) {
      gid = grp->gr_gid;
    } else {
      gid = 1;
    }

    if (pw != NULL) {
      if (getuid() != pw->pw_uid) {
        gid_t glist[10];
        int gnum;
        gnum = get_user_groups(pw, glist, 10);
        if (setgroups(gnum, glist)) {
          tvhlog(LOG_ALERT, "START", "setgroups() failed, do you have permission?");
          return 1;
        }
      }
      uid     = pw->pw_uid;
      homedir = pw->pw_dir;
      setenv("HOME", homedir, 1);
    } else {
      uid = 1;
    }
    if ((getgid() != gid) && setgid(gid)) {
      tvhlog(LOG_ALERT, "START", "setgid() failed, do you have permission?");
      return 1;
    }
    if ((getuid() != uid) && setuid(uid)) {
      tvhlog(LOG_ALERT, "START", "setuid() failed, do you have permission?");
      return 1;
    }

    if(daemon(0, 0)) {
      exit(2);
    }
    if(pidfile != NULL) {
      fprintf(pidfile, "%d\n", getpid());
      fclose(pidfile);
    }

    umask(0);
  }

  log_stderr = !forkaway;
  log_decorate = isatty(2);

  sigfillset(&set);
  sigprocmask(SIG_BLOCK, &set, NULL);

  openlog("tvheadend", LOG_PID, logfacility);

  hts_settings_init(confpath);

  pthread_mutex_init(&ffmpeg_lock, NULL);
  pthread_mutex_init(&fork_lock, NULL);
  pthread_mutex_init(&global_lock, NULL);

  pthread_mutex_lock(&global_lock);

  time(&dispatch_clock);

  trap_init(argv[0]);
  
  /**
   * Initialize subsystems
   */

  config_init();

  imagecache_init();

  service_init();

  channels_init();

  subscription_init();

  access_init(createdefault);

#if ENABLE_LINUXDVB
  muxes_init();
  dvb_init(adapter_mask, dvb_rawts_input);
#endif

  iptv_input_init();

#if ENABLE_V4L
  v4l_init();
#endif

  tcp_server_init();
  http_server_init();
  webui_init();

  serviceprobe_init();

#if ENABLE_CWC
  cwc_init();
  capmt_init();
#if (!ENABLE_DVBCSA)
  ffdecsa_init();
#endif
#endif

  epggrab_init();
  epg_init();

  dvr_init();

  htsp_init();

  if(rawts_input != NULL)
    rawts_init(rawts_input);

  if(join_transport != NULL)
    subscription_dummy_join(join_transport, 1);

#ifdef CONFIG_AVAHI
  avahi_init();
#endif

  epg_updated(); // cleanup now all prev ref's should have been created

  pthread_mutex_unlock(&global_lock);


  /**
   * Wait for SIGTERM / SIGINT, but only in this thread
   */

  running = 1;
  sigemptyset(&set);
  sigaddset(&set, SIGTERM);
  sigaddset(&set, SIGINT);

  signal(SIGTERM, doexit);
  signal(SIGINT, doexit);

  pthread_sigmask(SIG_UNBLOCK, &set, NULL);

  tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
	 "running as PID:%d UID:%d GID:%d, settings located in '%s'",
	 tvheadend_version,
	 getpid(), getuid(), getgid(), hts_settings_get_root());

  if(crash)
    abort();

  mainloop();

  epg_save();

  tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");

  if(forkaway)
    unlink("/var/run/tvheadend.pid");

  return 0;

}
Esempio n. 2
0
int
main(int argc, char **argv)
{
  int i;
  sigset_t set;
#if ENABLE_LINUXDVB
  uint32_t adapter_mask;
#endif

  /* Defaults */
  log_stderr                = 1;
  log_decorate              = isatty(2);
  log_debug_to_syslog       = 0;
  log_debug_to_console      = 0;
  log_debug_to_path         = 0;
  log_path                  = NULL;
  tvheadend_webui_port      = 9981;
  tvheadend_webroot         = NULL;
  tvheadend_htsp_port       = 9982;
  tvheadend_htsp_port_extra = 0;

  /* Command line options */
  int         opt_help         = 0,
              opt_version      = 0,
              opt_fork         = 0,
              opt_firstrun     = 0,
              opt_debug        = 0,
              opt_syslog       = 0,
              opt_uidebug      = 0,
              opt_abort        = 0,
              opt_noacl        = 0,
              opt_ipv6         = 0;
  const char *opt_config       = NULL,
             *opt_user         = NULL,
             *opt_group        = NULL,
             *opt_pidpath      = "/var/run/tvheadend.pid",
#if ENABLE_LINUXDVB
             *opt_dvb_adapters = NULL,
             *opt_dvb_raw      = NULL,
#endif
             *opt_rawts        = NULL,
             *opt_subscribe    = NULL;
  cmdline_opt_t cmdline_opts[] = {
    {   0, NULL,        "Generic Options",         OPT_BOOL, NULL         },
    { 'h', "help",      "Show this page",          OPT_BOOL, &opt_help    },
    { 'v', "version",   "Show version infomation", OPT_BOOL, &opt_version },

    {   0, NULL,        "Service Configuration",   OPT_BOOL, NULL         },
    { 'c', "config",    "Alternate config path",   OPT_STR,  &opt_config  },
    { 'f', "fork",      "Fork and run as daemon",  OPT_BOOL, &opt_fork    },
    { 'u', "user",      "Run as user",             OPT_STR,  &opt_user    },
    { 'g', "group",     "Run as group",            OPT_STR,  &opt_group   },
    { 'p', "pid",       "Alternate pid path",      OPT_STR,  &opt_pidpath },
    { 'C', "firstrun",  "If no useraccount exist then create one with\n"
	                      "no username and no password. Use with care as\n"
	                      "it will allow world-wide administrative access\n"
	                      "to your Tvheadend installation until you edit\n"
	                      "the access-control from within the Tvheadend UI",
      OPT_BOOL, &opt_firstrun },
#if ENABLE_LINUXDVB
    { 'a', "adapters",  "Use only specified DVB adapters",
      OPT_STR, &opt_dvb_adapters },
#endif
    {   0, NULL,         "Server Connectivity",    OPT_BOOL, NULL         },
    { '6', "ipv6",       "Listen on IPv6",         OPT_BOOL, &opt_ipv6    },
    {   0, "http_port",  "Specify alternative http port",
      OPT_INT, &tvheadend_webui_port },
    {   0, "http_root",  "Specify alternative http webroot",
      OPT_STR, &tvheadend_webroot },
    {   0, "htsp_port",  "Specify alternative htsp port",
      OPT_INT, &tvheadend_htsp_port },
    {   0, "htsp_port2", "Specify extra htsp port",
      OPT_INT, &tvheadend_htsp_port_extra },

    {   0, NULL,        "Debug Options",           OPT_BOOL, NULL         },
    { 'd', "debug",     "Enable all debug",        OPT_BOOL, &opt_debug   },
    { 's', "syslog",    "Enable debug to syslog",  OPT_BOOL, &opt_syslog  },
    {   0, "uidebug",   "Enable webUI debug",      OPT_BOOL, &opt_uidebug },
    { 'l', "log",       "Log to file",             OPT_STR,  &log_path    },
    { 'A', "abort",     "Immediately abort",       OPT_BOOL, &opt_abort   },
    {   0, "noacl",     "Disable all access control checks",
      OPT_BOOL, &opt_noacl },
#if ENABLE_LINUXDVB
    { 'R', "dvbraw",    "Use rawts file to create virtual adapter",
      OPT_STR, &opt_dvb_raw },
#endif
    { 'r', "rawts",     "Use rawts file to generate virtual services",
      OPT_STR, &opt_rawts },
    { 'j', "join",      "Subscribe to a service permanently",
      OPT_STR, &opt_subscribe }
  };

  /* Get current directory */
  tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0])));

  /* Set locale */
  setlocale(LC_ALL, "");

  /* make sure the timezone is set */
  tzset();

  /* Process command line */
  for (i = 1; i < argc; i++) {

    /* Find option */
    cmdline_opt_t *opt
      = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]);
    if (!opt)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 "invalid option specified [%s]", argv[i]);

    /* Process */
    if (opt->type == OPT_BOOL)
      *((int*)opt->param) = 1;
    else if (++i == argc)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 "option %s requires a value", opt->lopt);
    else if (opt->type == OPT_INT)
      *((int*)opt->param) = atoi(argv[i]);
    else
      *((char**)opt->param) = argv[i];

    /* Stop processing */
    if (opt_help)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL);
    if (opt_version)
      show_version(argv[0]);
  }

  /* Additional cmdline processing */
  log_debug_to_console  = opt_debug;
  log_debug_to_syslog   = opt_syslog;
  log_debug_to_path     = opt_debug;
  tvheadend_webui_debug = opt_debug || opt_uidebug;
  tvhlog(LOG_INFO, "START", "initialising");
#if ENABLE_LINUXDVB
  if (!opt_dvb_adapters) {
    adapter_mask = ~0;
  } else {
    char *p, *r, *e;
    adapter_mask = 0x0;
    p = strtok_r((char*)opt_dvb_adapters, ",", &r);
    while (p) {
      int a = strtol(p, &e, 10);
      if (*e != 0 || a < 0 || a > 31) {
        tvhlog(LOG_ERR, "START", "Invalid adapter number '%s'", p);
        return 1;
      }
      adapter_mask |= (1 << a);
      p = strtok_r(NULL, ",", &r);
    }
    if (!adapter_mask) {
      tvhlog(LOG_ERR, "START", "No adapters specified!");
      return 1;
    }
  }
#endif
  if (tvheadend_webroot) {
    char *tmp;
    if (*tvheadend_webroot == '/')
      tmp = strdup(tvheadend_webroot);
    else {
      tmp = malloc(strlen(tvheadend_webroot)+1);
      *tmp = '/';
      strcpy(tmp+1, tvheadend_webroot);
    }
    if (tmp[strlen(tmp)-1] == '/')
      tmp[strlen(tmp)-1] = '\0';
    tvheadend_webroot = tmp;
  }

  signal(SIGPIPE, handle_sigpipe); // will be redundant later

  /* Daemonise */
  if(opt_fork) {
    const char *homedir;
    gid_t gid;
    uid_t uid;
    struct group  *grp = getgrnam(opt_group ?: "video");
    struct passwd *pw  = opt_user ? getpwnam(opt_user) : NULL;
    FILE   *pidfile    = fopen(opt_pidpath, "w+");

    if(grp != NULL) {
      gid = grp->gr_gid;
    } else {
      gid = 1;
    }

    if (pw != NULL) {
      if (getuid() != pw->pw_uid) {
        gid_t glist[10];
        int gnum;
        gnum = get_user_groups(pw, glist, 10);
        if (setgroups(gnum, glist)) {
          tvhlog(LOG_ALERT, "START",
                 "setgroups() failed, do you have permission?");
          return 1;
        }
      }
      uid     = pw->pw_uid;
      homedir = pw->pw_dir;
      setenv("HOME", homedir, 1);
    } else {
      uid = 1;
    }
    if ((getgid() != gid) && setgid(gid)) {
      tvhlog(LOG_ALERT, "START",
             "setgid() failed, do you have permission?");
      return 1;
    }
    if ((getuid() != uid) && setuid(uid)) {
      tvhlog(LOG_ALERT, "START",
             "setuid() failed, do you have permission?");
      return 1;
    }

    if(daemon(0, 0)) {
      exit(2);
    }
    if(pidfile != NULL) {
      fprintf(pidfile, "%d\n", getpid());
      fclose(pidfile);
    }

    umask(0);
  }

  /* Setup logging */
  log_stderr   = !opt_fork;
  log_decorate = isatty(2);
  openlog("tvheadend", LOG_PID, LOG_DAEMON);

  /* Initialise configuration */
  hts_settings_init(opt_config);

  /* Setup global mutexes */
  pthread_mutex_init(&ffmpeg_lock, NULL);
  pthread_mutex_init(&fork_lock, NULL);
  pthread_mutex_init(&global_lock, NULL);
  pthread_mutex_lock(&global_lock);

  time(&dispatch_clock);

  /* Signal handling */
  sigfillset(&set);
  sigprocmask(SIG_BLOCK, &set, NULL);
  trap_init(argv[0]);
  
  /**
   * Initialize subsystems
   */

#if ENABLE_LIBAV
  libav_init();
#endif

  config_init();

  imagecache_init();

  service_init();

  channels_init();

  subscription_init();

  access_init(opt_firstrun, opt_noacl);

#if ENABLE_LINUXDVB
  muxes_init();
  dvb_init(adapter_mask, opt_dvb_raw);
#endif

  iptv_input_init();

#if ENABLE_V4L
  v4l_init();
#endif

#if ENABLE_TIMESHIFT
  timeshift_init();
#endif

  tcp_server_init(opt_ipv6);
  http_server_init();
  webui_init();

  serviceprobe_init();

#if ENABLE_CWC
  cwc_init();
  capmt_init();
#if (!ENABLE_DVBCSA)
  ffdecsa_init();
#endif
#endif

  epggrab_init();
  epg_init();

  dvr_init();

  htsp_init();

  if(opt_rawts != NULL)
    rawts_init(opt_rawts);

  if(opt_subscribe != NULL)
    subscription_dummy_join(opt_subscribe, 1);

#ifdef CONFIG_AVAHI
  avahi_init();
#endif

  epg_updated(); // cleanup now all prev ref's should have been created

  pthread_mutex_unlock(&global_lock);

  /**
   * Wait for SIGTERM / SIGINT, but only in this thread
   */

  running = 1;
  sigemptyset(&set);
  sigaddset(&set, SIGTERM);
  sigaddset(&set, SIGINT);

  signal(SIGTERM, doexit);
  signal(SIGINT, doexit);

  pthread_sigmask(SIG_UNBLOCK, &set, NULL);

  tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
	 "running as PID:%d UID:%d GID:%d, settings located in '%s'",
	 tvheadend_version,
	 getpid(), getuid(), getgid(), hts_settings_get_root());

  if(opt_abort)
    abort();

  mainloop();

  epg_save();

#if ENABLE_TIMESHIFT
  timeshift_term();
#endif

  tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");

  if(opt_fork)
    unlink(opt_pidpath);

  return 0;

}
Esempio n. 3
0
int
main(int argc, char **argv)
{
  int c;
  int forkaway = 0;
  FILE *pidfile;
  const char *pidpath = "/var/run/tvheadend.pid";
  struct group *grp;
  struct passwd *pw;
  const char *usernam = NULL;
  const char *groupnam = NULL;
  int logfacility = LOG_DAEMON;
  int createdefault = 0;
  sigset_t set;
  const char *homedir;
  const char *rawts_input = NULL;
  const char *join_transport = NULL;
  const char *confpath = NULL;
  char *p, *endp;
  uint32_t adapter_mask = 0xffffffff;
  int crash = 0;

  // make sure the timezone is set
  tzset();

  while((c = getopt(argc, argv, "Aa:fp:u:g:c:Chdr:j:s")) != -1) {
    switch(c) {
    case 'a':
      adapter_mask = 0x0;
      p = strtok(optarg, ",");
      if (p != NULL) {
        do {
          int adapter = strtol(p, &endp, 10);
          if (*endp != 0 || adapter < 0 || adapter > 31) {
              fprintf(stderr, "Invalid adapter number '%s'\n", p);
              return 1;
          }
          adapter_mask |= (1 << adapter);
        } while ((p = strtok(NULL, ",")) != NULL);
        if (adapter_mask == 0x0) {
          fprintf(stderr, "No adapters specified!\n");
          return 1;
        }
      } else {
        usage(argv[0]);
      }
      break;
    case 'A':
      crash = 1;
      break;
    case 'f':
      forkaway = 1;
      break;
    case 'p':
      pidpath = optarg;
      break;
    case 'u':
      usernam = optarg;
      break;
    case 'g':
      groupnam = optarg;
      break;
    case 'c':
      confpath = optarg;
      break;
    case 'd':
      log_debug_to_console = 1;
      break;
    case 's':
      log_debug_to_syslog = 1;
      break;
    case 'C':
      createdefault = 1;
      break;
    case 'r':
      rawts_input = optarg;
      break;
    case 'j':
      join_transport = optarg;
      break;
    default:
      usage(argv[0]);
      break;
    }
  }

  signal(SIGPIPE, handle_sigpipe);

  grp = getgrnam(groupnam ?: "video");
  pw = usernam ? getpwnam(usernam) : NULL;


  if(forkaway) {

    if(daemon(0, 0)) {
      exit(2);
    }
    pidfile = fopen(pidpath, "w+");
    if(pidfile != NULL) {
      fprintf(pidfile, "%d\n", getpid());
      fclose(pidfile);
    }

   if(grp != NULL) {
      setgid(grp->gr_gid);
    } else {
      setgid(1);
    }

   if(pw != NULL) {
      setuid(pw->pw_uid);
    } else {
      setuid(1);
    }

   if(pw != NULL) {
     homedir = pw->pw_dir;
     setenv("HOME", homedir, 1);
   }

    umask(0);
  }

  log_stderr = !forkaway;
  log_decorate = isatty(2);

  sigfillset(&set);
  sigprocmask(SIG_BLOCK, &set, NULL);

  openlog("tvheadend", LOG_PID, logfacility);

  hts_settings_init(confpath);

  pthread_mutex_init(&ffmpeg_lock, NULL);
  pthread_mutex_init(&fork_lock, NULL);
  pthread_mutex_init(&global_lock, NULL);

  pthread_mutex_lock(&global_lock);

  time(&dispatch_clock);

  trap_init(argv[0]);
  
  /**
   * Initialize subsystems
   */
  xmltv_init();   /* Must be initialized before channels */

  service_init();

  channels_init();

  access_init(createdefault);

  tcp_server_init();
#if ENABLE_LINUXDVB
  dvb_init(adapter_mask);
#endif
  iptv_input_init();
#if ENABLE_V4L
  v4l_init();
#endif
  http_server_init();

  webui_init(tvheadend_dataroot());

  serviceprobe_init();

  cwc_init();

  capmt_init();

  epg_init();

  dvr_init();

  htsp_init();

  ffdecsa_init();
  
  if(rawts_input != NULL)
    rawts_init(rawts_input);

  if(join_transport != NULL)
    subscription_dummy_join(join_transport, 1);

#ifdef CONFIG_AVAHI
  avahi_init();
#endif

  pthread_mutex_unlock(&global_lock);


  /**
   * Wait for SIGTERM / SIGINT, but only in this thread
   */

  running = 1;
  sigemptyset(&set);
  sigaddset(&set, SIGTERM);
  sigaddset(&set, SIGINT);

  signal(SIGTERM, doexit);
  signal(SIGINT, doexit);

  pthread_sigmask(SIG_UNBLOCK, &set, NULL);

  tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
	 "running as PID:%d UID:%d GID:%d, settings located in '%s', "
	 "dataroot: %s",
	 tvheadend_version,
	 getpid(), getuid(), getgid(), hts_settings_get_root(),
	 tvheadend_dataroot() ?: "<Embedded file system>");

  if(crash)
    abort();

  mainloop();

  epg_save();

  tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");

  if(forkaway)
    unlink("/var/run/tvheadend.pid");

  return 0;

}