// 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 "vserver.h"
#include "util.h"
#include "internal.h"
-#include "wrappers.h"
-#include "wrappers-dirent.h"
-#include "wrappers-vserver.h"
+
+#include <ensc_vector/vector.h>
#include <stdio.h>
#include <stdlib.h>
#include <syscall.h>
#include <time.h>
#include <stdbool.h>
+#include <sys/param.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 CTX_DIR_NAME "/var/run/vservers/"
int wrapper_exit_code = 1;
-struct ctx_list
+#ifndef AT_CLKTCK
+#define AT_CLKTCK 17 /* frequency of times() */
+#endif
+
+static unsigned long hertz=0x42;
+
+struct XidData
{
- xid_t ctx;
- int process_count;
- int VmSize_total;
- int VmRSS_total;
- long start_time_oldest;
- long stime_total, utime_total;
- char name[CTX_NAME_MAX_LEN];
- struct ctx_list *next;
-} *my_ctx_list;
+ xid_t xid;
+ int process_count;
+ int VmSize_total;
+ int VmRSS_total;
+ uint64_t start_time_oldest;
+ uint64_t stime_total, utime_total;
+};
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;
};
-char *process_name;
-
struct ArgInfo {
enum { tpUNSET, tpCTX, tpPID } type;
xid_t ctx;
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;
}
-// insert a new record to the list
-static struct ctx_list *
-insert_ctx(int ctx, struct ctx_list *next)
+static int
+cmpData(void const *xid_v, void const *map_v)
{
- struct ctx_list *new;
-
- new = (struct ctx_list *)malloc(sizeof(struct ctx_list));
- new->ctx = ctx;
- new->process_count = 0;
- new->VmSize_total = 0;
- new->VmRSS_total = 0;
- new->utime_total = 0;
- new->stime_total = 0;
- new->start_time_oldest = 0;
- new->next = next;
- new->name[0] = '\0';
-
- return new;
+ xid_t const * const xid = xid_v;
+ struct XidData const * const map = map_v;
+ int res = *xid - map->xid;
+
+ return res;
}
-// compute the process info into the list
static void
-add_ctx(struct ctx_list *list, struct process_info *process)
+registerXid(struct Vector *vec, struct process_info *process)
{
- list->process_count ++;
- list->VmSize_total += process->VmSize;
- list->VmRSS_total += process->VmRSS;
- list->utime_total += process->utime + process->cutime;
- list->stime_total += process->stime + process->cstime;
-
- if (list->start_time_oldest == 0) // first entry
- list->start_time_oldest = process->start_time;
- else
- if (list->start_time_oldest > process->start_time)
- list->start_time_oldest = process->start_time;
+ 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);
}
-// increment the count number in the ctx record using ctx number
-static void
-count_ctx(struct ctx_list **ptr, struct process_info *process)
+static inline uint64_t
+toMsec(uint64_t v)
{
- for (;;) {
- if (*ptr==0 || (*ptr)->ctx > process->s_context) {
- *ptr = insert_ctx(process->s_context, *ptr);
- break;
- }
+ return v*1000llu/hertz;
+}
- if ((*ptr)->ctx == process->s_context)
- break;
- ptr = &(*ptr)->next;
+// 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;
}
-
- add_ctx(*ptr, process);
+ return (unsigned long)(-1);
}
-// free mem
+static void initHertz() __attribute__((__constructor__));
+
static void
-free_ctx(struct ctx_list *list)
+initHertz()
{
- struct ctx_list *prev;
-
- for(;list != NULL; list = prev)
- {
- prev = list->next;
- free(list);
- }
+ hertz = find_elf_note(AT_CLKTCK);
+ if (hertz==(unsigned long)(-1))
+ hertz = sysconf(_SC_CLK_TCK);
}
-
// 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];
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, "): ");
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;
}
-
-
static size_t
fillUintZero(char *buf, unsigned long val, size_t cnt)
{
unsigned long hh, mm, ss, ms;
- ms = t % 100;
- t /= 100;
+ ms = t % 1000;
+ t /= 1000;
ss = t%60;
t /= 60;
hh = t%60;
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);
}
-void showContexts(struct ctx_list *list)
+static void
+showContexts(struct Vector *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);
+
WRITE_MSG(1, "CTX PROC VSZ RSS userTIME sysTIME UPTIME NAME\n");
- while (list!=0) {
+ 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, list->ctx);
- l = utilvserver_fmt_long(tmp, list->process_count);
+ l = utilvserver_fmt_long(buf, ptr->xid);
+ l = utilvserver_fmt_long(tmp, ptr->process_count);
memcpy(buf+10-l, tmp, l);
- shortenMem (buf+10, list->VmSize_total);
- shortenMem (buf+17, list->VmRSS_total);
- shortenTime(buf+24, list->utime_total);
- shortenTime(buf+34, list->stime_total);
- shortenTime(buf+44, uptime - list->start_time_oldest);
+ shortenMem (buf+10, ptr->VmSize_total);
+ shortenMem (buf+17, ptr->VmRSS_total);
+ 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 (list->ctx) {
- case 0 : strncpy(buf+55, "root server", 20); break;
- case 1 : strncpy(buf+55, "monitoring server", 20); break;
+ switch (ptr->xid) {
+ case 0 : strcpy(buf+55, "root server" ); break;
+ case 1 : strcpy(buf+55, "monitoring server"); break;
default : {
- char * name = 0;
- char * cfgpath = 0;
+ char * name = 0;
+ char * cfgpath = 0;
vcCfgStyle cfgstyle = vcCFG_AUTO;
- if ((cfgpath = vc_getVserverByCtx(list->ctx, &cfgstyle, 0))!=0 &&
- (name = vc_getVserverName(cfgpath, cfgstyle))!=0)
- strncpy(buf+55, name, 20);
+ if ((cfgpath = vc_getVserverByCtx(ptr->xid, &cfgstyle, 0))==0 ||
+ (name = vc_getVserverName(cfgpath, cfgstyle))==0) {
+ name = strdup("");
+ cfgstyle = vcCFG_NONE;
+ }
+
+ switch (cfgstyle) {
+ case vcCFG_LEGACY : {
+ size_t len = MIN(strlen(name), 18);
+ buf[55] = '[';
+ memcpy(buf+56, name, len);
+ memcpy(buf+56+len, "]", 2);
+ break;
+ }
+ default : {
+ size_t len = MIN(strlen(name), 20);
+ memcpy(buf+55, name, len);
+ buf[55+len] = '\0';
+ break;
+ }
+ }
+
free(name);
free(cfgpath);
}
}
- write(1, buf, 80);
- write(1, "\n", 1);
-
- list = list->next;
+ Vwrite(1, buf, strlen(buf));
+ Vwrite(1, "\n", 1);
}
}
int main(int argc, char **argv)
{
- DIR *proc_dir;
- struct dirent *dir_entry;
- pid_t my_pid;
-
- // for error msg
- process_name = argv[0];
+ DIR * proc_dir;
+ struct dirent* dir_entry;
+ pid_t my_pid;
+ struct Vector xid_data;
+ char const * errptr;
if (argc==2) {
if (strcmp(argv[1], "--help") ==0) showHelp(1, argv[0], 0);
return EXIT_FAILURE;
}
+ if (hertz==0x42) initHertz();
+
+ //printf("hertz=%lu\n", hertz);
// do not include own stat
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);
-#endif
-
- // create the fist...
- my_ctx_list = insert_ctx(0, NULL);
- // init with the default name for the context 0
- strncpy(my_ctx_list->name, "root server", CTX_NAME_MAX_LEN);
+ 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));
Echdir(PROC_DIR_NAME);
proc_dir = Eopendir(".");
if (!isdigit(*dir_entry->d_name))
continue;
- if (atoi(dir_entry->d_name) != my_pid)
- count_ctx(&my_ctx_list, 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);
// output the ctx_list
- showContexts(my_ctx_list);
-
- // free the ctx_list
- free_ctx(my_ctx_list);
+ showContexts(&xid_data);
+#ifndef NDEBUG
+ Vector_free(&xid_data);
+#endif
+
return 0;
}