diff options
-rw-r--r-- | auto/help | 1 | ||||
-rw-r--r-- | auto/options | 6 | ||||
-rw-r--r-- | auto/summary | 1 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | src/nxt_controller.c | 87 | ||||
-rw-r--r-- | src/nxt_main_process.c | 100 | ||||
-rw-r--r-- | src/nxt_port.h | 2 | ||||
-rw-r--r-- | src/nxt_runtime.c | 40 | ||||
-rw-r--r-- | src/nxt_runtime.h | 3 | ||||
-rw-r--r-- | src/nxt_worker_process.c | 4 |
10 files changed, 244 insertions, 2 deletions
@@ -17,6 +17,7 @@ cat << END --sbindir=DIRECTORY set system admin executables directory name default: "$NXT_SBINDIR" --modules=DIRECTORY set modules directory name, default: "$NXT_MODULES" + --state=DIRECTORY set state directory name, default: "$NXT_STATE" --pid=FILE set pid filename, default: "$NXT_PID" --log=FILE set log filename, default: "$NXT_LOG" diff --git a/auto/options b/auto/options index cb4a8b56..9563bbc8 100644 --- a/auto/options +++ b/auto/options @@ -55,6 +55,7 @@ do --bindir=*) NXT_BINDIR="$value" ;; --sbindir=*) NXT_SBINDIR="$value" ;; --modules=*) NXT_MODULES="$value" ;; + --state=*) NXT_STATE="$value" ;; --pid=*) NXT_PID="$value" ;; --log=*) NXT_LOG="$value" ;; @@ -132,6 +133,11 @@ case "$NXT_MODULES" in *) NXT_MODULES="$NXT_PREFIX$NXT_MODULES" ;; esac +case "$NXT_STATE" in + /*) ;; + *) NXT_STATE="$NXT_PREFIX$NXT_STATE" ;; +esac + case "$NXT_PID" in /*) ;; *) NXT_PID="$NXT_PREFIX$NXT_PID" ;; diff --git a/auto/summary b/auto/summary index 93324869..a45855d6 100644 --- a/auto/summary +++ b/auto/summary @@ -10,6 +10,7 @@ Configuration summary: unit pid file: "$NXT_PID" unit log file: "$NXT_LOG" unit modules path: "$NXT_MODULES" + unit state path: "$NXT_STATE" unit control API socket: "$NXT_CONTROL" @@ -33,6 +33,7 @@ NXT_DAEMON=unitd NXT_BINDIR="bin" NXT_SBINDIR="sbin" NXT_MODULES="$NXT_BUILD_DIR" +NXT_STATE="$NXT_BUILD_DIR" NXT_PID="unit.pid" NXT_LOG="unit.log" NXT_CONTROL="unix:control.unit.sock" @@ -81,6 +82,7 @@ cat << END >> $NXT_AUTO_CONFIG_H #define NXT_PID "$NXT_PID" #define NXT_LOG "$NXT_LOG" #define NXT_MODULES "$NXT_MODULES" +#define NXT_STATE "$NXT_STATE" #define NXT_CONTROL_SOCK "$NXT_CONTROL" diff --git a/src/nxt_controller.c b/src/nxt_controller.c index e41452a3..1a595bcf 100644 --- a/src/nxt_controller.c +++ b/src/nxt_controller.c @@ -71,6 +71,8 @@ static void nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req); static void nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data); +static void nxt_controller_conf_store(nxt_task_t *task, + nxt_conf_value_t *conf); static void nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, nxt_controller_response_t *resp); static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now, @@ -86,6 +88,7 @@ static nxt_http_fields_hash_entry_t nxt_controller_request_fields[] = { static nxt_http_fields_hash_t *nxt_controller_fields_hash; +static nxt_uint_t nxt_controller_listening; static nxt_controller_conf_t nxt_controller_conf; static nxt_queue_t nxt_controller_waiting_requests; @@ -115,7 +118,10 @@ nxt_port_handler_t nxt_controller_process_port_handlers[] = { nxt_int_t nxt_controller_start(nxt_task_t *task, void *data) { + nxt_mp_t *mp; + nxt_str_t *json; nxt_runtime_t *rt; + nxt_conf_value_t *conf; nxt_http_fields_hash_t *hash; rt = task->thread->runtime; @@ -129,6 +135,42 @@ nxt_controller_start(nxt_task_t *task, void *data) nxt_controller_fields_hash = hash; nxt_queue_init(&nxt_controller_waiting_requests); + json = data; + + if (json->length == 0) { + return NXT_OK; + } + + mp = nxt_mp_create(1024, 128, 256, 32); + if (nxt_slow_path(mp == NULL)) { + return NXT_ERROR; + } + + conf = nxt_conf_json_parse_str(mp, json); + nxt_free(json->start); + + if (nxt_slow_path(conf == NULL)) { + nxt_log(task, NXT_LOG_ALERT, + "failed to restore previous configuration: " + "file is corrupted or not enough memory"); + + nxt_mp_destroy(mp); + return NXT_OK; + } + + if (nxt_slow_path(nxt_conf_validate(conf) != NXT_OK)) { + nxt_log(task, NXT_LOG_ALERT, + "failed to restore previous configuration: " + "invalid configuration"); + + nxt_mp_destroy(mp); + return NXT_OK; + } + + + nxt_controller_conf.root = conf; + nxt_controller_conf.pool = mp; + return NXT_OK; } @@ -173,6 +215,8 @@ nxt_controller_process_new_port_handler(nxt_task_t *task, if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) { nxt_abort(); } + + nxt_controller_listening = 1; } @@ -208,13 +252,29 @@ static void nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) { + nxt_runtime_t *rt; + if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) { + nxt_log(task, NXT_LOG_ALERT, "failed to apply previous configuration"); + nxt_mp_destroy(nxt_controller_conf.pool); if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { nxt_abort(); } } + + if (nxt_controller_listening == 0) { + rt = task->thread->runtime; + + if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) + == NULL)) + { + nxt_abort(); + } + + nxt_controller_listening = 1; + } } @@ -926,6 +986,8 @@ nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, nxt_controller_conf = req->conf; + nxt_controller_conf_store(task, req->conf.root); + resp.status = 200; resp.title = (u_char *) "Reconfiguration done."; @@ -951,6 +1013,31 @@ nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, static void +nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf) +{ + size_t size; + nxt_buf_t *b; + nxt_port_t *main_port; + nxt_runtime_t *rt; + + rt = task->thread->runtime; + + main_port = rt->port_by_type[NXT_PROCESS_MAIN]; + + size = nxt_conf_json_length(conf, NULL); + + b = nxt_buf_mem_alloc(main_port->mem_pool, size, 0); + + if (nxt_fast_path(b != NULL)) { + b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL); + + (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CONF_STORE, + -1, 0, -1, b); + } +} + + +static void nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, nxt_controller_response_t *resp) { diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index ded19055..7748d07f 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -49,6 +49,8 @@ static nxt_int_t nxt_main_listening_socket(nxt_sockaddr_t *sa, static void nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); static int nxt_cdecl nxt_app_lang_compare(const void *v1, const void *v2); +static void nxt_main_port_conf_store_handler(nxt_task_t *task, + nxt_port_recv_msg_t *msg); const nxt_sig_event_t nxt_main_process_signals[] = { @@ -224,6 +226,7 @@ static nxt_port_handler_t nxt_main_process_port_handlers[] = { nxt_port_main_start_worker_handler, nxt_main_port_socket_handler, nxt_main_port_modules_handler, + nxt_main_port_conf_store_handler, nxt_port_rpc_handler, nxt_port_rpc_handler, }; @@ -295,8 +298,47 @@ nxt_main_process_title(nxt_task_t *task) static nxt_int_t nxt_main_start_controller_process(nxt_task_t *task, nxt_runtime_t *rt) { + ssize_t n; + nxt_int_t ret; + nxt_str_t conf; + nxt_file_t file; + nxt_file_info_t fi; nxt_process_init_t *init; + conf.length = 0; + + nxt_memzero(&file, sizeof(nxt_file_t)); + + file.name = (nxt_file_name_t *) rt->conf; + + if (nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0) == NXT_OK) { + + if (nxt_fast_path(nxt_file_info(&file, &fi) == NXT_OK + && nxt_is_file(&fi))) + { + conf.length = nxt_file_size(&fi); + conf.start = nxt_malloc(conf.length); + + if (nxt_slow_path(conf.start == NULL)) { + nxt_file_close(task, &file); + return NXT_ERROR; + } + + n = nxt_file_read(&file, conf.start, conf.length, 0); + + if (nxt_slow_path(n != (ssize_t) conf.length)) { + conf.length = 0; + nxt_free(conf.start); + + nxt_log(task, NXT_LOG_ALERT, + "failed to restore previous configuration: " + "cannot read the file"); + } + } + + nxt_file_close(task, &file); + } + init = nxt_malloc(sizeof(nxt_process_init_t)); if (nxt_slow_path(init == NULL)) { return NXT_ERROR; @@ -308,11 +350,17 @@ nxt_main_start_controller_process(nxt_task_t *task, nxt_runtime_t *rt) init->port_handlers = nxt_controller_process_port_handlers; init->signals = nxt_worker_process_signals; init->type = NXT_PROCESS_CONTROLLER; - init->data = rt; + init->data = &conf; init->stream = 0; init->restart = 1; - return nxt_main_create_worker_process(task, rt, init); + ret = nxt_main_create_worker_process(task, rt, init); + + if (ret == NXT_OK && conf.length != 0) { + nxt_free(conf.start); + } + + return ret; } @@ -1054,3 +1102,51 @@ nxt_app_lang_compare(const void *v1, const void *v2) return -n; } + + +static void +nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) +{ + ssize_t n, size; + nxt_buf_t *b; + nxt_int_t ret; + nxt_file_t file; + nxt_runtime_t *rt; + + nxt_memzero(&file, sizeof(nxt_file_t)); + + rt = task->thread->runtime; + + file.name = (nxt_file_name_t *) rt->conf_tmp; + + if (nxt_slow_path(nxt_file_open(task, &file, NXT_FILE_WRONLY, + NXT_FILE_TRUNCATE, NXT_FILE_OWNER_ACCESS) + != NXT_OK)) + { + goto error; + } + + for (b = msg->buf; b != NULL; b = b->next) { + size = nxt_buf_mem_used_size(&b->mem); + + n = nxt_file_write(&file, b->mem.pos, size, 0); + + if (nxt_slow_path(n != size)) { + nxt_file_close(task, &file); + (void) nxt_file_delete(file.name); + goto error; + } + } + + nxt_file_close(task, &file); + + ret = nxt_file_rename(file.name, (nxt_file_name_t *) rt->conf); + + if (nxt_fast_path(ret == NXT_OK)) { + return; + } + +error: + + nxt_log(task, NXT_LOG_ALERT, "failed to store current configuration"); +} diff --git a/src/nxt_port.h b/src/nxt_port.h index 78228ff7..a338a8c4 100644 --- a/src/nxt_port.h +++ b/src/nxt_port.h @@ -25,6 +25,7 @@ typedef enum { _NXT_PORT_MSG_START_WORKER, _NXT_PORT_MSG_SOCKET, _NXT_PORT_MSG_MODULES, + _NXT_PORT_MSG_CONF_STORE, _NXT_PORT_MSG_RPC_READY, _NXT_PORT_MSG_RPC_ERROR, @@ -43,6 +44,7 @@ typedef enum { NXT_PORT_MSG_LAST, NXT_PORT_MSG_SOCKET = _NXT_PORT_MSG_SOCKET | NXT_PORT_MSG_LAST, NXT_PORT_MSG_MODULES = _NXT_PORT_MSG_MODULES | NXT_PORT_MSG_LAST, + NXT_PORT_MSG_CONF_STORE = _NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_LAST, NXT_PORT_MSG_RPC_READY = _NXT_PORT_MSG_RPC_READY, NXT_PORT_MSG_RPC_READY_LAST = _NXT_PORT_MSG_RPC_READY | NXT_PORT_MSG_LAST, NXT_PORT_MSG_RPC_ERROR = _NXT_PORT_MSG_RPC_ERROR | NXT_PORT_MSG_LAST, diff --git a/src/nxt_runtime.c b/src/nxt_runtime.c index f569f3f2..ac0775ee 100644 --- a/src/nxt_runtime.c +++ b/src/nxt_runtime.c @@ -722,6 +722,7 @@ nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt) rt->pid = NXT_PID; rt->log = NXT_LOG; rt->modules = NXT_MODULES; + rt->state = NXT_STATE; rt->control = NXT_CONTROL_SOCK; if (nxt_runtime_conf_read_cmd(task, rt) != NXT_OK) { @@ -771,6 +772,28 @@ nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt) rt->modules = (char *) file_name.start; + slash = ""; + n = nxt_strlen(rt->state); + + if (n > 1 && rt->state[n - 1] != '/') { + slash = "/"; + } + + ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sconf.json%Z", + rt->state, slash); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + rt->conf = (char *) file_name.start; + + ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s.tmp%Z", rt->conf); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + rt->conf_tmp = (char *) file_name.start; + control.length = nxt_strlen(rt->control); control.start = (u_char *) rt->control; @@ -808,6 +831,7 @@ nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt) static const char no_log[] = "option \"--log\" requires filename\n"; static const char no_modules[] = "option \"--modules\" requires directory\n"; + static const char no_state[] = "option \"--state\" requires directory\n"; static const char help[] = "\n" @@ -829,6 +853,9 @@ nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt) " --modules DIRECTORY set modules directory name\n" " default: \"" NXT_MODULES "\"\n" "\n" + " --state DIRECTORY set state directory name\n" + " default: \"" NXT_STATE "\"\n" + "\n" " --user USER set non-privileged processes to run" " as specified user\n" " default: \"" NXT_USER "\"\n" @@ -938,6 +965,19 @@ nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt) continue; } + if (nxt_strcmp(p, "--state") == 0) { + if (*argv == NULL) { + write(STDERR_FILENO, no_state, sizeof(no_state) - 1); + return NXT_ERROR; + } + + p = *argv++; + + rt->state = p; + + continue; + } + if (nxt_strcmp(p, "--no-daemon") == 0) { rt->daemon = 0; continue; diff --git a/src/nxt_runtime.h b/src/nxt_runtime.h index b491002e..d0decfd2 100644 --- a/src/nxt_runtime.h +++ b/src/nxt_runtime.h @@ -58,6 +58,9 @@ struct nxt_runtime_s { const char *pid; const char *log; const char *modules; + const char *state; + const char *conf; + const char *conf_tmp; const char *control; nxt_queue_t engines; /* of nxt_event_engine_t */ diff --git a/src/nxt_worker_process.c b/src/nxt_worker_process.c index 6804f8ab..1a7d0c53 100644 --- a/src/nxt_worker_process.c +++ b/src/nxt_worker_process.c @@ -31,6 +31,7 @@ nxt_port_handler_t nxt_worker_process_port_handlers[] = { NULL, /* NXT_PORT_MSG_START_WORKER */ NULL, /* NXT_PORT_MSG_SOCKET */ NULL, /* NXT_PORT_MSG_MODULES */ + NULL, /* NXT_PORT_MSG_CONF_STORE */ nxt_port_rpc_handler, nxt_port_rpc_handler, }; @@ -47,6 +48,7 @@ nxt_port_handler_t nxt_app_process_port_handlers[] = { NULL, /* NXT_PORT_MSG_START_WORKER */ NULL, /* NXT_PORT_MSG_SOCKET */ NULL, /* NXT_PORT_MSG_MODULES */ + NULL, /* NXT_PORT_MSG_CONF_STORE */ nxt_port_rpc_handler, nxt_port_rpc_handler, }; @@ -63,6 +65,7 @@ nxt_port_handler_t nxt_router_process_port_handlers[] = { NULL, /* NXT_PORT_MSG_START_WORKER */ NULL, /* NXT_PORT_MSG_SOCKET */ NULL, /* NXT_PORT_MSG_MODULES */ + NULL, /* NXT_PORT_MSG_CONF_STORE */ nxt_port_rpc_handler, nxt_port_rpc_handler, }; @@ -79,6 +82,7 @@ nxt_port_handler_t nxt_discovery_process_port_handlers[] = { NULL, /* NXT_PORT_MSG_START_WORKER */ NULL, /* NXT_PORT_MSG_SOCKET */ NULL, /* NXT_PORT_MSG_MODULES */ + NULL, /* NXT_PORT_MSG_CONF_STORE */ nxt_port_rpc_handler, nxt_port_rpc_handler, }; |