| | 77 | |
|---|
| | 78 | /* check if some backend is listening on the socket |
|---|
| | 79 | * as if we delete the socket-file and rebind there will be no "socket already in use" error |
|---|
| | 80 | */ |
|---|
| | 81 | if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { |
|---|
| | 82 | fprintf(stderr, "%s.%d\n", |
|---|
| | 83 | __FILE__, __LINE__); |
|---|
| | 84 | return -1; |
|---|
| | 85 | } |
|---|
| | 86 | |
|---|
| | 87 | if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) { |
|---|
| | 88 | fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", |
|---|
| | 89 | __FILE__, __LINE__); |
|---|
| | 90 | return -1; |
|---|
| | 91 | } |
|---|
| | 92 | |
|---|
| | 93 | /* cleanup previous socket if it exists */ |
|---|
| | 94 | unlink(unixsocket); |
|---|
| | 95 | close(fcgi_fd); |
|---|
| 94 | | if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { |
|---|
| 95 | | /* server is not up, spawn in */ |
|---|
| 96 | | pid_t child; |
|---|
| 97 | | int val; |
|---|
| 98 | | |
|---|
| 99 | | if (unixsocket) unlink(unixsocket); |
|---|
| 100 | | |
|---|
| 101 | | close(fcgi_fd); |
|---|
| 102 | | |
|---|
| 103 | | /* reopen socket */ |
|---|
| 104 | | if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { |
|---|
| 105 | | fprintf(stderr, "%s.%d\n", |
|---|
| 106 | | __FILE__, __LINE__); |
|---|
| 107 | | return -1; |
|---|
| 108 | | } |
|---|
| 109 | | |
|---|
| 110 | | val = 1; |
|---|
| 111 | | if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { |
|---|
| 112 | | fprintf(stderr, "%s.%d\n", |
|---|
| 113 | | __FILE__, __LINE__); |
|---|
| 114 | | return -1; |
|---|
| 115 | | } |
|---|
| 116 | | |
|---|
| 117 | | /* create socket */ |
|---|
| 118 | | if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { |
|---|
| 119 | | fprintf(stderr, "%s.%d: bind failed: %s\n", |
|---|
| | 117 | val = 1; |
|---|
| | 118 | if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { |
|---|
| | 119 | fprintf(stderr, "%s.%d\n", |
|---|
| | 120 | __FILE__, __LINE__); |
|---|
| | 121 | return -1; |
|---|
| | 122 | } |
|---|
| | 123 | |
|---|
| | 124 | /* create socket */ |
|---|
| | 125 | if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { |
|---|
| | 126 | fprintf(stderr, "%s.%d: bind failed: %s\n", |
|---|
| | 127 | __FILE__, __LINE__, |
|---|
| | 128 | strerror(errno)); |
|---|
| | 129 | return -1; |
|---|
| | 130 | } |
|---|
| | 131 | |
|---|
| | 132 | if (-1 == listen(fcgi_fd, 1024)) { |
|---|
| | 133 | fprintf(stderr, "%s.%d: fd = -1\n", |
|---|
| | 134 | __FILE__, __LINE__); |
|---|
| | 135 | return -1; |
|---|
| | 136 | } |
|---|
| | 137 | |
|---|
| | 138 | if (!nofork) { |
|---|
| | 139 | child = fork(); |
|---|
| | 140 | } else { |
|---|
| | 141 | child = 0; |
|---|
| | 142 | } |
|---|
| | 143 | |
|---|
| | 144 | switch (child) { |
|---|
| | 145 | case 0: { |
|---|
| | 146 | char cgi_childs[64]; |
|---|
| | 147 | |
|---|
| | 148 | int i = 0; |
|---|
| | 149 | |
|---|
| | 150 | /* is safe as we limit to 256 childs */ |
|---|
| | 151 | sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); |
|---|
| | 152 | |
|---|
| | 153 | if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { |
|---|
| | 154 | close(FCGI_LISTENSOCK_FILENO); |
|---|
| | 155 | dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); |
|---|
| | 156 | close(fcgi_fd); |
|---|
| | 157 | } |
|---|
| | 158 | |
|---|
| | 159 | /* we don't need the client socket */ |
|---|
| | 160 | for (i = 3; i < 256; i++) { |
|---|
| | 161 | close(i); |
|---|
| | 162 | } |
|---|
| | 163 | |
|---|
| | 164 | /* create environment */ |
|---|
| | 165 | |
|---|
| | 166 | putenv(cgi_childs); |
|---|
| | 167 | |
|---|
| | 168 | /* fork and replace shell */ |
|---|
| | 169 | if (appArgv) { |
|---|
| | 170 | execv(appArgv[0], appArgv); |
|---|
| | 171 | |
|---|
| | 172 | } else { |
|---|
| | 173 | char *b = malloc(strlen("exec ") + strlen(appPath) + 1); |
|---|
| | 174 | strcpy(b, "exec "); |
|---|
| | 175 | strcat(b, appPath); |
|---|
| | 176 | |
|---|
| | 177 | /* exec the cgi */ |
|---|
| | 178 | execl("/bin/sh", "sh", "-c", b, (char *)NULL); |
|---|
| | 179 | } |
|---|
| | 180 | |
|---|
| | 181 | exit(errno); |
|---|
| | 182 | |
|---|
| | 183 | break; |
|---|
| | 184 | } |
|---|
| | 185 | case -1: |
|---|
| | 186 | /* error */ |
|---|
| | 187 | break; |
|---|
| | 188 | default: |
|---|
| | 189 | /* father */ |
|---|
| | 190 | |
|---|
| | 191 | /* wait */ |
|---|
| | 192 | select(0, NULL, NULL, NULL, &tv); |
|---|
| | 193 | |
|---|
| | 194 | switch (waitpid(child, &status, WNOHANG)) { |
|---|
| | 195 | case 0: |
|---|
| | 196 | fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", |
|---|
| 121 | | strerror(errno)); |
|---|
| 122 | | return -1; |
|---|
| 123 | | } |
|---|
| 124 | | |
|---|
| 125 | | if (-1 == listen(fcgi_fd, 1024)) { |
|---|
| 126 | | fprintf(stderr, "%s.%d: fd = -1\n", |
|---|
| 127 | | __FILE__, __LINE__); |
|---|
| 128 | | return -1; |
|---|
| 129 | | } |
|---|
| 130 | | |
|---|
| 131 | | if (!nofork) { |
|---|
| 132 | | child = fork(); |
|---|
| 133 | | } else { |
|---|
| 134 | | child = 0; |
|---|
| 135 | | } |
|---|
| 136 | | |
|---|
| 137 | | switch (child) { |
|---|
| 138 | | case 0: { |
|---|
| 139 | | char cgi_childs[64]; |
|---|
| 140 | | |
|---|
| 141 | | int i = 0; |
|---|
| 142 | | |
|---|
| 143 | | /* is safe as we limit to 256 childs */ |
|---|
| 144 | | sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); |
|---|
| 145 | | |
|---|
| 146 | | if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { |
|---|
| 147 | | close(FCGI_LISTENSOCK_FILENO); |
|---|
| 148 | | dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); |
|---|
| 149 | | close(fcgi_fd); |
|---|
| 150 | | } |
|---|
| 151 | | |
|---|
| 152 | | /* we don't need the client socket */ |
|---|
| 153 | | for (i = 3; i < 256; i++) { |
|---|
| 154 | | close(i); |
|---|
| 155 | | } |
|---|
| 156 | | |
|---|
| 157 | | /* create environment */ |
|---|
| 158 | | |
|---|
| 159 | | putenv(cgi_childs); |
|---|
| 160 | | |
|---|
| 161 | | /* fork and replace shell */ |
|---|
| 162 | | if (appArgv) { |
|---|
| 163 | | execv(appArgv[0], appArgv); |
|---|
| 164 | | |
|---|
| 165 | | } else { |
|---|
| 166 | | char *b = malloc(strlen("exec ") + strlen(appPath) + 1); |
|---|
| 167 | | strcpy(b, "exec "); |
|---|
| 168 | | strcat(b, appPath); |
|---|
| 169 | | |
|---|
| 170 | | /* exec the cgi */ |
|---|
| 171 | | execl("/bin/sh", "sh", "-c", b, (char *)NULL); |
|---|
| 172 | | } |
|---|
| 173 | | |
|---|
| 174 | | exit(errno); |
|---|
| | 198 | child); |
|---|
| | 199 | |
|---|
| | 200 | /* write pid file */ |
|---|
| | 201 | if (pid_fd != -1) { |
|---|
| | 202 | /* assume a 32bit pid_t */ |
|---|
| | 203 | char pidbuf[12]; |
|---|
| | 204 | |
|---|
| | 205 | snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); |
|---|
| | 206 | |
|---|
| | 207 | write(pid_fd, pidbuf, strlen(pidbuf)); |
|---|
| | 208 | close(pid_fd); |
|---|
| | 209 | pid_fd = -1; |
|---|
| | 210 | } |
|---|
| 182 | | /* father */ |
|---|
| 183 | | |
|---|
| 184 | | /* wait */ |
|---|
| 185 | | select(0, NULL, NULL, NULL, &tv); |
|---|
| 186 | | |
|---|
| 187 | | switch (waitpid(child, &status, WNOHANG)) { |
|---|
| 188 | | case 0: |
|---|
| 189 | | fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", |
|---|
| 190 | | __FILE__, __LINE__, |
|---|
| 191 | | child); |
|---|
| 192 | | |
|---|
| 193 | | /* write pid file */ |
|---|
| 194 | | if (pid_fd != -1) { |
|---|
| 195 | | /* assume a 32bit pid_t */ |
|---|
| 196 | | char pidbuf[12]; |
|---|
| 197 | | |
|---|
| 198 | | snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); |
|---|
| 199 | | |
|---|
| 200 | | write(pid_fd, pidbuf, strlen(pidbuf)); |
|---|
| 201 | | close(pid_fd); |
|---|
| 202 | | pid_fd = -1; |
|---|
| 203 | | } |
|---|
| 204 | | |
|---|
| 205 | | break; |
|---|
| 206 | | case -1: |
|---|
| 207 | | break; |
|---|
| 208 | | default: |
|---|
| 209 | | if (WIFEXITED(status)) { |
|---|
| 210 | | fprintf(stderr, "%s.%d: child exited with: %d, %s\n", |
|---|
| 211 | | __FILE__, __LINE__, |
|---|
| 212 | | WEXITSTATUS(status), strerror(WEXITSTATUS(status))); |
|---|
| 213 | | } else if (WIFSIGNALED(status)) { |
|---|
| 214 | | fprintf(stderr, "%s.%d: child signaled: %d\n", |
|---|
| 215 | | __FILE__, __LINE__, |
|---|
| 216 | | WTERMSIG(status)); |
|---|
| 217 | | } else { |
|---|
| 218 | | fprintf(stderr, "%s.%d: child died somehow: %d\n", |
|---|
| 219 | | __FILE__, __LINE__, |
|---|
| 220 | | status); |
|---|
| 221 | | } |
|---|
| 222 | | } |
|---|
| 223 | | |
|---|
| 224 | | break; |
|---|
| 225 | | } |
|---|
| 226 | | } else { |
|---|
| 227 | | fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", |
|---|
| 228 | | __FILE__, __LINE__); |
|---|
| 229 | | return -1; |
|---|
| | 216 | if (WIFEXITED(status)) { |
|---|
| | 217 | fprintf(stderr, "%s.%d: child exited with: %d, %s\n", |
|---|
| | 218 | __FILE__, __LINE__, |
|---|
| | 219 | WEXITSTATUS(status), strerror(WEXITSTATUS(status))); |
|---|
| | 220 | } else if (WIFSIGNALED(status)) { |
|---|
| | 221 | fprintf(stderr, "%s.%d: child signaled: %d\n", |
|---|
| | 222 | __FILE__, __LINE__, |
|---|
| | 223 | WTERMSIG(status)); |
|---|
| | 224 | } else { |
|---|
| | 225 | fprintf(stderr, "%s.%d: child died somehow: %d\n", |
|---|
| | 226 | __FILE__, __LINE__, |
|---|
| | 227 | status); |
|---|
| | 228 | } |
|---|
| | 229 | } |
|---|
| | 230 | |
|---|
| | 231 | break; |
|---|