1804Svbart@nginx.com 2804Svbart@nginx.com /* 3804Svbart@nginx.com * Copyright (C) Max Romanov 4804Svbart@nginx.com * Copyright (C) NGINX, Inc. 5804Svbart@nginx.com */ 6804Svbart@nginx.com 7804Svbart@nginx.com #include <nxt_main.h> 8804Svbart@nginx.com #include <nxt_router.h> 9804Svbart@nginx.com #include <nxt_unit.h> 10804Svbart@nginx.com 11804Svbart@nginx.com 12804Svbart@nginx.com static nxt_int_t nxt_external_init(nxt_task_t *task, 13804Svbart@nginx.com nxt_common_app_conf_t *conf); 14804Svbart@nginx.com 15804Svbart@nginx.com 16804Svbart@nginx.com nxt_app_module_t nxt_external_module = { 17804Svbart@nginx.com 0, 18804Svbart@nginx.com NULL, 19804Svbart@nginx.com nxt_string("external"), 20804Svbart@nginx.com "*", 21*977Smax.romanov@gmail.com NULL, 22804Svbart@nginx.com nxt_external_init, 23804Svbart@nginx.com }; 24804Svbart@nginx.com 25804Svbart@nginx.com 26804Svbart@nginx.com extern char **environ; 27804Svbart@nginx.com 28804Svbart@nginx.com 29804Svbart@nginx.com nxt_inline nxt_int_t 30804Svbart@nginx.com nxt_external_fd_no_cloexec(nxt_task_t *task, nxt_socket_t fd) 31804Svbart@nginx.com { 32804Svbart@nginx.com int res, flags; 33804Svbart@nginx.com 34804Svbart@nginx.com if (fd == -1) { 35804Svbart@nginx.com return NXT_OK; 36804Svbart@nginx.com } 37804Svbart@nginx.com 38804Svbart@nginx.com flags = fcntl(fd, F_GETFD); 39804Svbart@nginx.com 40804Svbart@nginx.com if (nxt_slow_path(flags == -1)) { 41804Svbart@nginx.com nxt_alert(task, "fcntl(%d, F_GETFD) failed %E", fd, nxt_errno); 42804Svbart@nginx.com return NXT_ERROR; 43804Svbart@nginx.com } 44804Svbart@nginx.com 45804Svbart@nginx.com flags &= ~FD_CLOEXEC; 46804Svbart@nginx.com 47804Svbart@nginx.com res = fcntl(fd, F_SETFD, flags); 48804Svbart@nginx.com 49804Svbart@nginx.com if (nxt_slow_path(res == -1)) { 50804Svbart@nginx.com nxt_alert(task, "fcntl(%d, F_SETFD) failed %E", fd, nxt_errno); 51804Svbart@nginx.com return NXT_ERROR; 52804Svbart@nginx.com } 53804Svbart@nginx.com 54804Svbart@nginx.com nxt_fd_blocking(task, fd); 55804Svbart@nginx.com 56804Svbart@nginx.com return NXT_OK; 57804Svbart@nginx.com } 58804Svbart@nginx.com 59804Svbart@nginx.com 60804Svbart@nginx.com static nxt_int_t 61804Svbart@nginx.com nxt_external_init(nxt_task_t *task, nxt_common_app_conf_t *conf) 62804Svbart@nginx.com { 63804Svbart@nginx.com char **argv; 64804Svbart@nginx.com u_char buf[256]; 65804Svbart@nginx.com u_char *p, *end; 66804Svbart@nginx.com uint32_t index; 67804Svbart@nginx.com size_t size; 68804Svbart@nginx.com nxt_str_t str; 69804Svbart@nginx.com nxt_int_t rc; 70804Svbart@nginx.com nxt_uint_t i, argc; 71804Svbart@nginx.com nxt_port_t *my_port, *main_port; 72804Svbart@nginx.com nxt_runtime_t *rt; 73804Svbart@nginx.com nxt_conf_value_t *value; 74804Svbart@nginx.com nxt_external_app_conf_t *c; 75804Svbart@nginx.com 76804Svbart@nginx.com rt = task->thread->runtime; 77804Svbart@nginx.com 78804Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 79804Svbart@nginx.com my_port = nxt_runtime_port_find(rt, nxt_pid, 0); 80804Svbart@nginx.com 81804Svbart@nginx.com if (nxt_slow_path(main_port == NULL || my_port == NULL)) { 82804Svbart@nginx.com return NXT_ERROR; 83804Svbart@nginx.com } 84804Svbart@nginx.com 85804Svbart@nginx.com rc = nxt_external_fd_no_cloexec(task, main_port->pair[1]); 86804Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 87804Svbart@nginx.com return NXT_ERROR; 88804Svbart@nginx.com } 89804Svbart@nginx.com 90804Svbart@nginx.com rc = nxt_external_fd_no_cloexec(task, my_port->pair[0]); 91804Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 92804Svbart@nginx.com return NXT_ERROR; 93804Svbart@nginx.com } 94804Svbart@nginx.com 95804Svbart@nginx.com end = buf + sizeof(buf); 96804Svbart@nginx.com 97804Svbart@nginx.com p = nxt_sprintf(buf, end, 98804Svbart@nginx.com "%s;%uD;" 99804Svbart@nginx.com "%PI,%ud,%d;" 100804Svbart@nginx.com "%PI,%ud,%d;" 101804Svbart@nginx.com "%d,%Z", 102804Svbart@nginx.com NXT_VERSION, my_port->process->init->stream, 103804Svbart@nginx.com main_port->pid, main_port->id, main_port->pair[1], 104804Svbart@nginx.com my_port->pid, my_port->id, my_port->pair[0], 105804Svbart@nginx.com 2); 106804Svbart@nginx.com 107804Svbart@nginx.com if (nxt_slow_path(p == end)) { 108804Svbart@nginx.com nxt_alert(task, "internal error: buffer too small for NXT_UNIT_INIT"); 109804Svbart@nginx.com 110804Svbart@nginx.com return NXT_ERROR; 111804Svbart@nginx.com } 112804Svbart@nginx.com 113804Svbart@nginx.com nxt_debug(task, "update "NXT_UNIT_INIT_ENV"=%s", buf); 114804Svbart@nginx.com 115804Svbart@nginx.com rc = setenv(NXT_UNIT_INIT_ENV, (char *) buf, 1); 116804Svbart@nginx.com if (nxt_slow_path(rc == -1)) { 117804Svbart@nginx.com nxt_alert(task, "setenv("NXT_UNIT_INIT_ENV", %s) failed %E", buf, 118804Svbart@nginx.com nxt_errno); 119804Svbart@nginx.com 120804Svbart@nginx.com return NXT_ERROR; 121804Svbart@nginx.com } 122804Svbart@nginx.com 123804Svbart@nginx.com c = &conf->u.external; 124804Svbart@nginx.com 125804Svbart@nginx.com argc = 2; 126804Svbart@nginx.com size = 0; 127804Svbart@nginx.com 128804Svbart@nginx.com if (c->arguments != NULL) { 129804Svbart@nginx.com 130804Svbart@nginx.com for (index = 0; /* void */ ; index++) { 131804Svbart@nginx.com value = nxt_conf_get_array_element(c->arguments, index); 132804Svbart@nginx.com if (value == NULL) { 133804Svbart@nginx.com break; 134804Svbart@nginx.com } 135804Svbart@nginx.com 136804Svbart@nginx.com nxt_conf_get_string(value, &str); 137804Svbart@nginx.com 138804Svbart@nginx.com size += str.length + 1; 139804Svbart@nginx.com argc++; 140804Svbart@nginx.com } 141804Svbart@nginx.com } 142804Svbart@nginx.com 143804Svbart@nginx.com argv = nxt_malloc(argc * sizeof(argv[0]) + size); 144804Svbart@nginx.com if (nxt_slow_path(argv == NULL)) { 145804Svbart@nginx.com nxt_alert(task, "failed to allocate arguments"); 146804Svbart@nginx.com return NXT_ERROR; 147804Svbart@nginx.com } 148804Svbart@nginx.com 149804Svbart@nginx.com argv[0] = c->executable; 150804Svbart@nginx.com i = 1; 151804Svbart@nginx.com 152804Svbart@nginx.com if (c->arguments != NULL) { 153804Svbart@nginx.com p = (u_char *) &argv[argc]; 154804Svbart@nginx.com 155804Svbart@nginx.com for (index = 0; /* void */ ; index++) { 156804Svbart@nginx.com value = nxt_conf_get_array_element(c->arguments, index); 157804Svbart@nginx.com if (value == NULL) { 158804Svbart@nginx.com break; 159804Svbart@nginx.com } 160804Svbart@nginx.com 161804Svbart@nginx.com argv[i++] = (char *) p; 162804Svbart@nginx.com 163804Svbart@nginx.com nxt_conf_get_string(value, &str); 164804Svbart@nginx.com 165804Svbart@nginx.com p = nxt_cpymem(p, str.start, str.length); 166804Svbart@nginx.com *p++ = '\0'; 167804Svbart@nginx.com } 168804Svbart@nginx.com } 169804Svbart@nginx.com 170804Svbart@nginx.com argv[i] = NULL; 171804Svbart@nginx.com 172804Svbart@nginx.com (void) execve(c->executable, argv, environ); 173804Svbart@nginx.com 174804Svbart@nginx.com nxt_alert(task, "execve(%s) failed %E", c->executable, nxt_errno); 175804Svbart@nginx.com 176804Svbart@nginx.com nxt_free(argv); 177804Svbart@nginx.com 178804Svbart@nginx.com return NXT_ERROR; 179804Svbart@nginx.com } 180