start to track Daniel's version
[util-vserver.git] / src / vserver-stat.c
diff --git a/src/vserver-stat.c b/src/vserver-stat.c
deleted file mode 100644 (file)
index 95b1272..0000000
+++ /dev/null
@@ -1,672 +0,0 @@
-// $Id: vserver-stat.c 2450 2007-01-10 19:27:56Z dhozac $
-
-// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
-// based on vserver-stat.cc by Guillaum Dallaire and Jacques Gelinas
-//  
-// 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.
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include "vserver.h"
-#include "util.h"
-#include "internal.h"
-
-#include <ensc_vector/vector.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-#include <syscall.h>
-#include <time.h>
-#include <stdbool.h>
-#include <getopt.h>
-#include <sys/param.h>
-#include <sys/resource.h>
-
-#define ENSC_WRAPPERS_DIRENT   1
-#define ENSC_WRAPPERS_VSERVER  1
-#define ENSC_WRAPPERS_FCNTL    1
-#define ENSC_WRAPPERS_UNISTD   1
-#include "wrappers.h"
-
-#define PROC_DIR_NAME "/proc"
-#define PROC_VIRT_DIR_NAME "/proc/virtual"
-#define CTX_DIR_NAME "/var/run/vservers/"
-#define CTX_NAME_MAX_LEN 50
-
-int    wrapper_exit_code = 1;
-
-#ifndef AT_CLKTCK
-#define AT_CLKTCK       17    /* frequency of times() */
-#endif
-
-static unsigned long   hertz   =0x42;
-static unsigned long   pagesize=0x42;
-
-struct XidData
-{
-    xid_t              xid;
-    int                        process_count;
-    int                        VmSize_total;
-    int                        VmRSS_total;
-    uint64_t           start_time_oldest;
-    uint64_t           stime_total, utime_total;
-
-    vcCfgStyle         cfgstyle;
-    char const *       name;
-};
-
-struct process_info
-{
-       long            VmSize;         // number of pages of virtual memory
-       long            VmRSS;          // resident set size from /proc/#/stat
-       uint64_t        start_time;     // start time of process -- milliseconds since 1-1-70
-        uint64_t       stime, utime;   // kernel & user-mode CPU time accumulated by process
-       uint64_t        cstime, cutime; // cumulative time of process and reaped children
-       xid_t           s_context;
-};
-
-struct ArgInfo {
-    enum { tpUNSET, tpCTX, tpPID }     type;
-    xid_t              ctx;
-    pid_t              pid;
-    unsigned int       interval;
-    bool               shutdown;
-    bool               omit_init;
-    size_t             argc;
-    char * const *     argv;
-};
-
-#define CMD_HELP               0x1000
-#define CMD_VERSION            0x1001
-
-struct option const
-CMDLINE_OPTIONS[] = {
-  { "help",     no_argument,  0, CMD_HELP },
-  { "version",  no_argument,  0, CMD_VERSION },
-  { "sort",     required_argument, 0, 'O' },
-  {0,0,0,0}
-};
-
-static void
-showHelp(char const *cmd)
-{
-  WRITE_MSG(1, "Usage:  ");
-  WRITE_STR(1, cmd);
-  WRITE_MSG(1,
-           "\n"
-           "Show informations about all the active context.\n\n"
-           "   CTX#            Context number\n"
-           "                   #0 = root context\n"
-           "                   #1 = monitoring context\n"
-           "   PROC QTY        Quantity of processes in each context\n"
-           "   VSZ             Number of pages of virtual memory\n"
-           "   RSS             Resident set size\n"
-           "   userTIME        User-mode CPU time accumulated\n"
-           "   sysTIME         Kernel-mode CPU time accumulated\n"
-           "   UPTIME          Uptime/context\n"
-           "   NAME            Virtual server name\n"
-           "\n");
-  exit(0);
-}
-
-static void
-showVersion()
-{
-  WRITE_MSG(1,
-           "vserver-stat " VERSION " -- show virtual context statistics\n"
-           "This program is part of " PACKAGE_STRING "\n\n"
-           "Copyright (C) 2003,2005 Enrico Scholz\n"
-           VERSION_COPYRIGHT_DISCLAIMER);
-  exit(0);
-}
-
-
-// return uptime (in ms) from /proc/uptime
-static uint64_t
-getUptime()
-{
-  int          fd;
-  char         buffer[64];
-  char *       errptr;
-  size_t       len;
-  uint64_t     secs;
-  uint32_t     msecs=0;
-
-    // open the /proc/uptime file
-  fd  = EopenD("/proc/uptime", O_RDONLY, 0);
-  len = Eread(fd, buffer, sizeof buffer);
-
-  if (len==sizeof(buffer)) {
-    WRITE_MSG(2, "Too much data in /proc/uptime; aborting...\n");
-    exit(1);
-  }
-  Eclose(fd);
-
-  while (len>0 && buffer[len-1]=='\n') --len;
-  buffer[len] = '\0';
-
-  secs = strtol(buffer, &errptr, 10);
-  if (*errptr!='.') errptr = buffer;
-  else {
-    unsigned int       mult;
-    switch (strlen(errptr+1)) {
-      case 0   :  mult = 1000; break;
-      case 1   :  mult = 100;  break;
-      case 2   :  mult = 10;   break;
-      case 3   :  mult = 1;    break;
-      default  :  mult = 0;    break;
-    }
-    msecs = strtol(errptr+1, &errptr, 10) * mult;
-  }
-
-  if ((*errptr!='\0' && *errptr!=' ') || errptr==buffer) {
-    WRITE_MSG(2, "Bad data in /proc/uptime\n");
-    exit(1);
-  }
-
-  return secs*1000 + msecs;
-}
-
-static int
-cmpData(void const *xid_v, void const *map_v)
-{
-  xid_t const * const                  xid = xid_v;
-  struct XidData const * const         map = map_v;
-  int  res = *xid - map->xid;
-
-  return res;
-}
-
-static void
-registerXid(struct Vector *vec, struct process_info *process)
-{
-  struct XidData       *res;
-
-  res = Vector_search(vec, &process->s_context, cmpData);
-  if (res==0) {
-    res = Vector_insert(vec, &process->s_context, cmpData);
-    res->xid           = process->s_context;
-    res->process_count = 0;
-    res->VmSize_total  = 0;
-    res->VmRSS_total   = 0;
-    res->utime_total   = 0;
-    res->stime_total   = 0;
-    res->start_time_oldest = process->start_time;
-  }
-
-  ++res->process_count;
-  res->VmSize_total += process->VmSize;
-  res->VmRSS_total  += process->VmRSS;
-  res->utime_total  += process->utime + process->cutime;
-  res->stime_total  += process->stime + process->cstime;
-
-  res->start_time_oldest = MIN(res->start_time_oldest, process->start_time);
-}
-
-static void
-registerXidVstat(struct Vector *vec, unsigned long xid_l)
-{
-  xid_t                        xid = (xid_t) xid_l;
-  struct XidData       *res;
-  struct vc_rlimit_stat        limit[3];
-  struct vc_virt_stat  vstat;
-  struct vc_sched_info sched;
-  int                  cpu;
-
-  res = Vector_search(vec, &xid, cmpData);
-  if (res!=0) {
-    WRITE_MSG(2, "Duplicate xid found?!\n");
-    return;
-  }
-  if (vc_virt_stat(xid, &vstat) == -1) {
-    perror("vc_virt_stat()");
-    return;
-  }
-  if (vc_rlimit_stat(xid, RLIMIT_NPROC, &limit[0]) == -1) {
-    perror("vc_rlimit_stat(RLIMIT_NRPOC)");
-    return;
-  }
-  if (vc_rlimit_stat(xid, RLIMIT_AS, &limit[1]) == -1) {
-    perror("vc_rlimit_stat(RLIMIT_AS)");
-    return;
-  }
-  if (vc_rlimit_stat(xid, RLIMIT_RSS, &limit[2]) == -1) {
-    perror("vc_rlimit_stat(RLIMIT_RSS)");
-    return;
-  }
-
-  res                  = Vector_insert(vec, &xid, cmpData);
-  res->xid             = xid;
-
-  res->process_count   = limit[0].value;
-  res->VmSize_total    = limit[1].value * pagesize;
-  res->VmRSS_total     = limit[2].value;
-  res->start_time_oldest= getUptime() - vstat.uptime/1000000;
-
-  res->utime_total     = 0;
-  res->stime_total     = 0;
-  // XXX: arbitrary CPU limit.
-  for (cpu = 0; cpu < 1024; cpu++) {
-    sched.cpu_id = cpu;
-    sched.bucket_id = 0;
-    if (vc_sched_info(xid, &sched) == -1)
-      break;
-
-    res->utime_total   += sched.user_msec;
-    res->stime_total   += sched.sys_msec;
-  }
-}
-
-static inline uint64_t
-toMsec(uint64_t v)
-{
-  return v*1000llu/hertz;
-}
-
-
-// shamelessly stolen from procps...
-static unsigned long
-find_elf_note(unsigned long findme){
-  unsigned long *ep = (unsigned long *)environ;
-  while(*ep++);
-  while(*ep){
-    if(ep[0]==findme) return ep[1];
-    ep+=2;
-  }
-  return (unsigned long)(-1);
-}
-
-static void initHertz()           __attribute__((__constructor__));
-static void initPageSize() __attribute__((__constructor__));
-
-static void
-initHertz()
-{
-  hertz = find_elf_note(AT_CLKTCK);
-  if (hertz==(unsigned long)(-1))
-    hertz = sysconf(_SC_CLK_TCK);
-}
-
-static void
-initPageSize()
-{
-  pagesize = sysconf(_SC_PAGESIZE);
-}
-
-// open the process's status file to get the ctx number, and other stat
-struct process_info *
-get_process_info(char *pid)
-{
-  int                          fd;
-  char                         buffer[1024];
-  char                         *p;
-  size_t                       idx, l=strlen(pid);
-  static struct process_info   process;
-
-#if 1
-  process.s_context = vc_get_task_xid(atoi(pid));
-#else
-#  warning Compiling in debug-code
-  process.s_context = random()%6;
-#endif
-
-  if (process.s_context==VC_NOCTX) {
-    int                err=errno;
-    WRITE_MSG(2, "vc_get_task_xid(");
-    WRITE_STR(2, pid);
-    WRITE_MSG(2, "): ");
-    WRITE_STR(2, strerror(err));
-    WRITE_MSG(2, "\n");
-
-    return 0;
-  }
-  
-  memcpy(buffer,     "/proc/", 6); idx  = 6;
-  memcpy(buffer+idx, pid,      l); idx += l;
-  memcpy(buffer+idx, "/stat",  6);
-       
-    // open the /proc/#/stat file
-  if ((fd = open(buffer, O_RDONLY, 0)) == -1)
-    return NULL;
-    // put the file in a buffer
-  if (read(fd, buffer, sizeof(buffer)) < 1)
-    return NULL;
-
-  close(fd);
-
-  p   = strchr(buffer, ')');           // go after the PID (process_name)
-  for (idx = 0; idx<12 && *p!='\0'; ++p)
-    if ((*p)==' ') ++idx;
-
-  process.utime  = toMsec(strtol(p,   &p, 10));
-  process.stime  = toMsec(strtol(p+1, &p, 10));
-  process.cutime = toMsec(strtol(p+1, &p, 10));
-  process.cstime = toMsec(strtol(p+1, &p, 10));
-
-  for (idx = 0; idx<5 && *p!='\0'; ++p)
-    if ((*p)==' ') ++idx;
-
-  process.start_time = toMsec(strtol(p,   &p, 10));
-  process.VmSize     = strtol(p+1, &p, 10);
-  process.VmRSS      = strtol(p+1, &p, 10);
-
-  //printf("pid=%s, start_time=%llu\n", pid, process.start_time);
-  return &process;
-}
-
-static size_t
-fillUintZero(char *buf, unsigned long val, size_t cnt)
-{
-  size_t       l;
-  
-  l = utilvserver_fmt_ulong(buf, val);
-  if (l<cnt) {
-    memmove(buf+cnt-l, buf, l);
-    memset(buf, '0', cnt-l);
-  }
-  buf[cnt] = '\0';
-
-  return cnt;
-}
-
-static void
-shortenMem(char *buf, unsigned long val)
-{
-  char const * SUFFIXES[] = { " ", "K", "M", "G", "T", "+" };
-  char         tmp[16];
-  char const * suffix = "+";
-  size_t       i, l;
-  unsigned int mod = 0;
-
-  for (i=0; i<6; ++i) {
-    if (val<1000) {
-      suffix = SUFFIXES[i];
-      break;
-    }
-    mod   = 10*(val & 1023)/1024;
-    val >>= 10;
-  }
-
-  if (val >9999) val=9999;
-  if (val>=1000) mod=0;
-
-  l = utilvserver_fmt_ulong(tmp, val);
-  if (mod!=0) {
-    tmp[l++] = '.';
-    l += utilvserver_fmt_ulong(tmp+l, mod);
-  }
-  i = 7-l-strlen(suffix);
-  
-  memcpy(buf+i,   tmp, l);
-  memcpy(buf+i+l, suffix, strlen(suffix));
-}
-
-static void
-shortenTime(char *buf, uint64_t t)
-{
-  char         tmp[32];
-  char         *ptr = tmp;
-
-  unsigned long        hh, mm, ss, ms;
-
-  ms = t % 1000;
-  t /= 1000;
-
-  ss = t%60;
-  t /= 60;
-  mm = t%60;
-  t /= 60;
-  hh = t%24;
-  t /= 24;
-
-  if (t>999*999) {
-    memcpy(ptr, "INVALID", 7);
-    ptr   += 7;
-  }
-  else if (t>999) {
-    ptr   += utilvserver_fmt_ulong(ptr, t/365);
-    *ptr++ = 'y';
-    ptr   += fillUintZero(ptr, t%365, 2);
-    *ptr++ = 'd';
-    ptr   += fillUintZero(ptr, hh, 2);
-  }    
-  else if (t>0) {
-    ptr   += utilvserver_fmt_ulong(ptr, t);
-    *ptr++ = 'd';
-    ptr   += fillUintZero(ptr, hh, 2);
-    *ptr++ = 'h';
-    ptr   += fillUintZero(ptr, mm, 2);
-  }
-  else if (hh>0) {
-    ptr   += utilvserver_fmt_ulong(ptr, hh);
-    *ptr++ = 'h';
-    ptr   += fillUintZero(ptr, mm, 2);
-    *ptr++ = 'm';
-    ptr   += fillUintZero(ptr, ss, 2);    
-  }
-  else {
-    ptr   += utilvserver_fmt_ulong(ptr, mm);
-    *ptr++ = 'm';
-    ptr   += fillUintZero(ptr, ss, 2);
-    *ptr++ = 's';
-    ptr   += fillUintZero(ptr, ms, 2);
-  }
-
-  *ptr = ' ';
-  memcpy(buf+10-(ptr-tmp), tmp, ptr-tmp);
-}
-
-static char *
-formatName(char *dst, vcCfgStyle style, char const *name)
-{
-  size_t               len;
-  
-  if (name==0) name = "";
-  len = strlen(name);
-
-  switch (style) {
-    case vcCFG_LEGACY  :
-      len    = MIN(len, 18);
-      *dst++ = '[';
-      memcpy(dst, name, len);
-      dst   += len;
-      *dst++ = ']';
-      break;
-
-    default            :
-      len    = MIN(len, 20);
-      memcpy(dst, name, len);
-      dst   += len;
-      break;
-  }
-
-  return dst;
-}
-
-static void
-showContexts(struct Vector const *vec)
-{
-  uint64_t                     uptime  = getUptime();
-  struct XidData const *       ptr     = Vector_begin_const(vec);
-  struct XidData const * const end_ptr = Vector_end_const(vec);
-  
-
-  WRITE_MSG(1, "CTX   PROC    VSZ    RSS  userTIME   sysTIME    UPTIME NAME\n");
-  for (; ptr<end_ptr; ++ptr) {
-    char       buf[sizeof(xid_t)*3 + 512];
-    char       tmp[sizeof(int)*3 + 2];
-    size_t     l;
-
-    memset(buf, ' ', sizeof(buf));
-    l = utilvserver_fmt_long(buf, ptr->xid);
-    l = utilvserver_fmt_long(tmp, ptr->process_count);
-    memcpy(buf+10-l, tmp, l);
-
-    shortenMem (buf+10, ptr->VmSize_total);
-    shortenMem (buf+17, ptr->VmRSS_total*pagesize);
-    shortenTime(buf+24, ptr->utime_total);
-    shortenTime(buf+34, ptr->stime_total);
-    //printf("%llu, %llu\n", uptime, ptr->start_time_oldest);
-    shortenTime(buf+44, uptime - ptr->start_time_oldest);
-
-    formatName(buf+55, ptr->cfgstyle, ptr->name)[0] = '\0';
-
-    Vwrite(1, buf, strlen(buf));
-    Vwrite(1, "\n", 1);
-  }
-}
-
-static void
-fillName(void *obj_v, void UNUSED * a)
-{
-  struct XidData *     obj = obj_v;
-
-  switch (obj->xid) {
-    case 0             :
-      obj->cfgstyle = vcCFG_NONE;
-      obj->name     = strdup("root server");
-      break;
-
-    case 1             :
-      obj->cfgstyle = vcCFG_NONE;
-      obj->name     = strdup("monitoring server");
-      break;
-
-    default            : {
-      char *           cfgpath;
-
-      obj->cfgstyle  = vcCFG_AUTO;
-
-      if ((cfgpath   = vc_getVserverByCtx(obj->xid, &obj->cfgstyle, 0))==0 ||
-         (obj->name = vc_getVserverName(cfgpath, obj->cfgstyle))==0) {
-       obj->name     = 0;
-       obj->cfgstyle = vcCFG_NONE;
-      }
-
-      free(cfgpath);
-
-      break;
-    }
-  }
-}
-
-static void UNUSED
-freeXidData(void *obj_v, void UNUSED * a)
-{
-  struct XidData *     obj = obj_v;
-
-  free(const_cast(char *)(obj->name));
-}
-
-int main(int argc, char **argv)
-{
-  DIR *                        proc_dir;
-  struct dirent*       dir_entry;
-  pid_t                        my_pid;
-  struct Vector                xid_data;
-  char const *         errptr;
-
-  while (1) {
-    int                c = getopt_long(argc, argv, "+O:", CMDLINE_OPTIONS, 0);
-    if (c==-1) break;
-
-    switch (c) {
-      case CMD_HELP    :  showHelp(argv[0]);
-      case CMD_VERSION :  showVersion();
-      case 'O'         :  break;
-      default          :
-       WRITE_MSG(2, "Try '");
-       WRITE_STR(2, argv[0]);
-       WRITE_MSG(2, " --help' for more information.\n");
-       return EXIT_FAILURE;
-       break;
-    }
-  }
-    
-  if (optind!=argc) {
-    WRITE_MSG(2, "Unknown parameter, use '--help' for more information\n");
-    return EXIT_FAILURE;
-  }
-
-  if (hertz==0x42)    initHertz();
-  if (pagesize==0x42) initPageSize();
-  
-  Vector_init(&xid_data, sizeof(struct XidData));
-
-  if (vc_isSupported(vcFEATURE_VSTAT)) {
-    unsigned long xid;
-    Echdir(PROC_VIRT_DIR_NAME);
-    proc_dir = Eopendir(".");
-    while ((dir_entry = readdir(proc_dir)) != NULL) {
-      if (!isNumberUnsigned(dir_entry->d_name, &xid, false))
-       continue;
-
-      registerXidVstat(&xid_data, xid);
-    }
-    closedir(proc_dir);
-  }
-  else {
-    my_pid = getpid();
-
-    if (!switchToWatchXid(&errptr)) {
-      perror(errptr);
-      exit(1);
-    }
-
-    if (access("/proc/uptime",R_OK)==-1 && errno==ENOENT)
-      WRITE_MSG(2,
-             "WARNING: can not access /proc/uptime. Usually, this is caused by\n"
-             "         procfs-security. Please read the FAQ for more details\n"
-             "         http://linux-vserver.org/Proc-Security\n");
-
-    Echdir(PROC_DIR_NAME);
-    proc_dir = Eopendir(".");
-    while ((dir_entry = readdir(proc_dir)) != NULL)
-    {
-      // select only process file
-      if (!isdigit(*dir_entry->d_name))
-        continue;
-
-      if (atoi(dir_entry->d_name) != my_pid) {
-       struct process_info *   info = get_process_info(dir_entry->d_name);
-       if (info)
-         registerXid(&xid_data, info);
-      }
-    }
-    closedir(proc_dir);
-  }
-
-  Vector_foreach(&xid_data, fillName, 0);
-
-    // output the ctx_list     
-  showContexts(&xid_data);
-
-#ifndef NDEBUG
-  Vector_foreach(&xid_data, freeXidData, 0);
-  Vector_free(&xid_data);
-#endif
-  
-  return 0;
-}