1 /*
2 * Copyright 1996 - 2005 Michiel Boland.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or
6 * without modification, are permitted provided that the following
7 * conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 *
18 * 3. The name of the author may not be used to endorse or promote
19 * products derived from this software without specific prior
20 * written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /* As */
37
38 static const char rcsid[] = "$Id: dump.c,v 1.60.2.2 2005/03/22 18:46:16 boland Exp $";
39
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <sys/stat.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include "mathopd.h"
53
dump_connections(FILE * f)54 static void dump_connections(FILE *f)
55 {
56 int i, n_reading, n_writing, n_waiting, n_forked;
57 size_t n;
58 struct connection *cn;
59
60 n_reading = 0;
61 n_writing = 0;
62 n_waiting = 0;
63 n_forked = 0;
64 i = -1;
65 fprintf(f, "Connections:\n");
66 for (n = 0; n < tuning.num_connections; n++) {
67 cn = connection_array + n;
68 if (++i == 50) {
69 putc('\n', f);
70 i = 0;
71 }
72 switch (cn->connection_state) {
73 case HC_FREE:
74 putc('.', f);
75 break;
76 case HC_READING:
77 putc('r', f);
78 ++n_reading;
79 break;
80 case HC_WRITING:
81 putc('W', f);
82 ++n_writing;
83 break;
84 case HC_WAITING:
85 putc('-', f);
86 ++n_waiting;
87 break;
88 case HC_FORKED:
89 putc('F', f);
90 ++n_forked;
91 break;
92 default:
93 putc('?', f);
94 break;
95 }
96 cn = cn->next;
97 }
98 fprintf(f, "\nReading: %d, Writing: %d, Waiting: %d, Forked: %d\n", n_reading, n_writing, n_waiting, n_forked);
99 }
100
tvadd(struct timeval * t1,struct timeval * t2,struct timeval * r)101 static void tvadd(struct timeval *t1, struct timeval *t2, struct timeval *r)
102 {
103 long u;
104
105 r->tv_sec = t1->tv_sec + t2->tv_sec;
106 u = t1->tv_usec + t2->tv_usec;
107 if (u >= 1000000) {
108 u -= 1000000;
109 ++r->tv_sec;
110 }
111 r->tv_usec = u;
112 }
113
fdump(FILE * f)114 static void fdump(FILE *f)
115 {
116 struct rusage ru;
117 struct timeval t;
118
119 fprintf(f, "Uptime: %d seconds\n", (int) (current_time - startuptime));
120 fprintf(f, "Active connections: %d out of %lu\n", stats.nconnections, tuning.num_connections);
121 fprintf(f, "Max simultaneous connections since last dump: %d\n", stats.maxconnections);
122 fprintf(f, "Forked child processes: %lu\n", stats.forked_children);
123 fprintf(f, "Exited child processes: %lu\n", stats.exited_children);
124 fprintf(f, "Requests executed: %lu\n", stats.nrequests);
125 fprintf(f, "Accepted connections: %lu\n", stats.accepted_connections);
126 fprintf(f, "Pipelined requests: %lu\n", stats.pipelined_requests);
127 fprintf(f, "\n");
128 getrusage(RUSAGE_SELF, &ru);
129 tvadd(&ru.ru_utime, &ru.ru_stime, &t);
130 fprintf(f, "CPU time used by this process: %8ld.%02ld\n", t.tv_sec, t.tv_usec / 10000);
131 getrusage(RUSAGE_CHILDREN, &ru);
132 tvadd(&ru.ru_utime, &ru.ru_stime, &t);
133 fprintf(f, " children: %8ld.%02ld\n\n", t.tv_sec, t.tv_usec / 10000);
134 stats.maxconnections = stats.nconnections;
135 dump_connections(f);
136 fprintf(f, "*** End of dump\n");
137 }
138
process_dump(struct request * r)139 int process_dump(struct request *r)
140 {
141 FILE *f;
142 int fd, fd2;
143 char name[32];
144
145 if (r->method != M_GET && r->method != M_HEAD) {
146 r->status = 405;
147 return 0;
148 }
149 if (r->path_args[0]) {
150 r->error_file = r->c->error_404_file;
151 r->status = 404;
152 return 1;
153 }
154 strcpy(name, "/tmp/mathop-dump.XXXXXXXX");
155 fd = mkstemp(name);
156 if (fd == -1) {
157 r->status = 500;
158 return 0;
159 }
160 fcntl(fd, F_SETFD, FD_CLOEXEC);
161 if (remove(name) == -1) {
162 log_d("cannot remove temporary file %s", name);
163 lerror("remove");
164 close(fd);
165 r->status = 500;
166 return 0;
167 }
168 fd2 = dup(fd);
169 if (fd2 == -1) {
170 lerror("dup");
171 close(fd);
172 r->status = 500;
173 return 0;
174 }
175 fcntl(fd2, F_SETFD, FD_CLOEXEC);
176 f = fdopen(fd2, "a+");
177 if (f == 0) {
178 log_d("dump: failed to associate stream with descriptor %d", fd2);
179 close(fd2);
180 close(fd);
181 r->status = 500;
182 return 0;
183 }
184 fdump(f);
185 if (fclose(f) == EOF) {
186 lerror("fclose");
187 close(fd2);
188 close(fd);
189 r->status = 500;
190 return 0;
191 }
192 if (fstat(fd, &r->finfo) == -1) {
193 lerror("fstat");
194 close(fd);
195 r->status = 500;
196 return 0;
197 }
198 r->content_length = r->finfo.st_size;
199 r->last_modified = r->finfo.st_mtime;
200 if (r->method == M_GET) {
201 lseek(fd, 0, SEEK_SET);
202 r->cn->file_offset = 0;
203 r->cn->rfd = fd;
204 } else
205 close(fd);
206 r->content_type = "text/plain";
207 r->num_content = 0;
208 r->status = 200;
209 return 0;
210 }
211
internal_dump(void)212 void internal_dump(void)
213 {
214 FILE *f;
215 int fd;
216 char name[40];
217 struct timeval tv;
218
219 sprintf(name, "/tmp/mathopd-%d-dump.XXXXXXX", my_pid);
220 fd = mkstemp(name);
221 if (fd == -1) {
222 lerror("mkstemp");
223 return;
224 }
225 f = fdopen(fd, "a");
226 if (f == 0) {
227 lerror("fdopen");
228 close(fd);
229 return;
230 }
231 gettimeofday(&tv, 0);
232 fprintf(f, "*** Dump performed at %ld.%06ld\n", tv.tv_sec, tv.tv_usec);
233 fdump(f);
234 fclose(f);
235 }
236