]> granicus.if.org Git - apache/blob - support/fcgistarter.c
Create the pidfile world readable by adding APR_FPROT_WREAD. Use
[apache] / support / fcgistarter.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <apr.h>
18 #include <apr_pools.h>
19 #include <apr_network_io.h>
20 #include <apr_thread_proc.h>
21 #include <apr_getopt.h>
22 #include <apr_portable.h>
23
24 #if APR_HAVE_STDLIB_H
25 #include <stdlib.h> /* For EXIT_SUCCESS, EXIT_FAILURE */
26 #endif
27
28 #if APR_HAVE_UNISTD_H
29 #include <unistd.h> /* For execl */
30 #endif
31
32 static const char *usage_message =
33     "usage: fcgistarter -c <command> -p <port> [-i <interface> -N <num>]\n"
34     "\n"
35     "If an interface is not specified, any available will be used.\n";
36
37 static void usage(void)
38 {
39     fprintf(stderr, "%s", usage_message);
40
41     exit(EXIT_FAILURE);
42 }
43
44 static void exit_error(apr_status_t rv, const char *func)
45 {
46     char buffer[1024];
47
48     fprintf(stderr,
49             "%s: %s\n",
50             func,
51             apr_strerror(rv, buffer, sizeof(buffer)));
52
53     exit(EXIT_FAILURE);
54 }
55
56 int main(int argc, const char * const argv[])
57 {
58     apr_file_t *infd, *skwrapper;
59     apr_sockaddr_t *skaddr;
60     apr_getopt_t *gopt;
61     apr_socket_t *skt;
62     apr_pool_t *pool;
63     apr_status_t rv;
64     apr_proc_t proc;
65
66
67     /* Command line arguments */
68     int num_to_start = 1, port = 0;
69     const char *interface = NULL;
70     const char *command = NULL;
71
72     apr_app_initialize(&argc, &argv, NULL);
73
74     atexit(apr_terminate);
75
76     apr_pool_create(&pool, NULL);
77
78     rv = apr_getopt_init(&gopt, pool, argc, argv);
79     if (rv) {
80         return EXIT_FAILURE;
81     }
82
83     for (;;) {
84         const char *arg;
85         char opt;
86
87         rv = apr_getopt(gopt, "c:p:i:N:", &opt, &arg);
88         if (APR_STATUS_IS_EOF(rv)) {
89             break;
90         } else if (rv) {
91             usage();
92         } else {
93             switch (opt) {
94             case 'c':
95                 command = arg;
96                 break;
97
98             case 'p':
99                 port = atoi(arg);
100                 if (! port) {
101                     usage();
102                 }
103                 break;
104
105             case 'i':
106                 interface = arg;
107                 break;
108
109             case 'N':
110                 num_to_start = atoi(arg);
111                 if (! num_to_start) {
112                     usage();
113                 }
114                 break;
115
116             default:
117                 break;
118             }
119         }
120     }
121
122     if (! command || ! port) {
123         usage();
124     }
125
126     rv = apr_socket_create(&skt, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool);
127     if (rv) {
128         exit_error(rv, "apr_socket_create");
129     }
130
131     rv = apr_sockaddr_info_get(&skaddr, interface, APR_UNSPEC, port, 0, pool);
132     if (rv) {
133         exit_error(rv, "apr_sockaddr_info_get");
134     }
135
136     rv = apr_socket_bind(skt, skaddr);
137     if (rv) {
138         exit_error(rv, "apr_socket_bind");
139     }
140
141     rv = apr_socket_listen(skt, 1024);
142     if (rv) {
143         exit_error(rv, "apr_socket_listen");
144     }
145
146     rv = apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
147     if (rv) {
148         exit_error(rv, "apr_proc_detach");
149     }
150
151 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
152
153 #error "Please implement me."
154
155 #else
156
157     while (--num_to_start >= 0) {
158         rv = apr_proc_fork(&proc, pool);
159         if (rv == APR_INCHILD) {
160             apr_os_file_t oft = 0;
161             apr_os_sock_t oskt;
162
163             /* Ok, so we need a file that has file descriptor 0 (which
164              * FastCGI wants), but points to our socket.  This isn't really
165              * possible in APR, so we cheat a bit.  I have no idea how to
166              * do this on a non-unix platform, so for now this is platform
167              * specific.  Ick.
168              *
169              * Note that this has to happen post-detach, otherwise fd 0
170              * gets closed during apr_proc_detach and it's all for nothing.
171              *
172              * Unfortunately, doing this post detach means we have no way
173              * to let anyone know if there's a problem at this point :( */
174
175             rv = apr_os_file_put(&infd, &oft, APR_READ | APR_WRITE, pool);
176             if (rv) {
177                 exit(EXIT_FAILURE);
178             }
179
180             rv = apr_os_sock_get(&oskt, skt);
181             if (rv) {
182                 exit(EXIT_FAILURE);
183             }
184
185             rv = apr_os_file_put(&skwrapper, &oskt, APR_READ | APR_WRITE,
186                                  pool);
187             if (rv) {
188                 exit(EXIT_FAILURE);
189             }
190
191             rv = apr_file_dup2(infd, skwrapper, pool);
192             if (rv) {
193                 exit(EXIT_FAILURE);
194             }
195
196             /* XXX Can't use apr_proc_create because there's no way to get
197              *     infd into the procattr without going through another dup2,
198              *     which means by the time it gets to the fastcgi process it
199              *     is no longer fd 0, so it doesn't work.  Sigh. */
200
201             execl(command, command, NULL);
202
203         } else if (rv == APR_INPARENT) {
204             if (num_to_start == 0) {
205                 apr_socket_close(skt);
206             }
207         } else {
208             exit_error(rv, "apr_proc_fork");
209         }
210     }
211
212 #endif
213
214     return EXIT_SUCCESS;
215 }