vserver-stat.c (21515B)
1 // $Id$ 2 3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // based on vserver-stat.cc by Guillaum Dallaire and Jacques Gelinas 5 // 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) 9 // any later version. 10 // 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. 15 // 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. 19 20 #ifdef HAVE_CONFIG_H 21 # include <config.h> 22 #endif 23 24 #include "vserver.h" 25 #include "util.h" 26 #include "internal.h" 27 #include "pathconfig.h" 28 29 #include <ensc_vector/vector.h> 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <fcntl.h> 35 #include <ctype.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <dirent.h> 39 #include <string.h> 40 #include <errno.h> 41 #include <syscall.h> 42 #include <time.h> 43 #include <stdbool.h> 44 #include <getopt.h> 45 #include <sys/param.h> 46 #include <sys/resource.h> 47 48 #define ENSC_WRAPPERS_DIRENT 1 49 #define ENSC_WRAPPERS_VSERVER 1 50 #define ENSC_WRAPPERS_FCNTL 1 51 #define ENSC_WRAPPERS_UNISTD 1 52 #include "wrappers.h" 53 54 #define PROC_DIR_NAME "/proc" 55 #define PROC_VIRT_DIR_NAME "/proc/virtual" 56 #define CTX_DIR_NAME "/var/run/vservers/" 57 #define CTX_NAME_MAX_LEN 50 58 59 int wrapper_exit_code = 1; 60 61 #ifndef AT_CLKTCK 62 #define AT_CLKTCK 17 /* frequency of times() */ 63 #endif 64 65 static unsigned long hertz =0x42; 66 static unsigned long pagesize=0x42; 67 68 struct XidData 69 { 70 xid_t xid; 71 unsigned int process_count; 72 uint64_t VmSize_total; 73 uint64_t VmRSS_total; 74 uint64_t start_time_oldest; 75 uint64_t stime_total, utime_total; 76 77 vcCfgStyle cfgstyle; 78 char const * name; 79 }; 80 81 struct process_info 82 { 83 long VmSize; // number of pages of virtual memory 84 long VmRSS; // resident set size from /proc/#/stat 85 uint64_t start_time; // start time of process -- milliseconds since 1-1-70 86 uint64_t stime, utime; // kernel & user-mode CPU time accumulated by process 87 uint64_t cstime, cutime; // cumulative time of process and reaped children 88 xid_t s_context; 89 }; 90 91 struct ArgInfo { 92 enum { tpUNSET, tpCTX, tpPID } type; 93 xid_t ctx; 94 pid_t pid; 95 unsigned int interval; 96 bool shutdown; 97 bool omit_init; 98 size_t argc; 99 char * const * argv; 100 }; 101 102 #define CMD_HELP 0x1000 103 #define CMD_VERSION 0x1001 104 105 struct option const 106 CMDLINE_OPTIONS[] = { 107 { "help", no_argument, 0, CMD_HELP }, 108 { "version", no_argument, 0, CMD_VERSION }, 109 { "sort", required_argument, 0, 'O' }, 110 {0,0,0,0} 111 }; 112 113 static void 114 showHelp(char const *cmd) 115 { 116 WRITE_MSG(1, "Usage: "); 117 WRITE_STR(1, cmd); 118 WRITE_MSG(1, 119 "\n" 120 "Show information about all active contexts.\n\n" 121 " CTX# Context number\n" 122 " #0 = root context\n" 123 " #1 = monitoring context\n" 124 " PROC QTY Quantity of processes in each context\n" 125 " VSZ Number of pages of virtual memory\n" 126 " RSS Resident set size\n" 127 " userTIME User-mode CPU time accumulated\n" 128 " sysTIME Kernel-mode CPU time accumulated\n" 129 " UPTIME Uptime/context\n" 130 " NAME Virtual server name\n" 131 "\n"); 132 exit(0); 133 } 134 135 static void 136 showVersion() 137 { 138 WRITE_MSG(1, 139 "vserver-stat " VERSION " -- show virtual context statistics\n" 140 "This program is part of " PACKAGE_STRING "\n\n" 141 "Copyright (C) 2003,2005 Enrico Scholz\n" 142 VERSION_COPYRIGHT_DISCLAIMER); 143 exit(0); 144 } 145 146 147 // return uptime (in ms) from /proc/uptime 148 static uint64_t 149 getUptime() 150 { 151 int fd; 152 char buffer[64]; 153 char * errptr; 154 size_t len; 155 uint64_t secs; 156 uint32_t msecs=0; 157 158 // open the /proc/uptime file 159 fd = EopenD("/proc/uptime", O_RDONLY, 0); 160 len = Eread(fd, buffer, sizeof buffer); 161 162 if (len==sizeof(buffer)) { 163 WRITE_MSG(2, "Too much data in /proc/uptime; aborting...\n"); 164 exit(1); 165 } 166 Eclose(fd); 167 168 while (len>0 && buffer[len-1]=='\n') --len; 169 buffer[len] = '\0'; 170 171 secs = strtol(buffer, &errptr, 10); 172 if (*errptr!='.') errptr = buffer; 173 else { 174 unsigned int mult; 175 switch (strlen(errptr+1)) { 176 case 0 : mult = 1000; break; 177 case 1 : mult = 100; break; 178 case 2 : mult = 10; break; 179 case 3 : mult = 1; break; 180 default : mult = 0; break; 181 } 182 msecs = strtol(errptr+1, &errptr, 10) * mult; 183 } 184 185 if ((*errptr!='\0' && *errptr!=' ') || errptr==buffer) { 186 WRITE_MSG(2, "Bad data in /proc/uptime\n"); 187 exit(1); 188 } 189 190 return secs*1000 + msecs; 191 } 192 193 static inline uint64_t 194 toMsec(uint64_t v) 195 { 196 return v*1000llu/hertz; 197 } 198 199 static int 200 cmpData(void const *xid_v, void const *map_v) 201 { 202 xid_t const * const xid = xid_v; 203 struct XidData const * const map = map_v; 204 int res = *xid - map->xid; 205 206 return res; 207 } 208 209 static void 210 registerXid(struct Vector *vec, struct process_info *process) 211 { 212 struct XidData *res; 213 214 res = Vector_search(vec, &process->s_context, cmpData); 215 if (res==0) { 216 res = Vector_insert(vec, &process->s_context, cmpData); 217 res->xid = process->s_context; 218 res->process_count = 0; 219 res->VmSize_total = 0; 220 res->VmRSS_total = 0; 221 res->utime_total = 0; 222 res->stime_total = 0; 223 res->start_time_oldest = process->start_time; 224 } 225 226 ++res->process_count; 227 res->VmSize_total += process->VmSize; 228 res->VmRSS_total += process->VmRSS; 229 res->utime_total += process->utime + process->cutime; 230 res->stime_total += process->stime + process->cstime; 231 232 res->start_time_oldest = MIN(res->start_time_oldest, process->start_time); 233 } 234 235 static void 236 registerXidVstat(struct Vector *vec, unsigned long xid_l) 237 { 238 xid_t xid = (xid_t) xid_l; 239 struct XidData *res; 240 struct vc_rlimit_stat limit[3]; 241 struct vc_virt_stat vstat; 242 struct vc_sched_info sched; 243 int cpu; 244 245 res = Vector_search(vec, &xid, cmpData); 246 if (res!=0) { 247 WRITE_MSG(2, "Duplicate xid found?!\n"); 248 return; 249 } 250 if (vc_virt_stat(xid, &vstat) == -1) { 251 perror("vc_virt_stat()"); 252 return; 253 } 254 if (vc_rlimit_stat(xid, RLIMIT_NPROC, &limit[0]) == -1) { 255 perror("vc_rlimit_stat(RLIMIT_NRPOC)"); 256 return; 257 } 258 if (vc_rlimit_stat(xid, RLIMIT_AS, &limit[1]) == -1) { 259 perror("vc_rlimit_stat(RLIMIT_AS)"); 260 return; 261 } 262 if (vc_rlimit_stat(xid, RLIMIT_RSS, &limit[2]) == -1) { 263 perror("vc_rlimit_stat(RLIMIT_RSS)"); 264 return; 265 } 266 267 res = Vector_insert(vec, &xid, cmpData); 268 res->xid = xid; 269 270 res->process_count = limit[0].value; 271 res->VmSize_total = limit[1].value * pagesize; 272 res->VmRSS_total = limit[2].value; 273 res->start_time_oldest= getUptime() - vstat.uptime/1000000; 274 275 res->utime_total = 0; 276 res->stime_total = 0; 277 // XXX: arbitrary CPU limit. 278 for (cpu = 0; cpu < 1024; cpu++) { 279 sched.cpu_id = cpu; 280 sched.bucket_id = 0; 281 if (vc_sched_info(xid, &sched) == -1) 282 break; 283 284 res->utime_total += sched.user_msec; 285 res->stime_total += sched.sys_msec; 286 } 287 } 288 289 static void 290 registerXidCgroups(struct Vector *vec, struct process_info *process) 291 { 292 xid_t xid = (xid_t) process->s_context; 293 struct XidData *res; 294 295 switch (vc_getXIDType(xid)) { 296 case vcTYPE_STATIC: 297 case vcTYPE_DYNAMIC: 298 break; 299 default: 300 return; 301 } 302 303 res = Vector_search(vec, &xid, cmpData); 304 if (res == 0) { 305 struct vc_rlimit_stat limit; 306 struct vc_virt_stat vstat; 307 struct vc_sched_info sched; 308 int cpu; 309 char vhi_name[65], 310 filename[128], 311 cgroup[129], 312 name[129], 313 buf[30]; 314 int fd; 315 ssize_t cgroup_len, name_len; 316 unsigned long long rss = 0; 317 char *endptr; 318 ssize_t len; 319 unsigned long long stime_total, utime_total; 320 int per_ss = 0; 321 FILE *fp; 322 323 324 if (vc_virt_stat(xid, &vstat) == -1) { 325 perror("vc_virt_stat()"); 326 return; 327 } 328 if (vc_rlimit_stat(xid, RLIMIT_NPROC, &limit) == -1) { 329 perror("vc_rlimit_stat(RLIMIT_NRPOC)"); 330 return; 331 } 332 if (vc_get_vhi_name(xid, vcVHI_CONTEXT, vhi_name, sizeof(vhi_name)) == -1) { 333 perror("vc_get_vhi_name(CONTEXT)"); 334 return; 335 } 336 337 if ((fd = open(DEFAULTCONFDIR "/cgroup/mnt", O_RDONLY)) == -1) { 338 if (utilvserver_isDirectory("/sys/fs/cgroup/memory", false)) { 339 strcpy(cgroup, "/sys/fs/cgroup/"); 340 cgroup_len = sizeof("/sys/fs/cgroup"); 341 per_ss = 1; 342 } else { 343 strcpy(cgroup, "/dev/cgroup/"); 344 cgroup_len = sizeof("/dev/cgroup"); 345 } 346 } 347 else { 348 cgroup_len = read(fd, cgroup, sizeof(cgroup)); 349 if (cgroup_len == -1) { 350 perror("read(cgroup/mnt)"); 351 return; 352 } 353 if (cgroup_len > 0) { 354 close(fd); 355 while (cgroup[cgroup_len - 1] == '\n' || cgroup[cgroup_len - 1] == '\r') 356 cgroup_len--; 357 cgroup[cgroup_len] = '/'; 358 cgroup_len += 1; 359 cgroup[cgroup_len] = 0; 360 } 361 } 362 363 if ((fd = open(DEFAULTCONFDIR "/cgroup/base", O_RDONLY)) != -1) { 364 len = read(fd, cgroup + cgroup_len, sizeof(cgroup) - cgroup_len); 365 if (len == -1) { 366 perror("read(cgroup/base)"); 367 return; 368 } 369 close(fd); 370 if (len > 0) { 371 while (cgroup[cgroup_len + len - 1] == '\n' || cgroup[cgroup_len + len - 1] == '\r') 372 len--; 373 cgroup_len += len; 374 if (cgroup[cgroup_len - 1] != '/') { 375 cgroup[cgroup_len] = '/'; 376 cgroup_len += 1; 377 } 378 cgroup[cgroup_len] = 0; 379 } 380 } 381 382 if (access(DEFAULTCONFDIR "/cgroup/per-ss", F_OK) == 0) 383 per_ss = 1; 384 385 len = strlen(vhi_name); 386 if ((len + sizeof("/cgroup/name")) >= sizeof(filename)) { 387 WRITE_MSG(2, "too long context name: "); 388 WRITE_STR(2, vhi_name); 389 WRITE_MSG(2, "\n"); 390 return; 391 } 392 strcpy(filename, vhi_name); 393 strcpy(filename + len, "/cgroup/name"); 394 395 if ((fd = open(filename, O_RDONLY)) == -1) { 396 char *dir = strrchr(vhi_name, '/'); 397 if (dir == NULL) { 398 WRITE_MSG(2, "invalid context name: "); 399 WRITE_STR(2, vhi_name); 400 WRITE_MSG(2, "\n"); 401 return; 402 } 403 name_len = strlen(dir); 404 if (name_len >= sizeof(name)) { 405 WRITE_MSG(2, "cgroup name too long: "); 406 WRITE_STR(2, dir); 407 WRITE_MSG(2, "\n"); 408 return; 409 } 410 strcpy(name, dir); 411 } 412 else { 413 name_len = read(fd, name, sizeof(name)); 414 if (name_len == -1) { 415 perror("read(cgroup/name)"); 416 return; 417 } 418 if (name_len > 0) { 419 while (name[name_len - 1] == '\n' || name[name_len - 1] == '\r') 420 name_len--; 421 name[name_len] = '\0'; 422 } 423 close(fd); 424 } 425 426 if ((cgroup_len + name_len + sizeof("/memory/memory.stat")) > sizeof(filename)) { 427 WRITE_MSG(2, "cgroup name too long: "); 428 WRITE_STR(2, cgroup); 429 WRITE_MSG(2, "\n"); 430 return; 431 } 432 snprintf(filename, sizeof(filename), "%s%s%s/memory.stat", cgroup, (per_ss ? "/memory" : ""), name); 433 434 if ((fp = fopen(filename, "r")) == NULL) 435 perror("open(memory.stat)"); 436 else { 437 unsigned long long _rss = 0, _mapped_file = 0; 438 while (fgets(buf, sizeof(buf), fp) != NULL) { 439 if (strncmp(buf, "rss ", 4) == 0) { 440 if ((_rss = strtoull(buf + 4, &endptr, 0)) == ULLONG_MAX || 441 (*endptr != '\n' && *endptr != '\0')) { 442 perror("strtoull(memory.stat:rss)"); 443 return; 444 } 445 } 446 else if (strncmp(buf, "mapped_file ", 12) == 0) { 447 if ((_mapped_file = strtoull(buf + 12, &endptr, 0)) == ULLONG_MAX || 448 (*endptr != '\n' && *endptr != '\0')) { 449 perror("strtoull(memory.stat:mapped_file)"); 450 return; 451 } 452 } 453 } 454 rss = _rss + _mapped_file; 455 } 456 457 snprintf(filename, sizeof(filename), "%s%s%s/cpuacct.stat", cgroup, (per_ss ? "/cpuacct" : ""), name); 458 459 if ((fd = open(filename, O_RDONLY)) == -1) { 460 utime_total = 0; 461 stime_total = 0; 462 // XXX: arbitrary CPU limit. 463 for (cpu = 0; cpu < 1024; cpu++) { 464 sched.cpu_id = cpu; 465 sched.bucket_id = 0; 466 if (vc_sched_info(xid, &sched) == -1) 467 break; 468 469 utime_total += sched.user_msec; 470 stime_total += sched.sys_msec; 471 } 472 } 473 else { 474 if (read(fd, buf, sizeof(buf)) == -1) { 475 perror("read(cpuacct.stat)"); 476 return; 477 } 478 close(fd); 479 480 if (sscanf(buf, "user %llu\nsystem %llu\n", &utime_total, &stime_total) != 2) { 481 perror("sscanf(cpuacct.stat)"); 482 return; 483 } 484 } 485 486 res = Vector_insert(vec, &xid, cmpData); 487 res->xid = xid; 488 489 res->process_count = limit.value; 490 res->VmRSS_total = rss / 4096; 491 res->start_time_oldest= getUptime() - vstat.uptime/1000000; 492 493 res->utime_total = toMsec(utime_total); 494 res->stime_total = toMsec(stime_total); 495 } 496 497 res->VmSize_total += process->VmSize; 498 } 499 500 501 // shamelessly stolen from procps... 502 static unsigned long 503 find_elf_note(unsigned long findme){ 504 unsigned long *ep = (unsigned long *)environ; 505 while(*ep++); 506 while(*ep){ 507 if(ep[0]==findme) return ep[1]; 508 ep+=2; 509 } 510 return (unsigned long)(-1); 511 } 512 513 static void initHertz() __attribute__((__constructor__)); 514 static void initPageSize() __attribute__((__constructor__)); 515 516 static void 517 initHertz() 518 { 519 hertz = find_elf_note(AT_CLKTCK); 520 if (hertz==(unsigned long)(-1)) 521 hertz = sysconf(_SC_CLK_TCK); 522 } 523 524 static void 525 initPageSize() 526 { 527 pagesize = sysconf(_SC_PAGESIZE); 528 } 529 530 // open the process's status file to get the ctx number, and other stat 531 struct process_info * 532 get_process_info(char *pid) 533 { 534 int fd; 535 char buffer[1024]; 536 char *p; 537 size_t idx, l=strlen(pid); 538 static struct process_info process; 539 540 #if 1 541 process.s_context = vc_get_task_xid(atoi(pid)); 542 #else 543 # warning Compiling in debug-code 544 process.s_context = random()%6; 545 #endif 546 547 if (process.s_context==VC_NOCTX) { 548 int err=errno; 549 if (err != ESRCH) { 550 WRITE_MSG(2, "vc_get_task_xid("); 551 WRITE_STR(2, pid); 552 WRITE_MSG(2, "): "); 553 WRITE_STR(2, strerror(err)); 554 WRITE_MSG(2, "\n"); 555 } 556 557 return 0; 558 } 559 560 memcpy(buffer, "/proc/", 6); idx = 6; 561 memcpy(buffer+idx, pid, l); idx += l; 562 memcpy(buffer+idx, "/stat", 6); 563 564 // open the /proc/#/stat file 565 if ((fd = open(buffer, O_RDONLY, 0)) == -1) 566 return NULL; 567 // put the file in a buffer 568 if (read(fd, buffer, sizeof(buffer)) < 1) 569 return NULL; 570 571 close(fd); 572 573 p = strchr(buffer, ')'); // go after the PID (process_name) 574 for (idx = 0; idx<12 && *p!='\0'; ++p) 575 if ((*p)==' ') ++idx; 576 577 process.utime = toMsec(strtol(p, &p, 10)); 578 process.stime = toMsec(strtol(p+1, &p, 10)); 579 process.cutime = toMsec(strtol(p+1, &p, 10)); 580 process.cstime = toMsec(strtol(p+1, &p, 10)); 581 582 for (idx = 0; idx<5 && *p!='\0'; ++p) 583 if ((*p)==' ') ++idx; 584 585 process.start_time = toMsec(strtol(p, &p, 10)); 586 process.VmSize = strtol(p+1, &p, 10); 587 process.VmRSS = strtol(p+1, &p, 10); 588 589 //printf("pid=%s, start_time=%llu\n", pid, process.start_time); 590 return &process; 591 } 592 593 static size_t 594 fillUintZero(char *buf, unsigned long val, size_t cnt) 595 { 596 size_t l; 597 598 l = utilvserver_fmt_ulong(buf, val); 599 if (l<cnt) { 600 memmove(buf+cnt-l, buf, l); 601 memset(buf, '0', cnt-l); 602 } 603 buf[cnt] = '\0'; 604 605 return cnt; 606 } 607 608 static void 609 shortenMem(char *buf, unsigned long val) 610 { 611 char const * SUFFIXES[] = { " ", "K", "M", "G", "T", "+" }; 612 char tmp[16]; 613 char const * suffix = "+"; 614 size_t i, l; 615 unsigned int mod = 0; 616 617 for (i=0; i<6; ++i) { 618 if (val<1000) { 619 suffix = SUFFIXES[i]; 620 break; 621 } 622 mod = 10*(val & 1023)/1024; 623 val >>= 10; 624 } 625 626 if (val >9999) val=9999; 627 if (val>=1000) mod=0; 628 629 l = utilvserver_fmt_ulong(tmp, val); 630 if (mod!=0) { 631 tmp[l++] = '.'; 632 l += utilvserver_fmt_ulong(tmp+l, mod); 633 } 634 i = 7-l-strlen(suffix); 635 636 memcpy(buf+i, tmp, l); 637 memcpy(buf+i+l, suffix, strlen(suffix)); 638 } 639 640 static void 641 shortenTime(char *buf, uint64_t t) 642 { 643 char tmp[32]; 644 char *ptr = tmp; 645 646 unsigned long hh, mm, ss, ms; 647 648 ms = t % 1000; 649 t /= 1000; 650 651 ss = t%60; 652 t /= 60; 653 mm = t%60; 654 t /= 60; 655 hh = t%24; 656 t /= 24; 657 658 if (t>999*999) { 659 memcpy(ptr, "INVALID", 7); 660 ptr += 7; 661 } 662 else if (t>999) { 663 ptr += utilvserver_fmt_ulong(ptr, t/365); 664 *ptr++ = 'y'; 665 ptr += fillUintZero(ptr, t%365, 2); 666 *ptr++ = 'd'; 667 ptr += fillUintZero(ptr, hh, 2); 668 } 669 else if (t>0) { 670 ptr += utilvserver_fmt_ulong(ptr, t); 671 *ptr++ = 'd'; 672 ptr += fillUintZero(ptr, hh, 2); 673 *ptr++ = 'h'; 674 ptr += fillUintZero(ptr, mm, 2); 675 } 676 else if (hh>0) { 677 ptr += utilvserver_fmt_ulong(ptr, hh); 678 *ptr++ = 'h'; 679 ptr += fillUintZero(ptr, mm, 2); 680 *ptr++ = 'm'; 681 ptr += fillUintZero(ptr, ss, 2); 682 } 683 else { 684 ptr += utilvserver_fmt_ulong(ptr, mm); 685 *ptr++ = 'm'; 686 ptr += fillUintZero(ptr, ss, 2); 687 *ptr++ = 's'; 688 ptr += fillUintZero(ptr, ms, 2); 689 } 690 691 *ptr = ' '; 692 memcpy(buf+10-(ptr-tmp), tmp, ptr-tmp); 693 } 694 695 static char * 696 formatName(char *dst, vcCfgStyle style, char const *name) 697 { 698 size_t len; 699 700 if (name==0) name = ""; 701 len = strlen(name); 702 703 switch (style) { 704 case vcCFG_LEGACY : 705 len = MIN(len, 18); 706 *dst++ = '['; 707 memcpy(dst, name, len); 708 dst += len; 709 *dst++ = ']'; 710 break; 711 712 default : 713 len = MIN(len, 20); 714 memcpy(dst, name, len); 715 dst += len; 716 break; 717 } 718 719 return dst; 720 } 721 722 static void 723 showContexts(struct Vector const *vec) 724 { 725 uint64_t uptime = getUptime(); 726 struct XidData const * ptr = Vector_begin_const(vec); 727 struct XidData const * const end_ptr = Vector_end_const(vec); 728 729 730 WRITE_MSG(1, "CTX PROC VSZ RSS userTIME sysTIME UPTIME NAME\n"); 731 for (; ptr<end_ptr; ++ptr) { 732 char buf[sizeof(xid_t)*3 + 512]; 733 char tmp[sizeof(int)*3 + 2]; 734 size_t l; 735 736 memset(buf, ' ', sizeof(buf)); 737 l = utilvserver_fmt_long(buf, ptr->xid); 738 l = utilvserver_fmt_long(tmp, ptr->process_count); 739 memcpy(buf+10-l, tmp, l); 740 741 shortenMem (buf+10, ptr->VmSize_total); 742 shortenMem (buf+17, ptr->VmRSS_total*pagesize); 743 shortenTime(buf+24, ptr->utime_total); 744 shortenTime(buf+34, ptr->stime_total); 745 //printf("%llu, %llu\n", uptime, ptr->start_time_oldest); 746 shortenTime(buf+44, uptime - ptr->start_time_oldest); 747 748 formatName(buf+55, ptr->cfgstyle, ptr->name)[0] = '\0'; 749 750 Vwrite(1, buf, strlen(buf)); 751 Vwrite(1, "\n", 1); 752 } 753 } 754 755 static void 756 fillName(void *obj_v, void UNUSED * a) 757 { 758 struct XidData * obj = obj_v; 759 760 switch (obj->xid) { 761 case 0 : 762 obj->cfgstyle = vcCFG_NONE; 763 obj->name = strdup("root server"); 764 break; 765 766 case 1 : 767 obj->cfgstyle = vcCFG_NONE; 768 obj->name = strdup("monitoring server"); 769 break; 770 771 default : { 772 char * cfgpath; 773 774 obj->cfgstyle = vcCFG_AUTO; 775 776 if ((cfgpath = vc_getVserverByCtx(obj->xid, &obj->cfgstyle, 0))==0 || 777 (obj->name = vc_getVserverName(cfgpath, obj->cfgstyle))==0) { 778 obj->name = 0; 779 obj->cfgstyle = vcCFG_NONE; 780 } 781 782 free(cfgpath); 783 784 break; 785 } 786 } 787 } 788 789 static void UNUSED 790 freeXidData(void *obj_v, void UNUSED * a) 791 { 792 struct XidData * obj = obj_v; 793 794 free(const_cast(char *)(obj->name)); 795 } 796 797 int main(int argc, char **argv) 798 { 799 DIR * proc_dir; 800 struct dirent* dir_entry; 801 pid_t my_pid; 802 struct Vector xid_data; 803 char const * errptr; 804 805 while (1) { 806 int c = getopt_long(argc, argv, "+O:", CMDLINE_OPTIONS, 0); 807 if (c==-1) break; 808 809 switch (c) { 810 case CMD_HELP : showHelp(argv[0]); 811 case CMD_VERSION : showVersion(); 812 case 'O' : break; 813 default : 814 WRITE_MSG(2, "Try '"); 815 WRITE_STR(2, argv[0]); 816 WRITE_MSG(2, " --help' for more information.\n"); 817 return EXIT_FAILURE; 818 break; 819 } 820 } 821 822 if (optind!=argc) { 823 WRITE_MSG(2, "Unknown parameter, use '--help' for more information\n"); 824 return EXIT_FAILURE; 825 } 826 827 if (hertz==0x42) initHertz(); 828 if (pagesize==0x42) initPageSize(); 829 830 Vector_init(&xid_data, sizeof(struct XidData)); 831 832 if (vc_isSupported(vcFEATURE_VSTAT)) { 833 unsigned long xid; 834 Echdir(PROC_VIRT_DIR_NAME); 835 proc_dir = Eopendir("."); 836 while ((dir_entry = readdir(proc_dir)) != NULL) { 837 if (!isNumberUnsigned(dir_entry->d_name, &xid, false)) 838 continue; 839 840 registerXidVstat(&xid_data, xid); 841 } 842 closedir(proc_dir); 843 } 844 else { 845 void (*handler)(struct Vector *vec, struct process_info *process); 846 847 my_pid = getpid(); 848 849 if (!switchToWatchXid(&errptr)) { 850 perror(errptr); 851 exit(1); 852 } 853 854 if (access("/proc/uptime",R_OK)==-1 && errno==ENOENT) 855 WRITE_MSG(2, 856 "WARNING: can not access /proc/uptime. Usually, this is caused by\n" 857 " procfs-security. Please read the FAQ for more details\n" 858 " http://linux-vserver.org/Proc-Security\n"); 859 860 if (vc_isSupported(vcFEATURE_MEMCG)) 861 handler = registerXidCgroups; 862 else 863 handler = registerXid; 864 865 Echdir(PROC_DIR_NAME); 866 proc_dir = Eopendir("."); 867 while ((dir_entry = readdir(proc_dir)) != NULL) 868 { 869 // select only process file 870 if (!isdigit(*dir_entry->d_name)) 871 continue; 872 873 if (atoi(dir_entry->d_name) != my_pid) { 874 struct process_info * info = get_process_info(dir_entry->d_name); 875 if (info) 876 handler(&xid_data, info); 877 } 878 } 879 closedir(proc_dir); 880 } 881 882 Vector_foreach(&xid_data, fillName, 0); 883 884 // output the ctx_list 885 showContexts(&xid_data); 886 887 #ifndef NDEBUG 888 Vector_foreach(&xid_data, freeXidData, 0); 889 Vector_free(&xid_data); 890 #endif 891 892 return 0; 893 }