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
39 #include <sys/types.h>
47 #define PROC_DIR_NAME "/proc"
48 #define CTX_DIR_NAME "/var/run/vservers/"
49 #define CTX_NAME_MAX_LEN 50
51 int call_new_s_context(int nbctx, int ctxs[], int remove_cap, int flags);
60 long start_time_oldest;
61 long stime_total, utime_total;
62 char name[CTX_NAME_MAX_LEN];
63 struct ctx_list *next;
68 long VmSize; // number of pages of virtual memory
69 long VmRSS; // resident set size from /proc/#/stat
70 long start_time; // start time of process -- seconds since 1-1-70
71 long stime, utime; // kernel & user-mode CPU time accumulated by process
72 long cstime, cutime; // cumulative time of process and reaped children
80 fprintf(stderr, "%s: from vserver kit version %s\n", process_name, VERSION);
81 fprintf(stderr, "(no argument needed)\n\n");
82 fprintf(stderr, "Show informations about all the active context.\n\n");
83 fprintf(stderr, " CTX# Context number\n");
84 fprintf(stderr, " #0 = root context\n");
85 fprintf(stderr, " #1 = monitoring context\n");
86 fprintf(stderr, " PROC QTY Quantity of processes in each context\n");
87 fprintf(stderr, " VSZ Number of pages of virtual memory\n");
88 fprintf(stderr, " RSS Resident set size\n");
89 fprintf(stderr, " userTIME User-mode CPU time accumulated\n");
90 fprintf(stderr, " sysTIME Kernel-mode CPU time accumulated\n");
91 fprintf(stderr, " UPTIME Uptime/context\n");
92 fprintf(stderr, " NAME Virtual server name\n");
93 fprintf(stderr, "\n");
97 // return uptime (in ms) from /proc/uptime
104 // open the /proc/uptime file
105 if ((fd = open("/proc/uptime", O_RDONLY, 0)) == -1)
108 if (read(fd, buffer, sizeof(buffer)) < 1)
113 if (sscanf(buffer, "%lf", &up) < 1)
115 fprintf(stderr, "%s: bad data in /proc/uptime\n", process_name);
122 // insert a new record to the list
123 struct ctx_list *insert_ctx(int ctx, struct ctx_list *next)
125 struct ctx_list *new;
127 new = (struct ctx_list *)malloc(sizeof(struct ctx_list));
129 new->process_count = 0;
130 new->VmSize_total = 0;
131 new->VmRSS_total = 0;
132 new->utime_total = 0;
133 new->stime_total = 0;
134 new->start_time_oldest = 0;
141 // find the ctx record with the ctx number
142 struct ctx_list *find_ctx(struct ctx_list *list, int ctx)
144 // very simple search engine...
148 if (list->ctx == ctx)
157 // compute the process info into the list
158 void add_ctx(struct ctx_list *list, struct process_info *process)
160 list->process_count ++;
161 list->VmSize_total += process->VmSize;
162 list->VmRSS_total += process->VmRSS;
163 list->utime_total += process->utime + process->cutime;
164 list->stime_total += process->stime + process->cstime;
166 if (list->start_time_oldest == 0) // first entry
167 list->start_time_oldest = process->start_time;
169 if (list->start_time_oldest > process->start_time)
170 list->start_time_oldest = process->start_time;
173 // increment the count number in the ctx record using ctx number
174 void count_ctx(struct ctx_list *list, struct process_info *process)
176 struct ctx_list *prev = list;
178 if (process == NULL) return;
184 if (list->ctx == process->s_context)
186 add_ctx(list, process);
190 if (list->ctx > process->s_context)
192 prev->next = insert_ctx(process->s_context, list);
193 add_ctx(prev->next, process);
201 prev->next = insert_ctx(process->s_context, NULL);
202 add_ctx(prev->next, process);
206 void free_ctx(struct ctx_list *list)
208 struct ctx_list *prev;
210 for(;list != NULL; list = prev)
218 Read the vserver description
220 static void read_description(
221 const char *name, // Vserver name
227 snprintf (conf,sizeof(conf)-1,"/etc/vservers/%s.conf",name);
228 fin = fopen (conf,"r");
231 while (fgets(line,sizeof(line)-1,fin)!=NULL){
234 while (isspace(*pt)) pt++;
235 if (strncmp(pt,"Description:",12)==0){
238 while (isspace(*pt)) pt++;
240 last = strlen(descrip)-1;
241 if (last >=0 && descrip[last] == '\n'){
242 descrip[last] = '\0';
251 // show the ctx_list with name from /var/run/servers/*.ctx
252 void show_ctx(struct ctx_list *list)
254 // fill the ctx_list using the /var/run/servers/*.ctx file(s)
255 __extension__ int bind_ctx_name(struct ctx_list *list)
257 // fetch the context number in /var/run/vservers/'filename'
258 int fetch_ctx_number(char *filename)
265 if ((fd = open(filename, O_RDONLY, 0)) == -1)
267 // put the file in a small buffer
268 if (read(fd, buf, sizeof(buf)) < 1)
273 sscanf(buf, "S_CONTEXT=%d", &ctx);
277 /* begin bind_ctx_name */
280 struct dirent *dir_entry;
282 char ctx_name[CTX_NAME_MAX_LEN];
283 struct ctx_list *ctx;
286 // open the /var/run/vservers directory
287 if ((ctx_dir = opendir(CTX_DIR_NAME)) == NULL)
289 fprintf(stderr, "%s: in openning %s: %s\n", process_name, CTX_DIR_NAME, strerror(errno));
294 while ((dir_entry = readdir(ctx_dir)) != NULL)
296 strncpy(ctx_name, dir_entry->d_name, sizeof(ctx_name));
297 p = strstr(ctx_name, ".ctx");
298 if (p != NULL) // make sure that it is a .ctx file..
300 *p = '\0'; // remove the .ctx in the file name
301 if ((ctx_number = fetch_ctx_number(dir_entry->d_name)) > 1)
303 if ((ctx = find_ctx(list, ctx_number)) != NULL)
304 strncpy(ctx->name, ctx_name, CTX_NAME_MAX_LEN);
307 // else fprintf(stderr, "invalid file %s in %s\n", dir_entry->d_name, CTX_DIR_NAME);
313 __extension__ char *convert_time(unsigned t, char *str)
315 unsigned hh, mm, ss, ms;
327 if (t > 0) // day > 0
329 snprintf(str, 25, "%3.ud%02uh%02u", t, (hh%12) ? hh%12 : 12, mm);
333 if (hh > 0) // hour > 0
334 snprintf(str, 25, " %2.uh%02um%02u", hh, mm, ss);
337 snprintf(str, 25, " %2.um%02u.%02u", mm, ss, ms);
343 __extension__ char *convert_mem(unsigned long total, char *str)
348 snprintf(str, 25, "%luB", total);
352 total >>= 10; // kByte
355 snprintf(str, 25, "%lukB", total);
359 total >>= 10; // MByte
362 snprintf(str, 25, "%luMB", total);
366 total >>= 10; // GByte
369 snprintf(str, 25, "%luGB", total);
372 total >>= 10; // TByte
373 snprintf(str, 25, "%luTB", total);
378 char utime[25], stime[25], ctx_uptime[25];
379 char vmsize[25], vmrss[25];
380 long uptime = get_uptime();
382 // now we have all the active context, fetch the name
383 // from /var/run/vservers/*.ctx
386 printf("CTX PROC VSZ RSS userTIME sysTIME UPTIME NAME DESCRIPTION\n");
391 strncpy(list->name, "monitoring server", CTX_NAME_MAX_LEN);
393 read_description (list->name,descrip);
395 printf("%-4d %4d %6s %6s %9s %9s %9s %-8s %s\n", list->ctx, list->process_count,
396 convert_mem(list->VmSize_total, vmsize), convert_mem(list->VmRSS_total, vmrss),
397 convert_time(list->utime_total, utime), convert_time(list->stime_total, stime), convert_time(uptime - list->start_time_oldest, ctx_uptime)
398 , list->name,descrip);
403 // open the process's status file to get the ctx number, and other stat
404 struct process_info *get_process_info(char *pid)
409 static struct process_info process;
411 // open the proc/#/status file
412 snprintf(buffer, sizeof(buffer), "/proc/%s/status", pid);
413 if ((fd = open(buffer, O_RDONLY, 0)) == -1)
415 // put the file in a buffer
416 if (read(fd, buffer, sizeof(buffer)) < 1)
421 // find the s_context entry
422 if ((p = strstr(buffer, "s_context:")) == NULL)
425 sscanf(p, "s_context: %d", &process.s_context);
427 // open the /proc/#/stat file
428 snprintf(buffer, sizeof(buffer), "/proc/%s/stat", pid);
429 if ((fd = open(buffer, O_RDONLY, 0)) == -1)
431 // put the file in a buffer
432 if (read(fd, buffer, sizeof(buffer)) < 1)
437 p = strchr(buffer, ')'); // go after the PID (process_name)
440 "%*s %*s %*s %*s %*s "
441 "%*s %*s %*s %*s %*s %ld %ld "
442 "%ld %ld %*s %*s %*s %*s "
444 "%ld ", &process.utime, &process.stime,
445 &process.cutime, &process.cstime,
447 &process.VmSize, &process.VmRSS);
452 int main(int argc, char **argv)
455 struct dirent *dir_entry;
457 static int ctx1[]={1};
460 process_name = argv[0];
468 // do not include own stat
471 // try to switch in context 1
472 if (call_new_s_context(1,ctx1, 0, 0) < 0)
474 fprintf(stderr, "%s: unable to switch in context security #1\n", process_name);
478 // create the fist...
479 my_ctx_list = insert_ctx(0, NULL);
480 // init with the default name for the context 0
481 strncpy(my_ctx_list->name, "root server", CTX_NAME_MAX_LEN);
483 // open the /proc dir
484 if ((proc_dir = opendir(PROC_DIR_NAME)) == NULL)
486 fprintf(stderr, "%s: %s\n", process_name, strerror(errno));
490 chdir(PROC_DIR_NAME);
491 while ((dir_entry = readdir(proc_dir)) != NULL)
493 // select only process file
494 if (!isdigit(*dir_entry->d_name))
497 if (atoi(dir_entry->d_name) != my_pid)
498 count_ctx(my_ctx_list, get_process_info(dir_entry->d_name));
503 // output the ctx_list
504 show_ctx(my_ctx_list);
507 free_ctx(my_ctx_list);