static char * ngx_http_groonga_conf_set_groonga_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *status; ngx_http_core_loc_conf_t *location_conf; ngx_http_groonga_loc_conf_t *groonga_location_conf = conf; status = ngx_conf_set_flag_slot(cf, cmd, conf); if (status != NGX_CONF_OK) { return status; } location_conf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); if (groonga_location_conf->enabled) { location_conf->handler = ngx_http_groonga_handler; groonga_location_conf->name = ngx_str_null_terminate(cf->pool, &(location_conf->name)); groonga_location_conf->config_file = ngx_str_null_terminate(cf->pool, &(cf->conf_file->file.name)); groonga_location_conf->config_line = cf->conf_file->line; } else { location_conf->handler = NULL; } return NGX_CONF_OK; }
/** * This function is called after forking and just before exec()ing the helper server. */ static void starting_helper_server_after_fork(void *arg) { ngx_cycle_t *cycle = (void *) arg; char *log_filename; FILE *log_file; ngx_core_conf_t *ccf; ngx_uint_t i; ngx_str_t *envs; const char *env; /* At this point, stdout and stderr may still point to the console. * Make sure that they're both redirected to the log file. */ log_file = NULL; if (cycle->new_log.file->name.len > 0) { log_filename = ngx_str_null_terminate(&cycle->new_log.file->name); log_file = fopen((const char *) log_filename, "a"); if (log_file == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "could not open the error log file for writing"); } free(log_filename); } else if (cycle->log != NULL && cycle->log->file->name.len > 0) { log_filename = ngx_str_null_terminate(&cycle->log->file->name); log_file = fopen((const char *) log_filename, "a"); if (log_file == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "could not open the error log file for writing"); } free(log_filename); } if (log_file == NULL) { /* If the log file cannot be opened then we redirect stdout * and stderr to /dev/null, because if the user disconnects * from the console on which Nginx is started, then on Linux * any writes to stdout or stderr will result in an EIO error. */ log_file = fopen("/dev/null", "w"); } if (log_file != NULL) { dup2(fileno(log_file), 1); dup2(fileno(log_file), 2); fclose(log_file); } /* Set environment variables in Nginx config file. */ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); envs = ccf->env.elts; for (i = 0; i < ccf->env.nelts; i++) { env = (const char *) envs[i].data; if (strchr(env, '=') != NULL) { putenv(strdup(env)); } } /* Set SERVER_SOFTWARE so that application processes know what web * server they're running on during startup. */ setenv("SERVER_SOFTWARE", NGINX_VER, 1); }
/** * This function is called after forking and just before exec()ing the helper server. */ static void starting_helper_server_after_fork(void *arg) { ngx_cycle_t *cycle = (void *) arg; char *log_filename; FILE *log_file; /* At this point, stdout and stderr may still point to the console. * Make sure that they're both redirected to the log file. */ log_file = NULL; if (cycle->new_log.file->name.len > 0) { log_filename = ngx_str_null_terminate(&cycle->new_log.file->name); log_file = fopen((const char *) log_filename, "a"); if (log_file == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "could not open the error log file for writing"); } free(log_filename); } else if (cycle->log != NULL && cycle->log->file->name.len > 0) { log_filename = ngx_str_null_terminate(&cycle->log->file->name); log_file = fopen((const char *) log_filename, "a"); if (log_file == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "could not open the error log file for writing"); } free(log_filename); } if (log_file == NULL) { /* If the log file cannot be opened then we redirect stdout * and stderr to /dev/null, because if the user disconnects * from the console on which Nginx is started, then on Linux * any writes to stdout or stderr will result in an EIO error. */ log_file = fopen("/dev/null", "w"); } if (log_file != NULL) { dup2(fileno(log_file), 1); dup2(fileno(log_file), 2); fclose(log_file); } /* Set SERVER_SOFTWARE so that application processes know what web * server they're running on during startup. */ setenv("SERVER_SOFTWARE", NGINX_VER, 1); }
static void ngx_http_groonga_open_database_callback(ngx_http_groonga_loc_conf_t *location_conf, void *user_data) { ngx_http_groonga_database_callback_data_t *data = user_data; grn_ctx *context; context = &(location_conf->context); data->rc = ngx_http_groonga_context_init(context, location_conf, data->pool, data->log); if (data->rc != NGX_OK) { return; } if (!location_conf->database_path.data) { ngx_log_error(NGX_LOG_EMERG, data->log, 0, "%s: \"groonga_database\" must be specified in block at %s:%d", location_conf->name, location_conf->config_file, location_conf->config_line); data->rc = NGX_ERROR; return; } if (!location_conf->database_path_cstr) { location_conf->database_path_cstr = ngx_str_null_terminate(data->pool, &(location_conf->database_path)); } grn_db_open(context, location_conf->database_path_cstr); if (context->rc != GRN_SUCCESS) { if (location_conf->database_auto_create) { ngx_http_groonga_create_database(location_conf, data); } else { ngx_log_error(NGX_LOG_EMERG, data->log, 0, "failed to open groonga database: %s", context->errbuf); data->rc = NGX_ERROR; return; } } location_conf->cache = grn_cache_open(context); if (!location_conf->cache) { ngx_log_error(NGX_LOG_EMERG, data->log, 0, "failed to open groonga cache: %s", context->errbuf); data->rc = NGX_ERROR; return; } if (location_conf->cache_limit != NGX_CONF_UNSET_SIZE) { grn_cache_set_max_n_entries(context, location_conf->cache, location_conf->cache_limit); } }
static char * ngx_http_groonga_conf_set_log_level_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *status = NGX_CONF_OK; ngx_http_groonga_loc_conf_t *groonga_location_conf = conf; char *value; value = ngx_str_null_terminate(cf->cycle->pool, ((ngx_str_t *)cf->args->elts) + 1); if (!grn_log_level_parse(value, &(groonga_location_conf->log_level))) { status = "must be one of 'none', 'emergency', 'alert', " "'critical', 'error', 'warning', 'notice', 'info', 'debug' and 'dump'"; } ngx_pfree(cf->cycle->pool, value); return status; }
static void ngx_http_groonga_open_database_callback(ngx_http_groonga_loc_conf_t *location_conf, void *user_data) { ngx_http_groonga_database_callback_data_t *data = user_data; grn_ctx *context; context = &(location_conf->context); grn_ctx_init(context, GRN_NO_FLAGS); if (!location_conf->database_path.data) { ngx_log_error(NGX_LOG_EMERG, data->log, 0, "%s: \"groonga_database\" must be specified in block at %s:%d", location_conf->name, location_conf->config_file, location_conf->config_line); data->rc = NGX_ERROR; return; } if (!location_conf->database_path_cstr) { location_conf->database_path_cstr = ngx_str_null_terminate(data->pool, &(location_conf->database_path)); } grn_db_open(context, location_conf->database_path_cstr); if (context->rc == GRN_SUCCESS) { return; } if (location_conf->database_auto_create) { ngx_http_groonga_create_database(location_conf, data); } else { ngx_log_error(NGX_LOG_EMERG, data->log, 0, "failed to open groonga database: %s", context->errbuf); data->rc = NGX_ERROR; } }
static char * ngx_http_groonga_conf_set_log_level_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *status = NGX_CONF_OK; ngx_http_groonga_loc_conf_t *groonga_location_conf = conf; char *value; value = ngx_str_null_terminate(cf->cycle->pool, ((ngx_str_t *)cf->args->elts) + 1); if (strcasecmp(value, "none") == 0) { groonga_location_conf->log_level = GRN_LOG_NONE; } else if (strcasecmp(value, "emergency") == 0) { groonga_location_conf->log_level = GRN_LOG_EMERG; } else if (strcasecmp(value, "alert") == 0) { groonga_location_conf->log_level = GRN_LOG_ALERT; } else if (strcasecmp(value, "critical") == 0) { groonga_location_conf->log_level = GRN_LOG_CRIT; } else if (strcasecmp(value, "error") == 0) { groonga_location_conf->log_level = GRN_LOG_ERROR; } else if (strcasecmp(value, "warning") == 0) { groonga_location_conf->log_level = GRN_LOG_WARNING; } else if (strcasecmp(value, "notice") == 0) { groonga_location_conf->log_level = GRN_LOG_NOTICE; } else if (strcasecmp(value, "info") == 0) { groonga_location_conf->log_level = GRN_LOG_INFO; } else if (strcasecmp(value, "debug") == 0) { groonga_location_conf->log_level = GRN_LOG_DEBUG; } else if (strcasecmp(value, "dump") == 0) { groonga_location_conf->log_level = GRN_LOG_DUMP; } else { status = "must be one of 'none', 'emergency', 'alert', " "'ciritical', 'error', 'warning', 'notice', 'info', 'debug' and 'dump'"; } ngx_pfree(cf->cycle->pool, value); return status; }
/** * Start the helper server and save its runtime information into various variables. * * @pre The helper server isn't already started. * @pre The Nginx configuration has been loaded. */ static ngx_int_t start_helper_server(ngx_cycle_t *cycle) { ngx_core_conf_t *core_conf; ngx_int_t ret, result; ngx_uint_t i; ngx_str_t *prestart_uris; char **prestart_uris_ary = NULL; u_char filename[NGX_MAX_PATH], *last; char *debug_log_file = NULL; char *default_user = NULL; char *default_group = NULL; char *passenger_root = NULL; char *analytics_log_user; char *analytics_log_group; char *union_station_gateway_address; char *union_station_gateway_cert; char *union_station_proxy_address; char *error_message = NULL; core_conf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); result = NGX_OK; /* Create null-terminated versions of some strings. */ debug_log_file = ngx_str_null_terminate(&passenger_main_conf.debug_log_file); default_user = ngx_str_null_terminate(&passenger_main_conf.default_user); default_group = ngx_str_null_terminate(&passenger_main_conf.default_group); passenger_root = ngx_str_null_terminate(&passenger_main_conf.root_dir); analytics_log_user = ngx_str_null_terminate(&passenger_main_conf.analytics_log_user); analytics_log_group = ngx_str_null_terminate(&passenger_main_conf.analytics_log_group); union_station_gateway_address = ngx_str_null_terminate(&passenger_main_conf.union_station_gateway_address); union_station_gateway_cert = ngx_str_null_terminate(&passenger_main_conf.union_station_gateway_cert); union_station_proxy_address = ngx_str_null_terminate(&passenger_main_conf.union_station_proxy_address); prestart_uris = (ngx_str_t *) passenger_main_conf.prestart_uris->elts; prestart_uris_ary = calloc(sizeof(char *), passenger_main_conf.prestart_uris->nelts); for (i = 0; i < passenger_main_conf.prestart_uris->nelts; i++) { prestart_uris_ary[i] = malloc(prestart_uris[i].len + 1); if (prestart_uris_ary[i] == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ENOMEM, "Cannot allocate memory"); result = NGX_ERROR; goto cleanup; } memcpy(prestart_uris_ary[i], prestart_uris[i].data, prestart_uris[i].len); prestart_uris_ary[i][prestart_uris[i].len] = '\0'; } ret = agents_starter_start(passenger_agents_starter, passenger_main_conf.log_level, debug_log_file, getpid(), "", passenger_main_conf.user_switching, default_user, default_group, core_conf->user, core_conf->group, passenger_root, "ruby", passenger_main_conf.max_pool_size, passenger_main_conf.max_instances_per_app, passenger_main_conf.pool_idle_time, "", analytics_log_user, analytics_log_group, union_station_gateway_address, passenger_main_conf.union_station_gateway_port, union_station_gateway_cert, union_station_proxy_address, (const char **) prestart_uris_ary, passenger_main_conf.prestart_uris->nelts, starting_helper_server_after_fork, cycle, &error_message); if (!ret) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "%s", error_message); result = NGX_ERROR; goto cleanup; } /* Create the file passenger_temp_dir + "/control_process.pid" * and make it writable by the worker processes. This is because * save_master_process_pid is run after Nginx has lowered privileges. */ last = ngx_snprintf(filename, sizeof(filename) - 1, "%s/control_process.pid", agents_starter_get_server_instance_dir(passenger_agents_starter)); *last = (u_char) '\0'; if (create_file(cycle, filename, (const u_char *) "", 0) != NGX_OK) { result = NGX_ERROR; goto cleanup; } do { ret = chown((const char *) filename, (uid_t) core_conf->user, (gid_t) -1); } while (ret == -1 && errno == EINTR); if (ret == -1) { result = NGX_ERROR; goto cleanup; } /* Create various other info files. */ last = ngx_snprintf(filename, sizeof(filename) - 1, "%s/web_server.txt", agents_starter_get_generation_dir(passenger_agents_starter)); *last = (u_char) '\0'; if (create_file(cycle, filename, (const u_char *) NGINX_VER, strlen(NGINX_VER)) != NGX_OK) { result = NGX_ERROR; goto cleanup; } last = ngx_snprintf(filename, sizeof(filename) - 1, "%s/config_files.txt", agents_starter_get_generation_dir(passenger_agents_starter)); *last = (u_char) '\0'; if (create_file(cycle, filename, cycle->conf_file.data, cycle->conf_file.len) != NGX_OK) { result = NGX_ERROR; goto cleanup; } cleanup: free(debug_log_file); free(default_user); free(default_group); free(passenger_root); free(analytics_log_user); free(analytics_log_group); free(union_station_gateway_address); free(union_station_gateway_cert); free(union_station_proxy_address); free(error_message); if (prestart_uris_ary != NULL) { for (i = 0; i < passenger_main_conf.prestart_uris->nelts; i++) { free(prestart_uris_ary[i]); } free(prestart_uris_ary); } if (result == NGX_ERROR && passenger_main_conf.abort_on_startup_error) { exit(1); } return result; }
/** * Start the helper server and save its runtime information into various variables. * * @pre The helper server isn't already started. * @pre The Nginx configuration has been loaded. */ static ngx_int_t start_helper_server(ngx_cycle_t *cycle) { ngx_core_conf_t *core_conf; ngx_int_t ret, result; ngx_uint_t i; ngx_str_t *prestart_uris; char **prestart_uris_ary = NULL; ngx_keyval_t *ctl = NULL; PP_VariantMap *params = NULL; u_char filename[NGX_MAX_PATH], *last; char *passenger_root = NULL; char *error_message = NULL; core_conf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); result = NGX_OK; params = pp_variant_map_new(); passenger_root = ngx_str_null_terminate(&passenger_main_conf.root_dir); prestart_uris = (ngx_str_t *) passenger_main_conf.prestart_uris->elts; prestart_uris_ary = calloc(sizeof(char *), passenger_main_conf.prestart_uris->nelts); for (i = 0; i < passenger_main_conf.prestart_uris->nelts; i++) { prestart_uris_ary[i] = malloc(prestart_uris[i].len + 1); if (prestart_uris_ary[i] == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ENOMEM, "Cannot allocate memory"); result = NGX_ERROR; goto cleanup; } memcpy(prestart_uris_ary[i], prestart_uris[i].data, prestart_uris[i].len); prestart_uris_ary[i][prestart_uris[i].len] = '\0'; } pp_variant_map_set_int (params, "web_server_pid", getpid()); pp_variant_map_set_int (params, "web_server_worker_uid", core_conf->user); pp_variant_map_set_int (params, "web_server_worker_gid", core_conf->group); pp_variant_map_set_int (params, "log_level", passenger_main_conf.log_level); pp_variant_map_set_ngx_str(params, "debug_log_file", &passenger_main_conf.debug_log_file); pp_variant_map_set_ngx_str(params, "temp_dir", &passenger_main_conf.temp_dir); pp_variant_map_set_bool (params, "user_switching", passenger_main_conf.user_switching); pp_variant_map_set_ngx_str(params, "default_user", &passenger_main_conf.default_user); pp_variant_map_set_ngx_str(params, "default_group", &passenger_main_conf.default_group); pp_variant_map_set_ngx_str(params, "default_ruby", &passenger_main_conf.default_ruby); pp_variant_map_set_int (params, "max_pool_size", passenger_main_conf.max_pool_size); pp_variant_map_set_int (params, "pool_idle_time", passenger_main_conf.pool_idle_time); pp_variant_map_set_ngx_str(params, "analytics_log_user", &passenger_main_conf.analytics_log_user); pp_variant_map_set_ngx_str(params, "analytics_log_group", &passenger_main_conf.analytics_log_group); pp_variant_map_set_ngx_str(params, "union_station_gateway_address", &passenger_main_conf.union_station_gateway_address); pp_variant_map_set_int (params, "union_station_gateway_port", passenger_main_conf.union_station_gateway_port); pp_variant_map_set_ngx_str(params, "union_station_gateway_cert", &passenger_main_conf.union_station_gateway_cert); pp_variant_map_set_ngx_str(params, "union_station_proxy_address", &passenger_main_conf.union_station_proxy_address); pp_variant_map_set_strset (params, "prestart_urls", (const char **) prestart_uris_ary, passenger_main_conf.prestart_uris->nelts); ctl = (ngx_keyval_t *) passenger_main_conf.ctl->elts; for (i = 0; i < passenger_main_conf.ctl->nelts; i++) { pp_variant_map_set2(params, (const char *) ctl[i].key.data, ctl[i].key.len - 1, (const char *) ctl[i].value.data, ctl[i].value.len - 1); } ret = pp_agents_starter_start(pp_agents_starter, passenger_root, params, starting_helper_server_after_fork, cycle, &error_message); if (!ret) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "%s", error_message); result = NGX_ERROR; goto cleanup; } /* Create the file passenger_temp_dir + "/control_process.pid" * and make it writable by the worker processes. This is because * save_master_process_pid is run after Nginx has lowered privileges. */ last = ngx_snprintf(filename, sizeof(filename) - 1, "%s/control_process.pid", pp_agents_starter_get_server_instance_dir(pp_agents_starter)); *last = (u_char) '\0'; if (create_file(cycle, filename, (const u_char *) "", 0) != NGX_OK) { result = NGX_ERROR; goto cleanup; } do { ret = chown((const char *) filename, (uid_t) core_conf->user, (gid_t) -1); } while (ret == -1 && errno == EINTR); if (ret == -1) { result = NGX_ERROR; goto cleanup; } /* Create various other info files. */ last = ngx_snprintf(filename, sizeof(filename) - 1, "%s/web_server.txt", pp_agents_starter_get_generation_dir(pp_agents_starter)); *last = (u_char) '\0'; if (create_file(cycle, filename, (const u_char *) NGINX_VER, strlen(NGINX_VER)) != NGX_OK) { result = NGX_ERROR; goto cleanup; } last = ngx_snprintf(filename, sizeof(filename) - 1, "%s/config_files.txt", pp_agents_starter_get_generation_dir(pp_agents_starter)); *last = (u_char) '\0'; if (create_file(cycle, filename, cycle->conf_file.data, cycle->conf_file.len) != NGX_OK) { result = NGX_ERROR; goto cleanup; } cleanup: pp_variant_map_free(params); free(passenger_root); free(error_message); if (prestart_uris_ary != NULL) { for (i = 0; i < passenger_main_conf.prestart_uris->nelts; i++) { free(prestart_uris_ary[i]); } free(prestart_uris_ary); } if (result == NGX_ERROR && passenger_main_conf.abort_on_startup_error) { exit(1); } return result; }