Logo  

CS471/571 - Operating Systems

Displaying exercises/e2/solution/rusage-opts.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdbool.h>
#include <string.h>

void run(char *argv[])
{
  execvp(argv[0], argv);
  perror("exec");
  exit(1);
}

double ftime(struct timeval t)
{
  double s = t.tv_sec + (double)t.tv_usec/1000000.0;
  return s;
}

void usage(void)
{
  printf("Usage: rusage [-mpic] [--mem] [--io] [--pfaults] [--ctxtsw] [--help] [--] <cmd...>\n");
  exit(0);
}

int main(int argc, char *argv[])
{
  if (argc < 2) {
    usage();
  }

  int mflag = false, pflag = false, ioflag = false, cflag = false;
  int optf = true;
  
  int nwords = 0, maxwords;
  char **words = malloc(sizeof(char *) * (maxwords=10));

  int i, j, n;

  for(n=i=1; i<argc; i=n) {
    n++;
    if (optf && argv[i][0] == '-' && argv[i][1]) {
      for(j=1; argv[i][j]; j++) {
        switch(argv[i][j]) {
          case 'm':
            mflag = true;
            break;
          case 'p':
            pflag = true;
            break;
          case 'i':
            ioflag = true;
            break;
          case 'c':
            cflag = true;
            break;
          case '-':
            if (j != 1) {
              printf("Invalid switch j=%d\n", j);
              exit(1);
            }
            if (strncmp("--mem", argv[i], 5) == 0) {
              j = strlen(argv[i])-1;
              mflag = true;
              break;
            }
            if (strncmp("--io", argv[i], 4) == 0) {
              j = strlen(argv[i])-1;
              ioflag = true;
              break;
            }
            if (strncmp("--pfaults", argv[i], 9) == 0) {
              j = strlen(argv[i])-1;
              pflag = true;
              break;
            }
            if (strncmp("--ctxtsw", argv[i], 8) == 0) {
              j = strlen(argv[i])-1;
              cflag = true;
              break;
            }
            if (strncmp("--help", argv[i], 6) == 0) {
              j = strlen(argv[i])-1;
              usage();
              break;
            }
            if (!strcmp("--", argv[i])) {
              optf = false;
              break;
            }
          default:
            printf("Invalid switch [%c].\n", argv[i][j]);
            exit(1);
        }
      }
    } else {
      // argv[i] is not a switch word:
      if (nwords >= maxwords-2) words = realloc(words, sizeof(char *) * (maxwords += 10));
      words[nwords++] = argv[i];
    }
  }

  words[nwords] = NULL;

  pid_t pid = fork();
  if (pid < 0) {
    perror("fork");
    return 1;
  }
  if (pid == 0) run(words);

  int status = 0;
  waitpid(pid, &status, 0);
  printf("--\n     Exit status: %d\n", WEXITSTATUS(status));
  struct rusage u;
  if (getrusage(RUSAGE_CHILDREN, &u) < 0) {
    perror("rusage");
    return 1;
  }
  printf("        CPU time: user: %.3fs, sys: %.3fs\n", ftime(u.ru_utime), ftime(u.ru_stime));
  if (mflag)  printf("         Max RSS: %ldK\n", u.ru_maxrss);
  if (pflag)  printf("     Page faults: minor: %d, major: %d\n", u.ru_minflt, u.ru_majflt);
  if (ioflag) printf("      I/O blocks: in: %d, out: %d\n", u.ru_inblock, u.ru_oublock);
  if (cflag)  printf("Context switches: voluntary: %d, involuntary: %d\n", u.ru_nvcsw, u.ru_nivcsw);

  return 0;
}