X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=util-vserver%2Fsrc%2Fvserver-stat.c;h=17425c1d9f7a02106e9753e00f155e4f76c1f041;hb=5341b9ca6659aa2f67eac0d58148ecaa1d2f4551;hp=7e2e0296abfd7641a52cfb97b4ef2c7648228a22;hpb=a4e4c8971eaf0e0448d1be21045f6605f57632fd;p=util-vserver.git diff --git a/util-vserver/src/vserver-stat.c b/util-vserver/src/vserver-stat.c index 7e2e029..17425c1 100644 --- a/util-vserver/src/vserver-stat.c +++ b/util-vserver/src/vserver-stat.c @@ -17,19 +17,6 @@ // 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 #endif @@ -37,9 +24,8 @@ #include "vserver.h" #include "util.h" #include "internal.h" -#include "wrappers.h" -#include "wrappers-dirent.h" -#include "wrappers-vserver.h" + +#include #include #include @@ -54,6 +40,13 @@ #include #include #include +#include + +#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/" @@ -61,30 +54,32 @@ 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 { - int 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 - int 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; @@ -138,11 +133,11 @@ getUptime() 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)) { @@ -156,111 +151,118 @@ getUptime() 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 *list, struct process_info *process) +static inline uint64_t +toMsec(uint64_t v) { - struct ctx_list *prev = list; - - if (process == NULL) return; - - // search - while(list != NULL) - { - // find - if (list->ctx == process->s_context) - { - add_ctx(list, process); - return; - } - // insert between - if (list->ctx > process->s_context) - { - prev->next = insert_ctx(process->s_context, list); - add_ctx(prev->next, process); - return; - } - // ++ - prev = list; - list = list->next; - } - // add at the end - prev->next = insert_ctx(process->s_context, NULL); - add_ctx(prev->next, process); + return v*1000llu/hertz; } -// free mem -static void -free_ctx(struct ctx_list *list) -{ - struct ctx_list *prev; - for(;list != NULL; list = prev) - { - prev = list->next; - free(list); - } +// 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 +initHertz() +{ + 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]; - char *p; - size_t idx, l=strlen(pid); - static struct process_info process; + 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 - process.s_context = vc_X_getctx(atoi(pid)); + 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; @@ -279,23 +281,22 @@ struct process_info *get_process_info(char *pid) 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) { @@ -351,8 +352,8 @@ shortenTime(char *buf, uint64_t t) unsigned long hh, mm, ss, ms; - ms = t % 100; - t /= 100; + ms = t % 1000; + t /= 1000; ss = t%60; t /= 60; @@ -361,7 +362,18 @@ shortenTime(char *buf, uint64_t t) 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); @@ -387,58 +399,79 @@ shortenTime(char *buf, uint64_t t) 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) { - char buf[512]; - char tmp[32]; + for (; ptrctx); - l = utilvserver_fmt_ulong(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, buf, strlen(buf)); write(1, "\n", 1); - - list = list->next; } } 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); @@ -449,19 +482,24 @@ int main(int argc, char **argv) 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 - 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("."); @@ -471,17 +509,20 @@ int main(int argc, char **argv) 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; }