aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2006-06-03 20:09:02 +0000
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2006-06-03 20:09:02 +0000
commitb1312c912532196e6167aff957bf31cf34f8bf03 (patch)
treec0c7c7a18964bd8b4c0d82035c9b9132622e3fe9
parentc89982dcd78b3076cf131dae3ec4ca4b83f1b4da (diff)
downloadbusybox-w32-b1312c912532196e6167aff957bf31cf34f8bf03.tar.gz
busybox-w32-b1312c912532196e6167aff957bf31cf34f8bf03.tar.bz2
busybox-w32-b1312c912532196e6167aff957bf31cf34f8bf03.zip
- use bb_msg_write_error in 3 places
- whitespace
-rw-r--r--miscutils/time.c714
1 files changed, 346 insertions, 368 deletions
diff --git a/miscutils/time.c b/miscutils/time.c
index 9d0d6c05f..e0bdfe13c 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -1,25 +1,13 @@
1/* vi: set sw=4 ts=4: */
1/* `time' utility to display resource usage of processes. 2/* `time' utility to display resource usage of processes.
2 Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc. 3 Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc.
3 4
4 This program is free software; you can redistribute it and/or modify 5 Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
5 it under the terms of the GNU General Public License as published by 6*/
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 02111-1307, USA. */
18
19/* Originally written by David Keppel <pardo@cs.washington.edu>. 7/* Originally written by David Keppel <pardo@cs.washington.edu>.
20 Heavily modified by David MacKenzie <djm@gnu.ai.mit.edu>. 8 Heavily modified by David MacKenzie <djm@gnu.ai.mit.edu>.
21 Heavily modified for busybox by Erik Andersen <andersen@codepoet.org> 9 Heavily modified for busybox by Erik Andersen <andersen@codepoet.org>
22 */ 10*/
23 11
24#include "busybox.h" 12#include "busybox.h"
25#include <stdlib.h> 13#include <stdlib.h>
@@ -30,19 +18,18 @@
30#include <string.h> 18#include <string.h>
31#include <limits.h> 19#include <limits.h>
32#include <unistd.h> 20#include <unistd.h>
33#include <sys/types.h> /* For pid_t. */ 21#include <sys/types.h> /* For pid_t. */
34#include <sys/wait.h> 22#include <sys/wait.h>
35#include <sys/param.h> /* For getpagesize, maybe. */ 23#include <sys/param.h> /* For getpagesize, maybe. */
36 24
37#define TV_MSEC tv_usec / 1000 25#define TV_MSEC tv_usec / 1000
38#include <sys/resource.h> 26#include <sys/resource.h>
39 27
40/* Information on the resources used by a child process. */ 28/* Information on the resources used by a child process. */
41typedef struct 29typedef struct {
42{ 30 int waitstatus;
43 int waitstatus; 31 struct rusage ru;
44 struct rusage ru; 32 struct timeval start, elapsed; /* Wallclock time of process. */
45 struct timeval start, elapsed; /* Wallclock time of process. */
46} resource_t; 33} resource_t;
47 34
48/* msec = milliseconds = 1/1,000 (1*10e-3) second. 35/* msec = milliseconds = 1/1,000 (1*10e-3) second.
@@ -69,78 +56,74 @@ static const char *const posix_format = "real %e\nuser %U\nsys %S";
69/* Format string for printing all statistics verbosely. 56/* Format string for printing all statistics verbosely.
70 Keep this output to 24 lines so users on terminals can see it all.*/ 57 Keep this output to 24 lines so users on terminals can see it all.*/
71static const char *const long_format = 58static const char *const long_format =
72 "\tCommand being timed: \"%C\"\n" 59 "\tCommand being timed: \"%C\"\n"
73 "\tUser time (seconds): %U\n" 60 "\tUser time (seconds): %U\n"
74 "\tSystem time (seconds): %S\n" 61 "\tSystem time (seconds): %S\n"
75 "\tPercent of CPU this job got: %P\n" 62 "\tPercent of CPU this job got: %P\n"
76 "\tElapsed (wall clock) time (h:mm:ss or m:ss): %E\n" 63 "\tElapsed (wall clock) time (h:mm:ss or m:ss): %E\n"
77 "\tAverage shared text size (kbytes): %X\n" 64 "\tAverage shared text size (kbytes): %X\n"
78 "\tAverage unshared data size (kbytes): %D\n" 65 "\tAverage unshared data size (kbytes): %D\n"
79 "\tAverage stack size (kbytes): %p\n" 66 "\tAverage stack size (kbytes): %p\n"
80 "\tAverage total size (kbytes): %K\n" 67 "\tAverage total size (kbytes): %K\n"
81 "\tMaximum resident set size (kbytes): %M\n" 68 "\tMaximum resident set size (kbytes): %M\n"
82 "\tAverage resident set size (kbytes): %t\n" 69 "\tAverage resident set size (kbytes): %t\n"
83 "\tMajor (requiring I/O) page faults: %F\n" 70 "\tMajor (requiring I/O) page faults: %F\n"
84 "\tMinor (reclaiming a frame) page faults: %R\n" 71 "\tMinor (reclaiming a frame) page faults: %R\n"
85 "\tVoluntary context switches: %w\n" 72 "\tVoluntary context switches: %w\n"
86 "\tInvoluntary context switches: %c\n" 73 "\tInvoluntary context switches: %c\n"
87 "\tSwaps: %W\n" 74 "\tSwaps: %W\n"
88 "\tFile system inputs: %I\n" 75 "\tFile system inputs: %I\n"
89 "\tFile system outputs: %O\n" 76 "\tFile system outputs: %O\n"
90 "\tSocket messages sent: %s\n" 77 "\tSocket messages sent: %s\n"
91 "\tSocket messages received: %r\n" 78 "\tSocket messages received: %r\n"
92 "\tSignals delivered: %k\n" 79 "\tSignals delivered: %k\n"
93 "\tPage size (bytes): %Z\n" 80 "\tPage size (bytes): %Z\n" "\tExit status: %x";
94 "\tExit status: %x";
95 81
96 82
97 /* Wait for and fill in data on child process PID. 83 /* Wait for and fill in data on child process PID.
98 Return 0 on error, 1 if ok. */ 84 Return 0 on error, 1 if ok. */
99 85
100/* pid_t is short on BSDI, so don't try to promote it. */ 86/* pid_t is short on BSDI, so don't try to promote it. */
101static int resuse_end (pid_t pid, resource_t *resp) 87static int resuse_end(pid_t pid, resource_t * resp)
102{ 88{
103 int status; 89 int status;
104 90
105 pid_t caught; 91 pid_t caught;
106 92
107 /* Ignore signals, but don't ignore the children. When wait3 93 /* Ignore signals, but don't ignore the children. When wait3
108 returns the child process, set the time the command finished. */ 94 returns the child process, set the time the command finished. */
109 while ((caught = wait3 (&status, 0, &resp->ru)) != pid) 95 while ((caught = wait3(&status, 0, &resp->ru)) != pid) {
110 { 96 if (caught == -1)
111 if (caught == -1) 97 return 0;
112 return 0; 98 }
113 } 99
114 100 gettimeofday(&resp->elapsed, (struct timezone *) 0);
115 gettimeofday (&resp->elapsed, (struct timezone *) 0); 101 resp->elapsed.tv_sec -= resp->start.tv_sec;
116 resp->elapsed.tv_sec -= resp->start.tv_sec; 102 if (resp->elapsed.tv_usec < resp->start.tv_usec) {
117 if (resp->elapsed.tv_usec < resp->start.tv_usec) 103 /* Manually carry a one from the seconds field. */
118 { 104 resp->elapsed.tv_usec += 1000000;
119 /* Manually carry a one from the seconds field. */ 105 --resp->elapsed.tv_sec;
120 resp->elapsed.tv_usec += 1000000; 106 }
121 --resp->elapsed.tv_sec; 107 resp->elapsed.tv_usec -= resp->start.tv_usec;
122 } 108
123 resp->elapsed.tv_usec -= resp->start.tv_usec; 109 resp->waitstatus = status;
124 110
125 resp->waitstatus = status; 111 return 1;
126
127 return 1;
128} 112}
129 113
130/* Print ARGV to FP, with each entry in ARGV separated by FILLER. */ 114/* Print ARGV to FP, with each entry in ARGV separated by FILLER. */
131static void fprintargv (FILE *fp, char *const *argv, const char *filler) 115static void fprintargv(FILE * fp, char *const *argv, const char *filler)
132{ 116{
133 char *const *av; 117 char *const *av;
134 118
135 av = argv; 119 av = argv;
136 fputs (*av, fp); 120 fputs(*av, fp);
137 while (*++av) 121 while (*++av) {
138 { 122 fputs(filler, fp);
139 fputs (filler, fp); 123 fputs(*av, fp);
140 fputs (*av, fp); 124 }
141 } 125 if (ferror(fp))
142 if (ferror (fp)) 126 bb_error_msg_and_die(bb_msg_write_error);
143 bb_error_msg_and_die("write error");
144} 127}
145 128
146/* Return the number of kilobytes corresponding to a number of pages PAGES. 129/* Return the number of kilobytes corresponding to a number of pages PAGES.
@@ -151,28 +134,25 @@ static void fprintargv (FILE *fp, char *const *argv, const char *filler)
151 Note: Some machines express getrusage statistics in terms of K, 134 Note: Some machines express getrusage statistics in terms of K,
152 others in terms of pages. */ 135 others in terms of pages. */
153 136
154static unsigned long ptok (unsigned long pages) 137static unsigned long ptok(unsigned long pages)
155{ 138{
156 static unsigned long ps = 0; 139 static unsigned long ps = 0;
157 unsigned long tmp; 140 unsigned long tmp;
158 static long size = LONG_MAX; 141 static long size = LONG_MAX;
159 142
160 /* Initialization. */ 143 /* Initialization. */
161 if (ps == 0) 144 if (ps == 0)
162 ps = (long) getpagesize (); 145 ps = (long) getpagesize();
163 146
164 /* Conversion. */ 147 /* Conversion. */
165 if (pages > (LONG_MAX / ps)) 148 if (pages > (LONG_MAX / ps)) { /* Could overflow. */
166 { /* Could overflow. */ 149 tmp = pages / 1024; /* Smaller first, */
167 tmp = pages / 1024; /* Smaller first, */ 150 size = tmp * ps; /* then larger. */
168 size = tmp * ps; /* then larger. */ 151 } else { /* Could underflow. */
169 } 152 tmp = pages * ps; /* Larger first, */
170 else 153 size = tmp / 1024; /* then smaller. */
171 { /* Could underflow. */ 154 }
172 tmp = pages * ps; /* Larger first, */ 155 return size;
173 size = tmp / 1024; /* then smaller. */
174 }
175 return size;
176} 156}
177 157
178/* summarize: Report on the system use of a command. 158/* summarize: Report on the system use of a command.
@@ -220,282 +200,280 @@ static unsigned long ptok (unsigned long pages)
220 COMMAND is the command and args that are being summarized. 200 COMMAND is the command and args that are being summarized.
221 RESP is resource information on the command. */ 201 RESP is resource information on the command. */
222 202
223static void summarize (FILE *fp, const char *fmt, char **command, resource_t *resp) 203static void summarize(FILE * fp, const char *fmt, char **command,
204 resource_t * resp)
224{ 205{
225 unsigned long r; /* Elapsed real milliseconds. */ 206 unsigned long r; /* Elapsed real milliseconds. */
226 unsigned long v; /* Elapsed virtual (CPU) milliseconds. */ 207 unsigned long v; /* Elapsed virtual (CPU) milliseconds. */
227 208
228 if (WIFSTOPPED (resp->waitstatus)) 209 if (WIFSTOPPED(resp->waitstatus))
229 fprintf (fp, "Command stopped by signal %d\n", WSTOPSIG (resp->waitstatus)); 210 fprintf(fp, "Command stopped by signal %d\n",
230 else if (WIFSIGNALED (resp->waitstatus)) 211 WSTOPSIG(resp->waitstatus));
231 fprintf (fp, "Command terminated by signal %d\n", WTERMSIG (resp->waitstatus)); 212 else if (WIFSIGNALED(resp->waitstatus))
232 else if (WIFEXITED (resp->waitstatus) && WEXITSTATUS (resp->waitstatus)) 213 fprintf(fp, "Command terminated by signal %d\n",
233 fprintf (fp, "Command exited with non-zero status %d\n", WEXITSTATUS (resp->waitstatus)); 214 WTERMSIG(resp->waitstatus));
234 215 else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus))
235 /* Convert all times to milliseconds. Occasionally, one of these values 216 fprintf(fp, "Command exited with non-zero status %d\n",
236 comes out as zero. Dividing by zero causes problems, so we first 217 WEXITSTATUS(resp->waitstatus));
237 check the time value. If it is zero, then we take `evasive action' 218
238 instead of calculating a value. */ 219 /* Convert all times to milliseconds. Occasionally, one of these values
239 220 comes out as zero. Dividing by zero causes problems, so we first
240 r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000; 221 check the time value. If it is zero, then we take `evasive action'
241 222 instead of calculating a value. */
242 v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC + 223
243 resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC; 224 r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000;
244 225
245 while (*fmt) 226 v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC +
246 { 227 resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC;
247 switch (*fmt) 228
248 { 229 while (*fmt) {
249 case '%': 230 switch (*fmt) {
250 switch (*++fmt) 231 case '%':
251 { 232 switch (*++fmt) {
252 case '%': /* Literal '%'. */ 233 case '%': /* Literal '%'. */
253 putc ('%', fp); 234 putc('%', fp);
254 break; 235 break;
255 case 'C': /* The command that got timed. */ 236 case 'C': /* The command that got timed. */
256 fprintargv (fp, command, " "); 237 fprintargv(fp, command, " ");
257 break; 238 break;
258 case 'D': /* Average unshared data size. */ 239 case 'D': /* Average unshared data size. */
259 fprintf (fp, "%lu", 240 fprintf(fp, "%lu",
260 MSEC_TO_TICKS (v) == 0 ? 0 : 241 MSEC_TO_TICKS(v) == 0 ? 0 :
261 ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) + 242 ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) +
262 ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v)); 243 ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
263 break; 244 break;
264 case 'E': /* Elapsed real (wall clock) time. */ 245 case 'E': /* Elapsed real (wall clock) time. */
265 if (resp->elapsed.tv_sec >= 3600) /* One hour -> h:m:s. */ 246 if (resp->elapsed.tv_sec >= 3600) /* One hour -> h:m:s. */
266 fprintf (fp, "%ldh %ldm %02lds", 247 fprintf(fp, "%ldh %ldm %02lds",
267 resp->elapsed.tv_sec / 3600, 248 resp->elapsed.tv_sec / 3600,
268 (resp->elapsed.tv_sec % 3600) / 60, 249 (resp->elapsed.tv_sec % 3600) / 60,
269 resp->elapsed.tv_sec % 60); 250 resp->elapsed.tv_sec % 60);
270 else 251 else
271 fprintf (fp, "%ldm %ld.%02lds", /* -> m:s. */ 252 fprintf(fp, "%ldm %ld.%02lds", /* -> m:s. */
272 resp->elapsed.tv_sec / 60, 253 resp->elapsed.tv_sec / 60,
273 resp->elapsed.tv_sec % 60, 254 resp->elapsed.tv_sec % 60,
274 resp->elapsed.tv_usec / 10000); 255 resp->elapsed.tv_usec / 10000);
275 break; 256 break;
276 case 'F': /* Major page faults. */ 257 case 'F': /* Major page faults. */
277 fprintf (fp, "%ld", resp->ru.ru_majflt); 258 fprintf(fp, "%ld", resp->ru.ru_majflt);
278 break; 259 break;
279 case 'I': /* Inputs. */ 260 case 'I': /* Inputs. */
280 fprintf (fp, "%ld", resp->ru.ru_inblock); 261 fprintf(fp, "%ld", resp->ru.ru_inblock);
281 break; 262 break;
282 case 'K': /* Average mem usage == data+stack+text. */ 263 case 'K': /* Average mem usage == data+stack+text. */
283 fprintf (fp, "%lu", 264 fprintf(fp, "%lu",
284 MSEC_TO_TICKS (v) == 0 ? 0 : 265 MSEC_TO_TICKS(v) == 0 ? 0 :
285 ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) + 266 ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) +
286 ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v) + 267 ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v) +
287 ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v)); 268 ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
288 break; 269 break;
289 case 'M': /* Maximum resident set size. */ 270 case 'M': /* Maximum resident set size. */
290 fprintf (fp, "%lu", ptok ((UL) resp->ru.ru_maxrss)); 271 fprintf(fp, "%lu", ptok((UL) resp->ru.ru_maxrss));
291 break; 272 break;
292 case 'O': /* Outputs. */ 273 case 'O': /* Outputs. */
293 fprintf (fp, "%ld", resp->ru.ru_oublock); 274 fprintf(fp, "%ld", resp->ru.ru_oublock);
294 break; 275 break;
295 case 'P': /* Percent of CPU this job got. */ 276 case 'P': /* Percent of CPU this job got. */
296 /* % cpu is (total cpu time)/(elapsed time). */ 277 /* % cpu is (total cpu time)/(elapsed time). */
297 if (r > 0) 278 if (r > 0)
298 fprintf (fp, "%lu%%", (v * 100 / r)); 279 fprintf(fp, "%lu%%", (v * 100 / r));
299 else 280 else
300 fprintf (fp, "?%%"); 281 fprintf(fp, "?%%");
301 break; 282 break;
302 case 'R': /* Minor page faults (reclaims). */ 283 case 'R': /* Minor page faults (reclaims). */
303 fprintf (fp, "%ld", resp->ru.ru_minflt); 284 fprintf(fp, "%ld", resp->ru.ru_minflt);
304 break; 285 break;
305 case 'S': /* System time. */ 286 case 'S': /* System time. */
306 fprintf (fp, "%ld.%02ld", 287 fprintf(fp, "%ld.%02ld",
307 resp->ru.ru_stime.tv_sec, 288 resp->ru.ru_stime.tv_sec,
308 resp->ru.ru_stime.TV_MSEC / 10); 289 resp->ru.ru_stime.TV_MSEC / 10);
309 break; 290 break;
310 case 'T': /* System time. */ 291 case 'T': /* System time. */
311 if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */ 292 if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */
312 fprintf (fp, "%ldh %ldm %02lds", 293 fprintf(fp, "%ldh %ldm %02lds",
313 resp->ru.ru_stime.tv_sec / 3600, 294 resp->ru.ru_stime.tv_sec / 3600,
314 (resp->ru.ru_stime.tv_sec % 3600) / 60, 295 (resp->ru.ru_stime.tv_sec % 3600) / 60,
315 resp->ru.ru_stime.tv_sec % 60); 296 resp->ru.ru_stime.tv_sec % 60);
316 else 297 else
317 fprintf (fp, "%ldm %ld.%02lds", /* -> m:s. */ 298 fprintf(fp, "%ldm %ld.%02lds", /* -> m:s. */
318 resp->ru.ru_stime.tv_sec / 60, 299 resp->ru.ru_stime.tv_sec / 60,
319 resp->ru.ru_stime.tv_sec % 60, 300 resp->ru.ru_stime.tv_sec % 60,
320 resp->ru.ru_stime.tv_usec / 10000); 301 resp->ru.ru_stime.tv_usec / 10000);
321 break; 302 break;
322 case 'U': /* User time. */ 303 case 'U': /* User time. */
323 fprintf (fp, "%ld.%02ld", 304 fprintf(fp, "%ld.%02ld",
324 resp->ru.ru_utime.tv_sec, 305 resp->ru.ru_utime.tv_sec,
325 resp->ru.ru_utime.TV_MSEC / 10); 306 resp->ru.ru_utime.TV_MSEC / 10);
326 break; 307 break;
327 case 'u': /* User time. */ 308 case 'u': /* User time. */
328 if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */ 309 if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */
329 fprintf (fp, "%ldh %ldm %02lds", 310 fprintf(fp, "%ldh %ldm %02lds",
330 resp->ru.ru_utime.tv_sec / 3600, 311 resp->ru.ru_utime.tv_sec / 3600,
331 (resp->ru.ru_utime.tv_sec % 3600) / 60, 312 (resp->ru.ru_utime.tv_sec % 3600) / 60,
332 resp->ru.ru_utime.tv_sec % 60); 313 resp->ru.ru_utime.tv_sec % 60);
333 else 314 else
334 fprintf (fp, "%ldm %ld.%02lds", /* -> m:s. */ 315 fprintf(fp, "%ldm %ld.%02lds", /* -> m:s. */
335 resp->ru.ru_utime.tv_sec / 60, 316 resp->ru.ru_utime.tv_sec / 60,
336 resp->ru.ru_utime.tv_sec % 60, 317 resp->ru.ru_utime.tv_sec % 60,
337 resp->ru.ru_utime.tv_usec / 10000); 318 resp->ru.ru_utime.tv_usec / 10000);
319 break;
320 case 'W': /* Times swapped out. */
321 fprintf(fp, "%ld", resp->ru.ru_nswap);
322 break;
323 case 'X': /* Average shared text size. */
324 fprintf(fp, "%lu",
325 MSEC_TO_TICKS(v) == 0 ? 0 :
326 ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
327 break;
328 case 'Z': /* Page size. */
329 fprintf(fp, "%d", getpagesize());
330 break;
331 case 'c': /* Involuntary context switches. */
332 fprintf(fp, "%ld", resp->ru.ru_nivcsw);
333 break;
334 case 'e': /* Elapsed real time in seconds. */
335 fprintf(fp, "%ld.%02ld",
336 resp->elapsed.tv_sec, resp->elapsed.tv_usec / 10000);
337 break;
338 case 'k': /* Signals delivered. */
339 fprintf(fp, "%ld", resp->ru.ru_nsignals);
340 break;
341 case 'p': /* Average stack segment. */
342 fprintf(fp, "%lu",
343 MSEC_TO_TICKS(v) == 0 ? 0 :
344 ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
345 break;
346 case 'r': /* Incoming socket messages received. */
347 fprintf(fp, "%ld", resp->ru.ru_msgrcv);
348 break;
349 case 's': /* Outgoing socket messages sent. */
350 fprintf(fp, "%ld", resp->ru.ru_msgsnd);
351 break;
352 case 't': /* Average resident set size. */
353 fprintf(fp, "%lu",
354 MSEC_TO_TICKS(v) == 0 ? 0 :
355 ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v));
356 break;
357 case 'w': /* Voluntary context switches. */
358 fprintf(fp, "%ld", resp->ru.ru_nvcsw);
359 break;
360 case 'x': /* Exit status. */
361 fprintf(fp, "%d", WEXITSTATUS(resp->waitstatus));
362 break;
363 case '\0':
364 putc('?', fp);
365 return;
366 default:
367 putc('?', fp);
368 putc(*fmt, fp);
369 }
370 ++fmt;
338 break; 371 break;
339 case 'W': /* Times swapped out. */ 372
340 fprintf (fp, "%ld", resp->ru.ru_nswap); 373 case '\\': /* Format escape. */
341 break; 374 switch (*++fmt) {
342 case 'X': /* Average shared text size. */ 375 case 't':
343 fprintf (fp, "%lu", 376 putc('\t', fp);
344 MSEC_TO_TICKS (v) == 0 ? 0 : 377 break;
345 ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v)); 378 case 'n':
346 break; 379 putc('\n', fp);
347 case 'Z': /* Page size. */ 380 break;
348 fprintf (fp, "%d", getpagesize ()); 381 case '\\':
349 break; 382 putc('\\', fp);
350 case 'c': /* Involuntary context switches. */ 383 break;
351 fprintf (fp, "%ld", resp->ru.ru_nivcsw); 384 default:
352 break; 385 putc('?', fp);
353 case 'e': /* Elapsed real time in seconds. */ 386 putc('\\', fp);
354 fprintf (fp, "%ld.%02ld", 387 putc(*fmt, fp);
355 resp->elapsed.tv_sec, 388 }
356 resp->elapsed.tv_usec / 10000); 389 ++fmt;
357 break;
358 case 'k': /* Signals delivered. */
359 fprintf (fp, "%ld", resp->ru.ru_nsignals);
360 break;
361 case 'p': /* Average stack segment. */
362 fprintf (fp, "%lu",
363 MSEC_TO_TICKS (v) == 0 ? 0 :
364 ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v));
365 break;
366 case 'r': /* Incoming socket messages received. */
367 fprintf (fp, "%ld", resp->ru.ru_msgrcv);
368 break;
369 case 's': /* Outgoing socket messages sent. */
370 fprintf (fp, "%ld", resp->ru.ru_msgsnd);
371 break;
372 case 't': /* Average resident set size. */
373 fprintf (fp, "%lu",
374 MSEC_TO_TICKS (v) == 0 ? 0 :
375 ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v));
376 break;
377 case 'w': /* Voluntary context switches. */
378 fprintf (fp, "%ld", resp->ru.ru_nvcsw);
379 break;
380 case 'x': /* Exit status. */
381 fprintf (fp, "%d", WEXITSTATUS (resp->waitstatus));
382 break;
383 case '\0':
384 putc ('?', fp);
385 return;
386 default:
387 putc ('?', fp);
388 putc (*fmt, fp);
389 }
390 ++fmt;
391 break;
392
393 case '\\': /* Format escape. */
394 switch (*++fmt)
395 {
396 case 't':
397 putc ('\t', fp);
398 break;
399 case 'n':
400 putc ('\n', fp);
401 break;
402 case '\\':
403 putc ('\\', fp);
404 break; 390 break;
405 default: 391
406 putc ('?', fp); 392 default:
407 putc ('\\', fp); 393 putc(*fmt++, fp);
408 putc (*fmt, fp);
409 } 394 }
410 ++fmt;
411 break;
412 395
413 default: 396 if (ferror(fp))
414 putc (*fmt++, fp); 397 bb_error_msg_and_die(bb_msg_write_error);
415 } 398 }
399 putc('\n', fp);
416 400
417 if (ferror (fp)) 401 if (ferror(fp))
418 bb_error_msg_and_die("write error"); 402 bb_error_msg_and_die(bb_msg_write_error);
419 }
420 putc ('\n', fp);
421
422 if (ferror (fp))
423 bb_error_msg_and_die("write error");
424} 403}
425 404
426/* Run command CMD and return statistics on it. 405/* Run command CMD and return statistics on it.
427 Put the statistics in *RESP. */ 406 Put the statistics in *RESP. */
428static void run_command (char *const *cmd, resource_t *resp) 407static void run_command(char *const *cmd, resource_t * resp)
429{ 408{
430 pid_t pid; /* Pid of child. */ 409 pid_t pid; /* Pid of child. */
431 __sighandler_t interrupt_signal, quit_signal; 410 __sighandler_t interrupt_signal, quit_signal;
432 411
433 gettimeofday (&resp->start, (struct timezone *) 0); 412 gettimeofday(&resp->start, (struct timezone *) 0);
434 pid = fork (); /* Run CMD as child process. */ 413 pid = fork(); /* Run CMD as child process. */
435 if (pid < 0) 414 if (pid < 0)
436 bb_error_msg_and_die("cannot fork"); 415 bb_error_msg_and_die("cannot fork");
437 else if (pid == 0) 416 else if (pid == 0) { /* If child. */
438 { /* If child. */ 417 /* Don't cast execvp arguments; that causes errors on some systems,
439 /* Don't cast execvp arguments; that causes errors on some systems, 418 versus merely warnings if the cast is left off. */
440 versus merely warnings if the cast is left off. */ 419 execvp(cmd[0], cmd);
441 execvp (cmd[0], cmd); 420 bb_error_msg("cannot run %s", cmd[0]);
442 bb_error_msg("cannot run %s", cmd[0]); 421 _exit(errno == ENOENT ? 127 : 126);
443 _exit (errno == ENOENT ? 127 : 126); 422 }
444 } 423
445 424 /* Have signals kill the child but not self (if possible). */
446 /* Have signals kill the child but not self (if possible). */ 425 interrupt_signal = signal(SIGINT, SIG_IGN);
447 interrupt_signal = signal (SIGINT, SIG_IGN); 426 quit_signal = signal(SIGQUIT, SIG_IGN);
448 quit_signal = signal (SIGQUIT, SIG_IGN); 427
449 428 if (resuse_end(pid, resp) == 0)
450 if (resuse_end (pid, resp) == 0) 429 bb_error_msg("error waiting for child process");
451 bb_error_msg("error waiting for child process"); 430
452 431 /* Re-enable signals. */
453 /* Re-enable signals. */ 432 signal(SIGINT, interrupt_signal);
454 signal (SIGINT, interrupt_signal); 433 signal(SIGQUIT, quit_signal);
455 signal (SIGQUIT, quit_signal);
456} 434}
457 435
458int time_main (int argc, char **argv) 436int time_main(int argc, char **argv)
459{ 437{
460 int gotone; 438 int gotone;
461 resource_t res; 439 resource_t res;
462 const char *output_format = default_format; 440 const char *output_format = default_format;
463 441
464 argc--; 442 argc--;
465 argv++; 443 argv++;
466 /* Parse any options -- don't use getopt() here so we don't 444 /* Parse any options -- don't use getopt() here so we don't
467 * consume the args of our client application... */ 445 * consume the args of our client application... */
468 while (argc > 0 && **argv == '-') { 446 while (argc > 0 && **argv == '-') {
469 gotone = 0; 447 gotone = 0;
470 while (gotone==0 && *++(*argv)) { 448 while (gotone == 0 && *++(*argv)) {
471 switch (**argv) { 449 switch (**argv) {
472 case 'v': 450 case 'v':
473 output_format = long_format; 451 output_format = long_format;
474 break; 452 break;
475 case 'p': 453 case 'p':
476 output_format = posix_format; 454 output_format = posix_format;
477 break; 455 break;
478 default: 456 default:
479 bb_show_usage(); 457 bb_show_usage();
480 } 458 }
481 argc--; 459 argc--;
482 argv++; 460 argv++;
483 gotone = 1; 461 gotone = 1;
462 }
484 } 463 }
485 } 464
486 465 if (argv == NULL || *argv == NULL)
487 if (argv == NULL || *argv == NULL) 466 bb_show_usage();
488 bb_show_usage(); 467
489 468 run_command(argv, &res);
490 run_command (argv, &res); 469 summarize(stderr, output_format, argv, &res);
491 summarize (stderr, output_format, argv, &res); 470 fflush(stderr);
492 fflush (stderr); 471
493 472 if (WIFSTOPPED(res.waitstatus))
494 if (WIFSTOPPED (res.waitstatus)) 473 exit(WSTOPSIG(res.waitstatus));
495 exit (WSTOPSIG (res.waitstatus)); 474 else if (WIFSIGNALED(res.waitstatus))
496 else if (WIFSIGNALED (res.waitstatus)) 475 exit(WTERMSIG(res.waitstatus));
497 exit (WTERMSIG (res.waitstatus)); 476 else if (WIFEXITED(res.waitstatus))
498 else if (WIFEXITED (res.waitstatus)) 477 exit(WEXITSTATUS(res.waitstatus));
499 exit (WEXITSTATUS (res.waitstatus)); 478 return 0;
500 return 0;
501} 479}