comment all fields
[oweals/busybox.git] / miscutils / time.c
index 24a5b9aae0efec91a9f9032ee8655062a3880114..8c7419b587a5f9e9f3a9929bf736dd56247a0ccd 100644 (file)
@@ -1,26 +1,15 @@
+/* vi: set sw=4 ts=4: */
 /* `time' utility to display resource usage of processes.
    Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
-
+   Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+*/
 /* Originally written by David Keppel <pardo@cs.washington.edu>.
-   Heavily modified by David MacKenzie <djm@gnu.ai.mit.edu>.  
+   Heavily modified by David MacKenzie <djm@gnu.ai.mit.edu>.
    Heavily modified for busybox by Erik Andersen <andersen@codepoet.org>
-   */
+*/
 
+#include "busybox.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <signal.h>
 #include <string.h>
 #include <limits.h>
 #include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>         /* For pid_t. */
+#include <sys/types.h> /* For pid_t. */
 #include <sys/wait.h>
-#include <sys/param.h>         /* For getpagesize, maybe.  */
+#include <sys/param.h> /* For getpagesize, maybe.  */
 
 #define TV_MSEC tv_usec / 1000
 #include <sys/resource.h>
-#include "busybox.h"
 
 /* Information on the resources used by a child process.  */
-typedef struct
-{
-  int waitstatus;
-  struct rusage ru;
-  struct timeval start, elapsed; /* Wallclock time of process.  */
+typedef struct {
+       int waitstatus;
+       struct rusage ru;
+       struct timeval start, elapsed;  /* Wallclock time of process.  */
 } resource_t;
 
 /* msec = milliseconds = 1/1,000 (1*10e-3) second.
@@ -70,78 +56,74 @@ static const char *const posix_format = "real %e\nuser %U\nsys %S";
 /* Format string for printing all statistics verbosely.
    Keep this output to 24 lines so users on terminals can see it all.*/
 static const char *const long_format =
-  "\tCommand being timed: \"%C\"\n"
-  "\tUser time (seconds): %U\n"
-  "\tSystem time (seconds): %S\n"
-  "\tPercent of CPU this job got: %P\n"
-  "\tElapsed (wall clock) time (h:mm:ss or m:ss): %E\n"
-  "\tAverage shared text size (kbytes): %X\n"
-  "\tAverage unshared data size (kbytes): %D\n"
-  "\tAverage stack size (kbytes): %p\n"
-  "\tAverage total size (kbytes): %K\n"
-  "\tMaximum resident set size (kbytes): %M\n"
-  "\tAverage resident set size (kbytes): %t\n"
-  "\tMajor (requiring I/O) page faults: %F\n"
-  "\tMinor (reclaiming a frame) page faults: %R\n"
-  "\tVoluntary context switches: %w\n"
-  "\tInvoluntary context switches: %c\n"
-  "\tSwaps: %W\n"
-  "\tFile system inputs: %I\n"
-  "\tFile system outputs: %O\n"
-  "\tSocket messages sent: %s\n"
-  "\tSocket messages received: %r\n"
-  "\tSignals delivered: %k\n"
-  "\tPage size (bytes): %Z\n"
-  "\tExit status: %x";
+       "\tCommand being timed: \"%C\"\n"
+       "\tUser time (seconds): %U\n"
+       "\tSystem time (seconds): %S\n"
+       "\tPercent of CPU this job got: %P\n"
+       "\tElapsed (wall clock) time (h:mm:ss or m:ss): %E\n"
+       "\tAverage shared text size (kbytes): %X\n"
+       "\tAverage unshared data size (kbytes): %D\n"
+       "\tAverage stack size (kbytes): %p\n"
+       "\tAverage total size (kbytes): %K\n"
+       "\tMaximum resident set size (kbytes): %M\n"
+       "\tAverage resident set size (kbytes): %t\n"
+       "\tMajor (requiring I/O) page faults: %F\n"
+       "\tMinor (reclaiming a frame) page faults: %R\n"
+       "\tVoluntary context switches: %w\n"
+       "\tInvoluntary context switches: %c\n"
+       "\tSwaps: %W\n"
+       "\tFile system inputs: %I\n"
+       "\tFile system outputs: %O\n"
+       "\tSocket messages sent: %s\n"
+       "\tSocket messages received: %r\n"
+       "\tSignals delivered: %k\n"
+       "\tPage size (bytes): %Z\n" "\tExit status: %x";
 
 
   /* Wait for and fill in data on child process PID.
-   Return 0 on error, 1 if ok.  */
+     Return 0 on error, 1 if ok.  */
 
 /* pid_t is short on BSDI, so don't try to promote it.  */
-static int resuse_end (pid_t pid, resource_t *resp)
+static int resuse_end(pid_t pid, resource_t * resp)
 {
-    int status;
-
-    pid_t caught;
-
-    /* Ignore signals, but don't ignore the children.  When wait3
-       returns the child process, set the time the command finished. */
-    while ((caught = wait3 (&status, 0, &resp->ru)) != pid)
-    {
-       if (caught == -1)
-           return 0;
-    }
-
-    gettimeofday (&resp->elapsed, (struct timezone *) 0);
-    resp->elapsed.tv_sec -= resp->start.tv_sec;
-    if (resp->elapsed.tv_usec < resp->start.tv_usec)
-    {
-       /* Manually carry a one from the seconds field.  */
-       resp->elapsed.tv_usec += 1000000;
-       --resp->elapsed.tv_sec;
-    }
-    resp->elapsed.tv_usec -= resp->start.tv_usec;
-
-    resp->waitstatus = status;
-
-    return 1;
+       int status;
+
+       pid_t caught;
+
+       /* Ignore signals, but don't ignore the children.  When wait3
+          returns the child process, set the time the command finished. */
+       while ((caught = wait3(&status, 0, &resp->ru)) != pid) {
+               if (caught == -1)
+                       return 0;
+       }
+
+       gettimeofday(&resp->elapsed, (struct timezone *) 0);
+       resp->elapsed.tv_sec -= resp->start.tv_sec;
+       if (resp->elapsed.tv_usec < resp->start.tv_usec) {
+               /* Manually carry a one from the seconds field.  */
+               resp->elapsed.tv_usec += 1000000;
+               --resp->elapsed.tv_sec;
+       }
+       resp->elapsed.tv_usec -= resp->start.tv_usec;
+
+       resp->waitstatus = status;
+
+       return 1;
 }
 
 /* Print ARGV to FP, with each entry in ARGV separated by FILLER.  */
-static void fprintargv (FILE *fp, char *const *argv, const char *filler)
+static void fprintargv(FILE * fp, char *const *argv, const char *filler)
 {
-    char *const *av;
-
-    av = argv;
-    fputs (*av, fp);
-    while (*++av)
-    {
-       fputs (filler, fp);
-       fputs (*av, fp);
-    }
-    if (ferror (fp))
-       error_msg_and_die("write error");
+       char *const *av;
+
+       av = argv;
+       fputs(*av, fp);
+       while (*++av) {
+               fputs(filler, fp);
+               fputs(*av, fp);
+       }
+       if (ferror(fp))
+               bb_error_msg_and_die(bb_msg_write_error);
 }
 
 /* Return the number of kilobytes corresponding to a number of pages PAGES.
@@ -152,28 +134,25 @@ static void fprintargv (FILE *fp, char *const *argv, const char *filler)
    Note: Some machines express getrusage statistics in terms of K,
    others in terms of pages.  */
 
-static unsigned long ptok (unsigned long pages)
+static unsigned long ptok(unsigned long pages)
 {
-    static unsigned long ps = 0;
-    unsigned long tmp;
-    static long size = LONG_MAX;
-
-    /* Initialization.  */
-    if (ps == 0)
-       ps = (long) getpagesize ();
-
-    /* Conversion.  */
-    if (pages > (LONG_MAX / ps))
-    {                          /* Could overflow.  */
-       tmp = pages / 1024;     /* Smaller first, */
-       size = tmp * ps;                /* then larger.  */
-    }
-    else
-    {                          /* Could underflow.  */
-       tmp = pages * ps;               /* Larger first, */
-       size = tmp / 1024;      /* then smaller.  */
-    }
-    return size;
+       static unsigned long ps = 0;
+       unsigned long tmp;
+       static long size = LONG_MAX;
+
+       /* Initialization.  */
+       if (ps == 0)
+               ps = (long) getpagesize();
+
+       /* Conversion.  */
+       if (pages > (LONG_MAX / ps)) {  /* Could overflow.  */
+               tmp = pages / 1024;     /* Smaller first, */
+               size = tmp * ps;        /* then larger.  */
+       } else {                        /* Could underflow.  */
+               tmp = pages * ps;       /* Larger first, */
+               size = tmp / 1024;      /* then smaller.  */
+       }
+       return size;
 }
 
 /* summarize: Report on the system use of a command.
@@ -221,282 +200,280 @@ static unsigned long ptok (unsigned long pages)
    COMMAND is the command and args that are being summarized.
    RESP is resource information on the command.  */
 
-static void summarize (FILE *fp, const char *fmt, char **command, resource_t *resp)
+static void summarize(FILE * fp, const char *fmt, char **command,
+                                         resource_t * resp)
 {
-    unsigned long r;           /* Elapsed real milliseconds.  */
-    unsigned long v;           /* Elapsed virtual (CPU) milliseconds.  */
-
-    if (WIFSTOPPED (resp->waitstatus))
-       fprintf (fp, "Command stopped by signal %d\n", WSTOPSIG (resp->waitstatus));
-    else if (WIFSIGNALED (resp->waitstatus))
-       fprintf (fp, "Command terminated by signal %d\n", WTERMSIG (resp->waitstatus));
-    else if (WIFEXITED (resp->waitstatus) && WEXITSTATUS (resp->waitstatus))
-       fprintf (fp, "Command exited with non-zero status %d\n", WEXITSTATUS (resp->waitstatus));
-
-    /* Convert all times to milliseconds.  Occasionally, one of these values
-       comes out as zero.  Dividing by zero causes problems, so we first
-       check the time value.  If it is zero, then we take `evasive action'
-       instead of calculating a value.  */
-
-    r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000;
-
-    v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC +
-       resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC;
-
-    while (*fmt)
-    {
-       switch (*fmt)
-       {
-           case '%':
-               switch (*++fmt)
-               {
-                   case '%':           /* Literal '%'.  */
-                       putc ('%', fp);
-                       break;
-                   case 'C':           /* The command that got timed.  */
-                       fprintargv (fp, command, " ");
-                       break;
-                   case 'D':           /* Average unshared data size.  */
-                       fprintf (fp, "%lu",
-                               MSEC_TO_TICKS (v) == 0 ? 0 :
-                               ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) +
-                               ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v));
-                       break;
-                   case 'E':           /* Elapsed real (wall clock) time.  */
-                       if (resp->elapsed.tv_sec >= 3600)       /* One hour -> h:m:s.  */
-                           fprintf (fp, "%ldh %ldm %02lds",
-                                   resp->elapsed.tv_sec / 3600,
-                                   (resp->elapsed.tv_sec % 3600) / 60,
-                                   resp->elapsed.tv_sec % 60);
-                       else
-                           fprintf (fp, "%ldm %ld.%02lds",     /* -> m:s.  */
-                                   resp->elapsed.tv_sec / 60,
-                                   resp->elapsed.tv_sec % 60,
-                                   resp->elapsed.tv_usec / 10000);
-                       break;
-                   case 'F':           /* Major page faults.  */
-                       fprintf (fp, "%ld", resp->ru.ru_majflt);
-                       break;
-                   case 'I':           /* Inputs.  */
-                       fprintf (fp, "%ld", resp->ru.ru_inblock);
-                       break;
-                   case 'K':           /* Average mem usage == data+stack+text.  */
-                       fprintf (fp, "%lu",
-                               MSEC_TO_TICKS (v) == 0 ? 0 :
-                               ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) +
-                               ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v) +
-                               ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v));
-                       break;
-                   case 'M':           /* Maximum resident set size.  */
-                       fprintf (fp, "%lu", ptok ((UL) resp->ru.ru_maxrss));
-                       break;
-                   case 'O':           /* Outputs.  */
-                       fprintf (fp, "%ld", resp->ru.ru_oublock);
-                       break;
-                   case 'P':           /* Percent of CPU this job got.  */
-                       /* % cpu is (total cpu time)/(elapsed time).  */
-                       if (r > 0)
-                           fprintf (fp, "%lu%%", (v * 100 / r));
-                       else
-                           fprintf (fp, "?%%");
-                       break;
-                   case 'R':           /* Minor page faults (reclaims).  */
-                       fprintf (fp, "%ld", resp->ru.ru_minflt);
-                       break;
-                   case 'S':           /* System time.  */
-                       fprintf (fp, "%ld.%02ld",
-                               resp->ru.ru_stime.tv_sec,
-                               resp->ru.ru_stime.TV_MSEC / 10);
-                       break;
-                   case 'T':           /* System time.  */
-                       if (resp->ru.ru_stime.tv_sec >= 3600)   /* One hour -> h:m:s.  */
-                           fprintf (fp, "%ldh %ldm %02lds",
-                                   resp->ru.ru_stime.tv_sec / 3600,
-                                   (resp->ru.ru_stime.tv_sec % 3600) / 60,
-                                   resp->ru.ru_stime.tv_sec % 60);
-                       else
-                           fprintf (fp, "%ldm %ld.%02lds",     /* -> m:s.  */
-                                   resp->ru.ru_stime.tv_sec / 60,
-                                   resp->ru.ru_stime.tv_sec % 60,
-                                   resp->ru.ru_stime.tv_sec / 10000);
-                       break;
-                   case 'U':           /* User time.  */
-                       fprintf (fp, "%ld.%02ld",
-                               resp->ru.ru_utime.tv_sec,
-                               resp->ru.ru_utime.TV_MSEC / 10);
+       unsigned long r;        /* Elapsed real milliseconds.  */
+       unsigned long v;        /* Elapsed virtual (CPU) milliseconds.  */
+
+       if (WIFSTOPPED(resp->waitstatus))
+               fprintf(fp, "Command stopped by signal %d\n",
+                               WSTOPSIG(resp->waitstatus));
+       else if (WIFSIGNALED(resp->waitstatus))
+               fprintf(fp, "Command terminated by signal %d\n",
+                               WTERMSIG(resp->waitstatus));
+       else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus))
+               fprintf(fp, "Command exited with non-zero status %d\n",
+                               WEXITSTATUS(resp->waitstatus));
+
+       /* Convert all times to milliseconds.  Occasionally, one of these values
+          comes out as zero.  Dividing by zero causes problems, so we first
+          check the time value.  If it is zero, then we take `evasive action'
+          instead of calculating a value.  */
+
+       r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000;
+
+       v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC +
+               resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC;
+
+       while (*fmt) {
+               switch (*fmt) {
+               case '%':
+                       switch (*++fmt) {
+                       case '%':       /* Literal '%'.  */
+                               putc('%', fp);
+                               break;
+                       case 'C':       /* The command that got timed.  */
+                               fprintargv(fp, command, " ");
+                               break;
+                       case 'D':       /* Average unshared data size.  */
+                               fprintf(fp, "%lu",
+                                               MSEC_TO_TICKS(v) == 0 ? 0 :
+                                               ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) +
+                                               ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
+                               break;
+                       case 'E':       /* Elapsed real (wall clock) time.  */
+                               if (resp->elapsed.tv_sec >= 3600)       /* One hour -> h:m:s.  */
+                                       fprintf(fp, "%ldh %ldm %02lds",
+                                                       resp->elapsed.tv_sec / 3600,
+                                                       (resp->elapsed.tv_sec % 3600) / 60,
+                                                       resp->elapsed.tv_sec % 60);
+                               else
+                                       fprintf(fp, "%ldm %ld.%02lds",  /* -> m:s.  */
+                                                       resp->elapsed.tv_sec / 60,
+                                                       resp->elapsed.tv_sec % 60,
+                                                       resp->elapsed.tv_usec / 10000);
+                               break;
+                       case 'F':       /* Major page faults.  */
+                               fprintf(fp, "%ld", resp->ru.ru_majflt);
+                               break;
+                       case 'I':       /* Inputs.  */
+                               fprintf(fp, "%ld", resp->ru.ru_inblock);
+                               break;
+                       case 'K':       /* Average mem usage == data+stack+text.  */
+                               fprintf(fp, "%lu",
+                                               MSEC_TO_TICKS(v) == 0 ? 0 :
+                                               ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) +
+                                               ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v) +
+                                               ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
+                               break;
+                       case 'M':       /* Maximum resident set size.  */
+                               fprintf(fp, "%lu", ptok((UL) resp->ru.ru_maxrss));
+                               break;
+                       case 'O':       /* Outputs.  */
+                               fprintf(fp, "%ld", resp->ru.ru_oublock);
+                               break;
+                       case 'P':       /* Percent of CPU this job got.  */
+                               /* % cpu is (total cpu time)/(elapsed time).  */
+                               if (r > 0)
+                                       fprintf(fp, "%lu%%", (v * 100 / r));
+                               else
+                                       fprintf(fp, "?%%");
+                               break;
+                       case 'R':       /* Minor page faults (reclaims).  */
+                               fprintf(fp, "%ld", resp->ru.ru_minflt);
+                               break;
+                       case 'S':       /* System time.  */
+                               fprintf(fp, "%ld.%02ld",
+                                               resp->ru.ru_stime.tv_sec,
+                                               resp->ru.ru_stime.TV_MSEC / 10);
+                               break;
+                       case 'T':       /* System time.  */
+                               if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s.  */
+                                       fprintf(fp, "%ldh %ldm %02lds",
+                                                       resp->ru.ru_stime.tv_sec / 3600,
+                                                       (resp->ru.ru_stime.tv_sec % 3600) / 60,
+                                                       resp->ru.ru_stime.tv_sec % 60);
+                               else
+                                       fprintf(fp, "%ldm %ld.%02lds",  /* -> m:s.  */
+                                                       resp->ru.ru_stime.tv_sec / 60,
+                                                       resp->ru.ru_stime.tv_sec % 60,
+                                                       resp->ru.ru_stime.tv_usec / 10000);
+                               break;
+                       case 'U':       /* User time.  */
+                               fprintf(fp, "%ld.%02ld",
+                                               resp->ru.ru_utime.tv_sec,
+                                               resp->ru.ru_utime.TV_MSEC / 10);
+                               break;
+                       case 'u':       /* User time.  */
+                               if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s.  */
+                                       fprintf(fp, "%ldh %ldm %02lds",
+                                                       resp->ru.ru_utime.tv_sec / 3600,
+                                                       (resp->ru.ru_utime.tv_sec % 3600) / 60,
+                                                       resp->ru.ru_utime.tv_sec % 60);
+                               else
+                                       fprintf(fp, "%ldm %ld.%02lds",  /* -> m:s.  */
+                                                       resp->ru.ru_utime.tv_sec / 60,
+                                                       resp->ru.ru_utime.tv_sec % 60,
+                                                       resp->ru.ru_utime.tv_usec / 10000);
+                               break;
+                       case 'W':       /* Times swapped out.  */
+                               fprintf(fp, "%ld", resp->ru.ru_nswap);
+                               break;
+                       case 'X':       /* Average shared text size.  */
+                               fprintf(fp, "%lu",
+                                               MSEC_TO_TICKS(v) == 0 ? 0 :
+                                               ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
+                               break;
+                       case 'Z':       /* Page size.  */
+                               fprintf(fp, "%d", getpagesize());
+                               break;
+                       case 'c':       /* Involuntary context switches.  */
+                               fprintf(fp, "%ld", resp->ru.ru_nivcsw);
+                               break;
+                       case 'e':       /* Elapsed real time in seconds.  */
+                               fprintf(fp, "%ld.%02ld",
+                                               resp->elapsed.tv_sec, resp->elapsed.tv_usec / 10000);
+                               break;
+                       case 'k':       /* Signals delivered.  */
+                               fprintf(fp, "%ld", resp->ru.ru_nsignals);
+                               break;
+                       case 'p':       /* Average stack segment.  */
+                               fprintf(fp, "%lu",
+                                               MSEC_TO_TICKS(v) == 0 ? 0 :
+                                               ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
+                               break;
+                       case 'r':       /* Incoming socket messages received.  */
+                               fprintf(fp, "%ld", resp->ru.ru_msgrcv);
+                               break;
+                       case 's':       /* Outgoing socket messages sent.  */
+                               fprintf(fp, "%ld", resp->ru.ru_msgsnd);
+                               break;
+                       case 't':       /* Average resident set size.  */
+                               fprintf(fp, "%lu",
+                                               MSEC_TO_TICKS(v) == 0 ? 0 :
+                                               ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v));
+                               break;
+                       case 'w':       /* Voluntary context switches.  */
+                               fprintf(fp, "%ld", resp->ru.ru_nvcsw);
+                               break;
+                       case 'x':       /* Exit status.  */
+                               fprintf(fp, "%d", WEXITSTATUS(resp->waitstatus));
+                               break;
+                       case '\0':
+                               putc('?', fp);
+                               return;
+                       default:
+                               putc('?', fp);
+                               putc(*fmt, fp);
+                       }
+                       ++fmt;
                        break;
-                   case 'u':           /* User time.  */
-                       if (resp->ru.ru_utime.tv_sec >= 3600)   /* One hour -> h:m:s.  */
-                           fprintf (fp, "%ldh %ldm %02lds",
-                                   resp->ru.ru_utime.tv_sec / 3600,
-                                   (resp->ru.ru_utime.tv_sec % 3600) / 60,
-                                   resp->ru.ru_utime.tv_sec % 60);
-                       else
-                           fprintf (fp, "%ldm %ld.%02lds",     /* -> m:s.  */
-                                   resp->ru.ru_utime.tv_sec / 60,
-                                   resp->ru.ru_utime.tv_sec % 60,
-                                   resp->ru.ru_utime.tv_sec / 10000);
-                       break;
-                   case 'W':           /* Times swapped out.  */
-                       fprintf (fp, "%ld", resp->ru.ru_nswap);
-                       break;
-                   case 'X':           /* Average shared text size.  */
-                       fprintf (fp, "%lu",
-                               MSEC_TO_TICKS (v) == 0 ? 0 :
-                               ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v));
-                       break;
-                   case 'Z':           /* Page size.  */
-                       fprintf (fp, "%d", getpagesize ());
-                       break;
-                   case 'c':           /* Involuntary context switches.  */
-                       fprintf (fp, "%ld", resp->ru.ru_nivcsw);
-                       break;
-                   case 'e':           /* Elapsed real time in seconds.  */
-                       fprintf (fp, "%ld.%02ld",
-                               resp->elapsed.tv_sec,
-                               resp->elapsed.tv_usec / 10000);
-                       break;
-                   case 'k':           /* Signals delivered.  */
-                       fprintf (fp, "%ld", resp->ru.ru_nsignals);
-                       break;
-                   case 'p':           /* Average stack segment.  */
-                       fprintf (fp, "%lu",
-                               MSEC_TO_TICKS (v) == 0 ? 0 :
-                               ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v));
-                       break;
-                   case 'r':           /* Incoming socket messages received.  */
-                       fprintf (fp, "%ld", resp->ru.ru_msgrcv);
-                       break;
-                   case 's':           /* Outgoing socket messages sent.  */
-                       fprintf (fp, "%ld", resp->ru.ru_msgsnd);
-                       break;
-                   case 't':           /* Average resident set size.  */
-                       fprintf (fp, "%lu",
-                               MSEC_TO_TICKS (v) == 0 ? 0 :
-                               ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v));
-                       break;
-                   case 'w':           /* Voluntary context switches.  */
-                       fprintf (fp, "%ld", resp->ru.ru_nvcsw);
-                       break;
-                   case 'x':           /* Exit status.  */
-                       fprintf (fp, "%d", WEXITSTATUS (resp->waitstatus));
-                       break;
-                   case '\0':
-                       putc ('?', fp);
-                       return;
-                   default:
-                       putc ('?', fp);
-                       putc (*fmt, fp);
-               }
-               ++fmt;
-               break;
-
-           case '\\':          /* Format escape.  */
-               switch (*++fmt)
-               {
-                   case 't':
-                       putc ('\t', fp);
-                       break;
-                   case 'n':
-                       putc ('\n', fp);
-                       break;
-                   case '\\':
-                       putc ('\\', fp);
+
+               case '\\':              /* Format escape.  */
+                       switch (*++fmt) {
+                       case 't':
+                               putc('\t', fp);
+                               break;
+                       case 'n':
+                               putc('\n', fp);
+                               break;
+                       case '\\':
+                               putc('\\', fp);
+                               break;
+                       default:
+                               putc('?', fp);
+                               putc('\\', fp);
+                               putc(*fmt, fp);
+                       }
+                       ++fmt;
                        break;
-                   default:
-                       putc ('?', fp);
-                       putc ('\\', fp);
-                       putc (*fmt, fp);
+
+               default:
+                       putc(*fmt++, fp);
                }
-               ++fmt;
-               break;
 
-           default:
-               putc (*fmt++, fp);
+               if (ferror(fp))
+                       bb_error_msg_and_die(bb_msg_write_error);
        }
+       putc('\n', fp);
 
-       if (ferror (fp))
-           error_msg_and_die("write error");
-    }
-    putc ('\n', fp);
-
-    if (ferror (fp))
-       error_msg_and_die("write error");
+       if (ferror(fp))
+               bb_error_msg_and_die(bb_msg_write_error);
 }
 
 /* Run command CMD and return statistics on it.
    Put the statistics in *RESP.  */
-static void run_command (char *const *cmd, resource_t *resp)
+static void run_command(char *const *cmd, resource_t * resp)
 {
-    pid_t pid;                 /* Pid of child.  */
-    __sighandler_t interrupt_signal, quit_signal;
-
-    gettimeofday (&resp->start, (struct timezone *) 0);
-    pid = fork ();             /* Run CMD as child process.  */
-    if (pid < 0)
-       error_msg_and_die("cannot fork");
-    else if (pid == 0)
-    {                          /* If child.  */
-       /* Don't cast execvp arguments; that causes errors on some systems,
-          versus merely warnings if the cast is left off.  */
-       execvp (cmd[0], cmd);
-       error_msg("cannot run %s", cmd[0]);
-       _exit (errno == ENOENT ? 127 : 126);
-    }
-
-    /* Have signals kill the child but not self (if possible).  */
-    interrupt_signal = signal (SIGINT, SIG_IGN);
-    quit_signal = signal (SIGQUIT, SIG_IGN);
-
-    if (resuse_end (pid, resp) == 0)
-       error_msg("error waiting for child process");
-
-    /* Re-enable signals.  */
-    signal (SIGINT, interrupt_signal);
-    signal (SIGQUIT, quit_signal);
+       pid_t pid;                      /* Pid of child.  */
+       __sighandler_t interrupt_signal, quit_signal;
+
+       gettimeofday(&resp->start, (struct timezone *) 0);
+       pid = vfork();          /* Run CMD as child process.  */
+       if (pid < 0)
+               bb_error_msg_and_die("cannot fork");
+       else if (pid == 0) {    /* If child.  */
+               /* Don't cast execvp arguments; that causes errors on some systems,
+                  versus merely warnings if the cast is left off.  */
+               execvp(cmd[0], cmd);
+               bb_error_msg("cannot run %s", cmd[0]);
+               _exit(errno == ENOENT ? 127 : 126);
+       }
+
+       /* Have signals kill the child but not self (if possible).  */
+       interrupt_signal = signal(SIGINT, SIG_IGN);
+       quit_signal = signal(SIGQUIT, SIG_IGN);
+
+       if (resuse_end(pid, resp) == 0)
+               bb_error_msg("error waiting for child process");
+
+       /* Re-enable signals.  */
+       signal(SIGINT, interrupt_signal);
+       signal(SIGQUIT, quit_signal);
 }
 
-extern int time_main (int argc, char **argv)
+int time_main(int argc, char **argv)
 {
-    int gotone;
-    resource_t res;
-    const char *output_format = default_format;
-
-    argc--;
-    argv++;
-    /* Parse any options  -- don't use getopt() here so we don't
-     * consume the args of our client application... */
-    while (argc > 0 && **argv == '-') {
-       gotone = 0;
-       while (gotone==0 && *++(*argv)) {
-           switch (**argv) {
-               case 'v':
-                   output_format = long_format;
-                   break;
-               case 'p':
-                   output_format = posix_format;
-                   break;
-               default:
-                   show_usage();
-           }
-           argc--;
-           argv++;
-           gotone = 1;
+       int gotone;
+       resource_t res;
+       const char *output_format = default_format;
+
+       argc--;
+       argv++;
+       /* Parse any options  -- don't use getopt() here so we don't
+        * consume the args of our client application... */
+       while (argc > 0 && **argv == '-') {
+               gotone = 0;
+               while (gotone == 0 && *++(*argv)) {
+                       switch (**argv) {
+                       case 'v':
+                               output_format = long_format;
+                               break;
+                       case 'p':
+                               output_format = posix_format;
+                               break;
+                       default:
+                               bb_show_usage();
+                       }
+                       argc--;
+                       argv++;
+                       gotone = 1;
+               }
        }
-    }
-
-    if (argv == NULL || *argv == NULL)
-       show_usage();
-
-    run_command (argv, &res);
-    summarize (stdout, output_format, argv, &res);
-    fflush (stdout);
-
-    if (WIFSTOPPED (res.waitstatus))
-       exit (WSTOPSIG (res.waitstatus));
-    else if (WIFSIGNALED (res.waitstatus))
-       exit (WTERMSIG (res.waitstatus));
-    else if (WIFEXITED (res.waitstatus))
-       exit (WEXITSTATUS (res.waitstatus));
-    return 0;
+
+       if (argv == NULL || *argv == NULL)
+               bb_show_usage();
+
+       run_command(argv, &res);
+       summarize(stderr, output_format, argv, &res);
+       fflush(stderr);
+
+       if (WIFSTOPPED(res.waitstatus))
+               exit(WSTOPSIG(res.waitstatus));
+       else if (WIFSIGNALED(res.waitstatus))
+               exit(WTERMSIG(res.waitstatus));
+       else if (WIFEXITED(res.waitstatus))
+               exit(WEXITSTATUS(res.waitstatus));
+       return 0;
 }