Example #1
0
/**
 * g_process_start:
 *
 * Start the process as directed by the options set by various
 * g_process_set_*() functions.
 **/
void
g_process_start(void)
{
  pid_t pid;

  g_process_detach_tty();
  g_process_change_limits();
  g_process_resolve_names();

  if (process_opts.mode == G_PM_BACKGROUND)
    {
      /* no supervisor, sends result to startup process directly */
      if (pipe(init_result_pipe) != 0)
        {
          g_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno));
          exit(1);
        }

      if ((pid = fork()) < 0)
        {
          g_process_message("Error forking child process; error='%s'", g_strerror(errno));
          exit(1);
        }
      else if (pid != 0)
        {
          /* shut down init_result_pipe write side */

          close(init_result_pipe[1]);

          /* connect startup_result_pipe with init_result_pipe */
          startup_result_pipe[0] = init_result_pipe[0];
          init_result_pipe[0] = -1;

          g_process_perform_startup();
          /* NOTE: never returns */
          g_assert_not_reached();
        }
      process_kind = G_PK_DAEMON;

      /* shut down init_result_pipe read side */
      close(init_result_pipe[0]);
      init_result_pipe[0] = -1;

      /* update systemd socket activation pid */
      inherit_systemd_activation();
    }
  else if (process_opts.mode == G_PM_SAFE_BACKGROUND)
    {
      /* full blown startup/supervisor/daemon */
      if (pipe(startup_result_pipe) != 0)
        {
          g_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno));
          exit(1);
        }
      /* first fork off supervisor process */
      if ((pid = fork()) < 0)
        {
          g_process_message("Error forking child process; error='%s'", g_strerror(errno));
          exit(1);
        }
      else if (pid != 0)
        {
          /* this is the startup process */

          /* shut down startup_result_pipe write side */
          close(startup_result_pipe[1]);
          startup_result_pipe[1] = -1;

          /* NOTE: never returns */
          g_process_perform_startup();
          g_assert_not_reached();
        }
      /* this is the supervisor process */

      /* shut down startup_result_pipe read side */
      close(startup_result_pipe[0]);
      startup_result_pipe[0] = -1;

      /* update systemd socket activation pid */
      inherit_systemd_activation();

      process_kind = G_PK_SUPERVISOR;
      g_process_perform_supervise();
      /* we only return in the daamon process here */
    }
  else if (process_opts.mode == G_PM_FOREGROUND)
    {
      process_kind = G_PK_DAEMON;
    }
  else
    {
      g_assert_not_reached();
    }

  /* daemon process, we should return to the caller to perform work */
  /* Only call setsid() for backgrounded processes. */
  if (process_opts.mode != G_PM_FOREGROUND)
    {
      setsid();
    }

  /* NOTE: we need to signal the parent in case of errors from this point.
   * This is accomplished by writing the appropriate exit code to
   * init_result_pipe, the easiest way doing so is calling g_process_startup_failed.
   * */

  if (!g_process_change_root() ||
      !g_process_change_user() ||
      !g_process_change_caps())
    {
      g_process_startup_failed(1, TRUE);
    }
  g_process_enable_core();
  g_process_change_dir();
}
Example #2
0
int
main(int argc, char *argv[])
{
  gint rc;
  GOptionContext *ctx;
  GError *error = NULL;

  z_mem_trace_init("syslog-ng.trace");

  g_process_set_argv_space(argc, (gchar **) argv);

  setup_caps();

  resolved_configurable_paths_init(&resolvedConfigurablePaths);

  ctx = g_option_context_new("syslog-ng");
  g_process_add_option_group(ctx);
  msg_add_option_group(ctx);
  g_option_context_add_main_entries(ctx, syslogng_options, NULL);
  main_loop_add_options(ctx);
  if (!g_option_context_parse(ctx, &argc, &argv, &error))
    {
      fprintf(stderr, "Error parsing command line arguments: %s\n", error ? error->message : "Invalid arguments");
      g_option_context_free(ctx);
      return 1;
    }
  g_option_context_free(ctx);
  if (argc > 1)
    {
      fprintf(stderr, "Excess number of arguments\n");
      return 1;
    }

  if (display_version)
    {
      interactive_mode();
      version();
      return 0;
    }
  if (display_module_registry)
    {
      interactive_mode();
      plugin_list_modules(stdout, TRUE);
      return 0;
    }

  if(startup_debug_flag && debug_flag)
    {
      startup_debug_flag = FALSE;
    }

  if(startup_debug_flag)
    {
      debug_flag = TRUE;
    }

  if (debug_flag)
    {
      log_stderr = TRUE;
    }

  if (syntax_only || debug_flag)
    {
      g_process_set_mode(G_PM_FOREGROUND);
    }
  g_process_set_name("syslog-ng");

  /* in this case we switch users early while retaining a limited set of
   * credentials in order to initialize/reinitialize the configuration.
   */
  g_process_start();
  app_startup();
  main_loop_init();
  rc = main_loop_read_and_init_config();

  if (rc)
    {
      g_process_startup_failed(rc, TRUE);
      return rc;
    }
  else
    {
      if (syntax_only)
        g_process_startup_failed(0, TRUE);
      else
        g_process_startup_ok();
    }

  /* we are running as a non-root user from this point */

  app_post_daemonized();
  app_post_config_loaded();

  if(startup_debug_flag)
    {
      debug_flag = FALSE;
      log_stderr = FALSE;
    }

  /* from now on internal messages are written to the system log as well */

  main_loop_run();
  main_loop_deinit();

  app_shutdown();
  z_mem_trace_dump();
  g_process_finish();
  return rc;
}
Example #3
0
/**
 * g_process_perform_supervise:
 *
 * Supervise process, returns only in the context of the daemon process, the
 * supervisor process exits here.
 **/
static void
g_process_perform_supervise(void)
{
  pid_t pid;
  gboolean first = TRUE, exited = FALSE;
  gchar proc_title[PROC_TITLE_SPACE];
  struct sigaction sa;

  g_snprintf(proc_title, PROC_TITLE_SPACE, "supervising %s", process_opts.name);
  g_process_setproctitle(proc_title);

  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SIG_IGN;
  sigaction(SIGHUP, &sa, NULL);

  while (1)
    {
      if (pipe(init_result_pipe) != 0)
        {
          g_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno));
          g_process_startup_failed(1, TRUE);
        }

      /* fork off a child process */
      if ((pid = fork()) < 0)
        {
          g_process_message("Error forking child process; error='%s'", g_strerror(errno));
          g_process_startup_failed(1, TRUE);
        }
      else if (pid != 0)
        {
          gint rc;
          gboolean deadlock = FALSE;

          /* this is the supervisor process */

          /* shut down init_result_pipe write side */
          close(init_result_pipe[1]);
          init_result_pipe[1] = -1;

          rc = g_process_recv_result();
          if (first)
            {
              /* first time encounter, we have a chance to report back, do it */
              g_process_send_result(rc);
              if (rc != 0)
                break;
              g_process_detach_stdio();
            }
          first = FALSE;
          if (rc != 0)
            {
              gint i = 0;
              /* initialization failed in daemon, it will probably exit soon, wait and restart */

              while (i < 6 && waitpid(pid, &rc, WNOHANG) == 0)
                {
                  if (i > 3)
                    kill(pid, i > 4 ? SIGKILL : SIGTERM);
                  sleep(1);
                  i++;
                }
              if (i == 6)
                g_process_message("Initialization failed but the daemon did not exit, even when forced to, trying to recover; pid='%d'",
                                  pid);
              continue;
            }

          if (process_opts.check_fn && (process_opts.check_period >= 0))
            {
              gint i = 1;
              while (!(exited = waitpid(pid, &rc, WNOHANG)))
                {
                  if (i >= process_opts.check_period)
                    {
                      if (!process_opts.check_fn())
                        break;
                      i = 0;
                    }
                  sleep(1);
                  i++;
                }

              if (!exited)
                {
                  gint j = 0;
                  g_process_message("Daemon deadlock detected, killing process;");
                  deadlock = TRUE;

                  while (j < 6 && waitpid(pid, &rc, WNOHANG) == 0)
                    {
                      if (j > 3)
                        kill(pid, j > 4 ? SIGKILL : SIGABRT);
                      sleep(1);
                      j++;
                    }
                  if (j == 6)
                    g_process_message("The daemon did not exit after deadlock, even when forced to, trying to recover; pid='%d'", pid);
                }
            }
          else
            {
              waitpid(pid, &rc, 0);
            }

          if (deadlock || WIFSIGNALED(rc) || (WIFEXITED(rc) && WEXITSTATUS(rc) != 0))
            {
              gchar argbuf[64];

              if (!access(G_PROCESS_FAILURE_NOTIFICATION, R_OK | X_OK))
                {
                  const gchar *notify_reason;
                  pid_t npid = fork();
                  gint nrc;
                  switch (npid)
                    {
                    case -1:
                      g_process_message("Could not fork for external notification; reason='%s'", strerror(errno));
                      break;

                    case 0:
                      switch(fork())
                        {
                        case -1:
                          g_process_message("Could not fork for external notification; reason='%s'", strerror(errno));
                          exit(1);
                          break;
                        case 0:
                          if (deadlock)
                            {
                              notify_reason = "deadlock detected";
                              argbuf[0] = 0;
                            }
                          else
                            {
                              snprintf(argbuf, sizeof(argbuf), "%d", WIFSIGNALED(rc) ? WTERMSIG(rc) : WEXITSTATUS(rc));
                              if (WIFSIGNALED(rc))
                                notify_reason = "signalled";
                              else
                                notify_reason = "non-zero exit code";
                            }
                          execlp(G_PROCESS_FAILURE_NOTIFICATION, G_PROCESS_FAILURE_NOTIFICATION,
                                 SAFE_STRING(process_opts.name),
                                 SAFE_STRING(process_opts.chroot_dir),
                                 SAFE_STRING(process_opts.pidfile_dir),
                                 SAFE_STRING(process_opts.pidfile),
                                 SAFE_STRING(process_opts.cwd),
                                 SAFE_STRING(process_opts.caps),
                                 notify_reason,
                                 argbuf,
                                 (deadlock || !WIFSIGNALED(rc) || WTERMSIG(rc) != SIGKILL) ? "restarting" : "not-restarting",
                                 (gchar *) NULL);
                          g_process_message("Could not execute external notification; reason='%s'", strerror(errno));
                          break;

                        default:
                          exit(0);
                          break;
                        } /* child process */
                    default:
                      waitpid(npid, &nrc, 0);
                      break;
                    }
                }
              if (deadlock || !WIFSIGNALED(rc) || WTERMSIG(rc) != SIGKILL)
                {
                  g_process_message("Daemon exited due to a deadlock/signal/failure, restarting; exitcode='%d'", rc);
                  sleep(1);
                }
              else
                {
                  g_process_message("Daemon was killed, not restarting; exitcode='%d'", rc);
                  break;
                }
            }
          else
            {
              g_process_message("Daemon exited gracefully, not restarting; exitcode='%d'", rc);
              break;
            }
        }
      else
        {
          /* this is the daemon process, thus we should return to the caller of g_process_start() */
          /* shut down init_result_pipe read side */
          process_kind = G_PK_DAEMON;
          close(init_result_pipe[0]);
          init_result_pipe[0] = -1;

          /* update systemd socket activation pid */
          inherit_systemd_activation();

          memcpy(process_opts.argv_start, process_opts.argv_orig, process_opts.argv_env_len);
          return;
        }
    }
  exit(0);
}