// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-/*
- vserver-stat help you to see all the active context currently in the kernel
- with some useful stat
-
- Changelog:
-
- 2003-01-08 Jacques Gelinas: Shows vserver description
- 2002-02-28 Jacques Gelinas: Use dynamic system call
- 2002-06-05 Martial Rioux : fix memory output error
- 2002-12-05 Martial Rioux : fix output glitch
- 2001-11-29 added uptime/ctx stat
- 2001-11-20 added vmsize, rss, stime and utime stat
-*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <syscall.h>
#include <time.h>
#include <stdbool.h>
+#include <getopt.h>
+#include <sys/param.h>
#define ENSC_WRAPPERS_DIRENT 1
#define ENSC_WRAPPERS_VSERVER 1
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;
- long start_time_oldest;
- long stime_total, utime_total;
+ 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
- long start_time; // start time of process -- seconds since 1-1-70
- long stime, utime; // kernel & user-mode CPU time accumulated by process
- long cstime, cutime; // cumulative time of process and reaped children
- xid_t s_context;
+ 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 {
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(int fd, char const *cmd, int res)
+showHelp(char const *cmd)
{
- WRITE_MSG(fd, "Usage: ");
- WRITE_STR(fd, cmd);
- WRITE_MSG(fd,
+ 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"
" UPTIME Uptime/context\n"
" NAME Virtual server name\n"
"\n");
- exit(res);
+ exit(0);
}
static void
WRITE_MSG(1,
"vserver-stat " VERSION " -- show virtual context statistics\n"
"This program is part of " PACKAGE_STRING "\n\n"
- "Copyright (C) 2003 Enrico Scholz\n"
+ "Copyright (C) 2003,2005 Enrico Scholz\n"
VERSION_COPYRIGHT_DISCLAIMER);
exit(0);
}
char buffer[64];
char * errptr;
size_t len;
- time_t secs;
+ uint64_t secs;
uint32_t msecs=0;
// open the /proc/uptime file
- fd = Eopen("/proc/uptime", O_RDONLY, 0);
+ fd = EopenD("/proc/uptime", O_RDONLY, 0);
len = Eread(fd, buffer, sizeof buffer);
if (len==sizeof(buffer)) {
secs = strtol(buffer, &errptr, 10);
if (*errptr!='.') errptr = buffer;
- else msecs = strtol(errptr+1, &errptr, 10);
+ 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*100 + msecs;
+ return secs*1000 + msecs;
}
static int
res->VmRSS_total = 0;
res->utime_total = 0;
res->stime_total = 0;
- res->start_time_oldest = 0;
+ res->start_time_oldest = process->start_time;
}
++res->process_count;
res->utime_total += process->utime + process->cutime;
res->stime_total += process->stime + process->cstime;
- if (res->start_time_oldest == 0) // first entry
- res->start_time_oldest = process->start_time;
- else
- if (res->start_time_oldest > process->start_time)
- res->start_time_oldest = process->start_time;
+ res->start_time_oldest = MIN(res->start_time_oldest, process->start_time);
+}
+
+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)
+struct process_info *
+get_process_info(char *pid)
{
int fd;
char buffer[1024];
WRITE_MSG(2, "): ");
WRITE_STR(2, strerror(err));
WRITE_MSG(2, "\n");
+
+ return 0;
}
memcpy(buffer, "/proc/", 6); idx = 6;
for (idx = 0; idx<12 && *p!='\0'; ++p)
if ((*p)==' ') ++idx;
- process.utime = strtol(p, &p, 10);
- process.stime = strtol(p+1, &p, 10);
- process.cutime = strtol(p+1, &p, 10);
- process.cstime = strtol(p+1, &p, 10);
+ 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 = strtol(p, &p, 10);
+ 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;
}
unsigned long hh, mm, ss, ms;
- ms = t % 100;
- t /= 100;
+ ms = t % 1000;
+ t /= 1000;
ss = t%60;
t /= 60;
mm = t%60;
t /= 60;
- hh = t%60;
+ hh = t%24;
t /= 24;
- if (t>0) {
+ 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);
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 *vec)
+showContexts(struct Vector const *vec)
{
- uint64_t uptime = getUptime();
+ uint64_t uptime = getUptime();
struct XidData const * ptr = Vector_begin_const(vec);
struct XidData const * const end_ptr = Vector_end_const(vec);
memcpy(buf+10-l, tmp, l);
shortenMem (buf+10, ptr->VmSize_total);
- shortenMem (buf+17, ptr->VmRSS_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);
- switch (ptr->xid) {
- case 0 : strncpy(buf+55, "root server", 20); break;
- case 1 : strncpy(buf+55, "monitoring server", 20); break;
- default : {
- char * name = 0;
- char * cfgpath = 0;
- vcCfgStyle cfgstyle = vcCFG_AUTO;
-
- if ((cfgpath = vc_getVserverByCtx(ptr->xid, &cfgstyle, 0))!=0 &&
- (name = vc_getVserverName(cfgpath, cfgstyle))!=0)
- strncpy(buf+55, name, 20);
- free(name);
- free(cfgpath);
+ 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;
}
- }
- write(1, buf, 80);
- write(1, "\n", 1);
+ 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;
-
- if (argc==2) {
- if (strcmp(argv[1], "--help") ==0) showHelp(1, argv[0], 0);
- if (strcmp(argv[1], "--version")==0) showVersion();
+ 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 (argc!=1) {
+
+ if (optind!=argc) {
WRITE_MSG(2, "Unknown parameter, use '--help' for more information\n");
return EXIT_FAILURE;
}
- // do not include own stat
+ if (hertz==0x42) initHertz();
+ if (pagesize==0x42) initPageSize();
+
my_pid = getpid();
-#if 1
- // try to switch in context 1
- if (vc_get_task_xid(0)!=1)
- Evc_new_s_context(1, 0,0);
-#else
-# warning Compiling in debug-code
-#endif
+ 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://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ\n");
Vector_init(&xid_data, sizeof(struct XidData));
if (!isdigit(*dir_entry->d_name))
continue;
- if (atoi(dir_entry->d_name) != my_pid)
- registerXid(&xid_data, get_process_info(dir_entry->d_name));
+ 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