1003 lines
29 KiB
C
1003 lines
29 KiB
C
/*
|
|
* snmpps.c - display process table on a network entity via SNMP.
|
|
*
|
|
*/
|
|
|
|
/* Portions of this file are subject to the following copyright(s). See
|
|
* the Net-SNMP's COPYING file for more details and other copyrights
|
|
* that may apply:
|
|
*/
|
|
/***********************************************************************
|
|
Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the name of CMU not be
|
|
used in advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
|
|
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
|
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
SOFTWARE.
|
|
******************************************************************/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
|
|
#if HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#if HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#if TIME_WITH_SYS_TIME
|
|
# include <sys/time.h>
|
|
# include <time.h>
|
|
#else
|
|
# if HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
# else
|
|
# include <time.h>
|
|
# endif
|
|
#endif
|
|
#if HAVE_SYS_SELECT_H
|
|
#include <sys/select.h>
|
|
#endif
|
|
#if HAVE_NETDB_H
|
|
#include <netdb.h>
|
|
#endif
|
|
#if HAVE_ARPA_INET_H
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
#if HAVE_NCURSES_CURSES_H
|
|
#include <ncurses/curses.h>
|
|
#elif HAVE_CURSES_H
|
|
#include <curses.h>
|
|
#endif
|
|
#include <signal.h>
|
|
|
|
#include <net-snmp/net-snmp-includes.h>
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
fprintf(stderr, "Usage: snmpps [-Cp] [-Ca] [-C m | n | t] AGENT");
|
|
snmp_parse_args_usage(stderr);
|
|
fprintf(stderr, "\n\n");
|
|
snmp_parse_args_descriptions(stderr);
|
|
fprintf(stderr, "\nsnmpps options:\n");
|
|
fprintf(stderr,
|
|
"\t-Cp\tShow hrSWRunPath instead of hrSWRunName\n");
|
|
fprintf(stderr,
|
|
"\t-Ca\tShow hrSWRunParameters in addition to hrSWRunName/Path\n");
|
|
fprintf(stderr,
|
|
"\t-Ct\tSort processes according to CPU time used\n");
|
|
fprintf(stderr,
|
|
"\t-Cm\tSort processes according to memory usage\n");
|
|
fprintf(stderr,
|
|
"\t-Cn\tSort processes by PID number (default)\n");
|
|
}
|
|
|
|
int command_args = 0,
|
|
command_path = 0;
|
|
int topsort = 'c';
|
|
char *progname;
|
|
|
|
static void
|
|
optProc(int argc, char *const *argv, int opt)
|
|
{
|
|
switch (opt) {
|
|
case 'C':
|
|
while (*optarg) {
|
|
switch (*optarg++) {
|
|
case 'a':
|
|
command_args = 1;
|
|
break;
|
|
case 'p':
|
|
command_path = 1;
|
|
break;
|
|
case 'm':
|
|
topsort = 'm';
|
|
break;
|
|
case 'n':
|
|
topsort = 'n';
|
|
break;
|
|
case 't':
|
|
topsort = 't';
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr,
|
|
"Unknown flag passed to -C: %c\n", optarg[-1]);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct hrSWRunTable {
|
|
u_long hrSWRunIndex;
|
|
char *hrSWRunName;
|
|
char *hrSWRunPath;
|
|
char *hrSWRunParameters;
|
|
u_long hrSWRunID;
|
|
u_long hrSWRunType;
|
|
u_long hrSWRunStatus;
|
|
u_long hrSWRunPerfMem;
|
|
u_long hrSWRunPerfCPU;
|
|
u_long hrSWRunPerfCPUInc;
|
|
};
|
|
|
|
struct cpuStats {
|
|
u_long user;
|
|
u_long nice;
|
|
u_long system;
|
|
u_long idle;
|
|
u_long wait;
|
|
u_long kernel;
|
|
u_long intr;
|
|
u_long softintr;
|
|
u_long steal;
|
|
u_long guest;
|
|
u_long guestnice;
|
|
};
|
|
|
|
struct memStats {
|
|
u_long totalSwap;
|
|
u_long availSwap;
|
|
u_long totalReal;
|
|
u_long availReal;
|
|
u_long shared;
|
|
u_long buffer;
|
|
u_long cached;
|
|
};
|
|
|
|
struct laStats {
|
|
u_long la1;
|
|
u_long la5;
|
|
u_long la15;
|
|
};
|
|
|
|
|
|
int
|
|
add(netsnmp_pdu *pdu, const char *mibnodename,
|
|
oid * index, size_t indexlen)
|
|
{
|
|
oid base[MAX_OID_LEN];
|
|
size_t base_length = MAX_OID_LEN;
|
|
|
|
memset(base, 0, MAX_OID_LEN * sizeof(oid));
|
|
|
|
if (!snmp_parse_oid(mibnodename, base, &base_length)) {
|
|
snmp_perror(mibnodename);
|
|
fprintf(stderr, "couldn't find mib node %s, giving up\n",
|
|
mibnodename);
|
|
#if HAVE_CURSES_H
|
|
endwin();
|
|
#endif
|
|
exit(1);
|
|
}
|
|
|
|
if (index && indexlen) {
|
|
memcpy(&(base[base_length]), index, indexlen * sizeof(oid));
|
|
base_length += indexlen;
|
|
}
|
|
DEBUGMSGTL(("add", "created: "));
|
|
DEBUGMSGOID(("add", base, base_length));
|
|
DEBUGMSG(("add", "\n"));
|
|
snmp_add_null_var(pdu, base, base_length);
|
|
|
|
return base_length;
|
|
}
|
|
|
|
netsnmp_variable_list *
|
|
collect_procs(netsnmp_session *ss, netsnmp_pdu *pdu,
|
|
oid * base, size_t base_length)
|
|
{
|
|
netsnmp_pdu *response;
|
|
int running = 1;
|
|
netsnmp_variable_list *saved = NULL, **vlpp = &saved;
|
|
int status;
|
|
|
|
while (running) {
|
|
/*
|
|
* gotta catch em all, gotta catch em all!
|
|
*/
|
|
status = snmp_synch_response(ss, pdu, &response);
|
|
if (status != STAT_SUCCESS || !response) {
|
|
snmp_sess_perror(progname, ss);
|
|
#if HAVE_CURSES_H
|
|
endwin();
|
|
#endif
|
|
exit(1);
|
|
}
|
|
if (response->errstat != SNMP_ERR_NOERROR) {
|
|
fprintf(stderr, "%s: Error in packet: %s\n", progname,
|
|
snmp_errstring(response->errstat));
|
|
#if HAVE_CURSES_H
|
|
endwin();
|
|
#endif
|
|
exit(1);
|
|
}
|
|
if (snmp_oid_compare(response->variables->name,
|
|
SNMP_MIN(base_length,
|
|
response->variables->name_length),
|
|
base, base_length) != 0)
|
|
running = 0;
|
|
else if (response->variables->type == SNMP_NOSUCHINSTANCE ||
|
|
response->variables->type == SNMP_NOSUCHOBJECT ||
|
|
response->variables->type == SNMP_ENDOFMIBVIEW)
|
|
running = 0;
|
|
else {
|
|
/*
|
|
* get response
|
|
*/
|
|
*vlpp = response->variables;
|
|
(*vlpp)->next_variable = NULL; /* shouldn't be any, but just in case */
|
|
|
|
/*
|
|
* create the next request
|
|
*/
|
|
pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
|
|
snmp_add_null_var(pdu, (*vlpp)->name, (*vlpp)->name_length);
|
|
|
|
/*
|
|
* finish loop setup
|
|
*/
|
|
vlpp = &((*vlpp)->next_variable);
|
|
response->variables = NULL; /* ahh, forget about it */
|
|
}
|
|
snmp_free_pdu(response);
|
|
}
|
|
return saved;
|
|
}
|
|
|
|
|
|
int
|
|
collect_perf(netsnmp_session *ss, struct hrSWRunTable **fproc)
|
|
{
|
|
netsnmp_pdu *pdu;
|
|
netsnmp_pdu *response;
|
|
netsnmp_variable_list *vlp;
|
|
oid base[MAX_OID_LEN];
|
|
size_t base_length;
|
|
int status, count = 0;
|
|
struct hrSWRunTable *procs = malloc(sizeof(struct hrSWRunTable));
|
|
|
|
pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
|
|
base_length =
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunIndex", NULL, 0);
|
|
memcpy(base, pdu->variables->name, base_length * sizeof(oid));
|
|
|
|
vlp = collect_procs(ss, pdu, base, base_length);
|
|
|
|
while (vlp) {
|
|
size_t len;
|
|
struct hrSWRunTable proc;
|
|
netsnmp_variable_list *vlp2;
|
|
|
|
pdu = snmp_pdu_create(SNMP_MSG_GET);
|
|
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunName",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunID",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunPath",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunParameters",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunType",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunStatus",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunPerfCPU",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSWRunPerfMem",
|
|
&vlp->name[base_length], vlp->name_length - base_length);
|
|
|
|
response = NULL;
|
|
status = snmp_synch_response(ss, pdu, &response);
|
|
if (status != STAT_SUCCESS || !response) {
|
|
snmp_sess_perror(progname, ss);
|
|
#if HAVE_CURSES_H
|
|
endwin();
|
|
#endif
|
|
exit(1);
|
|
}
|
|
if (response->errstat != SNMP_ERR_NOERROR) {
|
|
vlp = vlp->next_variable;
|
|
continue;
|
|
}
|
|
|
|
memset(&proc, 0, sizeof(proc));
|
|
|
|
proc.hrSWRunIndex = vlp->name[base_length];
|
|
|
|
vlp2 = response->variables;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
len = vlp2->val_len;
|
|
proc.hrSWRunName = malloc(len+1);
|
|
memcpy(proc.hrSWRunName, vlp2->val.string, len);
|
|
proc.hrSWRunName[len] = '\0';
|
|
|
|
vlp2 = vlp2->next_variable;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
proc.hrSWRunID = *vlp2->val.integer;
|
|
|
|
vlp2 = vlp2->next_variable;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
len = vlp2->val_len;
|
|
proc.hrSWRunPath = malloc(len+1);
|
|
memcpy(proc.hrSWRunPath, vlp2->val.string, len);
|
|
proc.hrSWRunPath[len] = '\0';
|
|
|
|
vlp2 = vlp2->next_variable;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
len = vlp2->val_len;
|
|
proc.hrSWRunParameters = malloc(len+1);
|
|
memcpy(proc.hrSWRunParameters, vlp2->val.string, len);
|
|
proc.hrSWRunParameters[len] = '\0';
|
|
|
|
vlp2 = vlp2->next_variable;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
proc.hrSWRunType = *vlp2->val.integer;
|
|
|
|
vlp2 = vlp2->next_variable;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
proc.hrSWRunStatus = *vlp2->val.integer;
|
|
|
|
vlp2 = vlp2->next_variable;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
proc.hrSWRunPerfCPU = *vlp2->val.integer;
|
|
|
|
vlp2 = vlp2->next_variable;
|
|
if (vlp2->type == SNMP_NOSUCHINSTANCE) goto next;
|
|
proc.hrSWRunPerfMem = *vlp2->val.integer;
|
|
|
|
count++;
|
|
procs = realloc(procs, count*sizeof(procs[0]));
|
|
procs[count-1] = proc;
|
|
|
|
snmp_free_pdu(response);
|
|
vlp2 = vlp;
|
|
vlp = vlp->next_variable;
|
|
free(vlp2);
|
|
continue;
|
|
|
|
next:
|
|
if (proc.hrSWRunName) free(proc.hrSWRunName);
|
|
if (proc.hrSWRunPath) free(proc.hrSWRunPath);
|
|
if (proc.hrSWRunParameters) free(proc.hrSWRunParameters);
|
|
snmp_free_pdu(response);
|
|
vlp2 = vlp;
|
|
vlp = vlp->next_variable;
|
|
free(vlp2);
|
|
}
|
|
*fproc = procs;
|
|
return count;
|
|
}
|
|
|
|
|
|
void free_perf(struct hrSWRunTable *procs, int nproc)
|
|
{
|
|
int i;
|
|
for (i = 0; i < nproc; i++) {
|
|
struct hrSWRunTable *proc = procs+i;
|
|
if (proc->hrSWRunName) free(proc->hrSWRunName);
|
|
if (proc->hrSWRunPath) free(proc->hrSWRunPath);
|
|
if (proc->hrSWRunParameters) free(proc->hrSWRunParameters);
|
|
}
|
|
free(procs);
|
|
}
|
|
|
|
|
|
int collect_cpu(netsnmp_session *ss, struct cpuStats *cpu)
|
|
{
|
|
netsnmp_pdu *pdu;
|
|
netsnmp_pdu *response;
|
|
int status;
|
|
int ret = 0;
|
|
|
|
pdu = snmp_pdu_create(SNMP_MSG_GET);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawUser.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawNice.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawSystem.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawIdle.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawWait.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawKernel.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawInterrupt.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawSoftIRQ.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawSteal.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawGuest.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:ssCpuRawGuestNice.0", NULL, 0);
|
|
|
|
status = snmp_synch_response(ss, pdu, &response);
|
|
memset(cpu, 0, sizeof(*cpu));
|
|
if (status != STAT_SUCCESS || !response ||
|
|
response->errstat != SNMP_ERR_NOERROR) {
|
|
goto out;
|
|
}
|
|
else {
|
|
netsnmp_variable_list *vlp = response->variables;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->user = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->nice = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->system = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->idle = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->wait = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->kernel = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
|
|
ret = 1;
|
|
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->intr = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->softintr = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->steal = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->guest = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
cpu->guestnice = *vlp->val.integer;
|
|
}
|
|
out:
|
|
if (response) snmp_free_pdu(response);
|
|
return ret;
|
|
}
|
|
|
|
|
|
int collect_mem(netsnmp_session *ss, struct memStats *mem)
|
|
{
|
|
netsnmp_pdu *pdu;
|
|
netsnmp_pdu *response;
|
|
int status;
|
|
int ret = 0;
|
|
|
|
pdu = snmp_pdu_create(SNMP_MSG_GET);
|
|
add(pdu, "UCD-SNMP-MIB:memTotalSwap.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:memAvailSwap.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:memTotalReal.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:memAvailReal.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:memShared.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:memBuffer.0", NULL, 0);
|
|
add(pdu, "UCD-SNMP-MIB:memCached.0", NULL, 0);
|
|
|
|
status = snmp_synch_response(ss, pdu, &response);
|
|
memset(mem, 0, sizeof(*mem));
|
|
if (status != STAT_SUCCESS || !response ||
|
|
response->errstat != SNMP_ERR_NOERROR) {
|
|
goto out;
|
|
}
|
|
else {
|
|
netsnmp_variable_list *vlp = response->variables;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
mem->totalSwap = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
mem->availSwap = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
mem->totalReal = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
mem->availReal = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
|
|
ret = 1;
|
|
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
mem->shared = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
mem->buffer = *vlp->val.integer;
|
|
vlp = vlp->next_variable;
|
|
if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
|
|
mem->cached = *vlp->val.integer;
|
|
}
|
|
out:
|
|
if (response) snmp_free_pdu(response);
|
|
return ret;
|
|
}
|
|
|
|
|
|
char *format_centisec(char *buf, size_t len, unsigned long csec)
|
|
{
|
|
long sec, min, hour, day;
|
|
|
|
day = csec / 100 / 3600 / 24;
|
|
csec -= day * 100 * 3600 * 24;
|
|
hour = csec / 100 / 3600;
|
|
csec -= hour * 100 * 3600;
|
|
min = csec / 100 / 60;
|
|
csec -= min * 100 * 60;
|
|
sec = csec / 100;
|
|
csec -= sec * 100;
|
|
|
|
if (day)
|
|
snprintf(buf, len, "%ldd%02ld:%02ld:%02ld.%02lu", day, hour, min, sec, csec);
|
|
else if (hour)
|
|
snprintf(buf, len, "%ld:%02ld:%02ld.%02lu", hour, min, sec, csec);
|
|
else if (min)
|
|
snprintf(buf, len, "%ld:%02ld.%02lu", min, sec, csec);
|
|
else
|
|
snprintf(buf, len, "%ld.%02lu", sec, csec);
|
|
return buf;
|
|
}
|
|
|
|
|
|
char *format_sec(char *buf, size_t len, unsigned long csec)
|
|
{
|
|
long sec, min, hour, day;
|
|
|
|
day = csec / 100 / 3600 / 24;
|
|
csec -= day * 100 * 3600 * 24;
|
|
hour = csec / 100 / 3600;
|
|
csec -= hour * 100 * 3600;
|
|
min = csec / 100 / 60;
|
|
csec -= min * 100 * 60;
|
|
sec = csec / 100;
|
|
csec -= sec * 100;
|
|
|
|
if (day)
|
|
snprintf(buf, len, "%ldd%02ld:%02ld:%02ld", day, hour, min, sec);
|
|
else if (hour)
|
|
snprintf(buf, len, "%ld:%02ld:%02ld.%02lu", hour, min, sec, csec);
|
|
else if (min)
|
|
snprintf(buf, len, "%ld:%02ld.%02lu", min, sec, csec);
|
|
else
|
|
snprintf(buf, len, "%ld.%02lu", sec, csec);
|
|
return buf;
|
|
}
|
|
|
|
|
|
char *format_humanmem(char *buf, size_t len, unsigned long mem)
|
|
{
|
|
if (mem >= 1024*1024)
|
|
snprintf(buf, len, "%4.2fGB", (float)mem/(1024*1024));
|
|
else if (mem >= 1024)
|
|
snprintf(buf, len, "%4.2fMB", (float)mem/1024);
|
|
else
|
|
snprintf(buf, len, "%4.2fkB", (float)mem);
|
|
return buf;
|
|
}
|
|
|
|
|
|
int cpucomp(const void *v1, const void *v2)
|
|
{
|
|
const struct hrSWRunTable *p1 = v1, *p2 = v2;
|
|
return p2->hrSWRunPerfCPUInc - p1->hrSWRunPerfCPUInc;
|
|
}
|
|
|
|
|
|
int memcomp(const void *v1, const void *v2)
|
|
{
|
|
const struct hrSWRunTable *p1 = v1, *p2 = v2;
|
|
return p2->hrSWRunPerfMem - p1->hrSWRunPerfMem;
|
|
}
|
|
|
|
|
|
int totcomp(const void *v1, const void *v2)
|
|
{
|
|
const struct hrSWRunTable *p1 = v1, *p2 = v2;
|
|
return p2->hrSWRunPerfCPU - p1->hrSWRunPerfCPU;
|
|
}
|
|
|
|
|
|
int pidcomp(const void *v1, const void *v2)
|
|
{
|
|
const struct hrSWRunTable *p1 = v1, *p2 = v2;
|
|
return p1->hrSWRunIndex - p2->hrSWRunIndex;
|
|
}
|
|
|
|
|
|
int
|
|
snmpps(int argc, char *argv[])
|
|
{
|
|
netsnmp_session session, *ss;
|
|
int arg;
|
|
struct hrSWRunTable *procs;
|
|
int count, pinx = 0;
|
|
|
|
/*
|
|
* get the common command line arguments
|
|
*/
|
|
switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
|
|
case NETSNMP_PARSE_ARGS_ERROR:
|
|
exit(1);
|
|
case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
|
|
exit(0);
|
|
case NETSNMP_PARSE_ARGS_ERROR_USAGE:
|
|
usage();
|
|
exit(1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (arg != argc) {
|
|
fprintf(stderr, "snmpps: extra argument: %s\n", argv[arg]);
|
|
exit(1);
|
|
}
|
|
|
|
SOCK_STARTUP;
|
|
|
|
/*
|
|
* Open an SNMP session.
|
|
*/
|
|
ss = snmp_open(&session);
|
|
if (ss == NULL) {
|
|
/*
|
|
* diagnose snmp_open errors with the input netsnmp_session pointer
|
|
*/
|
|
snmp_sess_perror("snmpps", &session);
|
|
SOCK_CLEANUP;
|
|
exit(1);
|
|
}
|
|
|
|
count = collect_perf(ss, &procs);
|
|
if (count == 0) {
|
|
fprintf(stderr, "snmpps: no processes found\n");
|
|
exit(1);
|
|
}
|
|
|
|
switch (topsort) {
|
|
case 'm':
|
|
qsort(procs, count, sizeof(procs[0]), memcomp);
|
|
break;
|
|
case 't':
|
|
qsort(procs, count, sizeof(procs[0]), totcomp);
|
|
break;
|
|
}
|
|
|
|
printf("%7s %4s %6s %10s %11s %-10s\n",
|
|
"Index", "Type", "Status", "Memory", "CPU", "Command");
|
|
|
|
while (pinx < count) {
|
|
struct hrSWRunTable *proc = procs+pinx;
|
|
const char *hr_status, *hr_type;
|
|
char b1[15], b2[20];
|
|
|
|
switch (proc->hrSWRunType) {
|
|
case 1: hr_type = "Unkn"; break;
|
|
case 2: hr_type = "Os"; break;
|
|
case 3: hr_type = "Drvr"; break;
|
|
case 4: hr_type = "Appl"; break;
|
|
default: hr_type = "?"; break;
|
|
}
|
|
|
|
switch (proc->hrSWRunStatus) {
|
|
case 1: hr_status = "Run"; break;
|
|
case 2: hr_status = "Wait"; break;
|
|
case 3: hr_status = "Event"; break;
|
|
case 4: hr_status = "Inval"; break;
|
|
default: hr_status = "?"; break;
|
|
}
|
|
|
|
printf("%7lu %4s %6s %10s %11.11s %s %s\n",
|
|
proc->hrSWRunIndex,
|
|
hr_type,
|
|
hr_status,
|
|
format_humanmem(b1, sizeof b1, proc->hrSWRunPerfMem),
|
|
format_centisec(b2, sizeof b2, proc->hrSWRunPerfCPU),
|
|
command_path && proc->hrSWRunPath[0] ? proc->hrSWRunPath : proc->hrSWRunName,
|
|
command_args ? proc->hrSWRunParameters : "");
|
|
|
|
pinx++;
|
|
}
|
|
|
|
snmp_close(ss);
|
|
SOCK_CLEANUP;
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if HAVE_CURSES_H
|
|
static void endtop(int sig)
|
|
{
|
|
endwin();
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int snmptop(int argc, char **argv)
|
|
{
|
|
netsnmp_session session, *ss;
|
|
int arg;
|
|
struct hrSWRunTable *oproc;
|
|
int ocount = 0;
|
|
int show_idle = 1;
|
|
int show_os = 1;
|
|
char ch;
|
|
struct cpuStats oldCpu;
|
|
struct memStats mem;
|
|
int has_cpu, has_mem;
|
|
|
|
/*
|
|
* get the common command line arguments
|
|
*/
|
|
switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
|
|
case NETSNMP_PARSE_ARGS_ERROR:
|
|
exit(1);
|
|
case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
|
|
exit(0);
|
|
case NETSNMP_PARSE_ARGS_ERROR_USAGE:
|
|
usage();
|
|
exit(1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (arg != argc) {
|
|
fprintf(stderr, "snmptop: extra argument: %s\n", argv[arg]);
|
|
exit(1);
|
|
}
|
|
|
|
SOCK_STARTUP;
|
|
|
|
/*
|
|
* Open an SNMP session.
|
|
*/
|
|
ss = snmp_open(&session);
|
|
if (ss == NULL) {
|
|
/*
|
|
* diagnose snmp_open errors with the input netsnmp_session pointer
|
|
*/
|
|
snmp_sess_perror("snmptop", &session);
|
|
SOCK_CLEANUP;
|
|
exit(1);
|
|
}
|
|
|
|
ocount = collect_perf(ss, &oproc);
|
|
if (ocount == 0) {
|
|
fprintf(stderr, "snmptop: no processes found\n");
|
|
exit(1);
|
|
}
|
|
|
|
collect_cpu(ss, &oldCpu);
|
|
|
|
signal(SIGINT, endtop);
|
|
initscr();
|
|
cbreak();
|
|
noecho();
|
|
nonl();
|
|
halfdelay(50);
|
|
|
|
while ((ch = getch()) != 'q') {
|
|
int ncount;
|
|
struct hrSWRunTable *nproc;
|
|
int oinx = 0, ninx = 0, line = 0;
|
|
netsnmp_pdu *pdu;
|
|
netsnmp_pdu *response = NULL;
|
|
int status;
|
|
time_t clock;
|
|
struct tm *ptm;
|
|
char uptime[40];
|
|
char timestr[40];
|
|
char b1[15], b2[15], b3[15], b4[15];
|
|
struct cpuStats newCpu;
|
|
|
|
if (ch == 'c' || ch == 'm' || ch == 'n' || ch == 't') topsort = ch;
|
|
if (ch == 'i') show_idle = !show_idle;
|
|
if (ch == 'o') show_os = !show_os;
|
|
if (ch == 'a') command_args = !command_args;
|
|
if (ch == 'p') command_path = !command_path;
|
|
|
|
ncount = collect_perf(ss, &nproc);
|
|
|
|
while (oinx < ocount && ninx < ncount) {
|
|
if (oproc[oinx].hrSWRunIndex == nproc[ninx].hrSWRunIndex) {
|
|
nproc[ninx].hrSWRunPerfCPUInc = nproc[ninx].hrSWRunPerfCPU-oproc[oinx].hrSWRunPerfCPU;
|
|
ninx++;
|
|
oinx++;
|
|
}
|
|
else if (nproc[oinx].hrSWRunIndex < oproc[ninx].hrSWRunIndex)
|
|
oinx++;
|
|
else {
|
|
nproc[ninx].hrSWRunPerfCPUInc = nproc[ninx].hrSWRunPerfCPU;
|
|
ninx++;
|
|
}
|
|
}
|
|
while (ninx < ncount) {
|
|
nproc[ninx].hrSWRunPerfCPUInc = nproc[ninx].hrSWRunPerfCPU;
|
|
ninx++;
|
|
}
|
|
|
|
switch (topsort) {
|
|
case 'c':
|
|
qsort(nproc, ncount, sizeof(nproc[0]), cpucomp);
|
|
break;
|
|
case 'm':
|
|
qsort(nproc, ncount, sizeof(nproc[0]), memcomp);
|
|
break;
|
|
case 't':
|
|
qsort(nproc, ncount, sizeof(nproc[0]), totcomp);
|
|
break;
|
|
}
|
|
|
|
has_cpu = collect_cpu(ss, &newCpu);
|
|
has_mem = collect_mem(ss, &mem);
|
|
|
|
pdu = snmp_pdu_create(SNMP_MSG_GET);
|
|
add(pdu, "HOST-RESOURCES-MIB:hrSystemUptime.0", NULL, 0);
|
|
status = snmp_synch_response(ss, pdu, &response);
|
|
if (status != STAT_SUCCESS || !response ||
|
|
response->errstat != SNMP_ERR_NOERROR) {
|
|
uptime[0] = '\0';
|
|
}
|
|
else {
|
|
netsnmp_variable_list *vlp = response->variables;
|
|
if (vlp->type == SNMP_NOSUCHINSTANCE) abort();
|
|
uptime_string_n(*vlp->val.integer, uptime, sizeof(uptime));
|
|
}
|
|
snmp_free_pdu(response);
|
|
|
|
clock = time(NULL);
|
|
ptm = localtime(&clock);
|
|
strftime(timestr, sizeof(timestr), "%H:%M:%S", ptm);
|
|
|
|
clear();
|
|
move(0, 0);
|
|
printw("%s %s%s", session.peername, uptime[0] ? "up " : "", uptime);
|
|
move(0, COLS-strlen(timestr)-1);
|
|
printw("%s", timestr);
|
|
if (has_cpu) {
|
|
struct cpuStats deltaCpu;
|
|
u_long sumCpu;
|
|
|
|
deltaCpu.user = newCpu.user - oldCpu.user;
|
|
deltaCpu.nice = newCpu.nice - oldCpu.nice;
|
|
deltaCpu.system = newCpu.system - oldCpu.system;
|
|
deltaCpu.idle = newCpu.idle - oldCpu.idle;
|
|
deltaCpu.wait = newCpu.wait - oldCpu.wait;
|
|
deltaCpu.kernel = newCpu.kernel - oldCpu.kernel;
|
|
deltaCpu.intr = newCpu.intr - oldCpu.intr;
|
|
deltaCpu.softintr = newCpu.softintr - oldCpu.softintr;
|
|
deltaCpu.steal = newCpu.steal - oldCpu.steal;
|
|
deltaCpu.guest = newCpu.guest - oldCpu.guest;
|
|
deltaCpu.guestnice = newCpu.guestnice - oldCpu.guestnice;
|
|
oldCpu = newCpu;
|
|
sumCpu = deltaCpu.user + deltaCpu.nice
|
|
+ deltaCpu.system + deltaCpu.idle
|
|
+ deltaCpu.wait + deltaCpu.kernel + deltaCpu.steal
|
|
+ deltaCpu.intr + deltaCpu.softintr
|
|
+ deltaCpu.guest + deltaCpu.guestnice;
|
|
|
|
printw("\nCPU%%: %4.1fUs %4.1fSy %4.1fId %3.1fWa %3.1fNi %3.1fKe %3.1fHi %3.1fSi %3.1fSt %3.1fGu %3.1fGN",
|
|
(float)deltaCpu.user*100/sumCpu,
|
|
(float)deltaCpu.system*100/sumCpu,
|
|
(float)deltaCpu.idle*100/sumCpu,
|
|
(float)deltaCpu.wait*100/sumCpu,
|
|
(float)deltaCpu.nice*100/sumCpu,
|
|
(float)deltaCpu.kernel*100/sumCpu,
|
|
(float)deltaCpu.intr*100/sumCpu,
|
|
(float)deltaCpu.softintr*100/sumCpu,
|
|
(float)deltaCpu.steal*100/sumCpu,
|
|
(float)deltaCpu.guest*100/sumCpu,
|
|
(float)deltaCpu.guestnice*100/sumCpu);
|
|
line++;
|
|
}
|
|
|
|
if (has_mem) {
|
|
printw("\nMem: %10s Total %10s Used %10s Free %10s Buffer",
|
|
format_humanmem(b1, sizeof b1, mem.totalReal),
|
|
format_humanmem(b2, sizeof b2, mem.totalReal-mem.availReal),
|
|
format_humanmem(b3, sizeof b3, mem.availReal),
|
|
format_humanmem(b4, sizeof b4, mem.buffer));
|
|
line++;
|
|
printw("\nSwap: %10s Total %10s Used %10s Free %10s Cached",
|
|
format_humanmem(b1, sizeof b1, mem.totalSwap),
|
|
format_humanmem(b2, sizeof b2, mem.totalSwap-mem.availSwap),
|
|
format_humanmem(b3, sizeof b3, mem.availSwap),
|
|
format_humanmem(b4, sizeof b4, mem.cached));
|
|
line++;
|
|
}
|
|
|
|
printw("\n%7s %4s %6s %10s %11s %5s %-10s",
|
|
"Index", "Type", "Status", "Memory", "Total CPU", "%CPU", "Command");
|
|
line++;
|
|
ninx = 0;
|
|
while (line < LINES && ninx < ncount) {
|
|
struct hrSWRunTable *proc = nproc+ninx;
|
|
const char *hr_status, *hr_type;
|
|
|
|
ninx++;
|
|
if (proc->hrSWRunPerfCPUInc == 0 && !show_idle)
|
|
continue;
|
|
if (proc->hrSWRunType != 4 && !show_os)
|
|
continue;
|
|
|
|
line++;
|
|
|
|
switch (proc->hrSWRunType) {
|
|
case 1: hr_type = "Unkn"; break;
|
|
case 2: hr_type = "Os"; break;
|
|
case 3: hr_type = "Drvr"; break;
|
|
case 4: hr_type = "Appl"; break;
|
|
default: hr_type = "?"; break;
|
|
}
|
|
|
|
switch (proc->hrSWRunStatus) {
|
|
case 1: hr_status = "Run"; break;
|
|
case 2: hr_status = "Wait"; break;
|
|
case 3: hr_status = "Event"; break;
|
|
case 4: hr_status = "Inval"; break;
|
|
default: hr_status = "?"; break;
|
|
}
|
|
|
|
printw("\n%7lu %4s %6s %10s %11s %5.1f %s %s",
|
|
proc->hrSWRunIndex,
|
|
hr_type,
|
|
hr_status,
|
|
format_humanmem(b1, sizeof b1, proc->hrSWRunPerfMem),
|
|
format_sec(b2,sizeof b2, proc->hrSWRunPerfCPU),
|
|
(float)proc->hrSWRunPerfCPUInc/5,
|
|
command_path && proc->hrSWRunPath[0] ? proc->hrSWRunPath : proc->hrSWRunName,
|
|
command_args ? proc->hrSWRunParameters : "");
|
|
}
|
|
refresh();
|
|
|
|
qsort(nproc, ncount, sizeof(nproc[0]), pidcomp);
|
|
free_perf(oproc, ocount);
|
|
oproc = nproc;
|
|
ocount = ncount;
|
|
}
|
|
endwin();
|
|
|
|
snmp_close(ss);
|
|
SOCK_CLEANUP;
|
|
return 0;
|
|
}
|
|
#else
|
|
int snmptop(int argc, char **argv)
|
|
{
|
|
fprintf(stderr, "%s: curses not detected during configure\n", progname);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
progname = strrchr(argv[0], '/');
|
|
if (progname) progname++;
|
|
else progname = argv[0];
|
|
if (strncmp(progname, "lt-", 3) == 0) progname += 3;
|
|
|
|
if (strcmp(progname, "snmpps") == 0) return snmpps(argc, argv);
|
|
if (strcmp(progname, "snmptop") == 0) return snmptop(argc, argv);
|
|
fprintf(stderr, "%s: unknown prognam name\n", progname);
|
|
exit(1);
|
|
}
|