int platform_init(void *ctx) { extern struct platform *__start_platforms, *__stop_platforms; struct platform **p; platform_ctx = talloc_new(ctx); for (p = &__start_platforms; p < &__stop_platforms; p++) { pb_debug("%s: Try platform %s\n", __func__, (*p)->name); if (!(*p)->probe(*p, platform_ctx)) continue; platform = *p; break; } config = talloc(platform_ctx, struct config); config_set_defaults(config); if (platform) { pb_log("Detected platform type: %s\n", platform->name); if (platform->load_config) platform->load_config(platform, config); } else { pb_log("No platform type detected, some platform-specific " "functionality will be disabled\n"); } dump_config(config); return 0; }
void config_load (void) { g_return_if_fail (! defaults && ! keyfile); pthread_mutex_lock (& mutex); defaults = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_destroy); keyfile = g_key_file_new (); char * path = g_strdup_printf ("%s/config", get_path (AUD_PATH_USER_DIR)); if (g_file_test (path, G_FILE_TEST_EXISTS)) { GError * error = NULL; if (! g_key_file_load_from_file (keyfile, path, 0, & error)) { fprintf (stderr, "Error loading config: %s\n", error->message); g_error_free (error); } } g_free (path); modified = FALSE; pthread_mutex_unlock (& mutex); config_set_defaults (NULL, core_defaults); }
/** * \fn void config_set_from_file (struct configuration *config, const char *fname) * \param config pointer to configuration structure * \param fname file with configuration items in it * \return ok * \return failure */ int config_set_from_file (struct configuration *config, const char *fname) { FILE *f; char *line = NULL; size_t ignore; ssize_t len; unsigned int linecount = 0; char *c; f = fopen(fname, "r"); if (f == NULL) { fprintf(info, "error: could not open file %s\n", fname); return failure; } config_set_defaults(config); while ((len = getline(&line, &ignore, f)) != -1) { int num; char lhs[LINEMAX], rhs[LINEMAX]; linecount++; if (len > LINEMAX) { fprintf(info, "error: line too long in file %s\n", fname); return failure; } /* ignore blank lines and comments */ c = line; while (isblank(*c)) { c++; } if (*c == '#' || *c == '\n') { ; } else { /* * a valid command line consists of a LHS, possibly followed by * an "=" and a RHS. The newline and # (start of comment) is * not part of the RHS. */ num = sscanf(line, "%[^=] = %[^\n#]", lhs, rhs); if (num == 2 || num == 1) { // printf("%s = %s ### %d ### %s", lhs, rhs, num, line); if (config_parse_command(config, lhs, rhs, num) != ok) { fprintf(info, "error: unknown command (%s)\n", lhs); exit(EXIT_FAILURE); } } else if (num == 1) { printf("error: could not parse line %u in file %s (\"%s ...\")\n", linecount, fname, lhs); exit(EXIT_FAILURE); } else { printf("error: could not parse line %s in file %s\n", line, fname); fprintf(info, "error: could not parse line %s in file %s\n", line, fname); } } } free(line); return ok; }
void config_load(void) { if (!g_extern.block_config_read) { config_set_defaults(); parse_config_file(); } }
int main(int argc, char *argv[]) { get_environment_settings(); rarch_main_clear_state(); config_set_defaults(); char full_path[1024]; snprintf(full_path, sizeof(full_path), "game:\\CORE.xex"); bool find_libretro_file = rarch_configure_libretro_core(full_path, "game:\\", "game:\\", SYS_CONFIG_FILE, ".xex"); set_default_settings(); rarch_config_load(SYS_CONFIG_FILE, "game:\\", ".xex", find_libretro_file); init_libretro_sym(); video_xdk360.start(); input_xdk360.init(); rarch_input_set_default_keybind_names_for_emulator(); menu_init(); begin_loop: if(g_console.mode_switch == MODE_EMULATION) { bool repeat = false; input_xdk360.poll(NULL); rarch_set_auto_viewport(g_extern.frame_cache.width, g_extern.frame_cache.height); do{ repeat = rarch_main_iterate(); }while(repeat && !g_console.frame_advance_enable); } else if(g_console.mode_switch == MODE_MENU) { menu_loop(); rarch_startup(SYS_CONFIG_FILE); } else goto begin_shutdown; goto begin_loop; begin_shutdown: if(path_file_exists(SYS_CONFIG_FILE)) rarch_config_save(SYS_CONFIG_FILE); menu_free(); video_xdk360.stop(); input_xdk360.free(NULL); rarch_exec(); return 0; }
void plugin_init(GeanyData *data) { /* read & prepare configuration */ gchar *config_dir = g_build_path(G_DIR_SEPARATOR_S, geany_data->app->configdir, "plugins", "unixtsconverter", NULL); plugin_config_path = g_build_path(G_DIR_SEPARATOR_S, config_dir, "unixtsconverter.conf", NULL); g_mkdir_with_parents(config_dir, S_IRUSR | S_IWUSR | S_IXUSR); g_free(config_dir); keyfile_plugin = g_key_file_new(); if (!g_key_file_load_from_file(keyfile_plugin, plugin_config_path, G_KEY_FILE_NONE, NULL)) { config_set_defaults(keyfile_plugin); config_save_setting(keyfile_plugin, plugin_config_path); } else { showResultInMsgPopupWindow = config_get_setting(keyfile_plugin, "show_result_in_message_window"); showErrors = config_get_setting(keyfile_plugin, "show_failure_messages"); useClipboard = config_get_setting(keyfile_plugin, "use_clipboard_too"); autodetectTimestampInMsAndUs = config_get_setting( keyfile_plugin, "autodetect_timestamp_in_ms_us"); } /* ---------------------------- */ main_menu_item = gtk_menu_item_new_with_mnemonic( "Unix Timestamp Converter"); gtk_widget_show(main_menu_item); gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), main_menu_item); g_signal_connect(main_menu_item, "activate", G_CALLBACK(item_activate_cb), NULL); /* Register shortcut key group */ geany_key_group = plugin_set_key_group( geany_plugin, _("unix_ts_converter"), 1, NULL); /* Ctrl + Alt + c */ keybindings_set_item(geany_key_group, 0, kb_run_unix_ts_converter, GDK_c, GDK_CONTROL_MASK | GDK_MOD1_MASK, "run_unix_ts_converter", _("Run the Unix Timestamp Converter"), main_menu_item); }
/** * \fn int config_set_from_argv (struct configuration *config, char *argv[], int argc) * \param config pointer to configuration structure * \param argv arguments passed in * \param argc number of arguments * \return ok * \return failure */ int config_set_from_argv (struct configuration *config, char *argv[], int argc) { const char *line = NULL; ssize_t len; unsigned int i, linecount = 0; const char *c; config_set_defaults(config); for (i=1; i<argc; i++) { int num; char lhs[LINEMAX], rhs[LINEMAX]; line = argv[i]; len = strlen(line); linecount++; if (len > LINEMAX) { fprintf(info, "error: line too long in argument %s\n", argv[i]); return failure; } /* ignore blank lines and comments */ c = line; while (isblank(*c)) { c++; } if (*c == '#' || *c == '\n') { ; } else { /* * a valid command line consists of a LHS, possibly followed by * an "=" and a RHS. The newline and # (start of comment) is * not part of the RHS. */ num = sscanf(line, "%[^=] = %[^\n#]", lhs, rhs); if (num == 2) { // printf("%s = %s ### %d ### %s", lhs, rhs, num, line); if (config_parse_command(config, lhs, rhs, num) != ok) { printf("error: did not understand command %s\n", lhs); exit(EXIT_FAILURE); // break; } } else if (num == 1) { /* * since there is no "=" in argument, we assume that it is a * filename */ break; } else { printf("error: could not parse argument %s\n", line); } } } return i-1; }
int main(void) { #ifdef HW_RVL L2Enhance(); #endif fatInitDefault(); #ifdef HAVE_FILE_LOGGER g_extern.verbose = true; log_fp = fopen("/retroarch-log.txt", "w"); #endif config_set_defaults(); g_settings.audio.rate_control = true; g_settings.audio.rate_control_delta = 0.004; g_console.block_config_read = true; wii_video_init(); input_wii.init(); rgui_handle_t *rgui = rgui_init("", menu_framebuf, RGUI_WIDTH * sizeof(uint16_t), _binary_console_font_bmp_start, folder_cb, NULL); rgui_iterate(rgui, RGUI_ACTION_REFRESH); int ret = 0; while (get_rom_path(rgui) && ret == 0) { bool repeat = false; input_wii.poll(NULL); do{ repeat = rarch_main_iterate(); }while(repeat && !g_console.frame_advance_enable); audio_stop_func(); } if(g_console.emulator_initialized) rarch_main_deinit(); wii_video_deinit(); input_wii.free(NULL); #ifdef HAVE_FILE_LOGGER fclose(log_fp); #endif rgui_free(rgui); return ret; }
int main(int argc, char *argv[], char **envp) { ripncode_t r; config_set_defaults(&r, argv[0]); parse_cmdline(&r, argc, argv, envp); device_open(&r); get_track_info(&r); return 0; }
IPlatformEnvironment * SetupEnvironment() { utf8 userPath[MAX_PATH]; platform_resolve_openrct_data_path(); platform_resolve_user_data_path(); platform_get_user_directory(userPath, NULL, sizeof(userPath)); if (!platform_ensure_directory_exists(userPath)) { Console::Error::WriteLine("Could not create user directory (do you have write access to your documents folder?)"); return nullptr; } openrct2_set_exe_path(); config_set_defaults(); if (!config_open_default()) { if (!config_find_or_browse_install_directory()) { gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION); config_save_default(); utf8 path[MAX_PATH]; config_get_default_path(path, sizeof(path)); Console::Error::WriteLine("An RCT2 install directory must be specified! Please edit \"game_path\" in %s.", path); return nullptr; } config_save_default(); } if (!rct2_init_directories()) { return nullptr; } if (!rct2_startup_checks()) { return nullptr; } utf8 path[260]; std::string basePaths[4]; basePaths[(size_t)DIRBASE::RCT1] = String::ToStd(gConfigGeneral.rct1_path); basePaths[(size_t)DIRBASE::RCT2] = String::ToStd(gConfigGeneral.rct2_path); platform_get_openrct_data_path(path, sizeof(path)); basePaths[(size_t)DIRBASE::OPENRCT2] = std::string(path); platform_get_user_directory(path, nullptr, sizeof(path)); basePaths[(size_t)DIRBASE::USER] = std::string(path); IPlatformEnvironment * env = CreatePlatformEnvironment(basePaths); return env; }
void config_load(void) { // Flush out per-core configs before loading a new config. if (*g_extern.core_specific_config_path && g_extern.config_save_on_exit && g_settings.core_specific_config) config_save_file(g_extern.core_specific_config_path); if (!g_extern.block_config_read) { config_set_defaults(); parse_config_file(); } // Per-core config handling. config_load_core_specific(); }
int main(int argc, char *argv[]) { #ifdef HW_RVL IOS_ReloadIOS(IOS_GetVersion()); L2Enhance(); gx_init_mem2(); #endif fatInitDefault(); #ifdef HAVE_LOGGER g_extern.verbose = true; logger_init(); devoptab_list[STD_OUT] = &dotab_stdout; devoptab_list[STD_ERR] = &dotab_stdout; dotab_stdout.write_r = gx_logger_net; #elif defined(HAVE_FILE_LOGGER) g_extern.verbose = true; log_fp = fopen("/retroarch-log.txt", "w"); devoptab_list[STD_OUT] = &dotab_stdout; devoptab_list[STD_ERR] = &dotab_stdout; dotab_stdout.write_r = gx_logger_file; #endif #ifdef HW_RVL lwp_t gx_device_thread; gx_devices[GX_DEVICE_SD].interface = &__io_wiisd; gx_devices[GX_DEVICE_SD].name = "sd"; gx_devices[GX_DEVICE_SD].mounted = fatMountSimple(gx_devices[GX_DEVICE_SD].name, gx_devices[GX_DEVICE_SD].interface); gx_devices[GX_DEVICE_USB].interface = &__io_usbstorage; gx_devices[GX_DEVICE_USB].name = "usb"; gx_devices[GX_DEVICE_USB].mounted = fatMountSimple(gx_devices[GX_DEVICE_USB].name, gx_devices[GX_DEVICE_USB].interface); LWP_MutexInit(&gx_device_mutex, false); LWP_CreateThread(&gx_device_thread, gx_devthread, NULL, NULL, 0, 66); #endif get_environment_settings(); make_directories(); config_set_defaults(); input_gx.init(); video_gx.start(); driver.video = &video_gx; gx_video_t *gx = (gx_video_t*)driver.video_data; gx->menu_data = (uint32_t *) menu_framebuf; char tmp_path[PATH_MAX]; const char *extension = default_paths.executable_extension; snprintf(tmp_path, sizeof(tmp_path), "%s/", default_paths.core_dir); const char *path_prefix = tmp_path; char full_path[1024]; snprintf(full_path, sizeof(full_path), "%sCORE%s", path_prefix, extension); bool find_libretro_file = rarch_configure_libretro_core(full_path, path_prefix, path_prefix, default_paths.config_file, extension); rarch_settings_set_default(&input_gx); rarch_config_load(default_paths.config_file, path_prefix, extension, find_libretro_file); char core_name[64]; rarch_console_name_from_id(core_name, sizeof(core_name)); char input_path[1024]; snprintf(input_path, sizeof(input_path), "%s/%s.cfg", default_paths.input_presets_dir, core_name); config_read_keybinds(input_path); init_libretro_sym(); input_gx.post_init(); menu_init(); if (argc > 2 && argv[1] != NULL && argv[2] != NULL) { char rom[PATH_MAX]; g_console.external_launcher_support = EXTERN_LAUNCHER_CHANNEL; snprintf(rom, sizeof(rom), "%s%s", argv[1], argv[2]); g_console.zip_extract_mode = ZIP_EXTRACT_TO_CURRENT_DIR_AND_LOAD_FIRST_FILE; rarch_console_load_game_wrap(rom, g_console.zip_extract_mode, S_DELAY_1); rgui_iterate(rgui, RGUI_ACTION_MESSAGE); gx->menu_render = true; rarch_render_cached_frame(); gx->menu_render = false; rarch_startup(default_paths.config_file); } else { g_console.external_launcher_support = EXTERN_LAUNCHER_SALAMANDER; } begin_loop: if(g_console.mode_switch == MODE_EMULATION) { bool repeat = false; input_gx.poll(NULL); video_set_aspect_ratio_func(g_console.aspect_ratio_index); audio_start_func(); do{ repeat = rarch_main_iterate(); }while(repeat && !g_console.frame_advance_enable); audio_stop_func(); } else if(g_console.mode_switch == MODE_MENU) { menu_loop(); if (g_console.mode_switch != MODE_EXIT) rarch_startup(default_paths.config_file); } else goto begin_shutdown; goto begin_loop; begin_shutdown: rarch_config_save(default_paths.config_file); config_save_keybinds(input_path); if(g_console.emulator_initialized) rarch_main_deinit(); input_gx.free(NULL); video_gx.stop(); menu_free(); #ifdef HAVE_LOGGER logger_shutdown(); #elif defined(HAVE_FILE_LOGGER) fclose(log_fp); #endif if(g_console.return_to_launcher) rarch_console_exec(g_console.launch_app_on_exit); exit(0); }
int main(int argc, char *argv[]) { get_environment_settings(); rarch_main_clear_state(); config_set_defaults(); #ifdef _XBOX1 configure_libretro("D:\\", ".xbe"); #else configure_libretro("game:\\", ".xex"); #endif #if defined(HAVE_D3D8) || defined(HAVE_D3D9) video_xdk_d3d.start(); #else video_null.start(); #endif input_xinput.init(); rarch_input_set_default_keybind_names_for_emulator(); menu_init(); begin_loop: if(g_console.mode_switch == MODE_EMULATION) { bool repeat = false; input_xinput.poll(NULL); rarch_set_auto_viewport(g_extern.frame_cache.width, g_extern.frame_cache.height); do { repeat = rarch_main_iterate(); } while(repeat && !g_console.frame_advance_enable); } else if(g_console.mode_switch == MODE_MENU) { menu_loop(); rarch_startup(SYS_CONFIG_FILE); } else goto begin_shutdown; goto begin_loop; begin_shutdown: if(path_file_exists(SYS_CONFIG_FILE)) rarch_config_save(SYS_CONFIG_FILE); menu_free(); #if defined(HAVE_D3D8) || defined(HAVE_D3D9) video_xdk_d3d.stop(); #else video_null.stop(); #endif input_xinput.free(NULL); rarch_exec(); return 0; }
int main(int argc, char *argv[]) { int fifo; int i, n; char *opt, *arg, *equal_arg, *homedir, *user; char *line, *eol, buf[4096]; pgm_name = argv[0]; bcm_host_init(); time(&pikrellcam.t_now); config_set_defaults(); for (i = 1; i < argc; i++) get_arg_pass1(argv[i]); if (!config_load(pikrellcam.config_file)) config_save(pikrellcam.config_file); if (!motion_regions_config_load(pikrellcam.motion_regions_config_file)) motion_regions_config_save(pikrellcam.motion_regions_config_file); if (!at_commands_config_load(pikrellcam.at_commands_config_file)) at_commands_config_save(pikrellcam.at_commands_config_file); for (i = 1; i < argc; i++) { if (get_arg_pass1(argv[i])) continue; opt = argv[i]; /* Just for initial install-pikrellcam.sh run to create config files. */ if (!strcmp(opt, "-quit")) exit(0); /* Accept: --opt arg -opt arg opt=arg --opt=arg -opt=arg */ for (i = 0; i < 2; ++i) if (*opt == '-') ++opt; if ((equal_arg = strchr(opt, '=')) != NULL) { *equal_arg++ = '\0'; arg = equal_arg; ++i; } else arg = argv[i + 1]; /* For camera parameters, do not set the camera, only replace | values in the parameter table. */ if ( !config_set_option(opt, arg, TRUE) && !mmalcam_config_parameter_set(opt, arg, FALSE) ) { log_printf("Bad arg: %s\n", opt); exit(1); } } homedir = getpwuid(geteuid())->pw_dir; user = strrchr(homedir, '/'); pikrellcam.effective_user = strdup(user ? user + 1 : "pi"); if (*pikrellcam.log_file != '/') { snprintf(buf, sizeof(buf), "%s/%s", pikrellcam.install_dir, pikrellcam.log_file); dup_string(&pikrellcam.log_file, buf); } if (*pikrellcam.media_dir != '/') { snprintf(buf, sizeof(buf), "%s/%s", pikrellcam.install_dir, pikrellcam.media_dir); dup_string(&pikrellcam.media_dir, buf); } strftime(buf, sizeof(buf), "%F %T", localtime(&pikrellcam.t_now)); log_printf("\n%s ==== PiKrellCam started ====\n", buf); snprintf(buf, sizeof(buf), "%s/%s", pikrellcam.install_dir, "www"); check_modes(buf, 0775); asprintf(&pikrellcam.command_fifo, "%s/www/FIFO", pikrellcam.install_dir); asprintf(&pikrellcam.script_dir, "%s/scripts", pikrellcam.install_dir); asprintf(&pikrellcam.mjpeg_filename, "%s/mjpeg.jpg", pikrellcam.mjpeg_dir); log_printf("using FIFO: %s\n", pikrellcam.command_fifo); log_printf("using mjpeg: %s\n", pikrellcam.mjpeg_filename); /* Subdirs must match www/config.php and the init script is supposed | to take care of that. */ asprintf(&pikrellcam.video_dir, "%s/%s", pikrellcam.media_dir, PIKRELLCAM_VIDEO_SUBDIR); asprintf(&pikrellcam.still_dir, "%s/%s", pikrellcam.media_dir, PIKRELLCAM_STILL_SUBDIR); asprintf(&pikrellcam.timelapse_dir, "%s/%s", pikrellcam.media_dir, PIKRELLCAM_TIMELAPSE_SUBDIR); if (!make_dir(pikrellcam.media_dir)) exit(1); snprintf(buf, sizeof(buf), "%s/scripts-dist/init $I $m $M $P $G", pikrellcam.install_dir); exec_wait(buf, NULL); /* User may have enabled a mount disk on media_dir */ exec_wait(pikrellcam.on_startup_cmd, NULL); check_modes(pikrellcam.media_dir, 0775); if ( !make_dir(pikrellcam.mjpeg_dir) || !make_dir(pikrellcam.video_dir) || !make_dir(pikrellcam.still_dir) || !make_dir(pikrellcam.timelapse_dir) || !make_fifo(pikrellcam.command_fifo) ) exit(1); if ((fifo = open(pikrellcam.command_fifo, O_RDONLY | O_NONBLOCK)) < 0) { log_printf("Failed to open FIFO: %s. %m\n", pikrellcam.command_fifo); exit(1); } fcntl(fifo, F_SETFL, 0); read(fifo, buf, sizeof(buf)); sun_times_init(); camera_start(); config_timelapse_load_status(); signal(SIGINT, signal_quit); signal(SIGTERM, signal_quit); signal(SIGCHLD, event_child_signal); while (1) { usleep(1000000 / EVENT_LOOP_FREQUENCY); event_process(); /* Process lines in the FIFO. Single lines via an echo "xxx" > FIFO | or from a web page may not have a terminating \n. | Local scripts may dump multiple \n terminated lines into the FIFO. */ if ((n = read(fifo, buf, sizeof(buf) - 2)) > 0) { if (buf[n - 1] != '\n') buf[n++] = '\n'; /* ensures all lines in buf end in \n */ buf[n] = '\0'; line = buf; eol = strchr(line, '\n'); while (eol > line) { *eol++ = '\0'; command_process(line); while (*eol == '\n') ++eol; line = eol; eol = strchr(line, '\n'); } } } return 0; }
static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator) { exitcode_t result = CommandLine::HandleCommandDefault(); if (result != EXITCODE_CONTINUE) { return result; } // Get the path that was passed const utf8 * rawPath; if (!enumerator->TryPopString(&rawPath)) { Console::Error::WriteLine("Expected a path."); return EXITCODE_FAIL; } utf8 path[MAX_PATH]; Path::GetAbsolute(path, sizeof(path), rawPath); // Check if path exists Console::WriteLine("Checking path..."); if (!platform_directory_exists(path)) { Console::Error::WriteLine("The path '%s' does not exist", path); return EXITCODE_FAIL; } // Check if g1.dat exists (naive but good check) Console::WriteLine("Checking g1.dat..."); utf8 pathG1Check[MAX_PATH]; String::Set(pathG1Check, sizeof(pathG1Check), path); Path::Append(pathG1Check, sizeof(pathG1Check), "Data"); Path::Append(pathG1Check, sizeof(pathG1Check), "g1.dat"); if (!platform_file_exists(pathG1Check)) { Console::Error::WriteLine("RCT2 path not valid."); Console::Error::WriteLine("Unable to find %s.", pathG1Check); return EXITCODE_FAIL; } // Check user path that will contain the config utf8 userPath[MAX_PATH]; platform_resolve_user_data_path(); platform_get_user_directory(userPath, NULL, sizeof(userPath)); if (!platform_ensure_directory_exists(userPath)) { Console::Error::WriteLine("Unable to access or create directory '%s'.", userPath); return EXITCODE_FAIL; } // Update RCT2 path in config config_set_defaults(); config_open_default(); String::DiscardDuplicate(&gConfigGeneral.rct2_path, path); if (config_save_default()) { Console::WriteFormat("Updating RCT2 path to '%s'.", path); Console::WriteLine(); Console::WriteLine("Updated config.ini"); return EXITCODE_OK; } else { Console::Error::WriteLine("Unable to update config.ini"); return EXITCODE_FAIL; } }
void parse_cmdline(int argc, char **argv) { # define OPTIONS "l:t:vd:nh" struct option options[] = { { "log-level" , required_argument, NULL, 'l' }, { "log-target", required_argument, NULL, 't' }, { "verbose" , optional_argument, NULL, 'v' }, { "debug" , required_argument, NULL, 'd' }, { "non-framed", no_argument , NULL, 'n' }, { "help" , no_argument , NULL, 'h' }, { NULL, 0, NULL, 0 } }; int opt; config_set_defaults(); while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { switch (opt) { case 'v': ctx.log_mask <<= 1; ctx.log_mask |= 1; break; case 'l': ctx.log_mask = mrp_log_parse_levels(optarg); if (ctx.log_mask < 0) print_usage(argv[0], EINVAL, "invalid log level '%s'", optarg); break; case 't': ctx.log_target = mrp_log_parse_target(optarg); if (!ctx.log_target) print_usage(argv[0], EINVAL, "invalid log target '%s'", optarg); break; case 'd': ctx.log_mask |= MRP_LOG_MASK_DEBUG; mrp_debug_set_config(optarg); mrp_debug_enable(TRUE); break; case'n': ctx.framed = FALSE; break; case 'h': print_usage(argv[0], -1, ""); exit(0); break; case '?': if (opterr) print_usage(argv[0], EINVAL, ""); break; default: print_usage(argv[0], EINVAL, "invalid option '%c'", opt); } } }
TSS_RESULT conf_file_init(struct tcsd_config *conf) { FILE *f = NULL; struct stat stat_buf; #ifndef SOLARIS struct group *grp; struct passwd *pw; mode_t mode = (S_IRUSR|S_IWUSR); #endif /* SOLARIS */ TSS_RESULT result; init_tcsd_config(conf); #ifdef SOLARIS /* * Solaris runs as Rajiv Andrade <[email protected].:sys but with reduced privileges * so we don't need to create a new user/group and also so * we can have auditing support. The permissions on * the tcsd configuration file are not checked on Solaris. */ #endif /* look for a config file, create if it doesn't exist */ if (stat(tcsd_config_file, &stat_buf) == -1) { if (errno == ENOENT) { /* no config file? use defaults */ config_set_defaults(conf); LogInfo("Config file %s not found, using defaults.", tcsd_config_file); return TSS_SUCCESS; } else { LogError("stat(%s): %s", tcsd_config_file, strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } } #ifndef SOLARIS /* find the gid that owns the conf file */ errno = 0; grp = getgrnam(TSS_GROUP_NAME); if (grp == NULL) { if (errno == 0) { LogError("Group \"%s\" not found, please add this group" " manually.", TSS_GROUP_NAME); } else { LogError("getgrnam(%s): %s", TSS_GROUP_NAME, strerror(errno)); } return TCSERR(TSS_E_INTERNAL_ERROR); } errno = 0; pw = getpwnam(TSS_USER_NAME); if (pw == NULL) { if (errno == 0) { LogError("User \"%s\" not found, please add this user" " manually.", TSS_USER_NAME); } else { LogError("getpwnam(%s): %s", TSS_USER_NAME, strerror(errno)); } return TCSERR(TSS_E_INTERNAL_ERROR); } /* make sure user/group TSS owns the conf file */ if (pw->pw_uid != stat_buf.st_uid || grp->gr_gid != stat_buf.st_gid) { LogError("TCSD config file (%s) must be user/group %s/%s", tcsd_config_file, TSS_USER_NAME, TSS_GROUP_NAME); return TCSERR(TSS_E_INTERNAL_ERROR); } /* make sure only the tss user can manipulate the config file */ if (((stat_buf.st_mode & 0777) ^ mode) != 0) { LogError("TCSD config file (%s) must be mode 0600", tcsd_config_file); return TCSERR(TSS_E_INTERNAL_ERROR); } #endif /* SOLARIS */ if ((f = fopen(tcsd_config_file, "r")) == NULL) { LogError("fopen(%s): %s", tcsd_config_file, strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } result = read_conf_file(f, conf); fclose(f); /* fill out any uninitialized options */ config_set_defaults(conf); #ifdef SOLARIS /* * The SMF value for "local_only" overrides the config file and * disables all remote operations. */ if (get_smf_prop("local_only", B_TRUE)) { (void) memset(conf->remote_ops, 0, sizeof(conf->remote_ops)); conf->unset |= TCSD_OPTION_REMOTE_OPS; } #endif return result; }
/* ****************** * 程序的入口点 ***************** */ int main(int argc, char **argv) { server *srv = NULL; int print_config = 0; int test_config = 0; int i_am_root; int o; int num_childs = 0; int pid_fd = -1, fd; size_t i; #ifdef HAVE_SIGACTION struct sigaction act; #endif #ifdef HAVE_GETRLIMIT struct rlimit rlim; #endif #ifdef USE_ALARM struct itimerval interval; interval.it_interval.tv_sec = 1; interval.it_interval.tv_usec = 0; interval.it_value.tv_sec = 1; interval.it_value.tv_usec = 0; #endif /* * for nice %b handling in strfime() */ setlocale(LC_TIME, "C"); if (NULL == (srv = server_init())) { fprintf(stderr, "did this really happen?\n"); return -1; } /* * init structs done */ srv->srvconf.port = 0; // #ifdef HAVE_GETUID i_am_root = (getuid() == 0); #else i_am_root = 0; #endif //程序将被设置为守护进程。 srv->srvconf.dont_daemonize = 0; //处理参数。 while (-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) { switch (o) { case 'f': if (config_read(srv, optarg)) { server_free(srv); return -1; } break; case 'm': buffer_copy_string(srv->srvconf.modules_dir, optarg); break; case 'p': print_config = 1; break; case 't': test_config = 1; break; case 'D': srv->srvconf.dont_daemonize = 1; break; case 'v': show_version(); return 0; case 'V': show_features(); return 0; case 'h': show_help(); return 0; default: show_help(); server_free(srv); return -1; } } if (!srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "No configuration available. Try using -f option."); server_free(srv); return -1; } if (print_config) { data_unset *dc = srv->config_context->data[0]; if (dc) { dc->print(dc, 0); fprintf(stdout, "\n"); } else { /* * shouldn't happend */ fprintf(stderr, "global config not found\n"); } } if (test_config) //没有进行任何测试。。。 { printf("Syntax OK\n"); } if (test_config || print_config) { server_free(srv); return 0; } /* * close stdin and stdout, as they are not needed * 关闭标准输入和标准输出。 */ openDevNull(STDIN_FILENO); openDevNull(STDOUT_FILENO); //设置为默认的配置。 if (0 != config_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting default values failed"); server_free(srv); return -1; } /* * UID handling */ #ifdef HAVE_GETUID //检查有效用户ID和有效组ID是否是0(root)。 if (!i_am_root && (geteuid() == 0 || getegid() == 0)) { /* * we are setuid-root * 程序的实际用户ID不是0,也就是程序不是由超级用户运行的,但是程序的有效用户ID * 或者有效组ID是超级用户(组),因此,程序可以访问任何文件而不受限制!这样很 * 不安全。因此程序退出并提示用户。 */ log_error_write(srv, __FILE__, __LINE__, "s", "Are you nuts ? Don't apply a SUID bit to this binary"); server_free(srv); return -1; } #endif /* * check document-root */ if (srv->config_storage[0]->document_root->used <= 1) { log_error_write(srv, __FILE__, __LINE__, "s", "document-root is not set\n"); server_free(srv); return -1; } /* * 加载插件 * * 插件是以动态链接库的形式存在的。在配置文件中,要配置好插件的链接库的 * 路径位置和库中函数的名称。在这个函数中,通过这些配置,获得函数的入口 * 地址。 * 可以看到,这个函数的调用是在整个程序的初始化阶段,而且只调用了这一次, * 因此,在服务器运行之前,要配置好所有的插件。 * 如果想增加插件,只能重启服务器。 * * 在实现plugins_load函数的时候,同时也有一个用于加载静态链接库的版本, * 但函数并没有什么实质性的实现。 * */ if (plugins_load(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "loading plugins finally failed"); plugins_free(srv); server_free(srv); return -1; } /* * open pid file BEFORE chroot * 打开pid文件,并将进程号写入pid文件。 */ if (srv->srvconf.pid_file->used) { if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) /** * O_EXCL和O_CREAT同时使用,测试文件是否存在,如果存在 * 则报错。 */ { //pid文件打开失败。。。 struct stat st; if (errno != EEXIST) //不是报文件已经存在的错误。 { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } //pid文件已经存在,测试文件的状态。 if (0 != stat(srv->srvconf.pid_file->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno)); } if (!S_ISREG(st.st_mode)) //pid文件是普通文件。 { log_error_write(srv, __FILE__, __LINE__, "sb", "pid-file exists and isn't regular file:", srv->srvconf.pid_file); return -1; } //重新打开pid文件。 //这里不在使用O_EXCL参数,由于pid文件已经存在且是普通文件,则覆盖原先的文件。 if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* * select limits itself as it is a hard limit and will lead to a segfault * we add some safety * select的硬限制。减去200是为了增加安全性,防止出现段错误。 */ srv->max_fds = FD_SETSIZE - 200; } else { srv->max_fds = 4096; } //程序是在超级用户模式下运行的。 if (i_am_root) { struct group *grp = NULL; struct passwd *pwd = NULL; int use_rlimit = 1; #ifdef HAVE_VALGRIND_VALGRIND_H if (RUNNING_ON_VALGRIND) use_rlimit = 0; #endif #ifdef HAVE_GETRLIMIT /** * getrlimit和setrlimit函数用于查询和修改进程的资源限制。 * * include <sys/resource.h> * int getrlimit(int resource, struct rlimit *rlim); * int setrlimit(int resource, const struct rlimit *rlim); * 返回:若成功为0,出错为非0 * * 对这两个函数的每一次调用都指定一个资源以及一个指向下列结构的指针。 * * struct rlimit * { * rlim_t rlim_cur; //软限制:当前限制 * rlim_t rlim_max; //硬限制:rlimcur的最大值 * }; * * 这两个函数不属于POSIX.1,但SVR4和4.3+BSD提供它们。SVR4在上面的结构中使用基本系统数据类型rlim_t。 * 其它系统则将这两个成员定义为整型或长整型。 * * 程序中使用的参数RLIMIT_NOFILE:Specifies a value one greater than the maximum file descriptor * number that can be opened by this process. 设置最大的文件打开数,且实际打开的文件数要比这个数 * 小一。 * * 详细使用:man getrlimit */ if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) //获得当前的文件打开数限制。 { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } if (use_rlimit && srv->srvconf.max_fds) { /* * set rlimits. 设置限制。 */ rlim.rlim_cur = srv->srvconf.max_fds; //软限制。 rlim.rlim_max = srv->srvconf.max_fds; //硬限制。 if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } //根据实际设置情况,重新设置max_fds。 if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* * set core file rlimit, if enable_cores is set * 设置core文件的限制。如果设置了enable_cores。 */ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* * don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > FD_SETSIZE - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } #ifdef HAVE_PWD_H /* * set user and group 设置用户和组。 */ if (srv->srvconf.username->used) { //根据配置中的用户名获取用户信息。 if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find username", srv->srvconf.username); return -1; } if (pwd->pw_uid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set uid to 0\n"); return -1; } } if (srv->srvconf.groupname->used) { //根据上面得到的用户所在的组的组名,获得组的信息。 if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find groupname", srv->srvconf.groupname); return -1; } if (grp->gr_gid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set gid to 0\n"); return -1; } } #endif /* * we need root-perms for port < 1024 * 使用超级用户模式获得小于1024的端口。初始化网络。 * 创建监听socket,绑定地址并开始监听。 */ if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } #ifdef HAVE_PWD_H /* * Change group before chroot, when we have access * to /etc/group * */ if (srv->srvconf.groupname->used) { setgid(grp->gr_gid); setgroups(0, NULL); //返回用户组的数目。 if (srv->srvconf.username->used) { //Initialize the group access list by reading the group database /etc/group and using all groups of which //user is a member. The additional group group is also added to the list. initgroups(srv->srvconf.username->ptr, grp->gr_gid); } } #endif #ifdef HAVE_CHROOT if (srv->srvconf.changeroot->used) { //The tzset() function initializes the tzname variable from the TZ environment variable. //This function is automatically called by the other time conversion functions that depend //on the time zone. //In a SysV-like environment it will also set the variables time-zone (seconds West of GMT) //and daylight //(0 if this time zone does not have any daylight saving time rules, nonzero if there is a //time during the year when daylight saving time applies). tzset(); //设置程序所参考的根目录,将被所有的子进程继承。 //也就是对于本程序而言,"/"并不是系统的根目录,而是这设置的目录。 if (-1 == chroot(srv->srvconf.changeroot->ptr)) { log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno)); return -1; } //修改工作目录. /* * 注意: * 由于前面已经设置了根目录。因此这里将工作目录切换到"/"并不是系统的根目录,而是 * 上面通过函数chroot设置的根目录。 */ if (-1 == chdir("/")) { log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno)); return -1; } } #endif #ifdef HAVE_PWD_H /* * drop root privs 放弃超级管理员权限。 */ if (srv->srvconf.username->used) { setuid(pwd->pw_uid); } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) /** * on IRIX 6.5.30 they have prctl() but no DUMPABLE */ if (srv->srvconf.enable_cores) { prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); } #endif } /* * 下面的是程序在非root用户下执行的设置。 */ else { #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } /** * we are not root can can't increase the fd-limit, but we can reduce it * 我们不是root,不能增加fd-limit,但我们可以减少。 */ if (srv->srvconf.max_fds && srv->srvconf.max_fds < rlim.rlim_cur) { /* * set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; //只能设置软限制。 if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* * set core file rlimit, if enable_cores is set */ if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* * don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > FD_SETSIZE - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } } /* * set max-conns 设置最大连接数。 */ if (srv->srvconf.max_conns > srv->max_fds) { /* * we can't have more connections than max-fds * 最大连接数要小于最大文件打开数(max-fds) */ srv->max_conns = srv->max_fds; } else if (srv->srvconf.max_conns) { /* * otherwise respect the wishes of the user * 根据用户设置。 */ srv->max_conns = srv->srvconf.max_conns; } else { /* * or use the default 默认。 */ srv->max_conns = srv->max_fds; } /* * 在前面的plugins_load函数中,已经所有的插件读入到系统中,并对插件中含有 * 的各种函数,确定入口地址。 * 在这里,程序对所有插件进行登记造册,确定插件中含有的功能,并计入表中(srv->plugins_slot) * */ if (HANDLER_GO_ON != plugins_call_init(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_FORK /* * network is up, let's deamonize ourself * 设置为守护进程。 */ if (srv->srvconf.dont_daemonize == 0) daemonize(); #endif srv->gid = getgid(); srv->uid = getuid(); /* * write pid file 写pid文件。 */ if (pid_fd != -1) { buffer_copy_long(srv->tmp_buf, getpid()); buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1); close(pid_fd); pid_fd = -1; } /* * Close stderr ASAP in the child process to make sure that nothing is * being written to that fd which may not be valid anymore. * 关闭向标准输出的输出,打开日志文件。 */ if (-1 == log_error_open(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } //将插件设置为默认配置 if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* * dump unused config-keys */ for (i = 0; i < srv->config_context->used; i++) { array *config = ((data_config *) srv->config_context->data[i])->value; size_t j; for (j = 0; config && j < config->used; j++) { data_unset *du = config->data[j]; /* * all var.* is known as user defined variable */ if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) { continue; } if (NULL == array_get_element(srv->config_touched, du->key->ptr)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "WARNING: unknown config-key:", du->key, "(ignored)"); } } } if (srv->config_unsupported) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains unsupported keys. Going down."); } if (srv->config_deprecated) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains deprecated keys. Going down."); } if (srv->config_unsupported || srv->config_deprecated) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } //设置一些信号的处理方法。 //SIGPIPE:在写管道时,读管道的进程终止,产生此信号。 #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); sigaction(SIGUSR1, &act, NULL); # if defined(SA_SIGINFO) act.sa_sigaction = sigaction_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; # else act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; # endif sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); #elif defined(HAVE_SIGNAL) /* * ignore the SIGPIPE from sendfile() */ signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGALRM, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGCHLD, signal_handler); signal(SIGINT, signal_handler); #endif #ifdef USE_ALARM signal(SIGALRM, signal_handler); /* * setup periodic timer (1 second) * The system provides each process with three interval timers, each decrementing in a distinct time domain. * When any timer expires a signal is sent to the process, and the timer (potentially) restarts. * * ITIMER_REAL decrements in real time, and delivers SIGALRM upon expiration. * ITIMER_VIRTUAL decrements only when the process is executing, and delivers SIGVTALRM upon expiration. * ITIMER_PROF decrements both when the process executes and when the system is executing on * behalf of the process. * Coupled with ITIMER_VIRTUAL, this timer is usually used to profile the time spent * by the application in user and kernel space. * SIGPROF is delivered upon expiration. * Timer values are defined by the following structures: * struct itimerval * { * struct timeval it_interval; //next value * struct timeval it_value; //current value * }; * struct timeval * { * long tv_sec; // seconds * long tv_usec; //microseconds * }; * The function getitimer() fills the structure indicated by value with the current setting for the timer * indicated by which (one of ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF). The element it_value is * set to the amount of time remaining on the timer, or zero ifthe timer is disabled. * Similarly, it_interval is set to the reset value. The function setitimer() sets the indicated timer to the * value in value. If ovalue is nonzero, the old value of the timer is stored there. */ if (setitimer(ITIMER_REAL, &interval, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed"); return -1; } getitimer(ITIMER_REAL, &interval); #endif #ifdef HAVE_FORK /* * ************************* * start watcher and workers * ************************* * * 下面程序将产生多个子进程。这些子进程成为worker,也就是用于接受处理用户的连接的进程。而当前的主进程将 * 成为watcher,主要工作就是监视workers的工作状态,当有worker因为意外而退出时,产生新的worker。 * 在程序退出时,watcher负责停止所有的workers并清理资源。 */ num_childs = srv->srvconf.max_worker;//最大worker数。 if (num_childs > 0) { int child = 0; while (!child && !srv_shutdown && !graceful_shutdown) { if (num_childs > 0) //继续产生worker { switch (fork()) { case -1: return -1; case 0: child = 1; break; default: num_childs--; break; } } else //watcher { /** * 当产生了足够的worker时,watcher就在这个while中不断的循环。 * 一但发现有worker退出(进程死亡),立即产生新的worker。 * 如果发生错误并接受到SIGHUP信号,向所有的进程(父进程及其子进程)包括自己发送SIGHUP信号。 * 并退出。 */ int status; if (-1 != wait(&status)) { /** * one of our workers went away */ num_childs++; } else { switch (errno) { case EINTR: /** * if we receive a SIGHUP we have to close our logs ourself as we don't * have the mainloop who can help us here */ if (handle_sig_hup) { handle_sig_hup = 0; log_error_cycle(srv); /** * forward to all procs in the process-group * 向所有进程发送SIGHUP信号。(父进程及其子进程) * we also send it ourself */ if (!forwarded_sig_hup) { forwarded_sig_hup = 1; kill(0, SIGHUP); } } break; default: break; } } } } /** * for the parent this is the exit-point * ***************************************************** * 父进程,也就是watcher在执行完这个if语句中就直接退出了。 * 后面是worker执行的代码。 * ***************************************************** */ if (!child) { /** * kill all children too 。杀死所有的子进程。 */ if (graceful_shutdown) { kill(0, SIGINT); } else if (srv_shutdown) { kill(0, SIGTERM); } log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; } } #endif /* * ************************** * 从这开始是worker执行的代码。 * ************************** */ if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) { log_error_write(srv, __FILE__, __LINE__, "s", "fdevent_init failed"); return -1; } /* * kqueue() is called here, select resets its internals, * all server sockets get their handlers * 将监听socket注册到fd events系统中。 * 在注册的时候为每个socket都同时注册了一个处理函数,用来处理这个socket的IO事件。 * 对于在这次调用中注册的监听socket,注册的处理函数是:network_server_handle_fdevent。 * 这个处理函数用来建立socket连接。 * */ if (0 != network_register_fdevents(srv)) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* * might fail if user is using fam (not gamin) and famd isn't running * famd没有运行,则运行失败。。。 */ if (NULL == (srv->stat_cache = stat_cache_init())) { log_error_write(srv, __FILE__, __LINE__, "s", "stat-cache could not be setup, dieing."); return -1; } #ifdef HAVE_FAM_H /* * setup FAM 设置FAM。 */ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) { log_error_write(srv, __FILE__, __LINE__, "s", "could not open a fam connection, dieing."); return -1; } #ifdef HAVE_FAMNOEXISTS FAMNoExists(srv->stat_cache->fam); #endif srv->stat_cache->fam_fcce_ndx = -1; fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN); } #endif /* * get the current number of FDs 获得当前可用的fd值 */ srv->cur_fds = open("/dev/null", O_RDONLY); close(srv->cur_fds); for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; /* * close fd on exec (cgi) */ if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); return -1; } } /* * main-loop * ******************* * worker工作的主循环。 * ******************* */ while (!srv_shutdown) { int n; size_t ndx; time_t min_ts; /** * 收到SIGHUP信号。主要是重新开始日志的周期并提示插件。 * 这个信号表示连接已经断开,通常是做一些清理和准备工作,等待下一次的连接。 */ if (handle_sig_hup) { handler_t r; /* * reset notification 重置 */ handle_sig_hup = 0; /* * cycle logfiles * 重新开始新一轮日志。 * 这里使用了switch而不是if语句,有意思。。。 * 调用插件关于SIGHUP信号的处理函数。 * 这个函数貌似也没实现。。。 */ switch (r = plugins_call_handle_sighup(srv)) { case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r); break; } if (-1 == log_error_cycle(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying"); return -1; } else { #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "logfiles cycled UID =", last_sighup_info.si_uid, "PID =", last_sighup_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled"); #endif } } /** * alarm函数发出的信号,表示一秒钟已经过去了。 */ if (handle_sig_alarm) { /* * a new second 新的一秒开始了。。。 */ #ifdef USE_ALARM /* * reset notification 重置 */ handle_sig_alarm = 0; #endif /* * get current time 当前时间。精确到一秒 */ min_ts = time(NULL); /** * 这里判断和服务器记录的当前时间是否相同。 * 相同,则表示服务器还在这一秒中,继续处理请求等。 * 如果不相同,则进入了一个新的周期(当然周期是一秒)。这就要做一些触发和检查以及清理的动作。 * 如插件的触发连接的超时清理状态缓存等。 * 其中,最主要的工作是检查连接的超时。 */ if (min_ts != srv->cur_ts) { int cs = 0; connections *conns = srv->conns; handler_t r; switch (r = plugins_call_handle_trigger(srv)) { case HANDLER_GO_ON: break; case HANDLER_ERROR: log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed"); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } /* * trigger waitpid 么意思?? */ srv->cur_ts = min_ts; /* * cleanup stat-cache 清理状态缓存。每秒钟清理一次。 */ stat_cache_trigger_cleanup(srv); /** * check all connections for timeouts 检查所有的连接是否超时。 */ for (ndx = 0; ndx < conns->used; ndx++) { int changed = 0; connection *con; int t_diff; con = conns->ptr[ndx]; //连接的状态是在读 if (con->state == CON_STATE_READ || con->state == CON_STATE_READ_POST) { if (con->request_count == 1) //连接正在处理一个请求 { if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { /* * time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } //这个连接同时处理多个请求 else { if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) { /* * time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } } //连接的状态是写 if ((con->state == CON_STATE_WRITE) && (con->write_request_ts != 0)) { #if 0 if (srv->cur_ts - con->write_request_ts > 60) { log_error_write(srv, __FILE__, __LINE__, "sdd", "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts); } #endif if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) { /* * time - out */ #if 1 log_error_write(srv, __FILE__, __LINE__, "sbsosds", "NOTE: a request for", con->request.uri, "timed out after writing", con->bytes_written, "bytes. We waited", (int) con->conf. max_write_idle, "seconds. If this a problem increase server.max-write-idle"); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } /* * we don't like div by zero 防止除0。。。 */ if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1; /** * 下面的if语句不是用来判断连接是否超时。 * lighttpd对每个连接设置了一个kbytes_per_second,这个变量设定每个连接在一秒钟内多能传输的最大数据量。 * 如果传送的数据大于这个值,那么这个连接将停止传输数据,被追加到作业队列中等待下一次处理。 * 作者这样做估计是为了平衡各个连接之间的数据传输。 */ if (con->traffic_limit_reached && (con->conf.kbytes_per_second == 0 || ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) { /* * enable connection again */ con->traffic_limit_reached = 0; changed = 1; } if (changed) { connection_state_machine(srv, con); } con->bytes_written_cur_second = 0; *(con->conf.global_bytes_per_second_cnt_ptr) = 0; #if 0 if (cs == 0) { fprintf(stderr, "connection-state: "); cs = 1; } fprintf(stderr, "c[%d,%d]: %s ", con->fd, con->fcgi.fd, connection_get_state(con->state)); #endif }//end of for( ndx = 0; ... if (cs == 1) fprintf(stderr, "\n"); }//end of if (min_ts != srv->cur_ts)... }//end of if (handle_sig_alarm)... if (srv->sockets_disabled) { /* * our server sockets are disabled, why ? * 服务器socket连接失效。为什么捏???后面的服务器过载处理中。。。 * * 将所有连接重新加入的fdevent中。 */ if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */ (srv->conns->used < srv->max_conns * 0.9) && (0 == graceful_shutdown)) { for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN); } log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again"); srv->sockets_disabled = 0; } } else { /* * 下面处理服务器过载的情况。 */ if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */ (srv->conns->used > srv->max_conns) || /* out of connections */ (graceful_shutdown)) /* graceful_shutdown */ { /* * disable server-fds 关闭所有的服务socket */ for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd); if (graceful_shutdown) { /* * we don't want this socket anymore, closing it right * away will make it possible for the next lighttpd to * take over (graceful restart) */ fdevent_unregister(srv->ev, srv_socket->fd); close(srv_socket->fd); srv_socket->fd = -1; /* * network_close() will cleanup after us */ if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv -> srvconf.pid_file, errno, strerror(errno)); } } } } }//end of for(i = 0; ... if (graceful_shutdown) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started"); } else if (srv->conns->used > srv->max_conns) { log_error_write(srv, __FILE__, __LINE__, "s","[note] sockets disabled, connection limit reached"); } else { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds"); } srv->sockets_disabled = 1; //服务器过载了,socket失效。 } } if (graceful_shutdown && srv->conns->used == 0) { /* * we are in graceful shutdown phase and all connections are closed * we are ready to terminate without harming anyone */ srv_shutdown = 1; } /* * we still have some fds to share */ if (srv->want_fds) { /* * check the fdwaitqueue for waiting fds */ int free_fds = srv->max_fds - srv->cur_fds - 16; connection *con; for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) { connection_state_machine(srv, con); srv->want_fds--; } } /** ********************************************************** * 至此,上面那些杂七杂八的事全部处理结束。下面,干正事!! * 也就是处理服务请求。 ********************************************************** */ //启动事件轮询。底层使用的是IO多路转接。 if ((n = fdevent_poll(srv->ev, 1000)) > 0) { /* * n is the number of events n是事件的数量(服务请求啦,文件读写啦什么的。。。) */ int revents; int fd_ndx; #if 0 if (n > 0) { log_error_write(srv, __FILE__, __LINE__, "sd", "polls:", n); } #endif fd_ndx = -1; /** * 这个循环中逐个的处理已经准备好的请求,知道所有的请求处理结束。 */ do { fdevent_handler handler; void *context; handler_t r; fd_ndx = fdevent_event_next_fdndx(srv->ev, fd_ndx); revents = fdevent_event_get_revent(srv->ev, fd_ndx); fd = fdevent_event_get_fd(srv->ev, fd_ndx); handler = fdevent_get_handler(srv->ev, fd); context = fdevent_get_context(srv->ev, fd); /* * connection_handle_fdevent needs a joblist_append */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sdd", "event for", fd, revents); #endif /** * 这里,调用请求的处理函数handler处理请求! * 这才是重点中的重点!! */ switch (r = (*handler) (srv, context, revents)) { case HANDLER_FINISHED: case HANDLER_GO_ON: case HANDLER_WAIT_FOR_EVENT: case HANDLER_WAIT_FOR_FD: break; case HANDLER_ERROR: /* * should never happen */ SEGFAULT(); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } }while (--n > 0); //到这里,本次的请求都处理结束了。。。累啊! } else if (n < 0 && errno != EINTR) { log_error_write(srv, __FILE__, __LINE__, "ss", "fdevent_poll failed:", strerror(errno)); } //由于上面处理的都是发生了IO事件的描述符,这些描述符的状态都被正确的设置了。 //对于没有发生IO事件的描述符,其状态机的状态也需要设置, //下面的循环就是对剩下的描述符进行处理。 for (ndx = 0; ndx < srv->joblist->used; ndx++) { connection *con = srv->joblist->ptr[ndx]; handler_t r; connection_state_machine(srv, con); switch (r = plugins_call_handle_joblist(srv, con)) { case HANDLER_FINISHED: case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } con->in_joblist = 0; } srv->joblist->used = 0; } /* end of main loop */ /* * 主循环的结束 */ if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0 && 0 == graceful_shutdown) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "server stopped by UID =", last_sigterm_info.si_uid,"PID =", last_sigterm_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "server stopped"); #endif /* * clean-up */ log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; }
int main(int ac, char **av) { char *t; int opt, mode = MODE_PAGER; extern int optind; extern char *optarg; if (ac < 2) usage(); setlocale(LC_ALL, ""); /* Populate $HOME */ t = getenv("HOME"); if (t == NULL || *t == '\0') errx(0, "Unknown variable '$HOME'."); mbstowcs(home, t, MAXPATHLEN); /* Populate $EDITOR */ t = getenv("EDITOR"); if (t != NULL) mbstowcs(editor, t, MAXPATHLEN); while ((opt = getopt(ac, av, "hVdeg:qrc:")) != -1) { switch (opt) { case 'd': cfg_debug = 1; break; case 'V': mode = MODE_VERSION; break; case 'q': mode = MODE_QUERY; break; case 'e': mode = MODE_EDIT; break; case 'g': mode = MODE_GENERATE; password_length = strtoumax(optarg, NULL, 10); break; case 'r': mode = MODE_RAW; break; case 'c': swprintf(cfg_config_path, MAXPATHLEN, L"%s", optarg); break; default: usage(); } } debug("read config"); config_set_defaults(); config_check_paths(); config_read(); ac -= optind; av += optind; keywords_load_from_argv(av); /* Decide if we use the internal pager or just dump to screen. */ switch (mode) { case MODE_VERSION: printf("mdp-%s\n", MDP_VERSION); break; case MODE_RAW: debug("mode: MODE_RAW"); if (ac == 0) usage(); gpg_check(); load_results(); filter_results(); print_results(); break; case MODE_PAGER: debug("mode: MODE_PAGER"); if (ac == 0) usage(); gpg_check(); load_results(); filter_results(); pager(START_WITHOUT_PROMPT); break; case MODE_QUERY: debug("mode: MODE_QUERY"); gpg_check(); load_results(); pager(START_WITH_PROMPT); break; case MODE_EDIT: debug("mode: MODE_EDIT"); if (ac != 0) usage(); gpg_check(); lock_set(); load_results(); edit_results(); break; case MODE_GENERATE: debug("mode: MODE_GENERATE"); if (ac != 0) usage(); print_passwords(password_length, cfg_password_count); break; default: errx(1, "unknown mode"); break; } debug("normal shutdown"); return 0; }
int parse_cmdline(test_config_t *cfg, int argc, char **argv) { #ifdef PULSE_ENABLED # define PULSE_OPTION "p" #else # define PULSE_OPTION "" #endif #ifdef ECORE_ENABLED # define ECORE_OPTION "e" #else # define ECORE_OPTION "" #endif #ifdef GLIB_ENABLED # define GLIB_OPTION "g" #else # define GLIB_OPTION "" #endif #ifdef QT_ENABLED # define QT_OPTION "q" #else # define QT_OPTION "" #endif # define OPTIONS "r:i:t:s:I:T:S:M:l:w:W:o:vd:h" \ PULSE_OPTION""ECORE_OPTION""GLIB_OPTION""QT_OPTION struct option options[] = { { "runtime" , required_argument, NULL, 'r' }, { "ios" , required_argument, NULL, 'i' }, { "timers" , required_argument, NULL, 't' }, { "signals" , required_argument, NULL, 's' }, { "glib-ios" , required_argument, NULL, 'I' }, { "glib-timers" , required_argument, NULL, 'T' }, { "dbus-signals", required_argument, NULL, 'S' }, { "dbus-methods", required_argument, NULL, 'M' }, #ifdef PULSE_ENABLED { "pulse" , no_argument , NULL, 'p' }, #endif #ifdef ECORE_ENABLED { "ecore" , no_argument , NULL, 'e' }, #endif #ifdef GLIB_ENABLED { "glib" , no_argument , NULL, 'g' }, #endif #ifdef QT_ENABLED { "qt" , no_argument , NULL, 'q' }, #endif { "wakeup-lpf" , required_argument, NULL, 'w' }, { "wakeup-force", required_argument, NULL, 'W' }, { "log-level" , required_argument, NULL, 'l' }, { "log-target" , required_argument, NULL, 'o' }, { "verbose" , optional_argument, NULL, 'v' }, { "debug" , required_argument, NULL, 'd' }, { "help" , no_argument , NULL, 'h' }, { NULL, 0, NULL, 0 } }; char *end; int opt; config_set_defaults(cfg); while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { switch (opt) { case 'r': cfg->runtime = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid runtime length '%s'.", optarg); break; case 'i': cfg->nio = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid number of I/O watches '%s'.", optarg); break; case 't': cfg->ntimer = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid number of timers '%s'.", optarg); break; case 's': cfg->nsignal = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid number of signals '%s'.", optarg); break; case 'I': cfg->ngio = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid number of glib I/O watches '%s'.", optarg); break; case 'T': cfg->ngtimer = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid number of glib timers '%s'.", optarg); break; case 'S': cfg->ndbus_signal = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid number of DBUS signals '%s'.", optarg); break; case 'M': cfg->ndbus_method = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid number of DBUS methods '%s'.", optarg); break; #ifdef PULSE_ENABLED case 'p': cfg->mainloop_type = MAINLOOP_PULSE; break; #endif #ifdef ECORE_ENABLED case 'e': cfg->mainloop_type = MAINLOOP_ECORE; break; #endif #ifdef GLIB_ENABLED case 'g': cfg->mainloop_type = MAINLOOP_GLIB; break; #endif #ifdef QT_ENABLED case 'q': cfg->mainloop_type = MAINLOOP_QT; break; #endif case 'w': cfg->wlpf = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid wakeup low-pass filter limit '%s'.", optarg); break; case 'W': cfg->wfrc = (int)strtoul(optarg, &end, 10); if (end && *end) print_usage(argv[0], EINVAL, "invalid wakeup force trigger limit '%s'.", optarg); break; case 'v': cfg->log_mask <<= 1; cfg->log_mask |= 1; break; case 'l': cfg->log_mask = mrp_log_parse_levels(optarg); if (cfg->log_mask < 0) print_usage(argv[0], EINVAL, "invalid log level '%s'", optarg); break; case 'o': cfg->log_target = mrp_log_parse_target(optarg); if (!cfg->log_target) print_usage(argv[0], EINVAL, "invalid log target '%s'", optarg); break; case 'd': cfg->log_mask |= MRP_LOG_MASK_DEBUG; mrp_debug_set_config(optarg); mrp_debug_enable(TRUE); break; case 'h': print_usage(argv[0], -1, ""); exit(0); break; default: print_usage(argv[0], EINVAL, "invalid option '%c'", opt); } } return TRUE; }
int main(int argc, char *argv[]) { rarch_main_clear_state(); get_environment_settings(); config_set_defaults(); input_xinput.init(); #ifdef _XBOX1 char path_prefix[256]; snprintf(path_prefix, sizeof(path_prefix), "D:\\"); #else const char *path_prefix = default_paths.filesystem_root_dir; #endif const char *extension = default_paths.executable_extension; const input_driver_t *input = &input_xinput; char full_path[1024]; snprintf(full_path, sizeof(full_path), "%sCORE%s", path_prefix, extension); bool find_libretro_file = rarch_configure_libretro_core(full_path, path_prefix, path_prefix, default_paths.config_file, extension); rarch_settings_set_default(); rarch_input_set_controls_default(input); rarch_config_load(default_paths.config_file, find_libretro_file); init_libretro_sym(); input_xinput.post_init(); #if defined(HAVE_D3D9) || defined(HAVE_D3D8) video_xdk_d3d.start(); driver.video = &video_xdk_d3d; #else video_null.start(); driver.video = &video_null; #endif system_init(); menu_init(); begin_loop: if(g_extern.console.rmenu.mode == MODE_EMULATION) { bool repeat = false; input_xinput.poll(NULL); driver.video->set_aspect_ratio(driver.video_data, g_settings.video.aspect_ratio_idx); do{ repeat = rarch_main_iterate(); }while(repeat && !g_extern.console.screen.state.frame_advance.enable); } else if(g_extern.console.rmenu.mode == MODE_MENU) { menu_loop(); if (g_extern.console.rmenu.mode != MODE_EXIT) rarch_startup(default_paths.config_file); } else goto begin_shutdown; goto begin_loop; begin_shutdown: rarch_config_save(default_paths.config_file); menu_free(); #if defined(HAVE_D3D8) || defined(HAVE_D3D9) video_xdk_d3d.stop(); #else video_null.stop(); #endif input_xinput.free(NULL); if(g_extern.console.external_launch.enable) rarch_console_exec(g_extern.console.external_launch.launch_app); return 0; }
bool config_load_file(const char *path, bool set_defaults) { unsigned i; config_file_t *conf = NULL; if (path) { conf = config_file_new(path); if (!conf) return false; } else conf = open_default_config_file(); if (conf == NULL) return true; if (set_defaults) config_set_defaults(); char *save; char tmp_append_path[PATH_MAX]; // Don't destroy append_config_path. strlcpy(tmp_append_path, g_extern.append_config_path, sizeof(tmp_append_path)); const char *extra_path = strtok_r(tmp_append_path, ",", &save); while (extra_path) { RARCH_LOG("Appending config \"%s\"\n", extra_path); bool ret = config_append_file(conf, extra_path); if (!ret) RARCH_ERR("Failed to append config \"%s\"\n", extra_path); extra_path = strtok_r(NULL, ";", &save); } if (g_extern.verbose) { RARCH_LOG_OUTPUT("=== Config ===\n"); config_file_dump_all(conf, stderr); RARCH_LOG_OUTPUT("=== Config end ===\n"); } char tmp_str[PATH_MAX]; CONFIG_GET_FLOAT(video.xscale, "video_xscale"); CONFIG_GET_FLOAT(video.yscale, "video_yscale"); CONFIG_GET_INT(video.fullscreen_x, "video_fullscreen_x"); CONFIG_GET_INT(video.fullscreen_y, "video_fullscreen_y"); if (!g_extern.force_fullscreen) CONFIG_GET_BOOL(video.fullscreen, "video_fullscreen"); CONFIG_GET_BOOL(video.windowed_fullscreen, "video_windowed_fullscreen"); CONFIG_GET_INT(video.monitor_index, "video_monitor_index"); CONFIG_GET_BOOL(video.disable_composition, "video_disable_composition"); CONFIG_GET_BOOL(video.vsync, "video_vsync"); CONFIG_GET_BOOL(video.hard_sync, "video_hard_sync"); CONFIG_GET_INT(video.hard_sync_frames, "video_hard_sync_frames"); if (g_settings.video.hard_sync_frames > 3) g_settings.video.hard_sync_frames = 3; CONFIG_GET_BOOL(video.black_frame_insertion, "video_black_frame_insertion"); CONFIG_GET_INT(video.swap_interval, "video_swap_interval"); g_settings.video.swap_interval = max(g_settings.video.swap_interval, 1); g_settings.video.swap_interval = min(g_settings.video.swap_interval, 4); CONFIG_GET_BOOL(video.threaded, "video_threaded"); CONFIG_GET_BOOL(video.smooth, "video_smooth"); CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect"); CONFIG_GET_BOOL(video.scale_integer, "video_scale_integer"); CONFIG_GET_BOOL(video.crop_overscan, "video_crop_overscan"); CONFIG_GET_FLOAT(video.aspect_ratio, "video_aspect_ratio"); CONFIG_GET_INT(video.aspect_ratio_idx, "aspect_ratio_index"); CONFIG_GET_BOOL(video.aspect_ratio_auto, "video_aspect_ratio_auto"); CONFIG_GET_FLOAT(video.refresh_rate, "video_refresh_rate"); CONFIG_GET_PATH(video.shader_path, "video_shader"); CONFIG_GET_BOOL(video.shader_enable, "video_shader_enable"); CONFIG_GET_BOOL(video.allow_rotate, "video_allow_rotate"); CONFIG_GET_PATH(video.font_path, "video_font_path"); CONFIG_GET_FLOAT(video.font_size, "video_font_size"); CONFIG_GET_BOOL(video.font_enable, "video_font_enable"); CONFIG_GET_BOOL(video.font_scale, "video_font_scale"); CONFIG_GET_FLOAT(video.msg_pos_x, "video_message_pos_x"); CONFIG_GET_FLOAT(video.msg_pos_y, "video_message_pos_y"); CONFIG_GET_INT(video.rotation, "video_rotation"); #ifdef RARCH_CONSOLE /* TODO - will be refactored later to make it more clean - it's more * important that it works for consoles right now */ CONFIG_GET_BOOL_EXTERN(console.screen.gamma_correction, "gamma_correction"); bool triple_buffering_enable = false; bool custom_bgm_enable = false; bool flicker_filter_enable = false; bool soft_filter_enable = false; #ifdef HAVE_RMENU if (config_get_path(conf, "menu_texture_path", tmp_str, sizeof(tmp_str))) strlcpy(g_extern.menu_texture_path, tmp_str, sizeof(g_extern.menu_texture_path)); #endif if (config_get_bool(conf, "triple_buffering_enable", &triple_buffering_enable)) { if (triple_buffering_enable) g_extern.lifecycle_state |= (1ULL << MODE_VIDEO_TRIPLE_BUFFERING_ENABLE); else g_extern.lifecycle_state &= ~(1ULL << MODE_VIDEO_TRIPLE_BUFFERING_ENABLE); } if (config_get_bool(conf, "custom_bgm_enable", &custom_bgm_enable)) { if (custom_bgm_enable) g_extern.lifecycle_state |= (1ULL << MODE_AUDIO_CUSTOM_BGM_ENABLE); else g_extern.lifecycle_state &= ~(1ULL << MODE_AUDIO_CUSTOM_BGM_ENABLE); } if (config_get_bool(conf, "flicker_filter_enable", &flicker_filter_enable)) { if (flicker_filter_enable) g_extern.lifecycle_state |= (1ULL << MODE_VIDEO_FLICKER_FILTER_ENABLE); else g_extern.lifecycle_state &= ~(1ULL << MODE_VIDEO_FLICKER_FILTER_ENABLE); } if (config_get_bool(conf, "soft_filter_enable", &soft_filter_enable)) { if (soft_filter_enable) g_extern.lifecycle_state |= (1ULL << MODE_VIDEO_SOFT_FILTER_ENABLE); else g_extern.lifecycle_state &= ~(1ULL << MODE_VIDEO_SOFT_FILTER_ENABLE); } CONFIG_GET_INT_EXTERN(console.screen.flicker_filter_index, "flicker_filter_index"); CONFIG_GET_INT_EXTERN(console.screen.soft_filter_index, "soft_filter_index"); #ifdef _XBOX1 CONFIG_GET_INT_EXTERN(console.sound.volume_level, "sound_volume_level"); #endif CONFIG_GET_INT_EXTERN(console.screen.resolutions.current.id, "current_resolution_id"); CONFIG_GET_INT_EXTERN(console.sound.mode, "sound_mode"); #endif CONFIG_GET_INT_EXTERN(state_slot, "state_slot"); CONFIG_GET_INT_EXTERN(console.screen.viewports.custom_vp.x, "custom_viewport_x"); CONFIG_GET_INT_EXTERN(console.screen.viewports.custom_vp.y, "custom_viewport_y"); CONFIG_GET_INT_EXTERN(console.screen.viewports.custom_vp.width, "custom_viewport_width"); CONFIG_GET_INT_EXTERN(console.screen.viewports.custom_vp.height, "custom_viewport_height"); unsigned msg_color = 0; if (config_get_hex(conf, "video_message_color", &msg_color)) { g_settings.video.msg_color_r = ((msg_color >> 16) & 0xff) / 255.0f; g_settings.video.msg_color_g = ((msg_color >> 8) & 0xff) / 255.0f; g_settings.video.msg_color_b = ((msg_color >> 0) & 0xff) / 255.0f; }
int main (int argc, char **argv) { server *srv = NULL; int print_config = 0; int test_config = 0; int i_am_root; int o; int num_childs = 0; int pid_fd = -1, fd; size_t i; #ifdef HAVE_SIGACTION struct sigaction act; #endif #ifdef HAVE_GETRLIMIT struct rlimit rlim; #endif #ifdef USE_ALARM struct itimerval interval; interval.it_interval.tv_sec = 1; interval.it_interval.tv_usec = 0; interval.it_value.tv_sec = 1; interval.it_value.tv_usec = 0; #endif /* for nice %b handling in strfime() */ setlocale(LC_TIME, "C"); if (NULL == (srv = server_init())) { fprintf(stderr, "did this really happen?\n"); return -1; } /* init structs done */ srv->srvconf.port = 0; #ifdef HAVE_GETUID i_am_root = (getuid() == 0); #else i_am_root = 0; #endif srv->srvconf.dont_daemonize = 0; while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) { switch(o) { case 'f': if (srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "Can only read one config file. Use the include command to use multiple config files."); server_free(srv); return -1; } if (config_read(srv, optarg)) { server_free(srv); return -1; } break; case 'm': buffer_copy_string(srv->srvconf.modules_dir, optarg); break; case 'p': print_config = 1; break; case 't': test_config = 1; break; case 'D': srv->srvconf.dont_daemonize = 1; break; case 'v': show_version(); return 0; case 'V': show_features(); return 0; case 'h': show_help(); return 0; default: show_help(); server_free(srv); return -1; } } if (!srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "No configuration available. Try using -f option."); server_free(srv); return -1; } if (print_config) { data_unset *dc = srv->config_context->data[0]; if (dc) { dc->print(dc, 0); fprintf(stdout, "\n"); } else { /* shouldn't happend */ fprintf(stderr, "global config not found\n"); } } if (test_config) { printf("Syntax OK\n"); } if (test_config || print_config) { server_free(srv); return 0; } /* close stdin and stdout, as they are not needed */ openDevNull(STDIN_FILENO); openDevNull(STDOUT_FILENO); if (0 != config_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting default values failed"); server_free(srv); return -1; } /* UID handling */ #ifdef HAVE_GETUID if (!i_am_root && issetugid()) { /* we are setuid-root */ log_error_write(srv, __FILE__, __LINE__, "s", "Are you nuts ? Don't apply a SUID bit to this binary"); server_free(srv); return -1; } #endif /* check document-root */ if (srv->config_storage[0]->document_root->used <= 1) { log_error_write(srv, __FILE__, __LINE__, "s", "document-root is not set\n"); server_free(srv); return -1; } if (plugins_load(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "loading plugins finally failed"); plugins_free(srv); server_free(srv); return -1; } /* open pid file BEFORE chroot */ if (srv->srvconf.pid_file->used) { if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { struct stat st; if (errno != EEXIST) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } if (0 != stat(srv->srvconf.pid_file->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno)); } if (!S_ISREG(st.st_mode)) { log_error_write(srv, __FILE__, __LINE__, "sb", "pid-file exists and isn't regular file:", srv->srvconf.pid_file); return -1; } if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* select limits itself * * as it is a hard limit and will lead to a segfault we add some safety * */ srv->max_fds = FD_SETSIZE - 200; } else { srv->max_fds = 4096; } if (i_am_root) { struct group *grp = NULL; struct passwd *pwd = NULL; int use_rlimit = 1; #ifdef HAVE_VALGRIND_VALGRIND_H if (RUNNING_ON_VALGRIND) use_rlimit = 0; #endif #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } if (use_rlimit && srv->srvconf.max_fds) { /* set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; rlim.rlim_max = srv->srvconf.max_fds; if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* set core file rlimit, if enable_cores is set */ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > ((int)FD_SETSIZE) - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } #ifdef HAVE_PWD_H /* set user and group */ if (srv->srvconf.username->used) { if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find username", srv->srvconf.username); return -1; } if (pwd->pw_uid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set uid to 0\n"); return -1; } } if (srv->srvconf.groupname->used) { if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find groupname", srv->srvconf.groupname); return -1; } if (grp->gr_gid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set gid to 0\n"); return -1; } } #endif /* we need root-perms for port < 1024 */ if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } #ifdef HAVE_PWD_H /* * Change group before chroot, when we have access * to /etc/group * */ if (NULL != grp) { setgid(grp->gr_gid); setgroups(0, NULL); if (srv->srvconf.username->used) { initgroups(srv->srvconf.username->ptr, grp->gr_gid); } } #endif #ifdef HAVE_CHROOT if (srv->srvconf.changeroot->used) { tzset(); if (-1 == chroot(srv->srvconf.changeroot->ptr)) { log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno)); return -1; } if (-1 == chdir("/")) { log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno)); return -1; } } #endif #ifdef HAVE_PWD_H /* drop root privs */ if (NULL != pwd) { setuid(pwd->pw_uid); } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) /** * on IRIX 6.5.30 they have prctl() but no DUMPABLE */ if (srv->srvconf.enable_cores) { prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); } #endif } else { #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } /** * we are not root can can't increase the fd-limit, but we can reduce it */ if (srv->srvconf.max_fds && srv->srvconf.max_fds < rlim.rlim_cur) { /* set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* set core file rlimit, if enable_cores is set */ if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > ((int)FD_SETSIZE) - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } } /* set max-conns */ if (srv->srvconf.max_conns > srv->max_fds/2) { /* we can't have more connections than max-fds/2 */ log_error_write(srv, __FILE__, __LINE__, "sdd", "can't have more connections than fds/2: ", srv->srvconf.max_conns, srv->max_fds); srv->max_conns = srv->max_fds/2; } else if (srv->srvconf.max_conns) { /* otherwise respect the wishes of the user */ srv->max_conns = srv->srvconf.max_conns; } else { /* or use the default: we really don't want to hit max-fds */ srv->max_conns = srv->max_fds/3; } if (HANDLER_GO_ON != plugins_call_init(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_FORK /* network is up, let's deamonize ourself */ if (srv->srvconf.dont_daemonize == 0) daemonize(); #endif srv->gid = getgid(); srv->uid = getuid(); /* write pid file */ if (pid_fd != -1) { buffer_copy_long(srv->tmp_buf, getpid()); buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1); close(pid_fd); pid_fd = -1; } /* Close stderr ASAP in the child process to make sure that nothing * is being written to that fd which may not be valid anymore. */ if (-1 == log_error_open(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* dump unused config-keys */ for (i = 0; i < srv->config_context->used; i++) { array *config = ((data_config *)srv->config_context->data[i])->value; size_t j; for (j = 0; config && j < config->used; j++) { data_unset *du = config->data[j]; /* all var.* is known as user defined variable */ if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) { continue; } if (NULL == array_get_element(srv->config_touched, du->key->ptr)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "WARNING: unknown config-key:", du->key, "(ignored)"); } } } if (srv->config_unsupported) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains unsupported keys. Going down."); } if (srv->config_deprecated) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains deprecated keys. Going down."); } if (srv->config_unsupported || srv->config_deprecated) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); sigaction(SIGUSR1, &act, NULL); # if defined(SA_SIGINFO) act.sa_sigaction = sigaction_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; # else act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; # endif sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); #elif defined(HAVE_SIGNAL) /* ignore the SIGPIPE from sendfile() */ signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGALRM, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGCHLD, signal_handler); signal(SIGINT, signal_handler); #endif #ifdef USE_ALARM signal(SIGALRM, signal_handler); /* setup periodic timer (1 second) */ if (setitimer(ITIMER_REAL, &interval, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed"); return -1; } getitimer(ITIMER_REAL, &interval); #endif #ifdef HAVE_FORK /* start watcher and workers */ num_childs = srv->srvconf.max_worker; if (num_childs > 0) { int child = 0; while (!child && !srv_shutdown && !graceful_shutdown) { if (num_childs > 0) { switch (fork()) { case -1: return -1; case 0: child = 1; break; default: num_childs--; break; } } else { int status; if (-1 != wait(&status)) { /** * one of our workers went away */ num_childs++; } else { switch (errno) { case EINTR: /** * if we receive a SIGHUP we have to close our logs ourself as we don't * have the mainloop who can help us here */ if (handle_sig_hup) { handle_sig_hup = 0; log_error_cycle(srv); /** * forward to all procs in the process-group * * we also send it ourself */ if (!forwarded_sig_hup) { forwarded_sig_hup = 1; kill(0, SIGHUP); } } break; default: break; } } } } /** * for the parent this is the exit-point */ if (!child) { /** * kill all children too */ if (graceful_shutdown) { kill(0, SIGINT); } else if (srv_shutdown) { kill(0, SIGTERM); } log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; } } #endif if (NULL == (srv->ev = fdevent_init(srv, srv->max_fds + 1, srv->event_handler))) { log_error_write(srv, __FILE__, __LINE__, "s", "fdevent_init failed"); return -1; } /* libev backend overwrites our SIGCHLD handler and calls waitpid on SIGCHLD; we want our own SIGCHLD handling. */ #ifdef HAVE_SIGACTION sigaction(SIGCHLD, &act, NULL); #elif defined(HAVE_SIGNAL) signal(SIGCHLD, signal_handler); #endif /* * kqueue() is called here, select resets its internals, * all server sockets get their handlers * * */ if (0 != network_register_fdevents(srv)) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* might fail if user is using fam (not gamin) and famd isn't running */ if (NULL == (srv->stat_cache = stat_cache_init())) { log_error_write(srv, __FILE__, __LINE__, "s", "stat-cache could not be setup, dieing."); return -1; } #ifdef HAVE_FAM_H /* setup FAM */ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) { log_error_write(srv, __FILE__, __LINE__, "s", "could not open a fam connection, dieing."); return -1; } #ifdef HAVE_FAMNOEXISTS FAMNoExists(srv->stat_cache->fam); #endif srv->stat_cache->fam_fcce_ndx = -1; fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); fdevent_event_set(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN); } #endif /* get the current number of FDs */ srv->cur_fds = open("/dev/null", O_RDONLY); close(srv->cur_fds); for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); return -1; } } /* main-loop */ while (!srv_shutdown) { int n; size_t ndx; time_t min_ts; if (handle_sig_hup) { handler_t r; /* reset notification */ handle_sig_hup = 0; /* cycle logfiles */ switch(r = plugins_call_handle_sighup(srv)) { case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r); break; } if (-1 == log_error_cycle(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying"); return -1; } else { #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "logfiles cycled UID =", last_sighup_info.si_uid, "PID =", last_sighup_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled"); #endif } } if (handle_sig_alarm) { /* a new second */ #ifdef USE_ALARM /* reset notification */ handle_sig_alarm = 0; #endif /* get current time */ min_ts = time(NULL); if (min_ts != srv->cur_ts) { int cs = 0; connections *conns = srv->conns; handler_t r; switch(r = plugins_call_handle_trigger(srv)) { case HANDLER_GO_ON: break; case HANDLER_ERROR: log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed"); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } /* trigger waitpid */ srv->cur_ts = min_ts; /* cleanup stat-cache */ stat_cache_trigger_cleanup(srv); /** * check all connections for timeouts * */ for (ndx = 0; ndx < conns->used; ndx++) { int changed = 0; connection *con; int t_diff; con = conns->ptr[ndx]; if (con->state == CON_STATE_READ || con->state == CON_STATE_READ_POST) { if (con->request_count == 1) { if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { /* time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } else { if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) { /* time - out */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } } if ((con->state == CON_STATE_WRITE) && (con->write_request_ts != 0)) { #if 0 if (srv->cur_ts - con->write_request_ts > 60) { log_error_write(srv, __FILE__, __LINE__, "sdd", "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts); } #endif if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) { /* time - out */ if (con->conf.log_timeouts) { log_error_write(srv, __FILE__, __LINE__, "sbsosds", "NOTE: a request for", con->request.uri, "timed out after writing", con->bytes_written, "bytes. We waited", (int)con->conf.max_write_idle, "seconds. If this a problem increase server.max-write-idle"); } connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } if (con->state == CON_STATE_CLOSE && (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT)) { changed = 1; } /* we don't like div by zero */ if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1; if (con->traffic_limit_reached && (con->conf.kbytes_per_second == 0 || ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) { /* enable connection again */ con->traffic_limit_reached = 0; changed = 1; } if (changed) { connection_state_machine(srv, con); } con->bytes_written_cur_second = 0; *(con->conf.global_bytes_per_second_cnt_ptr) = 0; #if 0 if (cs == 0) { fprintf(stderr, "connection-state: "); cs = 1; } fprintf(stderr, "c[%d,%d]: %s ", con->fd, con->fcgi.fd, connection_get_state(con->state)); #endif } if (cs == 1) fprintf(stderr, "\n"); } } if (srv->sockets_disabled) { /* our server sockets are disabled, why ? */ if ((srv->cur_fds + srv->want_fds < srv->max_fds * 8 / 10) && /* we have enough unused fds */ (srv->conns->used <= srv->max_conns * 9 / 10) && (0 == graceful_shutdown)) { for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN); } log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again"); srv->sockets_disabled = 0; } } else { if ((srv->cur_fds + srv->want_fds > srv->max_fds * 9 / 10) || /* out of fds */ (srv->conns->used >= srv->max_conns) || /* out of connections */ (graceful_shutdown)) { /* graceful_shutdown */ /* disable server-fds */ for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd); if (graceful_shutdown) { /* we don't want this socket anymore, * * closing it right away will make it possible for * the next lighttpd to take over (graceful restart) * */ fdevent_unregister(srv->ev, srv_socket->fd); close(srv_socket->fd); srv_socket->fd = -1; /* network_close() will cleanup after us */ if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } } } if (graceful_shutdown) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started"); } else if (srv->conns->used >= srv->max_conns) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached"); } else { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds"); } srv->sockets_disabled = 1; } } if (graceful_shutdown && srv->conns->used == 0) { /* we are in graceful shutdown phase and all connections are closed * we are ready to terminate without harming anyone */ srv_shutdown = 1; } /* we still have some fds to share */ if (srv->want_fds) { /* check the fdwaitqueue for waiting fds */ int free_fds = srv->max_fds - srv->cur_fds - 16; connection *con; for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) { connection_state_machine(srv, con); srv->want_fds--; } } if ((n = fdevent_poll(srv->ev, 1000)) > 0) { /* n is the number of events */ int revents; int fd_ndx; #if 0 if (n > 0) { log_error_write(srv, __FILE__, __LINE__, "sd", "polls:", n); } #endif fd_ndx = -1; do { fdevent_handler handler; void *context; handler_t r; fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx); if (-1 == fd_ndx) break; /* not all fdevent handlers know how many fds got an event */ revents = fdevent_event_get_revent (srv->ev, fd_ndx); fd = fdevent_event_get_fd (srv->ev, fd_ndx); handler = fdevent_get_handler(srv->ev, fd); context = fdevent_get_context(srv->ev, fd); /* connection_handle_fdevent needs a joblist_append */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sdd", "event for", fd, revents); #endif switch (r = (*handler)(srv, context, revents)) { case HANDLER_FINISHED: case HANDLER_GO_ON: case HANDLER_WAIT_FOR_EVENT: case HANDLER_WAIT_FOR_FD: break; case HANDLER_ERROR: /* should never happen */ SEGFAULT(); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } } while (--n > 0); } else if (n < 0 && errno != EINTR) { log_error_write(srv, __FILE__, __LINE__, "ss", "fdevent_poll failed:", strerror(errno)); } for (ndx = 0; ndx < srv->joblist->used; ndx++) { connection *con = srv->joblist->ptr[ndx]; handler_t r; connection_state_machine(srv, con); switch(r = plugins_call_handle_joblist(srv, con)) { case HANDLER_FINISHED: case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } con->in_joblist = 0; } srv->joblist->used = 0; } if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0 && 0 == graceful_shutdown) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "server stopped by UID =", last_sigterm_info.si_uid, "PID =", last_sigterm_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "server stopped"); #endif /* clean-up */ log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; }
bool openrct2_initialise() { utf8 userPath[MAX_PATH]; platform_resolve_user_data_path(); platform_get_user_directory(userPath, NULL); if (!platform_ensure_directory_exists(userPath)) { log_fatal("Could not create user directory (do you have write access to your documents folder?)"); return false; } if (!openrct2_setup_rct2_segment()) { log_fatal("Unable to load RCT2 data sector"); return false; } openrct2_set_exe_path(); config_set_defaults(); if (!config_open_default()) { if (!config_find_or_browse_install_directory()) { log_fatal("An RCT2 install directory must be specified!"); return false; } } gOpenRCT2ShowChangelog = true; if (gConfigGeneral.last_run_version != NULL && (strcmp(gConfigGeneral.last_run_version, OPENRCT2_VERSION) == 0)) gOpenRCT2ShowChangelog = false; gConfigGeneral.last_run_version = OPENRCT2_VERSION; config_save_default(); // TODO add configuration option to allow multiple instances // if (!gOpenRCT2Headless && !platform_lock_single_instance()) { // log_fatal("OpenRCT2 is already running."); // return false; // } get_system_info(); if (!gOpenRCT2Headless) { audio_init(); audio_get_devices(); } if (!language_open(gConfigGeneral.language)) { log_fatal("Failed to open language, exiting."); return false; } http_init(); themes_set_default(); themes_load_presets(); title_sequences_set_default(); title_sequences_load_presets(); openrct2_setup_rct2_hooks(); if (!rct2_init()) return false; chat_init(); openrct2_copy_original_user_files_over(); // TODO move to audio initialise function if (str_is_null_or_empty(gConfigSound.device)) { Mixer_Init(NULL); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = 0; } else { Mixer_Init(gConfigSound.device); for (int i = 0; i < gAudioDeviceCount; i++) { if (strcmp(gAudioDevices[i].name, gConfigSound.device) == 0) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = i; } } } return true; }
int main(int argc, char *argv[]) { #ifdef HAVE_SYSUTILS RARCH_LOG("Registering system utility callback...\n"); cellSysutilRegisterCallback(0, callback_sysutil_exit, NULL); #endif #ifdef HAVE_SYSMODULES cellSysmoduleLoadModule(CELL_SYSMODULE_IO); cellSysmoduleLoadModule(CELL_SYSMODULE_FS); cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_GAME); cellSysmoduleLoadModule(CELL_SYSMODULE_AVCONF_EXT); cellSysmoduleLoadModule(CELL_SYSMODULE_PNGDEC); cellSysmoduleLoadModule(CELL_SYSMODULE_JPGDEC); cellSysmoduleLoadModule(CELL_SYSMODULE_NET); cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_NP); #endif sys_net_initialize_network(); #ifdef HAVE_LOGGER logger_init(); #endif sceNpInit(NP_POOL_SIZE, np_pool); rarch_main_clear_state(); get_environment_settings(argc, argv); config_set_defaults(); input_ps3.init(); char tmp_path[PATH_MAX]; snprintf(tmp_path, sizeof(tmp_path), "%s/", default_paths.core_dir); rarch_configure_libretro(&input_ps3, tmp_path, default_paths.executable_extension); #if(CELL_SDK_VERSION > 0x340000) if (g_console.screenshots_enable) { #ifdef HAVE_SYSMODULES cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_SCREENSHOT); #endif #ifdef HAVE_SYSUTILS CellScreenShotSetParam screenshot_param = {0, 0, 0, 0}; screenshot_param.photo_title = "RetroArch PS3"; screenshot_param.game_title = "RetroArch PS3"; cellScreenShotSetParameter (&screenshot_param); cellScreenShotEnable(); #endif } #ifdef HAVE_SYSUTILS if (g_console.custom_bgm_enable) cellSysutilEnableBgmPlayback(); #endif #endif video_gl.start(); #ifdef HAVE_OSKUTIL oskutil_init(&g_console.oskutil_handle, 0); #endif rarch_input_set_default_keybind_names_for_emulator(); menu_init(); switch(g_console.external_launcher_support) { case EXTERN_LAUNCHER_SALAMANDER: g_console.mode_switch = MODE_MENU; break; #ifdef HAVE_MULTIMAN case EXTERN_LAUNCHER_MULTIMAN: RARCH_LOG("Started from multiMAN, will auto-start game.\n"); strlcpy(g_console.rom_path, argv[1], sizeof(g_console.rom_path)); rarch_settings_change(S_START_RARCH); rarch_startup(default_paths.config_file); break; #endif default: break; } begin_loop: if(g_console.mode_switch == MODE_EMULATION) { bool repeat = false; input_ps3.poll(NULL); rarch_set_auto_viewport(g_extern.frame_cache.width, g_extern.frame_cache.height); do{ repeat = rarch_main_iterate(); }while(repeat && !g_console.frame_advance_enable); } else if(g_console.mode_switch == MODE_MENU) { menu_loop(); rarch_startup(default_paths.config_file); } else goto begin_shutdown; goto begin_loop; begin_shutdown: if(path_file_exists(default_paths.config_file)) rarch_config_save(default_paths.config_file); if(g_console.emulator_initialized) rarch_main_deinit(); input_ps3.free(NULL); video_gl.stop(); menu_free(); #ifdef HAVE_OSKUTIL if(g_console.oskutil_handle.is_running) oskutil_unload(&g_console.oskutil_handle); #endif #ifdef HAVE_LOGGER logger_shutdown(); #endif #ifdef HAVE_SYSMODULES if(g_console.screenshots_enable) cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_SCREENSHOT); cellSysmoduleUnloadModule(CELL_SYSMODULE_JPGDEC); cellSysmoduleUnloadModule(CELL_SYSMODULE_PNGDEC); cellSysmoduleUnloadModule(CELL_SYSMODULE_AVCONF_EXT); cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_GAME); #endif #ifdef HAVE_HDD_CACHE_PARTITION int ret = cellSysCacheClear(); if(ret != CELL_SYSCACHE_RET_OK_CLEARED) { RARCH_ERR("System cache partition could not be cleared on exit.\n"); } #endif rarch_exec(); return 1; }
int parse_cmdline(context_t *ctx, int argc, char **argv) { # define OPTIONS "sab:l:t:vdh" struct option options[] = { { "server" , no_argument , NULL, 's' }, { "bus" , required_argument, NULL, 'b' }, { "all-pongs" , no_argument , NULL, 'a' }, { "log-level" , required_argument, NULL, 'l' }, { "log-target", required_argument, NULL, 't' }, { "verbose" , optional_argument, NULL, 'v' }, { "debug" , no_argument , NULL, 'd' }, { "help" , no_argument , NULL, 'h' }, { NULL, 0, NULL, 0 } }; int opt, debug; debug = FALSE; config_set_defaults(ctx); while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { switch (opt) { case 's': ctx->server = TRUE; break; case 'b': ctx->busaddr = optarg; break; case 'a': ctx->all_pongs = TRUE; break; case 'v': ctx->log_mask <<= 1; ctx->log_mask |= 1; break; case 'l': ctx->log_mask = mrp_log_parse_levels(optarg); if (ctx->log_mask < 0) print_usage(argv[0], EINVAL, "invalid log level '%s'", optarg); break; case 't': ctx->log_target = mrp_log_parse_target(optarg); if (!ctx->log_target) print_usage(argv[0], EINVAL, "invalid log target '%s'", optarg); break; case 'd': debug = TRUE; break; case 'h': print_usage(argv[0], -1, ""); exit(0); break; default: print_usage(argv[0], EINVAL, "invalid option '%c'", opt); } } if (debug) ctx->log_mask |= MRP_LOG_MASK_DEBUG; return TRUE; }