// 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 <syscall.h>
#include <time.h>
#include <stdbool.h>
+#include <sys/param.h>
#define ENSC_WRAPPERS_DIRENT 1
#define ENSC_WRAPPERS_VSERVER 1
int wrapper_exit_code = 1;
+#ifndef AT_CLKTCK
+#define AT_CLKTCK 17 /* frequency of times() */
+#endif
+
+static unsigned long hertz=0x42;
+
struct XidData
{
xid_t xid;
int process_count;
int VmSize_total;
int VmRSS_total;
- long start_time_oldest;
- long stime_total, utime_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;
};
struct ArgInfo {
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;
}
static int
res->VmRSS_total = 0;
res->utime_total = 0;
res->stime_total = 0;
- res->start_time_oldest = 0;
+ res->start_time_oldest = process->start_time;
}
++res->process_count;
res->utime_total += process->utime + process->cutime;
res->stime_total += process->stime + process->cstime;
- if (res->start_time_oldest == 0) // first entry
- res->start_time_oldest = process->start_time;
- else
- if (res->start_time_oldest > process->start_time)
- res->start_time_oldest = process->start_time;
+ res->start_time_oldest = MIN(res->start_time_oldest, process->start_time);
+}
+
+static inline uint64_t
+toMsec(uint64_t v)
+{
+ return v*1000llu/hertz;
+}
+
+
+// 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];
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;
}
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);
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);
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 (ptr->xid) {
- case 0 : strncpy(buf+55, "root server", 20); break;
- case 1 : strncpy(buf+55, "monitoring server", 20); break;
+ case 0 : strcpy(buf+55, "root server" ); break;
+ case 1 : strcpy(buf+55, "monitoring server"); break;
default : {
char * name = 0;
char * cfgpath = 0;
vcCfgStyle cfgstyle = vcCFG_AUTO;
- if ((cfgpath = vc_getVserverByCtx(ptr->xid, &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);
}
}
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);
-#else
-# warning Compiling in debug-code
-#endif
+ 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));
if (!isdigit(*dir_entry->d_name))
continue;
- if (atoi(dir_entry->d_name) != my_pid)
- registerXid(&xid_data, 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);