3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on vserver-stat.cc by Guillaum Dallaire and Jacques Gelinas
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 vserver-stat help you to see all the active context currently in the kernel
26 2003-01-08 Jacques Gelinas: Shows vserver description
27 2002-02-28 Jacques Gelinas: Use dynamic system call
28 2002-06-05 Martial Rioux : fix memory output error
29 2002-12-05 Martial Rioux : fix output glitch
30 2001-11-29 added uptime/ctx stat
31 2001-11-20 added vmsize, rss, stime and utime stat
47 #include <sys/types.h>
56 #define PROC_DIR_NAME "/proc"
57 #define CTX_DIR_NAME "/var/run/vservers/"
58 #define CTX_NAME_MAX_LEN 50
60 int wrapper_exit_code = 1;
68 long start_time_oldest;
69 long stime_total, utime_total;
70 char name[CTX_NAME_MAX_LEN];
71 struct ctx_list *next;
76 long VmSize; // number of pages of virtual memory
77 long VmRSS; // resident set size from /proc/#/stat
78 long start_time; // start time of process -- seconds since 1-1-70
79 long stime, utime; // kernel & user-mode CPU time accumulated by process
80 long cstime, cutime; // cumulative time of process and reaped children
87 enum { tpUNSET, tpCTX, tpPID } type;
90 unsigned int interval;
98 showHelp(int fd, char const *cmd, int res)
100 WRITE_MSG(fd, "Usage: ");
104 "Show informations about all the active context.\n\n"
105 " CTX# Context number\n"
106 " #0 = root context\n"
107 " #1 = monitoring context\n"
108 " PROC QTY Quantity of processes in each context\n"
109 " VSZ Number of pages of virtual memory\n"
110 " RSS Resident set size\n"
111 " userTIME User-mode CPU time accumulated\n"
112 " sysTIME Kernel-mode CPU time accumulated\n"
113 " UPTIME Uptime/context\n"
114 " NAME Virtual server name\n"
123 "vserver-stat " VERSION " -- show virtual context statistics\n"
124 "This program is part of " PACKAGE_STRING "\n\n"
125 "Copyright (C) 2003 Enrico Scholz\n"
126 VERSION_COPYRIGHT_DISCLAIMER);
131 // return uptime (in ms) from /proc/uptime
142 // open the /proc/uptime file
143 fd = Eopen("/proc/uptime", O_RDONLY, 0);
144 len = Eread(fd, buffer, sizeof buffer);
146 if (len==sizeof(buffer)) {
147 WRITE_MSG(2, "Too much data in /proc/uptime; aborting...\n");
152 while (len>0 && buffer[len-1]=='\n') --len;
155 secs = strtol(buffer, &errptr, 10);
156 if (*errptr!='.') errptr = buffer;
157 else msecs = strtol(errptr+1, &errptr, 10);
159 if ((*errptr!='\0' && *errptr!=' ') || errptr==buffer) {
160 WRITE_MSG(2, "Bad data in /proc/uptime\n");
164 return secs*100 + msecs;
167 // insert a new record to the list
168 static struct ctx_list *
169 insert_ctx(int ctx, struct ctx_list *next)
171 struct ctx_list *new;
173 new = (struct ctx_list *)malloc(sizeof(struct ctx_list));
175 new->process_count = 0;
176 new->VmSize_total = 0;
177 new->VmRSS_total = 0;
178 new->utime_total = 0;
179 new->stime_total = 0;
180 new->start_time_oldest = 0;
187 // compute the process info into the list
189 add_ctx(struct ctx_list *list, struct process_info *process)
191 list->process_count ++;
192 list->VmSize_total += process->VmSize;
193 list->VmRSS_total += process->VmRSS;
194 list->utime_total += process->utime + process->cutime;
195 list->stime_total += process->stime + process->cstime;
197 if (list->start_time_oldest == 0) // first entry
198 list->start_time_oldest = process->start_time;
200 if (list->start_time_oldest > process->start_time)
201 list->start_time_oldest = process->start_time;
204 // increment the count number in the ctx record using ctx number
206 count_ctx(struct ctx_list *list, struct process_info *process)
208 struct ctx_list *prev = list;
210 if (process == NULL) return;
216 if (list->ctx == process->s_context)
218 add_ctx(list, process);
222 if (list->ctx > process->s_context)
224 prev->next = insert_ctx(process->s_context, list);
225 add_ctx(prev->next, process);
233 prev->next = insert_ctx(process->s_context, NULL);
234 add_ctx(prev->next, process);
239 free_ctx(struct ctx_list *list)
241 struct ctx_list *prev;
243 for(;list != NULL; list = prev)
251 // open the process's status file to get the ctx number, and other stat
252 struct process_info *get_process_info(char *pid)
257 size_t idx, l=strlen(pid);
258 static struct process_info process;
260 process.s_context = vc_X_getctx(atoi(pid));
263 memcpy(buffer, "/proc/", 6); idx = 6;
264 memcpy(buffer+idx, pid, l); idx += l;
265 memcpy(buffer+idx, "/stat", 6);
267 // open the /proc/#/stat file
268 if ((fd = open(buffer, O_RDONLY, 0)) == -1)
270 // put the file in a buffer
271 if (read(fd, buffer, sizeof(buffer)) < 1)
276 p = strchr(buffer, ')'); // go after the PID (process_name)
277 for (idx = 0; idx<12 && *p!='\0'; ++p)
278 if ((*p)==' ') ++idx;
280 process.utime = strtol(p, &p, 10);
281 process.stime = strtol(p+1, &p, 10);
282 process.cutime = strtol(p+1, &p, 10);
283 process.cstime = strtol(p+1, &p, 10);
285 for (idx = 0; idx<5 && *p!='\0'; ++p)
286 if ((*p)==' ') ++idx;
288 process.start_time = strtol(p, &p, 10);
289 process.VmSize = strtol(p+1, &p, 10);
290 process.VmRSS = strtol(p+1, &p, 10);
298 fillUintZero(char *buf, unsigned long val, size_t cnt)
302 l = utilvserver_fmt_ulong(buf, val);
304 memmove(buf+cnt-l, buf, l);
305 memset(buf, '0', cnt-l);
313 shortenMem(char *buf, unsigned long val)
315 char const * SUFFIXES[] = { " ", "K", "M", "G", "T", "+" };
317 char const * suffix = "+";
319 unsigned int mod = 0;
321 for (i=0; i<6; ++i) {
323 suffix = SUFFIXES[i];
326 mod = 10*(val & 1023)/1024;
330 if (val >9999) val=9999;
331 if (val>=1000) mod=0;
333 l = utilvserver_fmt_ulong(tmp, val);
336 l += utilvserver_fmt_ulong(tmp+l, mod);
338 i = 7-l-strlen(suffix);
340 memcpy(buf+i, tmp, l);
341 memcpy(buf+i+l, suffix, strlen(suffix));
345 shortenTime(char *buf, uint64_t t)
350 unsigned long hh, mm, ss, ms;
363 ptr += utilvserver_fmt_ulong(ptr, t);
365 ptr += fillUintZero(ptr, hh, 2);
367 ptr += fillUintZero(ptr, mm, 2);
370 ptr += utilvserver_fmt_ulong(ptr, hh);
372 ptr += fillUintZero(ptr, mm, 2);
374 ptr += fillUintZero(ptr, ss, 2);
377 ptr += utilvserver_fmt_ulong(ptr, mm);
379 ptr += fillUintZero(ptr, ss, 2);
381 ptr += fillUintZero(ptr, ms, 2);
385 memcpy(buf+10-(ptr-tmp), tmp, ptr-tmp);
388 void showContexts(struct ctx_list *list)
390 uint64_t uptime = getUptime();
392 WRITE_MSG(1, "CTX PROC VSZ RSS userTIME sysTIME UPTIME NAME\n");
398 memset(buf, ' ', sizeof(buf));
399 l = utilvserver_fmt_ulong(buf, list->ctx);
400 l = utilvserver_fmt_ulong(tmp, list->process_count);
401 memcpy(buf+10-l, tmp, l);
403 shortenMem (buf+10, list->VmSize_total);
404 shortenMem (buf+17, list->VmRSS_total);
405 shortenTime(buf+24, list->utime_total);
406 shortenTime(buf+34, list->stime_total);
407 shortenTime(buf+44, uptime - list->start_time_oldest);
410 case 0 : strncpy(buf+55, "root server", 20); break;
411 case 1 : strncpy(buf+55, "monitoring server", 20); break;
415 vcCfgStyle cfgstyle = vcCFG_AUTO;
417 if ((cfgpath = vc_getVserverByCtx(list->ctx, &cfgstyle, 0))!=0 &&
418 (name = vc_getVserverName(cfgpath, cfgstyle))!=0)
419 strncpy(buf+55, name, 20);
432 int main(int argc, char **argv)
435 struct dirent *dir_entry;
439 process_name = argv[0];
442 if (strcmp(argv[1], "--help") ==0) showHelp(1, argv[0], 0);
443 if (strcmp(argv[1], "--version")==0) showVersion();
446 WRITE_MSG(2, "Unknown parameter, use '--help' for more information\n");
450 // do not include own stat
454 // try to switch in context 1
455 if (vc_new_s_context(1,0, 0) < 0)
457 perror("vc_new_s_context(#1,...)");
462 // create the fist...
463 my_ctx_list = insert_ctx(0, NULL);
464 // init with the default name for the context 0
465 strncpy(my_ctx_list->name, "root server", CTX_NAME_MAX_LEN);
467 // open the /proc dir
468 if ((proc_dir = opendir(PROC_DIR_NAME)) == NULL) {
473 chdir(PROC_DIR_NAME);
474 while ((dir_entry = readdir(proc_dir)) != NULL)
476 // select only process file
477 if (!isdigit(*dir_entry->d_name))
480 if (atoi(dir_entry->d_name) != my_pid)
481 count_ctx(my_ctx_list, get_process_info(dir_entry->d_name));
486 // output the ctx_list
487 showContexts(my_ctx_list);
490 free_ctx(my_ctx_list);