int main()

in common/recipes-core/rackmon/rackmon/rackmond.c [1902:2076]


int main(int argc, char** argv) {
  int error = 0;
  int sock = -1;
  pthread_t monitoring_tid;
  sigset_t new_mask, old_mask;
  struct sockaddr_un client;

  if (single_instance_lock(DAEMON_NAME) < 0) {
    fprintf(stderr, "Another %s instance is running. Exiting!\n",
            DAEMON_NAME);
    return -1;
  }

  obmc_log_init(DAEMON_NAME, LOG_INFO, 0);
  obmc_log_set_syslog(LOG_CONS, LOG_DAEMON);
  if (getenv("RACKMOND_FOREGROUND") == NULL) {
    obmc_log_unset_std_stream();
    if (daemon(0, 0) < 0)
      OBMC_ERROR(errno, "daemon error");
  }

#ifdef RACKMON_PROFILING
  OBMC_INFO("ticks_per_sec: %ld", sysconf(_SC_CLK_TCK));
#endif /* RACKMON_PROFILING */

  if (signal_handler_init() != 0)
    return -1;

  if (getenv("RACKMOND_TIMEOUT") != NULL) {
    rackmond_config.modbus_timeout = atoll(getenv("RACKMOND_TIMEOUT"));
    OBMC_INFO("set timeout to RACKMOND_TIMEOUT (%dms)",
              rackmond_config.modbus_timeout / 1000);
  }
  if (getenv("RACKMOND_MIN_DELAY") != NULL) {
    rackmond_config.min_delay = atoll(getenv("RACKMOND_MIN_DELAY"));
    OBMC_INFO("set mindelay to RACKMOND_MIN_DELAY(%dus)",
              rackmond_config.min_delay);
  }
  verbose = getenv("RACKMOND_VERBOSE") != NULL ? 1 : 0;

  if (getenv("RACKMOND_MULTI_PORT") != NULL){
    rackmond_config.multi_port = 1;
    OBMC_INFO("set RACKMOND_MULTI_PORT to %d, for FT4232",
                rackmond_config.multi_port);
  } else {
    rackmond_config.multi_port = 0;
    OBMC_INFO("set RACKMOND_MULTI_PORT to %d, for FT232",
                rackmond_config.multi_port);
  }

    if (getenv("RACKMOND_SWAP_ADDR") != NULL){
    rackmond_config.swap_addr = 1;
    OBMC_INFO("set RACKMOND_SWAP_ADDR to %d, for W400 MP Respin",
                rackmond_config.multi_port);
  } else {
    rackmond_config.swap_addr = 0;
    OBMC_INFO("set RACKMOND_SWAP_ADDR to %d.",
                rackmond_config.multi_port);
  }

  if (getenv("RACKMOND_DESIRED_BAUDRATE") != NULL) {
    int parsed_baudrate_int = atoi(getenv("RACKMOND_DESIRED_BAUDRATE"));
    rackmond_config.desired_baudrate = int_to_baudrate(parsed_baudrate_int);
    OBMC_INFO("set desired baudrate value to RACKMOND_DESIRED_BAUDRATE (%d -> %s)",
              parsed_baudrate_int,
              baud_to_str(rackmond_config.desired_baudrate));
  }
  if (getenv("RACKMOND_IGNORE_PSUS") != NULL) {
    char *ignore_list = strdup(getenv("RACKMOND_IGNORE_PSUS"));
    if (ignore_list) {
      char *psu_str;
      for (psu_str = strtok(ignore_list, ",");
          psu_str != NULL;
          psu_str = strtok(NULL, ",")) {
        unsigned int psu_addr = strtoul(psu_str, 0, 16);
        int rack, shelf, psu;
        if (!psu_location(psu_addr, &rack, &shelf, &psu)) {
          rackmond_config.ignored_psus[rack][shelf][psu] = true;
          OBMC_INFO("Ignoring PSU: 0x%x\n", psu_addr);
        } else {
          OBMC_ERROR(EINVAL, "Unsupported PSU: 0x%x provided to RACKMOND_IGNORE_PSUS\n", psu_addr);
        }
      }
      free(ignore_list);
    }
  }

  OBMC_INFO("rackmon/modbus service starting");
  if (rackmon_plat_init() != 0) {
    return -1;
  }

  if (rackmond_config.multi_port) {
    if (rs485_device_init(DEFAULT_TTY1, &rackmond_config.rs485[0]) != 0) {
      error = -1;
      goto exit_rs485;
    }
    if (rs485_device_init(DEFAULT_TTY2, &rackmond_config.rs485[1]) != 0) {
      error = -1;
      goto exit_rs485;
    }
    if (rs485_device_init(DEFAULT_TTY3, &rackmond_config.rs485[2]) != 0) {
      error = -1;
      goto exit_rs485;
    }
  } else {
    if (rs485_device_init(DEFAULT_TTY, &rackmond_config.rs485[0]) != 0) {
      error = -1;
      goto exit_rs485;
    }
  }

  error = pthread_create(&monitoring_tid, NULL, monitoring_loop, NULL);
  if (error != 0) {
    OBMC_ERROR(error, "failed to create monitor loop thread");
    error = -1;
    goto exit_thread;
  }

  sock = user_socket_init(RACKMON_IPC_SOCKET);
  if (sock < 0) {
    goto exit_sock;
  }
  OBMC_INFO("rackmon is listening to user connections");

  /*
   * SIGINT and SIGTERM are blocked before testing "should_exit", and
   * they will be unblocked in pselect(): this is to prevent the race
   * when the signals were delivered right after testing "should_exit"
   * but before calling pselect().
   */
  sigemptyset(&new_mask);
  sigaddset(&new_mask, SIGINT);
  sigaddset(&new_mask, SIGTERM);
  sigprocmask(SIG_BLOCK, &new_mask, &old_mask);

  while (!should_exit) {
    int ret;
    fd_set rfds;
    socklen_t clisocklen = sizeof(struct sockaddr_un);

    FD_ZERO(&rfds);
    FD_SET(sock, &rfds);
    ret = pselect(sock + 1, &rfds, NULL, NULL, NULL, &old_mask);
    if (ret > 0 && FD_ISSET(sock, &rfds)) {
        int clisock = accept(sock, (struct sockaddr*)&client, &clisocklen);
        if (clisock < 0) {
          OBMC_ERROR(errno, "failed to accept new connection");
          continue;
        }

        handle_connection(clisock);
        close(clisock);
    }
  }

  close(sock); /* ignore errors */
  if (reset_psu_baudrate() != 0)
    error = -1;
exit_sock:
  pthread_cancel(monitoring_tid);     /* ignore errors */
  pthread_join(monitoring_tid, NULL); /* ignore errors */
exit_thread:
  if (rackmond_config.multi_port) {
    rs485_device_cleanup(&rackmond_config.rs485[0]);
    rs485_device_cleanup(&rackmond_config.rs485[1]);
    rs485_device_cleanup(&rackmond_config.rs485[2]);
  } else {
    rs485_device_cleanup(&rackmond_config.rs485[0]);
  }
exit_rs485:
  rackmon_plat_cleanup();
  OBMC_INFO("rackmon is terminated, exit code: %d", error);
  return error;
}