int main
(int argc, char **argv)
{
  const char *conf_file = DEFAULT_CONF_FILE;
  const char *progname = argv[0];
  char *user = NULL, *log_file = NULL;
  struct passwd *pw;
  int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
  int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = 0;
  int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
  int clock_control = 1, system_log = 1, log_severity = LOGS_INFO;
  int config_args = 0;

  do_platform_checks();

  LOG_Initialise();

  /* Parse (undocumented) long command-line options */
  for (optind = 1; optind < argc; optind++) {
    if (!strcmp("--help", argv[optind])) {
      print_help(progname);
      return 0;
    } else if (!strcmp("--version", argv[optind])) {
      print_version();
      return 0;
    }
  }

  optind = 1;

  /* Parse short command-line options */
  while ((opt = getopt(argc, argv, "46df:F:hl:L:mnP:qQrRst:u:vx")) != -1) {
    switch (opt) {
      case '4':
      case '6':
        address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
        break;
      case 'd':
        debug++;
        nofork = 1;
        system_log = 0;
        break;
      case 'f':
        conf_file = optarg;
        break;
      case 'F':
        scfilter_level = parse_int_arg(optarg);
        break;
      case 'l':
        log_file = optarg;
        break;
      case 'L':
        log_severity = parse_int_arg(optarg);
        break;
      case 'm':
        lock_memory = 1;
        break;
      case 'n':
        nofork = 1;
        break;
      case 'P':
        sched_priority = parse_int_arg(optarg);
        break;
      case 'q':
        ref_mode = REF_ModeUpdateOnce;
        nofork = 1;
        client_only = 0;
        system_log = 0;
        break;
      case 'Q':
        ref_mode = REF_ModePrintOnce;
        nofork = 1;
        client_only = 1;
        clock_control = 0;
        system_log = 0;
        break;
      case 'r':
        reload = 1;
        break;
      case 'R':
        restarted = 1;
        break;
      case 's':
        do_init_rtc = 1;
        break;
      case 't':
        timeout = parse_int_arg(optarg);
        break;
      case 'u':
        user = optarg;
        break;
      case 'v':
        print_version();
        return 0;
      case 'x':
        clock_control = 0;
        break;
      default:
        print_help(progname);
        return opt != 'h';
    }
  }

  if (getuid() && !client_only)
    LOG_FATAL("Not superuser");

  /* Turn into a daemon */
  if (!nofork) {
    go_daemon();
  }

  if (log_file) {
    LOG_OpenFileLog(log_file);
  } else if (system_log) {
    LOG_OpenSystemLog();
  }
  
  LOG_SetMinSeverity(debug >= 2 ? LOGS_DEBUG : log_severity);
  
  LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);

  DNS_SetAddressFamily(address_family);

  CNF_Initialise(restarted, client_only);

  /* Parse the config file or the remaining command line arguments */
  config_args = argc - optind;
  if (!config_args) {
    CNF_ReadFile(conf_file);
  } else {
    for (; optind < argc; optind++)
      CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
  }

  /* Check whether another chronyd may already be running */
  check_pidfile();

  if (!user)
    user = CNF_GetUser();

  pw = getpwnam(user);
  if (!pw)
    LOG_FATAL("Could not get user/group ID of %s", user);

  /* Create directories for sockets, log files, and dump files */
  CNF_CreateDirs(pw->pw_uid, pw->pw_gid);

  /* Write our pidfile to prevent other instances from running */
  write_pidfile();

  PRV_Initialise();
  LCL_Initialise();
  SCH_Initialise();
  SYS_Initialise(clock_control);
  RTC_Initialise(do_init_rtc);
  SRC_Initialise();
  RCL_Initialise();
  KEY_Initialise();
  SCK_Initialise();

  /* Open privileged ports before dropping root */
  CAM_Initialise(address_family);
  NIO_Initialise(address_family);
  NCR_Initialise();
  CNF_SetupAccessRestrictions();

  /* Command-line switch must have priority */
  if (!sched_priority) {
    sched_priority = CNF_GetSchedPriority();
  }
  if (sched_priority) {
    SYS_SetScheduler(sched_priority);
  }

  if (lock_memory || CNF_GetLockMemory()) {
    SYS_LockMemory();
  }

  /* Drop root privileges if the specified user has a non-zero UID */
  if (!geteuid() && (pw->pw_uid || pw->pw_gid))
    SYS_DropRoot(pw->pw_uid, pw->pw_gid);

  REF_Initialise();
  SST_Initialise();
  NSR_Initialise();
  NSD_Initialise();
  CLG_Initialise();
  MNL_Initialise();
  TMC_Initialise();
  SMT_Initialise();

  /* From now on, it is safe to do finalisation on exit */
  initialised = 1;

  UTI_SetQuitSignalsHandler(signal_cleanup, 1);

  CAM_OpenUnixSocket();

  if (scfilter_level)
    SYS_EnableSystemCallFilter(scfilter_level);

  if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
    ref_mode = REF_ModeInitStepSlew;
  }

  REF_SetModeEndHandler(reference_mode_end);
  REF_SetMode(ref_mode);

  if (timeout > 0)
    SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL);

  if (do_init_rtc) {
    RTC_TimeInit(post_init_rtc_hook, NULL);
  } else {
    post_init_rtc_hook(NULL);
  }

  /* The program normally runs under control of the main loop in
     the scheduler. */
  SCH_MainLoop();

  LOG(LOGS_INFO, "chronyd exiting");

  MAI_CleanupAndExit();

  return 0;
}