Exemple #1
0
static void handle_sighup(void) {
	FILE *log_file = log_get_file();

	if (log_file != NULL) {
		if (fileno(log_file) == STDOUT_FILENO || fileno(log_file) == STDERR_FILENO) {
			return; // don't close stdout or stderr
		}

		fclose(log_file);
	}

	log_file = fopen(_log_filename, "a+");

	if (log_file == NULL) {
		log_set_file(stderr);

		log_error("Could not reopen log file '%s': %s (%d)",
		          _log_filename, get_errno_name(errno), errno);

		return;
	}

	log_set_file(log_file);

	log_info("Reopened log file '%s'", _log_filename);
}
Exemple #2
0
void
ilog(enum log_type type, const char *fmt, ...)
{
  char buf[LOG_BUFSIZE] = "";
  va_list args;

  if (!log_type_table[type].file || !ConfigLog.use_logging)
    return;

  va_start(args, fmt);
  vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);

  log_write(type, buf);

  if (log_exceed_size(type) <= 0)
    return;

  snprintf(buf, sizeof(buf), "Rotating logfile %s",
           log_type_table[type].path);
  log_write(type, buf);

  fclose(log_type_table[type].file);
  log_type_table[type].file = NULL;

  snprintf(buf, sizeof(buf), "%s.old", log_type_table[type].path);
  unlink(buf);
  rename(log_type_table[type].path, buf);

  log_set_file(type, log_type_table[type].size, log_type_table[type].path);
  log_type_table[type].file = fopen(log_type_table[type].path, "a");
}
Exemple #3
0
int main(int argc, char **argv)
{
	struct evdns_base *dns;
	struct event_base *base;
	struct bufferevent *bev;
	struct url *socks, *host;
	int s4;

	base = event_base_new();
	dns = evdns_base_new(base, 1);
	
	log_set_file(NULL);
	log_set_min_level(LOG_DEBUG);
	if (argc >= 3) {
		socks = url_tokenize(argv[2]);
		s4 = !evutil_ascii_strcasecmp("socks4", socks->scheme);
		if (conn_set_socks_server(socks->host, socks->port, s4?
				SOCKS_4 : SOCKS_4a) < 0)
			return 0;
	}
	
	host = url_connect_tokenize(argv[1]);

	bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

	conn_connect_bufferevent(bev, dns, AF_INET, host->host, host->port,
				 do_connect, NULL);

	event_base_dispatch(base);

	return 0;
}
Exemple #4
0
int main(void)
{
    int count = 100000;
    log_set_file("/var/va_server/test.log");
    log_set_level(LOG_LEVEL_DEBUG);

    if(fork() > 0){
        while(count-- > 0){
            log_debug("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
            log_info("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
            log_warn("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
            log_error("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        }
        log_close();
    }
    else{
        while(count-- > 0){
            log_debug("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
            log_info("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
            log_warn("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
            log_error("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
        }
        log_close();
    }

    return 1;
}
Exemple #5
0
static void loop(sigset_t *set)
{
    for (;;) {
        int sig;
        if (0 != sigwait(set, &sig)) continue;

        switch (sig) {
            case SIGHUP:
                SLOG(LOG_INFO, "SIGHUP Caught. Reopen logfile.");
                log_set_file(log_get_file());
                break;
            case SIGTERM:
            case SIGINT:
                SLOG(LOG_INFO, "SIGINT Caught. Exiting.");
                exit(EXIT_SUCCESS); // call all destructors
                break;
            case SIGPIPE:
                SLOG(LOG_INFO, "SIGPIPE Caught. Ignoring.");
                break;
            case SIGCHLD:
                SLOG(LOG_INFO, "SIGCHLD Caught. Ignoring.");
                break;
        }
    }
}
Exemple #6
0
estream_t
log_get_stream ()
{
  if (!logstream)
    {
      log_set_file (NULL); /* Make sure a log stream has been set.  */
      assert (logstream);
    }
  return logstream;
}
Exemple #7
0
int main(void)
{
    log_init();
    log_set_level(LOG_DEBUG, NULL);
    log_set_file("cursor_check.log");

    cursor_check();

    log_fini();
    return EXIT_SUCCESS;
}
Exemple #8
0
int main(int argc, char *argv[]) {
    FILE *log = fopen("/dev/null", "w");
    log_set_file(log);
    log_set_level(LOG_WARN);
    
    log_trace("NOT OK");
    log_debug("NOT OK");
    log_info("NOT OK");
    log_warn("OK");
    log_error("OK");
    log_fatal("OK");
    
    if (log_trace()) abort();
    if (log_debug()) abort();
    if (log_info()) abort();
    if (log_warn()) {log_warn();}
    if (log_error()) {log_error();}
    if (log_fatal()) {log_fatal();}
    
    fclose(log);
    
    log_info("NOT OK");
    log_warn("OK");
    
    log_set_file(NULL);
    log_warn("OK");

    /* Test the timestamp stuff
    FILE *logf = fopen("/tmp/foo.log","w");
    log_set_file(logf);

    log_warn("OK");
    log_warn("OK");
    log_warn("OK AGAIN");

    fclose(logf);
    */
    
    return 0;
}
Exemple #9
0
static void
handle_arguments(int argc, char *argv[])
{
   for (int i = 1; i < argc; ++i) {
      if (chck_cstreq(argv[i], "--log")) {
         if (i + 1 >= argc) {
            plog(0, PLOG_ERROR, "--log takes an argument (filename)");
            abort();
         }
         log_set_file(argv[++i]);
      }
   }
}
Exemple #10
0
int
main(int argc, char **argv)
{
	struct event_base *base;
	struct evdns_base *dns = NULL;
	int opt;
	const char *laddr, *lport;

	init_socket_stuff();

	base = event_base_new();
#ifndef DISABLE_DIRECT_CONNECTIONS
	dns = evdns_base_new(base, 1);
#endif
	log_set_file(NULL);

	laddr = DEFAULT_LISTEN_ADDR;
	lport = DEFAULT_LISTEN_PORT;

	while ((opt = getopt(argc, argv, "l:p:Vvq")) >= 0) {
		switch (opt) {
		case 'l':
			laddr = optarg;
			break;
		case 'p':
			lport = optarg;
			break;
		case 'V':
			printf("%s\n", PACKAGE_STRING);
			exit(1);
		case 'v':
			increase_log_verbosity();
			break;
		case 'q':
			decrease_log_verbosity();
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc)
		set_socks_server(argv[0]);
	start_listening(base, dns, laddr, lport);
	event_base_dispatch(base);

	return 0;	
}
Exemple #11
0
int main(void)
{
    log_init();
    log_set_level(LOG_DEBUG, NULL);
    log_set_file("ip_addr_check.log");

    ip_addr_check();
    ip_addr_ctor_from_str_check();
    ip_addr_routable_check();
    broadcast_check();
    scm_conv_check();

    log_fini();
    return EXIT_SUCCESS;
}
int main(void)
{
    log_init();
    ext_init();
    mallocer_init();
    mutex_init();
    log_set_level(LOG_DEBUG, NULL);
    log_set_file("mallocer_check.log");

    malloc_check();
    realloc_check();

    mutex_fini();
    mallocer_fini();
    ext_fini();
    log_fini();

    return EXIT_SUCCESS;
}
Exemple #13
0
int
main ( int argc, char **argv)
{
  ARGPARSE_ARGS pargs;
  int orig_argc;
  char **orig_argv;
  gpg_error_t err = 0;
  /* const char *fname; */
  int may_coredump;
  FILE *configfp = NULL;
  char *configname = NULL;
  unsigned configlineno;
  int parse_debug = 0;
  int no_more_options = 0;
  int default_config =1;
  char *logfile = NULL;
  /* int debug_wait = 0; */
  int use_random_seed = 1;
  /* int nodetach = 0; */
  /* int nokeysetup = 0; */
  struct server_control_s ctrl;

  /*mtrace();*/

  early_system_init ();
  gnupg_reopen_std (G13_NAME "-syshelp");
  set_strusage (my_strusage);
  gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);

  log_set_prefix (G13_NAME "-syshelp", 1);

  /* Make sure that our subsystems are ready.  */
  i18n_init ();
  init_common_subsystems (&argc, &argv);

  /* Check that the Libgcrypt is suitable.  */
  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
    log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
               NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );

  /* Take extra care of the random pool.  */
  gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);

  may_coredump = disable_core_dumps ();

  g13_init_signals ();

  dotlock_create (NULL, 0); /* Register locking cleanup.  */

  opt.session_env = session_env_new ();
  if (!opt.session_env)
    log_fatal ("error allocating session environment block: %s\n",
               strerror (errno));

  opt.homedir = default_homedir ();
  /* Fixme: We enable verbose mode here because there is currently no
     way to do this when starting g13-syshelp.  To fix that we should
     add a g13-syshelp.conf file in /etc/gnupg.  */
  opt.verbose = 1;

  /* First check whether we have a debug option on the commandline.  */
  orig_argc = argc;
  orig_argv = argv;
  pargs.argc = &argc;
  pargs.argv = &argv;
  pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
  while (arg_parse( &pargs, opts))
    {
      if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
        parse_debug++;
    }

  /* Initialize the secure memory. */
  gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
  maybe_setuid = 0;

  /*
     Now we are now working under our real uid
  */

  /* Setup malloc hooks. */
  {
    struct assuan_malloc_hooks malloc_hooks;

    malloc_hooks.malloc = gcry_malloc;
    malloc_hooks.realloc = gcry_realloc;
    malloc_hooks.free = gcry_free;
    assuan_set_malloc_hooks (&malloc_hooks);
  }

  /* Prepare libassuan.  */
  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
  /*assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);*/
  setup_libassuan_logging (&opt.debug);

  /* Setup a default control structure for command line mode.  */
  memset (&ctrl, 0, sizeof ctrl);
  g13_syshelp_init_default_ctrl (&ctrl);
  ctrl.no_server = 1;
  ctrl.status_fd = -1; /* No status output. */

  if (default_config )
    configname = make_filename (gnupg_sysconfdir (),
                                G13_NAME"-syshelp.conf", NULL);

  argc        = orig_argc;
  argv        = orig_argv;
  pargs.argc  = &argc;
  pargs.argv  = &argv;
  pargs.flags =  1;  /* Do not remove the args.  */

 next_pass:
  if (configname)
    {
      configlineno = 0;
      configfp = fopen (configname, "r");
      if (!configfp)
        {
          if (default_config)
            {
              if (parse_debug)
                log_info (_("NOTE: no default option file '%s'\n"), configname);
            }
          else
            {
              log_error (_("option file '%s': %s\n"),
                         configname, strerror(errno));
              g13_exit(2);
            }
          xfree (configname);
          configname = NULL;
        }
      if (parse_debug && configname)
        log_info (_("reading options from '%s'\n"), configname);
      default_config = 0;
    }

  while (!no_more_options
         && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
    {
      switch (pargs.r_opt)
        {
        case oQuiet: opt.quiet = 1; break;

        case oDryRun: opt.dry_run = 1; break;

        case oVerbose:
          opt.verbose++;
          gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
          break;
        case oNoVerbose:
          opt.verbose = 0;
          gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
          break;

        case oLogFile: logfile = pargs.r.ret_str; break;
        case oNoLogFile: logfile = NULL; break;

        case oNoDetach: /*nodetach = 1; */break;

        case oDebug:
          if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
            {
              pargs.r_opt = ARGPARSE_INVALID_ARG;
              pargs.err = ARGPARSE_PRINT_ERROR;
            }
            break;
        case oDebugAll: debug_value = ~0; break;
        case oDebugNone: debug_value = 0; break;
        case oDebugLevel: debug_level = pargs.r.ret_str; break;
        case oDebugWait: /*debug_wait = pargs.r.ret_int; */break;
        case oDebugAllowCoreDump:
          may_coredump = enable_core_dumps ();
          break;

        case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
        case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;

        case oHomedir: opt.homedir = pargs.r.ret_str; break;

        case oFakedSystemTime:
          {
            time_t faked_time = isotime2epoch (pargs.r.ret_str);
            if (faked_time == (time_t)(-1))
              faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
            gnupg_set_time (faked_time, 0);
          }
          break;

        case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break;

        case oNoRandomSeedFile: use_random_seed = 0; break;

        default:
          pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
          break;
	}
    }

  if (configfp)
    {
      fclose (configfp);
      configfp = NULL;
      /* Keep a copy of the config filename. */
      opt.config_filename = configname;
      configname = NULL;
      goto next_pass;
    }
  xfree (configname);
  configname = NULL;

  if (!opt.config_filename)
    opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);

  if (log_get_errorcount(0))
    g13_exit(2);

  /* Now that we have the options parsed we need to update the default
     control structure.  */
  g13_syshelp_init_default_ctrl (&ctrl);

  if (may_coredump && !opt.quiet)
    log_info (_("WARNING: program may create a core file!\n"));

  if (logfile)
    {
      log_set_file (logfile);
      log_set_prefix (NULL, 1|2|4);
    }

  if (gnupg_faked_time_p ())
    {
      gnupg_isotime_t tbuf;

      log_info (_("WARNING: running with faked system time: "));
      gnupg_get_isotime (tbuf);
      dump_isotime (tbuf);
      log_printf ("\n");
    }

  /* Print any pending secure memory warnings.  */
  gcry_control (GCRYCTL_RESUME_SECMEM_WARN);

  /* Setup the debug flags for all subsystems.  */
  set_debug ();

  /* Install a regular exit handler to make real sure that the secure
     memory gets wiped out.  */
  g13_install_emergency_cleanup ();

  /* Terminate if we found any error until now.  */
  if (log_get_errorcount(0))
    g13_exit (2);

  /* Set the standard GnuPG random seed file.  */
  if (use_random_seed)
    {
      char *p = make_filename (opt.homedir, "random_seed", NULL);
      gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
      xfree(p);
    }

  /* Get the UID of the caller.  */
#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
  {
    const char *uidstr;
    struct passwd *pwd = NULL;

    uidstr = getenv ("USERV_UID");

    /* Print a quick note if we are not started via userv.  */
    if (!uidstr)
      {
        if (getuid ())
          {
            log_info ("WARNING: Not started via userv\n");
            ctrl.fail_all_cmds = 1;
          }
        ctrl.client.uid = getuid ();
      }
    else
      {
        unsigned long myuid;

        errno = 0;
        myuid = strtoul (uidstr, NULL, 10);
        if (myuid == ULONG_MAX && errno)
          {
            log_info ("WARNING: Started via broken userv: %s\n",
                      strerror (errno));
            ctrl.fail_all_cmds = 1;
            ctrl.client.uid = getuid ();
          }
        else
          ctrl.client.uid = (uid_t)myuid;
      }

    pwd = getpwuid (ctrl.client.uid);
    if (!pwd || !*pwd->pw_name)
      {
        log_info ("WARNING: Name for UID not found: %s\n", strerror (errno));
        ctrl.fail_all_cmds = 1;
        ctrl.client.uname = xstrdup ("?");
      }
    else
      ctrl.client.uname = xstrdup (pwd->pw_name);

    /* Check that the user name does not contain a directory
       separator. */
    if (strchr (ctrl.client.uname, '/'))
      {
        log_info ("WARNING: Invalid user name passed\n");
        ctrl.fail_all_cmds = 1;
      }
  }
#else /*!HAVE_PWD_H || !HAVE_GETPWUID*/
  log_info ("WARNING: System does not support required syscalls\n");
  ctrl.fail_all_cmds = 1;
  ctrl.client.uid = getuid ();
  ctrl.client.uname = xstrdup ("?");
#endif /*!HAVE_PWD_H || !HAVE_GETPWUID*/

  /* Read the table entries for this user.  */
  if (!ctrl.fail_all_cmds
      && !(ctrl.client.tab = parse_g13tab (ctrl.client.uname)))
    ctrl.fail_all_cmds = 1;

  /* Start the server.  */
  err = syshelp_server (&ctrl);
  if (err)
    log_error ("server exited with error: %s <%s>\n",
               gpg_strerror (err), gpg_strsource (err));

  /* Cleanup.  */
  g13_syshelp_deinit_default_ctrl (&ctrl);
  g13_exit (0);
  return 8; /*NOTREACHED*/
}
Exemple #14
0
int main(int argc, char *argv[])
{
    int fd = -1;
    pid_t pgid = -1;
    server_conf_t *conf;
    int log_priority = LOG_INFO;

#ifndef NDEBUG
    log_priority = LOG_DEBUG;
#endif /* NDEBUG */
    log_set_file(stderr, log_priority, 0);

    conf = create_server_conf();
    tp_global = conf->tp;

    process_cmdline(conf, argc, argv);
    if (!conf->enableForeground) {
        begin_daemonize(&fd, &pgid);
    }
    process_config(conf);
    setup_coredump(conf);
    setup_signals(conf);

    if (!(environ = get_sane_env())) {
        log_err(ENOMEM, "Unable to create sanitized environment");
    }
    if (conf->enableVerbose) {
        display_configuration(conf);
    }
    if (list_is_empty(conf->objs)) {
        log_err(0, "Configuration \"%s\" has no consoles defined",
            conf->confFileName);
    }
    if (conf->tStampMinutes > 0) {
        schedule_timestamp(conf);
    }
    create_listen_socket(conf);

    if (!conf->enableForeground) {
        if (conf->syslogFacility > 0) {
            log_set_syslog(argv[0], conf->syslogFacility);
        }
        if (conf->logFileName) {
            open_daemon_logfile(conf);
        }
        else {
            log_set_file(NULL, 0, 0);
        }
        end_daemonize(fd);
    }

    log_msg(LOG_NOTICE, "Starting ConMan daemon %s (pid %d)",
        VERSION, (int) getpid());

#if WITH_FREEIPMI
    ipmi_init(conf->numIpmiObjs);
#endif /* WITH_FREEIPMI */

    open_objs(conf);
    mux_io(conf);

#if WITH_FREEIPMI
    ipmi_fini();
#endif /* WITH_FREEIPMI */

    destroy_server_conf(conf);

    if (pgid > 0) {
        if (kill(-pgid, SIGTERM) < 0) {
            log_msg(LOG_WARNING, "Unable to terminate process group ID %d: %s",
                pgid, strerror(errno));
        }
    }
    log_msg(LOG_NOTICE, "Stopping ConMan daemon %s (pid %d)",
        VERSION, (int) getpid());
    exit(0);
}
Exemple #15
0
static void open_daemon_logfile(server_conf_t *conf)
{
/*  (Re)opens the daemon logfile.
 *  Since this logfile can be re-opened after the daemon has chdir()'d,
 *    it must be specified with an absolute pathname.
 */
    static int  once = 1;
    const char *mode = "a";
    mode_t      mask;
    char        dirname[PATH_MAX];
    FILE       *fp = NULL;
    int         fd;

    assert(conf->logFileName != NULL);
    assert(conf->logFileName[0] == '/');
    assert(!conf->enableForeground);

    /*  Only truncate logfile at startup if needed.
     */
    if (once) {
        if (conf->enableZeroLogs) {
            mode = "w";
        }
        once = 0;
    }
    /*  Perform conversion specifier expansion.
     */
    if (conf->logFmtName) {

        char buf[MAX_LINE];

        if (format_obj_string(buf, sizeof(buf), NULL, conf->logFmtName) < 0) {
            log_msg(LOG_WARNING,
                "Unable to open daemon logfile: filename too long");
            goto err;
        }
        free(conf->logFileName);
        conf->logFileName = create_string(buf);
    }
    /*  Protect logfile against unauthorized writes by removing
     *    group+other write-access from current mask.
     */
    mask = umask(0);
    umask(mask | 022);
    /*
     *  Create intermediate directories.
     */
    if (get_dir_name(conf->logFileName, dirname, sizeof(dirname))) {
        (void) create_dirs(dirname);
    }
    /*  Open the logfile.
     */
    fp = fopen(conf->logFileName, mode);
    umask(mask);

    if (!fp) {
        log_msg(LOG_WARNING, "Unable to open daemon logfile \"%s\": %s",
            conf->logFileName, strerror(errno));
        goto err;
    }
    if ((fd = fileno(fp)) < 0) {
        log_msg(LOG_WARNING,
            "Unable to obtain descriptor for daemon logfile \"%s\": %s",
            conf->logFileName, strerror(errno));
        goto err;
    }
    if (get_write_lock(fd) < 0) {
        log_msg(LOG_WARNING, "Unable to lock daemon logfile \"%s\"",
            conf->logFileName);
        goto err;
    }
    set_fd_closed_on_exec(fd);
    /*
     *  Transition to new log file.
     */
    log_set_file(fp, conf->logFileLevel, 1);
    if (conf->logFilePtr) {
        if (fclose(conf->logFilePtr) == EOF) {
            log_msg(LOG_WARNING, "Unable to close daemon logfile \"%s\"",
                conf->logFileName);
        }
    }
    conf->logFilePtr = fp;
    DPRINTF((9, "Opened logfile \"%s\": fd=%d.\n", conf->logFileName, fd));
    return;

err:
    if (fp) {
        (void) fclose(fp);
    }
    /*  Abandon old log file and go logless.
     */
    log_set_file(NULL, 0, 0);
    if (conf->logFilePtr) {
        if (fclose(conf->logFilePtr) == EOF) {
            log_msg(LOG_WARNING, "Unable to close daemon logfile \"%s\"",
                conf->logFileName);
        }
    }
    conf->logFilePtr = NULL;
    return;
}
Exemple #16
0
static void begin_daemonize(int *fd_ptr, pid_t *pgid_ptr)
{
/*  Begins the daemonization of the process.
 *  Despite the fact that this routine backgrounds the process, control
 *    will not be returned to the shell until end_daemonize() is called.
 *  If 'fd_ptr' is non-null, it will be set to the fd to pass to
 *    end_daemonize() in order to complete the daemonization.
 *  If 'pgid_ptr' is non-null, it will be set to the daemonized
 *    process group ID.
 */
    int fds[2];
    pid_t pid;
    int n;
    signed char priority;
    char ebuf[1024];
    pid_t pgid;

    /*  Clear file mode creation mask.
     */
    umask(0);

    /*  Create pipe for IPC so parent process will wait to terminate until
     *    signaled by grandchild process.  This allows messages written to
     *    stdout/stderr by the grandchild to be properly displayed before
     *    the parent process returns control to the shell.
     */
    if (pipe(fds) < 0) {
        log_err(errno, "Unable to create daemon pipe");
    }
    /*  Set the fd used by log_err() to return status back to the parent.
     */
    log_set_err_pipe(fds[1]);

    /*  Automatically background the process and
     *    ensure child is not a process group leader.
     */
    if ((pid = fork()) < 0) {
        log_err(errno, "Unable to create child process");
    }
    else if (pid > 0) {
        log_set_err_pipe(-1);
        /*
         *  FIXME: The following log_err()s don't necessarily indicate the
         *    daemon has failed since the grandchild process may still be
         *    running.  This could confuse the user.  Should they be warnings
         *    instead?
         */
        if (close(fds[1]) < 0) {
            log_err(errno, "Unable to close write-pipe in parent process");
        }
        if ((n = read(fds[0], &priority, sizeof(priority))) < 0) {
            log_err(errno, "Unable to read status from grandchild process");
        }
        if ((n > 0) && (priority >= 0)) {
            if ((n = read(fds[0], ebuf, sizeof(ebuf))) < 0) {
                log_err(errno,
                    "Unable to read error message from grandchild process");
            }
            if ((n > 0) && (ebuf[0] != '\0')) {
                log_set_file(stderr, priority, 0);
                log_msg(priority, "%s", ebuf);
            }
            exit(1);
        }
        exit(0);
    }
    if (close(fds[0]) < 0) {
        log_err(errno, "Unable to close read-pipe in child process");
    }
    /*  Become a session leader and process group leader
     *    with no controlling tty.
     */
    if ((pgid = setsid()) < 0) {
        log_err(errno, "Unable to disassociate controlling tty");
    }
    /*  Ignore SIGHUP to keep child from terminating when
     *    the session leader (ie, the parent) terminates.
     */
    posix_signal(SIGHUP, SIG_IGN);

    /*  Abdicate session leader position in order to guarantee
     *    daemon cannot automatically re-acquire a controlling tty.
     */
    if ((pid = fork()) < 0) {
        log_err(errno, "Unable to create grandchild process");
    }
    else if (pid > 0) {
        exit(0);
    }
    /*  Return.
     */
    if (fd_ptr) {
        *fd_ptr = fds[1];
    }
    if (pgid_ptr) {
        *pgid_ptr = pgid;
    }
    return;
}
Exemple #17
0
int mpidag(int argc, char *argv[]) {
    int numprocs;
    program = argv[0];
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    
    std::list<char *> flags;
    for (int i=1; i<argc; i++) {
        flags.push_back(argv[i]);
    }
    
    std::string outfile;
    std::string errfile;
    std::string logfile;
    std::list<std::string> args;
    int loglevel = LOG_INFO;
    bool skiprescue = false;
    int max_failures = 0;
    int tries = 1;
    
    while (flags.size() > 0) {
        std::string flag = flags.front();
        if (flag == "-h" || flag == "--help") {
            usage();
            return 0;
        } else if (flag == "-o" || flag == "--stdout") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-o/--stdout requires PATH\n");
                }
                return 1;
            }
            outfile = flags.front();
        } else if (flag == "-e" || flag == "--stderr") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-e/--stderr requires PATH\n");
                }
                return 1;
            }
            errfile = flags.front();
        } else if (flag == "-q" || flag == "--quiet") {
            loglevel -= 1;
        } else if (flag == "-v" || flag == "--verbose") {
            loglevel += 1;
        } else if (flag == "-L" || flag == "--logfile") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-L/--logfile requires PATH\n");
                }
                return 1;
            }
            logfile = flags.front();
        } else if (flag == "-s" || flag == "--skip-rescue") {
            skiprescue = true;
        } else if (flag == "-m" || flag == "--max-failures") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-m/--max-failures requires N\n");
                }
                return 1;
            }
            std::string N = flags.front();
            if (!sscanf(N.c_str(), "%d", &max_failures)) {
                fprintf(stderr, "N for -m/--max-failures is invalid\n");
                return 1;
            }
            if (max_failures < 0) {
                fprintf(stderr, "N for -m/--max-failures must be >= 0\n");
                return 1;
            }
        } else if (flag == "-t" || flag == "--tries") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-t/--tries requires N\n");
                }
                return 1;
            }
            std::string N = flags.front();
            if (!sscanf(N.c_str(), "%d", &tries)) {
                fprintf(stderr, "N for -t/--tries is invalid\n");
                return 1;
            }
            if (tries < 1) {
                fprintf(stderr, "N for -t/--tries must be >= 1\n");
                return 1;
            }
        } else if (flag[0] == '-') {
            if (rank == 0) {
                fprintf(stderr, "Unrecognized argument: %s\n", flag.c_str());
            }
            return 1;
        } else {
            args.push_back(flag);
        }
        flags.pop_front();
    }
    
    if (args.size() == 0) {
        usage();
        return 1;
    }
    
    if (args.size() > 1) {
        fprintf(stderr, "Invalid argument\n");
        return 1;
    }
    
    std::string dagfile = args.front();
    
    if (numprocs < 2) {
        fprintf(stderr, "At least one worker process is required\n");
        return 1;
    }
    
    // Everything is pretty deterministic up until the processes reach
    // this point. Once we get here the different processes can diverge 
    // in their behavior for many reasons (file systems issues, bad nodes,
    // etc.), so be careful how failures are handled after this point
    // and make sure MPI_Abort is called when something bad happens.
    
    char dotrank[25];
    sprintf(dotrank, ".%d", rank);
    
    FILE *log = NULL;
    log_set_level(loglevel);
    if (logfile.size() > 0) {
        logfile += dotrank;
        log = fopen(logfile.c_str(), "w");
        if (log == NULL) {
            failure("Unable to open log file: %s: %s\n", 
                logfile.c_str(), strerror(errno));
        }
        log_set_file(log);
    }
    
    try {
        if (rank == 0) {
            
            // IMPORTANT: The rank 0 process figures out the names
            // of these files so that we don't have 1000 workers all
            // slamming the file system with stat() calls to check if
            // the out/err/rescue files exist. The master will figure
            // it out here, and then broadcast it to the workers when
            // it starts up.
            
            // Determine task stdout file
            if (outfile.size() == 0) {
                outfile = dagfile;
                outfile += ".out";
            }
            next_retry_file(outfile);
            log_debug("Using stdout file: %s", outfile.c_str());
            
            
            // Determine task stderr file
            if (errfile.size() == 0) {
                errfile = dagfile;
                errfile += ".err";
            }
            next_retry_file(errfile);
            log_debug("Using stderr file: %s", errfile.c_str());
            
            
            // Determine old and new rescue files
            std::string rescuebase = dagfile;
            rescuebase += ".rescue";
            std::string oldrescue;
            std::string newrescue = rescuebase;
            int next = next_retry_file(newrescue);
            if (next == 0 || skiprescue) {
                // Either there is no old rescue file, or the
                // user doesnt want to read it.
                oldrescue = "";
            } else {
                char rbuf[5];
                snprintf(rbuf, 5, ".%03d", next-1);
                oldrescue = rescuebase;
                oldrescue += rbuf;
            }
            log_debug("Using old rescue file: %s", oldrescue.c_str());
            log_debug("Using new rescue file: %s", newrescue.c_str());
            
            DAG dag(dagfile, oldrescue);
            Engine engine(dag, newrescue, max_failures, tries);
            
            return Master(engine, dag, outfile, errfile).run();
        } else {
            return Worker().run();
        }
    } catch (...) {
        // Make sure we close the log
        if (log != NULL) {
            fclose(log);
        }
        throw;
    }
    
    if (log != NULL) {
        fclose(log);
    }

    return 0;
}
Exemple #18
0
int
main(int argc, char *argv[])
{
  /* Check to see if the user is running us as root, which is a nono */
  if (!geteuid())
  {
    fprintf(stderr, "ERROR: This server won't run as root/superuser\n");
    return -1;
  }

  /* Setup corefile size immediately after boot -kre */
  setup_corefile();

  /* Save server boot time right away, so getrusage works correctly */
  set_time();

  /* It's not random, but it ought to be a little harder to guess */
  init_genrand(SystemTime.tv_sec ^ (SystemTime.tv_usec | (getpid() << 20)));

  dlinkAdd(&me, &me.node, &global_client_list);

  ConfigGeneral.dpath      = DPATH;
  ConfigGeneral.spath      = SPATH;
  ConfigGeneral.mpath      = MPATH;
  ConfigGeneral.configfile = CPATH;    /* Server configuration file */
  ConfigGeneral.klinefile  = KPATH;    /* Server kline file         */
  ConfigGeneral.glinefile  = GPATH;    /* Server gline file         */
  ConfigGeneral.xlinefile  = XPATH;    /* Server xline file         */
  ConfigGeneral.dlinefile  = DLPATH;   /* dline file                */
  ConfigGeneral.resvfile   = RESVPATH; /* resv file                 */

  myargv = argv;
  umask(077);  /* umask 077: u=rwx,g=,o= */

  parseargs(&argc, &argv, myopts);

  if (printVersion)
  {
    printf("ircd: version %s(%s)\n", ircd_version, serno);
    exit(EXIT_SUCCESS);
  }

  if (chdir(ConfigGeneral.dpath))
  {
    perror("chdir");
    exit(EXIT_FAILURE);
  }

  ssl_init();

  if (!server_state.foreground)
  {
    make_daemon();
    close_standard_fds(); /* this needs to be before init_netio()! */
  }
  else
    print_startup(getpid());

  setup_signals();

  /* We need this to initialise the fd array before anything else */
  fdlist_init();
  log_set_file(LOG_TYPE_IRCD, 0, logFileName);

  init_netio();         /* This needs to be setup early ! -- adrian */

  /* Check if there is pidfile and daemon already running */
  check_pidfile(pidFileName);

  mp_pool_init();
  init_dlink_nodes();
  init_isupport();
  dbuf_init();
  hash_init();
  ipcache_init();
  client_init();
  class_init();
  whowas_init();
  watch_init();
  auth_init();          /* Initialise the auth code */
  init_resolver();      /* Needs to be setup before the io loop */
  modules_init();
  read_conf_files(1);   /* cold start init conf files */
  init_uid();
  initialize_server_capabs();   /* Set up default_server_capabs */
  initialize_global_set_options();  /* Has to be called after read_conf_files() */
  channel_init();
  read_links_file();
  motd_init();
  user_usermodes_init();
#ifdef HAVE_LIBGEOIP
  geoip_ctx = GeoIP_new(GEOIP_MEMORY_CACHE);
#endif

  if (EmptyString(ConfigServerInfo.sid))
  {
    ilog(LOG_TYPE_IRCD, "ERROR: No server id specified in serverinfo block.");
    exit(EXIT_FAILURE);
  }

  strlcpy(me.id, ConfigServerInfo.sid, sizeof(me.id));

  if (EmptyString(ConfigServerInfo.name))
  {
    ilog(LOG_TYPE_IRCD, "ERROR: No server name specified in serverinfo block.");
    exit(EXIT_FAILURE);
  }

  strlcpy(me.name, ConfigServerInfo.name, sizeof(me.name));

  /* serverinfo{} description must exist.  If not, error out.*/
  if (EmptyString(ConfigServerInfo.description))
  {
    ilog(LOG_TYPE_IRCD, "ERROR: No server description specified in serverinfo block.");
    exit(EXIT_FAILURE);
  }

  strlcpy(me.info, ConfigServerInfo.description, sizeof(me.info));

  me.from = &me;
  me.servptr = &me;
  me.connection->lasttime = CurrentTime;
  me.connection->since = CurrentTime;
  me.connection->firsttime = CurrentTime;

  SetMe(&me);
  make_server(&me);

  hash_add_id(&me);
  hash_add_client(&me);

  dlinkAdd(&me, make_dlink_node(), &global_server_list);

  load_kline_database();
  load_dline_database();
  load_gline_database();
  load_xline_database();
  load_resv_database();

  load_all_modules(1);
  load_conf_modules();
  load_core_modules(1);

  write_pidfile(pidFileName);

  ilog(LOG_TYPE_IRCD, "Server Ready");

  event_addish(&event_cleanup_glines, NULL);
  event_addish(&event_cleanup_tklines, NULL);

  /* We want try_connections to be called as soon as possible now! -- adrian */
  /* No, 'cause after a restart it would cause all sorts of nick collides */
  event_addish(&event_try_connections, NULL);

  /* Setup the timeout check. I'll shift it later :)  -- adrian */
  event_add(&event_comm_checktimeouts, NULL);

  event_addish(&event_save_all_databases, NULL);

  if (ConfigServerHide.links_delay > 0)
  {
    event_write_links_file.when = ConfigServerHide.links_delay;
    event_addish(&event_write_links_file, NULL);
  }
  else
    ConfigServerHide.links_disabled = 1;

  if (splitmode)
    event_addish(&splitmode_event, NULL);

  io_loop();
  return 0;
}
Exemple #19
0
int
main(int argc, char *argv[])
{
	int r;

	char *data_file = NULL;
	char *save_file = NULL;

	int map_generator = 0;


	log_set_file(stdout);

	init_config_data();

	//- read config data
	int screen_width = get_config_int(CONFIG_SCREEN_WIDTH, DEFAULT_SCREEN_WIDTH);
	int screen_height = get_config_int(CONFIG_SCREEN_HEIGHT, DEFAULT_SCREEN_HEIGHT);
	int fullscreen = get_config_bool(CONFIG_FULLSCREEN, 0);
	int log_level = get_config_int(CONFIG_LOGGLEVEL, DEFAULT_LOG_LEVEL);
	enum_lng_t language = str_to_lagEnum((char *)get_config_string(CONFIG_LANGUAGE, "EN"));
	int play_midi = get_config_bool(CONFIG_MUSIC, 1);
	int play_SFX = get_config_bool(CONFIG_SFX, 1);
	int volume = get_config_int(CONFIG_VOLUME, 75);

	//- read command line parameters
	int opt;
	while (1) {
		opt = getopt(argc, argv, "d:fg:hl:r:t:s:");
		if (opt < 0) break;

		switch (opt) {
		case 'd':
			{
				int d = atoi(optarg);
				if (d >= 0 && d < LOG_LEVEL_MAX) {
					log_level = d;
				}
			}
			break;
		case 'f':
			fullscreen = 1;
			break;
		case 'g':
			data_file = (char *)malloc(strlen(optarg)+1);
			if (data_file == NULL) exit(EXIT_FAILURE);
			strcpy(data_file, optarg);
			break;
		case 'h':
			fprintf(stdout, HELP, argv[0]);
			exit(EXIT_SUCCESS);
			break;
		case 'l':
			save_file = (char *)malloc(strlen(optarg)+1);
			if (save_file == NULL) exit(EXIT_FAILURE);
			strcpy(save_file, optarg);
			break;
		case 'r':
			{
				char *hstr = strchr(optarg, 'x');
				if (hstr == NULL) {
					fprintf(stderr, USAGE, argv[0]);
					exit(EXIT_FAILURE);
				}
				screen_width = atoi(optarg);
				screen_height = atoi(hstr+1);
			}
			break;
		case 't':
			map_generator = atoi(optarg);
			break;
		case 's':
			{
				char *  tmp_language_str = (char *) malloc(strlen(optarg) + 1);
				if (tmp_language_str != NULL)
				{
					strcpy(tmp_language_str, optarg);
					language = str_to_lagEnum(tmp_language_str);
				}
			}
			break;
		default:
			fprintf(stderr, USAGE, argv[0]);
			exit(EXIT_FAILURE);
			break;
		}
	}

	/* Set up logging */
	log_set_level((log_level_t)log_level);

	LOGI("main", "freeserf %s", FREESERF_VERSION);

	/* load language */
	init_language_data(language);


	r = load_data_file(data_file);
	if (r < 0) {
		LOGE("main", "Could not load game data.");
		exit(EXIT_FAILURE);
	}

	free(data_file);

	gfx_data_fixup();

	LOGI("main", "SDL init...");

	r = sdl_init();
	if (r < 0) exit(EXIT_FAILURE);

	/* TODO move to right place */
	midi_play_track(MIDI_TRACK_0);
	audio_set_volume(volume);

	midi_enable(play_midi);
	sfx_enable(play_SFX);


	/*gfx_set_palette(DATA_PALETTE_INTRO);*/
	gfx_set_palette(DATA_PALETTE_GAME);

	LOGI("main", "SDL resolution %ix%i...", screen_width, screen_height);

	r = sdl_set_resolution(screen_width, screen_height, fullscreen);
	if (r < 0) exit(EXIT_FAILURE);

	game.map_generator = map_generator;

	/* Initialize global lookup tables */
	init_spiral_pattern();

	game_init();

	/* Initialize Missions*/
	init_mission("missions.xml");

	/* Initialize interface */
	interface_init(&interface);
	gui_object_set_size((gui_object_t *)&interface,
			    screen_width, screen_height);
	gui_object_set_displayed((gui_object_t *)&interface, 1);

	/* Either load a save game if specified or
	   start a new game. */
	if (save_file != NULL) {
		int r = game_load_save_game(save_file);
		if (r < 0) exit(EXIT_FAILURE);
		free(save_file);

		interface_set_player(&interface, 0);
	} else {
		int r = game_load_random_map(3, &interface.random);
		if (r < 0) exit(EXIT_FAILURE);

		/* Add default player */
		r = game_add_player(12, 64, 40, 40, 40);
		if (r < 0) exit(EXIT_FAILURE);

		interface_set_player(&interface, r);
	}

	viewport_map_reinit();

	if (save_file != NULL) {
		interface_close_game_init(&interface);
	}

	/* Start game loop */
	game_loop();

	LOGI("main", "Cleaning up...");

	/* Clean up */
	map_deinit();
	viewport_map_deinit();
	audio_cleanup();
	sdl_deinit();
	gfx_unload();
	language_cleanup();
	mission_cleanup();
	config_cleanup();

	return EXIT_SUCCESS;
}
Exemple #20
0
static void
do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
{
  if (!logstream)
    {
#ifdef HAVE_W32_SYSTEM
      char *tmp;

      tmp = (no_registry
             ? NULL
             : read_w32_registry_string (NULL, GNUPG_REGISTRY_DIR,
                                         "DefaultLogFile"));
      log_set_file (tmp && *tmp? tmp : NULL);
      xfree (tmp);
#else
      log_set_file (NULL); /* Make sure a log stream has been set.  */
#endif
      assert (logstream);
    }

  es_flockfile (logstream);
  if (missing_lf && level != GPGRT_LOG_CONT)
    es_putc_unlocked ('\n', logstream );
  missing_lf = 0;

  if (level != GPGRT_LOG_CONT)
    { /* Note this does not work for multiple line logging as we would
       * need to print to a buffer first */
      if (with_time && !force_prefixes)
        {
          struct tm *tp;
          time_t atime = time (NULL);

          tp = localtime (&atime);
          es_fprintf_unlocked (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
                               1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
                               tp->tm_hour, tp->tm_min, tp->tm_sec );
        }
      if (with_prefix || force_prefixes)
        es_fputs_unlocked (prefix_buffer, logstream);
      if (with_pid || force_prefixes)
        {
          unsigned long pidsuf;
          int pidfmt;

          if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf)))
            es_fprintf_unlocked (logstream, pidfmt == 1? "[%u.%lu]":"[%u.%lx]",
                                 (unsigned int)getpid (), pidsuf);
          else
            es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ());
        }
      if (!with_time || force_prefixes)
        es_putc_unlocked (':', logstream);
      /* A leading backspace suppresses the extra space so that we can
         correctly output, programname, filename and linenumber. */
      if (fmt && *fmt == '\b')
        fmt++;
      else
        es_putc_unlocked (' ', logstream);
    }

  switch (level)
    {
    case GPGRT_LOG_BEGIN: break;
    case GPGRT_LOG_CONT: break;
    case GPGRT_LOG_INFO: break;
    case GPGRT_LOG_WARN: break;
    case GPGRT_LOG_ERROR: break;
    case GPGRT_LOG_FATAL: es_fputs_unlocked ("Fatal: ",logstream ); break;
    case GPGRT_LOG_BUG:   es_fputs_unlocked ("Ohhhh jeeee: ", logstream); break;
    case GPGRT_LOG_DEBUG: es_fputs_unlocked ("DBG: ", logstream ); break;
    default:
      es_fprintf_unlocked (logstream,"[Unknown log level %d]: ", level);
      break;
    }

  if (fmt)
    {
      if (ignore_arg_ptr)
        es_fputs_unlocked (fmt, logstream);
      else
        es_vfprintf_unlocked (logstream, fmt, arg_ptr);
      if (*fmt && fmt[strlen(fmt)-1] != '\n')
        missing_lf = 1;
    }

  if (level == GPGRT_LOG_FATAL)
    {
      if (missing_lf)
        es_putc_unlocked ('\n', logstream);
      es_funlockfile (logstream);
      exit (2);
    }
  else if (level == GPGRT_LOG_BUG)
    {
      if (missing_lf)
        es_putc_unlocked ('\n', logstream );
      es_funlockfile (logstream);
      abort ();
    }
  else
    es_funlockfile (logstream);
}
Exemple #21
0
static void
do_logv (int level, const char *fmt, va_list arg_ptr)
{
  if (!logstream)
    {
      log_set_file (NULL); /* Make sure a log stream has been set.  */
      assert (logstream);
    }

  if (missing_lf && level != JNLIB_LOG_CONT)
    putc('\n', logstream );
  missing_lf = 0;

  if (level != JNLIB_LOG_CONT)
    { /* Note this does not work for multiple line logging as we would
       * need to print to a buffer first */
      if (with_time && !force_prefixes)
        {
          struct tm *tp;
          time_t atime = time (NULL);
          
          tp = localtime (&atime);
          fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
                   1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
                   tp->tm_hour, tp->tm_min, tp->tm_sec );
        }
      if (with_prefix || force_prefixes)
        fputs (prefix_buffer, logstream);
      if (with_pid || force_prefixes)
        {
          if (get_tid_callback)
            fprintf (logstream, "[%u.%lx]", 
                     (unsigned int)getpid (), get_tid_callback ());
          else
            fprintf (logstream, "[%u]", (unsigned int)getpid ());
        }
      if (!with_time || force_prefixes)
        putc (':', logstream);
      /* A leading backspace suppresses the extra space so that we can
         correctly output, programname, filename and linenumber. */
      if (fmt && *fmt == '\b')
        fmt++;
      else
        putc (' ', logstream);
    }

  switch (level)
    {
    case JNLIB_LOG_BEGIN: break;
    case JNLIB_LOG_CONT: break;
    case JNLIB_LOG_INFO: break;
    case JNLIB_LOG_WARN: break;
    case JNLIB_LOG_ERROR: break;
    case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
    case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
    case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
    default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
    }


  if (fmt)
    {
      vfprintf(logstream,fmt,arg_ptr) ;
      if (*fmt && fmt[strlen(fmt)-1] != '\n')
        missing_lf = 1;
#ifdef HAVE_W32_SYSTEM
      else
        fflush (logstream);
#endif
    }

  if (level == JNLIB_LOG_FATAL)
    {
      if (missing_lf)
        putc('\n', logstream );
      exit(2);
    }
  if (level == JNLIB_LOG_BUG)
    {
      if (missing_lf)
        putc('\n', logstream );
      abort();
    }
}
Exemple #22
0
int
main(int argc, char *argv[])
{
	int r;

	char *data_file = NULL;
	char *save_file = NULL;

	int screen_width = DEFAULT_SCREEN_WIDTH;
	int screen_height = DEFAULT_SCREEN_HEIGHT;
	int fullscreen = 0;
	int game_map = 1;
	int map_generator = 0;
	int preserve_map_bugs = 0;

	int log_level = DEFAULT_LOG_LEVEL;

	int opt;
	while (1) {
		opt = getopt(argc, argv, "d:fg:hl:m:pr:t:");
		if (opt < 0) break;

		switch (opt) {
		case 'd':
		{
			int d = atoi(optarg);
			if (d >= 0 && d < LOG_LEVEL_MAX) {
				log_level = d;
			}
		}
			break;
		case 'f':
			fullscreen = 1;
			break;
		case 'g':
			data_file = malloc(strlen(optarg)+1);
			if (data_file == NULL) exit(EXIT_FAILURE);
			strcpy(data_file, optarg);
			break;
		case 'h':
			fprintf(stdout, HELP, argv[0]);
			exit(EXIT_SUCCESS);
			break;
		case 'l':
			save_file = malloc(strlen(optarg)+1);
			if (save_file == NULL) exit(EXIT_FAILURE);
			strcpy(save_file, optarg);
			break;
		case 'm':
			game_map = atoi(optarg);
			break;
		case 'p':
			preserve_map_bugs = 1;
			break;
		case 'r':
		{
			char *hstr = strchr(optarg, 'x');
			if (hstr == NULL) {
				fprintf(stderr, USAGE, argv[0]);
				exit(EXIT_FAILURE);
			}
			screen_width = atoi(optarg);
			screen_height = atoi(hstr+1);
		}
			break;
		case 't':
			map_generator = atoi(optarg);
			break;
		default:
			fprintf(stderr, USAGE, argv[0]);
			exit(EXIT_FAILURE);
			break;
		}
	}

	/* Set up logging */
	log_set_file(stdout);
	log_set_level(log_level);

	LOGI("main", "freeserf %s", FREESERF_VERSION);

	r = load_data_file(data_file);
	if (r < 0) {
		LOGE("main", "Could not load game data.");
		exit(EXIT_FAILURE);
	}

	free(data_file);

	gfx_data_fixup();

	LOGI("main", "SDL init...");

	r = sdl_init();
	if (r < 0) exit(EXIT_FAILURE);

	/* TODO move to right place */
	midi_play_track(MIDI_TRACK_0);
	audio_set_volume(75);

	/*gfx_set_palette(DATA_PALETTE_INTRO);*/
	gfx_set_palette(DATA_PALETTE_GAME);

	LOGI("main", "SDL resolution %ix%i...", screen_width, screen_height);

	r = sdl_set_resolution(screen_width, screen_height, fullscreen);
	if (r < 0) exit(EXIT_FAILURE);

	game.mission_level = game_map - 1; /* set game map */
	game.map_generator = map_generator;
	game.map_preserve_bugs = preserve_map_bugs;

	/* Init globals */
	allocate_global_memory();
	player_interface_init();

	/* Initialize global lookup tables */
	init_spiral_pattern();

	game_init();

	/* Either load a save game if specified or
	   start a new game. */
	if (save_file != NULL) {
		int r = game_load_save_game(save_file);
		if (r < 0) exit(EXIT_FAILURE);
		free(save_file);
	} else {
		game_load_random_map();
	}

	/* Move viewport to initial position */
	viewport_move_to_map_pos(&interface.viewport, interface.map_cursor_pos);

	/* Start game loop */
	game_loop();

	LOGI("main", "Cleaning up...");

	/* Clean up */
	audio_cleanup();
	sdl_deinit();
	gfx_unload();

	return EXIT_SUCCESS;
}
Exemple #23
0
int
main (int argc, char **argv )
{
  ARGPARSE_ARGS pargs;
  int orig_argc;
  gpg_error_t err;
  int may_coredump;
  char **orig_argv;
  FILE *configfp = NULL;
  char *configname = NULL;
  const char *shell;
  unsigned int configlineno;
  int parse_debug = 0;
  const char *debug_level = NULL;
  int default_config =1;
  int greeting = 0;
  int nogreeting = 0;
  int multi_server = 0;
  int is_daemon = 0;
  int nodetach = 0;
  int csh_style = 0;
  char *logfile = NULL;
  int debug_wait = 0;
  int gpgconf_list = 0;
  const char *config_filename = NULL;
  int allow_coredump = 0;
  int standard_socket = 0;
  struct assuan_malloc_hooks malloc_hooks;

  set_strusage (my_strusage);
  gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
  /* Please note that we may running SUID(ROOT), so be very CAREFUL
     when adding any stuff between here and the call to INIT_SECMEM()
     somewhere after the option parsing */
  log_set_prefix ("scdaemon", 1|4);

  /* Make sure that our subsystems are ready.  */
  i18n_init ();
  init_common_subsystems (&argc, &argv);


  /* Libgcrypt requires us to register the threading model first.
     Note that this will also do the pth_init. */
  gcry_threads_pth.init = fixed_gcry_pth_init;
  err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
  if (err)
    {
      log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
                 gpg_strerror (err));
    }

  /* Check that the libraries are suitable.  Do it here because
     the option parsing may need services of the library */
  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
    {
      log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
                 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
    }

  ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);

  malloc_hooks.malloc = gcry_malloc;
  malloc_hooks.realloc = gcry_realloc;
  malloc_hooks.free = gcry_free;
  assuan_set_malloc_hooks (&malloc_hooks);
  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
  assuan_set_system_hooks (ASSUAN_SYSTEM_PTH);
  assuan_sock_init ();
  setup_libassuan_logging (&opt.debug);

  setup_libgcrypt_logging ();
  gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);

  may_coredump = disable_core_dumps ();

  /* Set default options. */
  opt.allow_admin = 1;
  opt.pcsc_driver = DEFAULT_PCSC_DRIVER;

#ifdef HAVE_W32_SYSTEM
  standard_socket = 1;  /* Under Windows we always use a standard
                           socket.  */
#endif


  shell = getenv ("SHELL");
  if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
    csh_style = 1;

  opt.homedir = default_homedir ();

  /* Check whether we have a config file on the commandline */
  orig_argc = argc;
  orig_argv = argv;
  pargs.argc = &argc;
  pargs.argv = &argv;
  pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
  while (arg_parse( &pargs, opts))
    {
      if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
        parse_debug++;
      else if (pargs.r_opt == oOptions)
        { /* yes there is one, so we do not try the default one, but
	     read the option file when it is encountered at the
	     commandline */
          default_config = 0;
	}
	else if (pargs.r_opt == oNoOptions)
          default_config = 0; /* --no-options */
	else if (pargs.r_opt == oHomedir)
          opt.homedir = pargs.r.ret_str;
    }

  /* initialize the secure memory. */
  gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
  maybe_setuid = 0;

  /*
     Now we are working under our real uid
  */


  if (default_config)
    configname = make_filename (opt.homedir, "scdaemon.conf", NULL );


  argc = orig_argc;
  argv = orig_argv;
  pargs.argc = &argc;
  pargs.argv = &argv;
  pargs.flags=  1;  /* do not remove the args */
 next_pass:
  if (configname)
    {
      configlineno = 0;
      configfp = fopen (configname, "r");
      if (!configfp)
        {
          if (default_config)
            {
              if( parse_debug )
                log_info (_("NOTE: no default option file `%s'\n"),
                          configname );
	    }
          else
            {
              log_error (_("option file `%s': %s\n"),
                         configname, strerror(errno) );
              exit(2);
	    }
          xfree (configname);
          configname = NULL;
	}
      if (parse_debug && configname )
        log_info (_("reading options from `%s'\n"), configname );
      default_config = 0;
    }

  while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
    {
      switch (pargs.r_opt)
        {
        case aGPGConfList: gpgconf_list = 1; break;
        case aGPGConfTest: gpgconf_list = 2; break;
        case oQuiet: opt.quiet = 1; break;
        case oVerbose: opt.verbose++; break;
        case oBatch: opt.batch=1; break;

        case oDebug: opt.debug |= pargs.r.ret_ulong; break;
        case oDebugAll: opt.debug = ~0; break;
        case oDebugLevel: debug_level = pargs.r.ret_str; break;
        case oDebugWait: debug_wait = pargs.r.ret_int; break;
        case oDebugAllowCoreDump:
          enable_core_dumps ();
          allow_coredump = 1;
          break;
        case oDebugCCIDDriver:
#ifdef HAVE_LIBUSB
          ccid_set_debug_level (ccid_set_debug_level (-1)+1);
#endif /*HAVE_LIBUSB*/
          break;
        case oDebugDisableTicker: ticker_disabled = 1; break;
        case oDebugLogTid:
          log_set_pid_suffix_cb (tid_log_callback);
          break;

        case oOptions:
          /* config files may not be nested (silently ignore them) */
          if (!configfp)
            {
		xfree(configname);
		configname = xstrdup(pargs.r.ret_str);
		goto next_pass;
	    }
          break;
        case oNoGreeting: nogreeting = 1; break;
        case oNoVerbose: opt.verbose = 0; break;
        case oNoOptions: break; /* no-options */
        case oHomedir: opt.homedir = pargs.r.ret_str; break;
        case oNoDetach: nodetach = 1; break;
        case oLogFile: logfile = pargs.r.ret_str; break;
        case oCsh: csh_style = 1; break;
        case oSh: csh_style = 0; break;
        case oServer: pipe_server = 1; break;
        case oMultiServer: pipe_server = 1; multi_server = 1; break;
        case oDaemon: is_daemon = 1; break;

        case oReaderPort: opt.reader_port = pargs.r.ret_str; break;
        case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
        case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break;
        case oDisableCCID: opt.disable_ccid = 1; break;
        case oDisableOpenSC: break;

        case oDisableKeypad: opt.disable_keypad = 1; break;

        case oAllowAdmin: /* Dummy because allow is now the default.  */
          break;
        case oDenyAdmin: opt.allow_admin = 0; break;

        case oCardTimeout: opt.card_timeout = pargs.r.ret_ulong; break;

        case oDisableApplication:
          add_to_strlist (&opt.disabled_applications, pargs.r.ret_str);
          break;

        default:
          pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
          break;
	}
    }
  if (configfp)
    {
      fclose( configfp );
      configfp = NULL;
      /* Keep a copy of the config name for use by --gpgconf-list. */
      config_filename = configname;
      configname = NULL;
      goto next_pass;
    }
  xfree (configname);
  configname = NULL;
  if (log_get_errorcount(0))
    exit(2);
  if (nogreeting )
    greeting = 0;

  if (greeting)
    {
      es_fprintf (es_stderr, "%s %s; %s\n",
                  strusage(11), strusage(13), strusage(14) );
      es_fprintf (es_stderr, "%s\n", strusage(15) );
    }
#ifdef IS_DEVELOPMENT_VERSION
  log_info ("NOTE: this is a development version!\n");
#endif


  if (atexit (cleanup))
    {
      log_error ("atexit failed\n");
      cleanup ();
      exit (1);
    }

  set_debug (debug_level);

  initialize_module_command ();

  if (gpgconf_list == 2)
    scd_exit (0);
  if (gpgconf_list)
    {
      /* List options and default values in the GPG Conf format.  */
      char *filename = NULL;
      char *filename_esc;

      if (config_filename)
	filename = xstrdup (config_filename);
      else
        filename = make_filename (opt.homedir, "scdaemon.conf", NULL);
      filename_esc = percent_escape (filename, NULL);

      es_printf ("gpgconf-scdaemon.conf:%lu:\"%s\n",
                 GC_OPT_FLAG_DEFAULT, filename_esc);
      xfree (filename_esc);
      xfree (filename);

      es_printf ("verbose:%lu:\n"
                 "quiet:%lu:\n"
                 "debug-level:%lu:\"none:\n"
                 "log-file:%lu:\n",
                 GC_OPT_FLAG_NONE,
                 GC_OPT_FLAG_NONE,
                 GC_OPT_FLAG_DEFAULT,
                 GC_OPT_FLAG_NONE );

      es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE );
      es_printf ("ctapi-driver:%lu:\n", GC_OPT_FLAG_NONE );
      es_printf ("pcsc-driver:%lu:\"%s:\n",
              GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER );
#ifdef HAVE_LIBUSB
      es_printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE );
#endif
      es_printf ("deny-admin:%lu:\n", GC_OPT_FLAG_NONE );
      es_printf ("disable-keypad:%lu:\n", GC_OPT_FLAG_NONE );
      es_printf ("card-timeout:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, 0);

      scd_exit (0);
    }

  /* Now start with logging to a file if this is desired.  */
  if (logfile)
    {
      log_set_file (logfile);
      log_set_prefix (NULL, 1|2|4);
    }

  if (debug_wait && pipe_server)
    {
      log_debug ("waiting for debugger - my pid is %u .....\n",
                 (unsigned int)getpid());
      gnupg_sleep (debug_wait);
      log_debug ("... okay\n");
    }

  if (pipe_server)
    {
      /* This is the simple pipe based server */
      ctrl_t ctrl;
      pth_attr_t tattr;
      int fd = -1;

#ifndef HAVE_W32_SYSTEM
      {
        struct sigaction sa;

        sa.sa_handler = SIG_IGN;
        sigemptyset (&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction (SIGPIPE, &sa, NULL);
      }
#endif

      /* If --debug-allow-core-dump has been given we also need to
         switch the working directory to a place where we can actually
         write. */
      if (allow_coredump)
        {
          if (chdir("/tmp"))
            log_debug ("chdir to `/tmp' failed: %s\n", strerror (errno));
          else
            log_debug ("changed working directory to `/tmp'\n");
        }

      /* In multi server mode we need to listen on an additional
         socket.  Create that socket now before starting the handler
         for the pipe connection.  This allows that handler to send
         back the name of that socket. */
      if (multi_server)
        {
          socket_name = create_socket_name (standard_socket,
                                            "S.scdaemon",
                                            "gpg-XXXXXX/S.scdaemon");

          fd = FD2INT(create_server_socket (standard_socket,
                                            socket_name, &socket_nonce));
        }

      tattr = pth_attr_new();
      pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
      pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 512*1024);
      pth_attr_set (tattr, PTH_ATTR_NAME, "pipe-connection");

      ctrl = xtrycalloc (1, sizeof *ctrl);
      if ( !ctrl )
        {
          log_error ("error allocating connection control data: %s\n",
                     strerror (errno) );
          scd_exit (2);
        }
      ctrl->thread_startup.fd = GNUPG_INVALID_FD;
      if ( !pth_spawn (tattr, start_connection_thread, ctrl) )
        {
          log_error ("error spawning pipe connection handler: %s\n",
                     strerror (errno) );
          xfree (ctrl);
          scd_exit (2);
        }

      /* We run handle_connection to wait for the shutdown signal and
         to run the ticker stuff.  */
      handle_connections (fd);
      if (fd != -1)
        close (fd);
    }
  else if (!is_daemon)
    {
      log_info (_("please use the option `--daemon'"
                  " to run the program in the background\n"));
    }
  else
    { /* Regular server mode */
      int fd;
#ifndef HAVE_W32_SYSTEM
      pid_t pid;
      int i;
#endif

      /* Create the socket.  */
      socket_name = create_socket_name (standard_socket,
                                        "S.scdaemon",
                                        "gpg-XXXXXX/S.scdaemon");

      fd = FD2INT (create_server_socket (standard_socket,
                                         socket_name, &socket_nonce));


      fflush (NULL);
#ifndef HAVE_W32_SYSTEM
      pid = fork ();
      if (pid == (pid_t)-1)
        {
          log_fatal ("fork failed: %s\n", strerror (errno) );
          exit (1);
        }
      else if (pid)
        { /* we are the parent */
          char *infostr;

          close (fd);

          /* create the info string: <name>:<pid>:<protocol_version> */
          if (estream_asprintf (&infostr, "SCDAEMON_INFO=%s:%lu:1",
				socket_name, (ulong) pid) < 0)
            {
              log_error ("out of core\n");
              kill (pid, SIGTERM);
              exit (1);
            }
          *socket_name = 0; /* don't let cleanup() remove the socket -
                               the child should do this from now on */
          if (argc)
            { /* run the program given on the commandline */
              if (putenv (infostr))
                {
                  log_error ("failed to set environment: %s\n",
                             strerror (errno) );
                  kill (pid, SIGTERM );
                  exit (1);
                }
              execvp (argv[0], argv);
              log_error ("failed to run the command: %s\n", strerror (errno));
              kill (pid, SIGTERM);
              exit (1);
            }
          else
            {
              /* Print the environment string, so that the caller can use
                 shell's eval to set it */
              if (csh_style)
                {
                  *strchr (infostr, '=') = ' ';
                  es_printf ( "setenv %s\n", infostr);
                }
              else
                {
                  es_printf ( "%s; export SCDAEMON_INFO;\n", infostr);
                }
              xfree (infostr);
              exit (0);
            }
          /* NOTREACHED */
        } /* end parent */

      /* This is the child. */

      /* Detach from tty and put process into a new session. */
      if (!nodetach )
        {
          /* Close stdin, stdout and stderr unless it is the log stream. */
          for (i=0; i <= 2; i++)
            {
              if ( log_test_fd (i) && i != fd)
                close (i);
            }
          if (setsid() == -1)
            {
              log_error ("setsid() failed: %s\n", strerror(errno) );
              cleanup ();
              exit (1);
            }
        }

      {
        struct sigaction sa;

        sa.sa_handler = SIG_IGN;
        sigemptyset (&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction (SIGPIPE, &sa, NULL);
      }

      if (chdir("/"))
        {
          log_error ("chdir to / failed: %s\n", strerror (errno));
          exit (1);
        }

#endif /*!HAVE_W32_SYSTEM*/

      handle_connections (fd);

      close (fd);
    }

  return 0;
}
Exemple #24
0
int main(int argc, char **argv)
{
        int err;

        server_init();

        parse_arguments(argc, argv);

        log_set_file(logFile);

        if (nodaemon == 0) {
                err = daemonise();
                if (err != 0) exit(1);

                err = writePidFile(pidFile);
                if (err != 0) exit(1);

                err = drop_privileges();
                if (err != 0) exit(1);
        }

        err = signalisation();
        if (err != 0) exit(1);

        serverSocket = openServerSocket(NULL, port);
        if (serverSocket == -1) exit(1);

        log_info("Server ready for connections");

        request_t req;
        response_t resp;

        memset(&req, 0, sizeof(request_t));
        memset(&resp, 0, sizeof(response_t));
                        
        while (serverSocket != -1) {

                int client = serverSocketAccept(serverSocket);
                if (client == -1) {
                        continue;
                }

                int r = parseRequest(client, &req, &resp);
                if (r != 0) {
                        clientPrintf(client, "HTTP/1.1 %03d\r\n", resp.status);
                        closeClient(client);
                        continue;
                }

                log_info("Request: %s", req.path);

                if (1) {
                        list_t* l = req.args;
                        while (l) {
                                pair_t* p = (pair_t*) l->data;
                                log_debug("args[]: %s = %s", p->name, p->value);
                                l = l->next;
                        }
                        l = req.headers;
                        while (l) {
                                pair_t* p = (pair_t*) l->data;
                                log_debug("headers[]: '%s': '%s'", p->name, p->value);
                                l = l->next;
                        }
                }

                server_handle_request(&req, &resp);

                // Debug printf
                
                if (resp.status != 0) {
                        clientPrintf(client, 
                                     "HTTP/1.1 %03d\r\n"
                                     "Content-Length: %d\r\n"
                                     "Content-Type: %s\r\n"
                                     "\r\n", 
                                     resp.status, resp.length, resp.content_type);

                        clientWrite(client, resp.body, resp.length);
                        
                } else {
                        log_err("main.c, request status == 0, request not handle!");
                }

                closeClient(client);
                
                request_clear(&req);
                response_clear(&resp);
        }

        removePidFile(pidFile); 

        return 0;
}
Exemple #25
0
// NOTE: this function needs to call RegisterServiceCtrlHandlerEx and
// SetServiceStatus in all circumstances if brickd is running as service
static int generic_main(bool log_to_file, bool debug, bool libusb_debug) {
	int exit_code = EXIT_FAILURE;
	const char *mutex_name = "Global\\Tinkerforge-Brick-Daemon-Single-Instance";
	HANDLE mutex_handle = NULL;
	bool fatal_error = false;
	DWORD service_exit_code = NO_ERROR;
	int rc;
	char filename[1024];
	int i;
	FILE *log_file = NULL;
	WSADATA wsa_data;
	DEV_BROADCAST_DEVICEINTERFACE notification_filter;
	HDEVNOTIFY notification_handle;

	mutex_handle = OpenMutex(SYNCHRONIZE, FALSE, mutex_name);

	if (mutex_handle == NULL) {
		rc = GetLastError();

		if (rc == ERROR_ACCESS_DENIED) {
			rc = service_is_running();

			if (rc < 0) {
				fatal_error = true;
				// FIXME: set service_exit_code

				goto error_mutex;
			} else if (rc) {
				fatal_error = true;
				service_exit_code = ERROR_SERVICE_ALREADY_RUNNING;

				log_error("Could not start as %s, another instance is already running as service",
				          _run_as_service ? "service" : "console application");

				goto error_mutex;
			}
		}

		if (rc != ERROR_FILE_NOT_FOUND) {
			fatal_error = true;
			// FIXME: set service_exit_code
			rc += ERRNO_WINAPI_OFFSET;

			log_error("Could not open single instance mutex: %s (%d)",
			          get_errno_name(rc), rc);

			goto error_mutex;
		}
	}

	if (mutex_handle != NULL) {
		fatal_error = true;
		service_exit_code = ERROR_SERVICE_ALREADY_RUNNING;

		log_error("Could not start as %s, another instance is already running",
		          _run_as_service ? "service" : "console application");

		goto error_mutex;
	}

	mutex_handle = CreateMutex(NULL, FALSE, mutex_name);

	if (mutex_handle == NULL) {
		fatal_error = true;
		// FIXME: set service_exit_code
		rc = ERRNO_WINAPI_OFFSET + GetLastError();

		log_error("Could not create single instance mutex: %s (%d)",
		          get_errno_name(rc), rc);

		goto error_mutex;
	}

	if (log_to_file) {
		if (GetModuleFileName(NULL, filename, sizeof(filename)) == 0) {
			rc = ERRNO_WINAPI_OFFSET + GetLastError();

			log_warn("Could not get module file name: %s (%d)",
			         get_errno_name(rc), rc);
		} else {
			i = strlen(filename);

			if (i < 4) {
				log_warn("Module file name '%s' is too short", filename);
			} else {
				filename[i - 3] = '\0';
				string_append(filename, "log", sizeof(filename));

				log_file = fopen(filename, "a+");

				if (log_file == NULL) {
					log_warn("Could not open log file '%s'", filename);
				} else {
					printf("Logging to '%s'\n", filename);

					log_set_file(log_file);
				}
			}
		}
	} else if (_run_as_service) {
		log_set_file(NULL);
	}

	if (!_run_as_service &&
	    !SetConsoleCtrlHandler(console_ctrl_handler, TRUE)) {
		rc = ERRNO_WINAPI_OFFSET + GetLastError();

		log_warn("Could not set console control handler: %s (%d)",
		         get_errno_name(rc), rc);
	}

	log_set_debug_override(debug);

	log_set_level(LOG_CATEGORY_EVENT, config_get_option("log_level.event")->value.log_level);
	log_set_level(LOG_CATEGORY_USB, config_get_option("log_level.usb")->value.log_level);
	log_set_level(LOG_CATEGORY_NETWORK, config_get_option("log_level.network")->value.log_level);
	log_set_level(LOG_CATEGORY_HOTPLUG, config_get_option("log_level.hotplug")->value.log_level);
	log_set_level(LOG_CATEGORY_HARDWARE, config_get_option("log_level.hardware")->value.log_level);
	log_set_level(LOG_CATEGORY_WEBSOCKET, config_get_option("log_level.websocket")->value.log_level);
	log_set_level(LOG_CATEGORY_OTHER, config_get_option("log_level.other")->value.log_level);

	if (config_has_error()) {
		log_error("Error(s) in config file '%s', run with --check-config option for details",
		          _config_filename);

		fatal_error = true;

		goto error_config;
	}

	if (_run_as_service) {
		log_info("Brick Daemon %s started (as service)", VERSION_STRING);
	} else {
		log_info("Brick Daemon %s started", VERSION_STRING);
	}

	if (config_has_warning()) {
		log_warn("Warning(s) in config file '%s', run with --check-config option for details",
		         _config_filename);
	}

	// initialize service status
error_config:
error_mutex:
	if (_run_as_service) {
		if (service_init(service_control_handler) < 0) {
			// FIXME: set service_exit_code
			goto error;
		}

		if (!fatal_error) {
			// service is starting
			service_set_status(SERVICE_START_PENDING, NO_ERROR);
		}
	}

	if (fatal_error) {
		goto error;
	}

	// initialize WinSock2
	if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
		// FIXME: set service_exit_code
		rc = ERRNO_WINAPI_OFFSET + WSAGetLastError();

		log_error("Could not initialize Windows Sockets 2.2: %s (%d)",
		          get_errno_name(rc), rc);

		goto error_event;
	}

	if (event_init() < 0) {
		// FIXME: set service_exit_code
		goto error_event;
	}

	if (hardware_init() < 0) {
		// FIXME: set service_exit_code
		goto error_hardware;
	}

	if (usb_init(libusb_debug) < 0) {
		// FIXME: set service_exit_code
		goto error_usb;
	}

	// create notification pipe
	if (pipe_create(&_notification_pipe) < 0) {
		// FIXME: set service_exit_code

		log_error("Could not create notification pipe: %s (%d)",
		          get_errno_name(errno), errno);

		goto error_pipe;
	}

	if (event_add_source(_notification_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC,
	                     EVENT_READ, forward_notifications, NULL) < 0) {
		// FIXME: set service_exit_code
		goto error_pipe_add;
	}

	// register device notification
	ZeroMemory(&notification_filter, sizeof(notification_filter));

	notification_filter.dbcc_size = sizeof(notification_filter);
	notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
	notification_filter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;

	if (_run_as_service) {
		notification_handle = RegisterDeviceNotification((HANDLE)service_get_status_handle(),
		                                                 &notification_filter,
		                                                 DEVICE_NOTIFY_SERVICE_HANDLE);
	} else {
		if (message_pump_start() < 0) {
			// FIXME: set service_exit_code
			goto error_pipe_add;
		}

		notification_handle = RegisterDeviceNotification(_message_pump_hwnd,
		                                                 &notification_filter,
		                                                 DEVICE_NOTIFY_WINDOW_HANDLE);
	}

	if (notification_handle == NULL) {
		// FIXME: set service_exit_code
		rc = ERRNO_WINAPI_OFFSET + GetLastError();

		log_error("Could not register for device notification: %s (%d)",
		          get_errno_name(rc), rc);

		goto error_notification;
	}

	if (network_init() < 0) {
		// FIXME: set service_exit_code
		goto error_network;
	}

	// running
	if (_run_as_service) {
		service_set_status(SERVICE_RUNNING, NO_ERROR);
	}

	if (event_run(network_cleanup_clients_and_zombies) < 0) {
		// FIXME: set service_exit_code
		goto error_run;
	}

	exit_code = EXIT_SUCCESS;

error_run:
	network_exit();

error_network:
	UnregisterDeviceNotification(notification_handle);

error_notification:
	if (!_run_as_service) {
		message_pump_stop();
	}

	event_remove_source(_notification_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC);

error_pipe_add:
	pipe_destroy(&_notification_pipe);

error_pipe:
	usb_exit();

error_usb:
	hardware_exit();

error_hardware:
	event_exit();

error_event:
	log_info("Brick Daemon %s stopped", VERSION_STRING);

error:
	if (!_run_as_service) {
		// unregister the console handler before exiting the log. otherwise a
		// control event might be send to the control handler after the log
		// is not available anymore and the control handler tries to write a
		// log messages triggering a crash. this situation could easily be
		// created by clicking the close button of the command prompt window
		// while the getch call is waiting for the user to press a key.
		SetConsoleCtrlHandler(console_ctrl_handler, FALSE);
	}

	log_exit();

	config_exit();

	if (_run_as_service) {
		// because the service process can be terminated at any time after
		// entering SERVICE_STOPPED state the mutex is closed beforehand,
		// even though this creates a tiny time window in which the service
		// is still running but the mutex is not held anymore
		if (mutex_handle != NULL) {
			CloseHandle(mutex_handle);
		}

		// service is now stopped
		service_set_status(SERVICE_STOPPED, service_exit_code);
	} else {
		if (_pause_before_exit) {
			printf("Press any key to exit...\n");
			getch();
		}

		if (mutex_handle != NULL) {
			CloseHandle(mutex_handle);
		}
	}

	return exit_code;
}
Exemple #26
0
// NOTE: this function needs to call RegisterServiceCtrlHandlerEx and
// SetServiceStatus in all circumstances if brickd is running as service
static int generic_main(int log_to_file, int debug) {
	int exit_code = EXIT_FAILURE;
	const char *mutex_name = "Global\\Tinkerforge-Brick-Daemon-Single-Instance";
	HANDLE mutex_handle = NULL;
	int mutex_error = 0;
	DWORD service_exit_code = NO_ERROR;
	int rc;
	char filename[1024];
	int i;
	FILE *logfile = NULL;
	WSADATA wsa_data;
	DEV_BROADCAST_DEVICEINTERFACE notification_filter;
	HDEVNOTIFY notification_handle;

	mutex_handle = OpenMutex(SYNCHRONIZE, FALSE, mutex_name);

	if (mutex_handle == NULL) {
		rc = GetLastError();

		if (rc == ERROR_ACCESS_DENIED) {
			rc = service_is_running();

			if (rc < 0) {
				mutex_error = 1;
				// FIXME: set service_exit_code

				goto error_mutex;
			} else if (rc) {
				mutex_error = 1;
				service_exit_code = ERROR_SERVICE_ALREADY_RUNNING;

				log_error("Could not start as %s, another instance is already running as service",
				          _run_as_service ? "service" : "console application");

				goto error_mutex;
			}
		}

		if (rc != ERROR_FILE_NOT_FOUND) {
			mutex_error = 1;
			// FIXME: set service_exit_code
			rc += ERRNO_WINAPI_OFFSET;

			log_error("Could not open single instance mutex: %s (%d)",
			          get_errno_name(rc), rc);

			goto error_mutex;
		}
	}

	if (mutex_handle != NULL) {
		mutex_error = 1;
		service_exit_code = ERROR_SERVICE_ALREADY_RUNNING;

		log_error("Could not start as %s, another instance is already running",
		          _run_as_service ? "service" : "console application");

		goto error_mutex;
	}

	mutex_handle = CreateMutex(NULL, FALSE, mutex_name);

	if (mutex_handle == NULL) {
		mutex_error = 1;
		// FIXME: set service_exit_code
		rc = ERRNO_WINAPI_OFFSET + GetLastError();

		log_error("Could not create single instance mutex: %s (%d)",
		          get_errno_name(rc), rc);

		goto error_mutex;
	}

	if (!_run_as_service &&
	    !SetConsoleCtrlHandler(console_ctrl_handler, TRUE)) {
		rc = ERRNO_WINAPI_OFFSET + GetLastError();

		log_warn("Could not set console control handler: %s (%d)",
		          get_errno_name(rc), rc);
	}

	if (log_to_file) {
		if (GetModuleFileName(NULL, filename, sizeof(filename)) == 0) {
			rc = ERRNO_WINAPI_OFFSET + GetLastError();

			log_warn("Could not get module file name: %s (%d)",
			         get_errno_name(rc), rc);
		} else {
			i = strlen(filename);

			if (i < 4) {
				log_warn("Module file name '%s' is too short", filename);
			} else {
				strcpy(filename + i - 3, "log");

				logfile = fopen(filename, "a+");

				if (logfile == NULL) {
					log_warn("Could not open logfile '%s'", filename);
				} else {
					log_set_file(logfile);
				}
			}
		}
	}

	if (debug) {
		log_set_level(LOG_CATEGORY_EVENT, LOG_LEVEL_DEBUG);
		log_set_level(LOG_CATEGORY_USB, LOG_LEVEL_DEBUG);
		log_set_level(LOG_CATEGORY_NETWORK, LOG_LEVEL_DEBUG);
		log_set_level(LOG_CATEGORY_HOTPLUG, LOG_LEVEL_DEBUG);
		log_set_level(LOG_CATEGORY_OTHER, LOG_LEVEL_DEBUG);
	} else {
		log_set_level(LOG_CATEGORY_EVENT, config_get_log_level(LOG_CATEGORY_EVENT));
		log_set_level(LOG_CATEGORY_USB, config_get_log_level(LOG_CATEGORY_USB));
		log_set_level(LOG_CATEGORY_NETWORK, config_get_log_level(LOG_CATEGORY_NETWORK));
		log_set_level(LOG_CATEGORY_HOTPLUG, config_get_log_level(LOG_CATEGORY_HOTPLUG));
		log_set_level(LOG_CATEGORY_OTHER, config_get_log_level(LOG_CATEGORY_OTHER));
	}

	if (_run_as_service) {
		log_info("Brick Daemon %s started (as service)", VERSION_STRING);
	} else {
		log_info("Brick Daemon %s started", VERSION_STRING);
	}

	if (config_has_error()) {
		log_warn("Errors found in config file '%s', run with --check-config option for details",
		         _config_filename);
	}

	// initialize service status
error_mutex:
	if (_run_as_service) {
		if (service_init(service_control_handler) < 0) {
			// FIXME: set service_exit_code
			goto error;
		}

		if (!mutex_error) {
			// service is starting
			service_set_status(SERVICE_START_PENDING, NO_ERROR);
		}
	}

	if (mutex_error) {
		goto error;
	}

	// initialize WinSock2
	if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
		// FIXME: set service_exit_code
		rc = ERRNO_WINAPI_OFFSET + WSAGetLastError();

		log_error("Could not initialize Windows Sockets 2.2: %s (%d)",
		          get_errno_name(rc), rc);

		goto error_event;
	}

	if (event_init() < 0) {
		// FIXME: set service_exit_code
		goto error_event;
	}

	if (usb_init() < 0) {
		// FIXME: set service_exit_code
		goto error_usb;
	}

	// create notification pipe
	if (pipe_create(_notification_pipe) < 0) {
		// FIXME: set service_exit_code

		log_error("Could not create notification pipe: %s (%d)",
		          get_errno_name(errno), errno);

		goto error_pipe;
	}

	if (event_add_source(_notification_pipe[0], EVENT_SOURCE_TYPE_GENERIC,
	                     EVENT_READ, forward_notifications, NULL) < 0) {
		// FIXME: set service_exit_code
		goto error_pipe_add;
	}

	// register device notification
	ZeroMemory(&notification_filter, sizeof(notification_filter));

	notification_filter.dbcc_size = sizeof(notification_filter);
	notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
	notification_filter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;

	if (_run_as_service) {
		notification_handle = RegisterDeviceNotification((HANDLE)service_get_status_handle(),
		                                                 &notification_filter,
		                                                 DEVICE_NOTIFY_SERVICE_HANDLE);
	} else {
		if (message_pump_start() < 0) {
			// FIXME: set service_exit_code
			goto error_pipe_add;
		}

		notification_handle = RegisterDeviceNotification(_message_pump_hwnd,
		                                                 &notification_filter,
		                                                 DEVICE_NOTIFY_WINDOW_HANDLE);
	}

	if (notification_handle == NULL) {
		// FIXME: set service_exit_code
		rc = ERRNO_WINAPI_OFFSET + GetLastError();

		log_error("Could not register for device notification: %s (%d)",
		          get_errno_name(rc), rc);

		goto error_notification;
	}

	if (network_init() < 0) {
		// FIXME: set service_exit_code
		goto error_network;
	}

	// running
	if (_run_as_service) {
		service_set_status(SERVICE_RUNNING, NO_ERROR);
	}

	if (event_run() < 0) {
		// FIXME: set service_exit_code
		goto error_run;
	}

	exit_code = EXIT_SUCCESS;

error_run:
	network_exit();

error_network:
	UnregisterDeviceNotification(notification_handle);

error_notification:
	if (!_run_as_service) {
		message_pump_stop();
	}

	event_remove_source(_notification_pipe[0], EVENT_SOURCE_TYPE_GENERIC);

error_pipe_add:
	pipe_destroy(_notification_pipe);

error_pipe:
	usb_exit();

error_usb:
	event_exit();

error_event:
	log_info("Brick Daemon %s stopped", VERSION_STRING);

error:
	log_exit();

	config_exit();

	if (_run_as_service) {
		// because the service process can be terminated at any time after
		// entering SERVICE_STOPPED state the mutex is closed beforehand,
		// even though this creates a tiny time window in which the service
		// is still running but the mutex is not held anymore
		if (mutex_handle != NULL) {
			CloseHandle(mutex_handle);
		}

		// service is now stopped
		service_set_status(SERVICE_STOPPED, service_exit_code);
	} else {
		if (_pause_before_exit) {
			printf("Press any key to exit...\n");
			getch();
		}

		if (mutex_handle != NULL) {
			CloseHandle(mutex_handle);
		}
	}

	return exit_code;
}
Exemple #27
0
int args_get(int argc, char **argv, args *arg)
{
    int i;
    int ret = 0;
    args_init(arg);
    for(i = 1; i < argc; i++)
    {
        if(!strcmp(*(argv + i), "-c") || !strcmp(*(argv + i), "--collect"))
        {
            arg->collect = 1;
            ret++;
        }
        else if(!strcmp(*(argv + i), "-g") || !strcmp(*(argv + i), "--graph"))
        {
            arg->graph = 1;
            arg->res = *(argv + i + 1);
            ret++;
        }
        else if(!strcmp(*(argv + i), "-t") || !strcmp(*(argv + i), "--test"))
        {
            arg->test = 1;
            ret++;
        }
        else if(!strcmp(*(argv + i), "-d") || !strcmp(*(argv + i), "--daemon"))
        {
            arg->daemon = 1;
            ret++;
        }
        else if(!strcmp(*(argv + i), "-r") || !strcmp(*(argv + i), "--rrdopt"))
        {
            arg->rrdopt = *(argv + i + 1);
            ret++;
        }
        else if(!strcmp(*(argv + i), "-v") || !strcmp(*(argv + i), "--version"))
        {
            arg->version = 1;
            ret++;
        }
        else if(!strcmp(*(argv + i), "-gp") || !strcmp(*(argv + i), "--gpath"))
        {
            if(!check_valid_path(*(argv + i + 1)))
            {
                arg->gpath = *(argv + i + 1);
                ret++;
            }
        }
        else if(!strcmp(*(argv + i), "-rp") || !strcmp(*(argv + i), "--rpath"))
        {
            if(!check_valid_path(*(argv + i + 1)))
            {
                arg->rpath = *(argv + i + 1);
                ret++;
            }
        }
        else if(!strcmp(*(argv + i), "-f") || !strcmp(*(argv + i), "--conffile"))
        {
            if(!check_configuration_file(*(argv + i + 1)))
            {
                arg->conffile = *(argv + i + 1);
                ret++;
            }
        }
        else if(!strcmp(*(argv + i), "-l") || !strcmp(*(argv + i), "--log"))
        {
            arg->logfile = *(argv + i + 1);
            log_set_file(*(argv + i + 1));
            ret++;
        }
        else if(!strcmp(*(argv + i), "-h") || !strcmp(*(argv + i), "--help"))
        {
            arg->help = 1;
            ret++;
        }
    }
    return ret;
}
Exemple #28
0
// public API
APIE process_spawn(ObjectID executable_id, ObjectID arguments_id,
                   ObjectID environment_id, ObjectID working_directory_id,
                   uint32_t uid, uint32_t gid, ObjectID stdin_id,
                   ObjectID stdout_id, ObjectID stderr_id, Session *session,
                   uint16_t object_create_flags, bool release_on_death,
                   ProcessStateChangedFunction state_changed, void *opaque,
                   ObjectID *id, Process **object) {
	int phase = 0;
	APIE error_code;
	String *executable;
	List *arguments;
	Array arguments_array;
	int i;
	char **item;
	List *environment;
	Array environment_array;
	String *working_directory;
	File *stdin;
	File *stdout;
	File *stderr;
	pid_t pid;
	int status_pipe[2];
	int sc_open_max;
	FILE *log_file;
	Process *process;

	// acquire and lock executable string object
	error_code = string_get_acquired_and_locked(executable_id, &executable);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 1;

	if (*executable->buffer == '\0') {
		error_code = API_E_INVALID_PARAMETER;

		log_warn("Cannot spawn child process using empty executable name");

		goto cleanup;
	}

	// lock arguments list object
	error_code = list_get_acquired_and_locked(arguments_id, OBJECT_TYPE_STRING,
	                                          &arguments);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 2;

	// prepare arguments array for execvpe
	if (array_create(&arguments_array, 1 + arguments->items.count + 1, sizeof(char *), true) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not create arguments array for spawning child process (executable: %s): %s (%d)",
		          executable->buffer, get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 3;

	item = array_append(&arguments_array);

	if (item == NULL) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not append to arguments array for spawning child process (executable: %s): %s (%d)",
		          executable->buffer, get_errno_name(errno), errno);

		goto cleanup;
	}

	*item = executable->buffer;

	for (i = 0; i < arguments->items.count; ++i) {
		item = array_append(&arguments_array);

		if (item == NULL) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not append to arguments array for spawning child process (executable: %s): %s (%d)",
			          executable->buffer, get_errno_name(errno), errno);

			goto cleanup;
		}

		*item = (*(String **)array_get(&arguments->items, i))->buffer;
	}

	item = array_append(&arguments_array);

	if (item == NULL) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not append to arguments array for spawning child process (executable: %s): %s (%d)",
		          executable->buffer, get_errno_name(errno), errno);

		goto cleanup;
	}

	*item = NULL;

	// lock environment list object
	error_code = list_get_acquired_and_locked(environment_id, OBJECT_TYPE_STRING,
	                                          &environment);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 4;

	// prepare environment array for execvpe
	if (array_create(&environment_array, environment->items.count + 1, sizeof(char *), true) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not create environment array for spawning child process (executable: %s): %s (%d)",
		          executable->buffer, get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 5;

	for (i = 0; i < environment->items.count; ++i) {
		item = array_append(&environment_array);

		if (item == NULL) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not append to environment array for spawning child process (executable: %s): %s (%d)",
			          executable->buffer, get_errno_name(errno), errno);

			goto cleanup;
		}

		// FIXME: if item is not <name>=<value>, but just <name> then use the parent <value>

		*item = (*(String **)array_get(&environment->items, i))->buffer;
	}

	item = array_append(&environment_array);

	if (item == NULL) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not append to environment array for spawning child process (executable: %s): %s (%d)",
		          executable->buffer, get_errno_name(errno), errno);

		goto cleanup;
	}

	*item = NULL;

	// acquire and lock working directory string object
	error_code = string_get_acquired_and_locked(working_directory_id, &working_directory);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 6;

	if (*working_directory->buffer == '\0') {
		error_code = API_E_INVALID_PARAMETER;

		log_warn("Cannot spawn child process (executable: %s) using empty working directory name",
		         executable->buffer);

		goto cleanup;
	}

	if (*working_directory->buffer != '/') {
		error_code = API_E_INVALID_PARAMETER;

		log_warn("Cannot spawn child process (executable: %s) using working directory with relative name '%s'",
		         executable->buffer, working_directory->buffer);

		goto cleanup;
	}

	// acquire stdin file object
	error_code = file_get_acquired(stdin_id, &stdin);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 7;

	// acquire stdout file object
	error_code = file_get_acquired(stdout_id, &stdout);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 8;

	// acquire stderr file object
	error_code = file_get_acquired(stderr_id, &stderr);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 9;

	// create status pipe
	if (pipe(status_pipe) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not create status pipe for spawning child process (executable: %s): %s (%d)",
		          executable->buffer, get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 10;

	// fork
	log_debug("Forking to spawn child process (executable: %s)", executable->buffer);

	error_code = process_fork(&pid);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	if (pid == 0) { // child
		close(status_pipe[0]);

		// change user and groups
		error_code = process_set_identity(uid, gid);

		if (error_code != API_E_SUCCESS) {
			goto child_error;
		}

		// change directory
		if (chdir(working_directory->buffer) < 0) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not change directory to '%s' for child process (executable: %s, pid: %u): %s (%d)",
			          working_directory->buffer, executable->buffer, getpid(), get_errno_name(errno), errno);

			goto child_error;
		}

		// get open FD limit
		sc_open_max = sysconf(_SC_OPEN_MAX);

		if (sc_open_max < 0) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not get SC_OPEN_MAX value: %s (%d)",
			          get_errno_name(errno), errno);

			goto child_error;
		}

		// redirect stdin
		if (dup2(file_get_read_handle(stdin), STDIN_FILENO) != STDIN_FILENO) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not redirect stdin for child process (executable: %s, pid: %u): %s (%d)",
			          executable->buffer, getpid(), get_errno_name(errno), errno);

			goto child_error;
		}

		// redirect stdout
		if (dup2(file_get_write_handle(stdout), STDOUT_FILENO) != STDOUT_FILENO) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not redirect stdout for child process (executable: %s, pid: %u): %s (%d)",
			          executable->buffer, getpid(), get_errno_name(errno), errno);

			goto child_error;
		}

		// stderr is the default log output in non-daemon mode. if this is
		// the case then disable the log output before redirecting stderr to
		// avoid polluting stderr for the new process
		log_file = log_get_file();

		if (log_file != NULL && fileno(log_file) == STDERR_FILENO) {
			log_debug("Disable logging to stderr for child process (executable: %s, pid: %u)",
			          executable->buffer, getpid());

			log_set_file(NULL);
		}

		// redirect stderr
		if (dup2(file_get_write_handle(stderr), STDERR_FILENO) != STDERR_FILENO) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not redirect stderr for child process (executable: %s, pid: %u): %s (%d)",
			          executable->buffer, getpid(), get_errno_name(errno), errno);

			goto child_error;
		}

		// notify parent
		if (robust_write(status_pipe[1], &error_code, sizeof(error_code)) < 0) {
			error_code = api_get_error_code_from_errno();

			log_error("Could not write to status pipe for child process (executable: %s, pid: %u): %s (%d)",
			          executable->buffer, getpid(), get_errno_name(errno), errno);

			goto child_error;
		}

		// disable log output. if stderr was not the current log output then
		// the log file is still open at this point. the next step is to close
		// all remaining file descriptors. just for good measure disable the
		// log output beforehand
		log_set_file(NULL);

		// close all file descriptors except the std* ones
		for (i = STDERR_FILENO + 1; i < sc_open_max; ++i) {
			close(i);
		}

		// execvpe only returns in case of an error
		execvpe(executable->buffer, (char **)arguments_array.bytes, (char **)environment_array.bytes);

		if (errno == ENOENT) {
			_exit(PROCESS_E_DOES_NOT_EXIST);
		} else {
			_exit(PROCESS_E_CANNOT_EXECUTE);
		}

	child_error:
		// notify parent in all cases
		if (robust_write(status_pipe[1], &error_code, sizeof(error_code)) < 0) {
			log_error("Could not write to status pipe for child process (executable: %s, pid: %u): %s (%d)",
			          executable->buffer, getpid(), get_errno_name(errno), errno);
		}

		close(status_pipe[1]);

		_exit(PROCESS_E_INTERNAL_ERROR);
	}

	phase = 11;

	// wait for child to start successfully
	if (robust_read(status_pipe[0], &error_code, sizeof(error_code)) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not read from status pipe for child process (executable: %s, pid: %u): %s (%d)",
		          executable->buffer, pid, get_errno_name(errno), errno);

		goto cleanup;
	}

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	// create process object
	process = calloc(1, sizeof(Process));

	if (process == NULL) {
		error_code = API_E_NO_FREE_MEMORY;

		log_error("Could not allocate process object: %s (%d)",
		          get_errno_name(ENOMEM), ENOMEM);

		goto cleanup;
	}

	phase = 12;

	// setup process object
	process->executable = executable;
	process->arguments = arguments;
	process->environment = environment;
	process->working_directory = working_directory;
	process->uid = uid;
	process->gid = gid;
	process->pid = pid;
	process->stdin = stdin;
	process->stdout = stdout;
	process->stderr = stderr;
	process->release_on_death = release_on_death;
	process->state_changed = state_changed;
	process->opaque = opaque;
	process->state = PROCESS_STATE_RUNNING;
	process->timestamp = time(NULL);
	process->exit_code = 0; // invalid

	if (pipe_create(&process->state_change_pipe, 0) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not create state change pipe child process (executable: %s, pid: %u): %s (%d)",
		          executable->buffer, pid, get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 13;

	if (event_add_source(process->state_change_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC,
	                     EVENT_READ, process_handle_state_change, process) < 0) {
		goto cleanup;
	}

	phase = 14;

	// create process object
	error_code = object_create(&process->base,
	                           OBJECT_TYPE_PROCESS,
	                           session,
	                           object_create_flags |
	                           OBJECT_CREATE_FLAG_INTERNAL,
	                           process_destroy,
	                           process_signature);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 15;

	if (id != NULL) {
		*id = process->base.id;
	}

	if (object != NULL) {
		*object = process;
	}

	// start thread to wait for child process state changes
	thread_create(&process->wait_thread, process_wait, process);

	log_debug("Spawned process object (id: %u, executable: %s, pid: %u)",
	          process->base.id, executable->buffer, process->pid);

	close(status_pipe[0]);
	close(status_pipe[1]);
	array_destroy(&arguments_array, NULL);
	array_destroy(&environment_array, NULL);

cleanup:
	switch (phase) { // no breaks, all cases fall through intentionally
	case 14:
		event_remove_source(process->state_change_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC);

	case 13:
		pipe_destroy(&process->state_change_pipe);

	case 12:
		free(process);

	case 11:
		kill(pid, SIGKILL);

	case 10:
		close(status_pipe[0]);
		close(status_pipe[1]);

	case 9:
		file_release(stderr);

	case 8:
		file_release(stdout);

	case 7:
		file_release(stdin);

	case 6:
		string_unlock_and_release(working_directory);

	case 5:
		array_destroy(&environment_array, NULL);

	case 4:
		list_unlock_and_release(environment);

	case 3:
		array_destroy(&arguments_array, NULL);

	case 2:
		list_unlock_and_release(arguments);

	case 1:
		string_unlock_and_release(executable);

	default:
		break;
	}

	return phase == 15 ? API_E_SUCCESS : error_code;
}