1 /*
2  * snmpps.c - display process table on a network entity via SNMP.
3  *
4  */
5 
6 /* Portions of this file are subject to the following copyright(s).  See
7  * the Net-SNMP's COPYING file for more details and other copyrights
8  * that may apply:
9  */
10 /***********************************************************************
11         Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of CMU not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 ******************************************************************/
31 
32 #include <net-snmp/net-snmp-config.h>
33 
34 #if HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #if HAVE_STRING_H
41 #include <string.h>
42 #else
43 #include <strings.h>
44 #endif
45 #include <sys/types.h>
46 #if HAVE_NETINET_IN_H
47 #include <netinet/in.h>
48 #endif
49 #include <stdio.h>
50 #include <ctype.h>
51 #if TIME_WITH_SYS_TIME
52 # include <sys/time.h>
53 # include <time.h>
54 #else
55 # if HAVE_SYS_TIME_H
56 #  include <sys/time.h>
57 # else
58 #  include <time.h>
59 # endif
60 #endif
61 #if HAVE_SYS_SELECT_H
62 #include <sys/select.h>
63 #endif
64 #if HAVE_NETDB_H
65 #include <netdb.h>
66 #endif
67 #if HAVE_ARPA_INET_H
68 #include <arpa/inet.h>
69 #endif
70 #if HAVE_NCURSES_CURSES_H
71 #include <ncurses/curses.h>
72 #elif HAVE_CURSES_H
73 #include <curses.h>
74 #endif
75 #include <signal.h>
76 
77 #include <net-snmp/net-snmp-includes.h>
78 
79 void
usage(void)80 usage(void)
81 {
82     fprintf(stderr, "Usage: snmpps [-Cp] [-Ca] [-C m | n | t] AGENT");
83     snmp_parse_args_usage(stderr);
84     fprintf(stderr, "\n\n");
85     snmp_parse_args_descriptions(stderr);
86     fprintf(stderr, "\nsnmpps options:\n");
87     fprintf(stderr,
88             "\t-Cp\tShow hrSWRunPath instead of hrSWRunName\n");
89     fprintf(stderr,
90             "\t-Ca\tShow hrSWRunParameters in addition to hrSWRunName/Path\n");
91     fprintf(stderr,
92             "\t-Ct\tSort processes according to CPU time used\n");
93     fprintf(stderr,
94             "\t-Cm\tSort processes according to memory usage\n");
95     fprintf(stderr,
96             "\t-Cn\tSort processes by PID number (default)\n");
97 }
98 
99 int   command_args = 0,
100       command_path = 0;
101 int   topsort = 'c';
102 char *progname;
103 
104 static void
optProc(int argc,char * const * argv,int opt)105 optProc(int argc, char *const *argv, int opt)
106 {
107     switch (opt) {
108     case 'C':
109         while (*optarg) {
110             switch (*optarg++) {
111             case 'a':
112                 command_args = 1;
113                 break;
114             case 'p':
115                 command_path = 1;
116                 break;
117             case 'm':
118                 topsort = 'm';
119                 break;
120             case 'n':
121                 topsort = 'n';
122                 break;
123             case 't':
124                 topsort = 't';
125                 break;
126 
127             default:
128                 fprintf(stderr,
129                         "Unknown flag passed to -C: %c\n", optarg[-1]);
130                 exit(1);
131             }
132         }
133     }
134 }
135 
136 struct hrSWRunTable {
137     u_long  hrSWRunIndex;
138     char   *hrSWRunName;
139     char   *hrSWRunPath;
140     char   *hrSWRunParameters;
141     u_long  hrSWRunID;
142     u_long  hrSWRunType;
143     u_long  hrSWRunStatus;
144     u_long  hrSWRunPerfMem;
145     u_long  hrSWRunPerfCPU;
146     u_long  hrSWRunPerfCPUInc;
147 };
148 
149 struct cpuStats {
150     u_long user;
151     u_long nice;
152     u_long system;
153     u_long idle;
154     u_long wait;
155     u_long kernel;
156     u_long intr;
157     u_long softintr;
158     u_long steal;
159     u_long guest;
160     u_long guestnice;
161 };
162 
163 struct memStats {
164     u_long totalSwap;
165     u_long availSwap;
166     u_long totalReal;
167     u_long availReal;
168     u_long shared;
169     u_long buffer;
170     u_long cached;
171 };
172 
173 struct laStats {
174     u_long la1;
175     u_long la5;
176     u_long la15;
177 };
178 
179 
180 int
add(netsnmp_pdu * pdu,const char * mibnodename,oid * index,size_t indexlen)181 add(netsnmp_pdu *pdu, const char *mibnodename,
182     oid * index, size_t indexlen)
183 {
184     oid             base[MAX_OID_LEN];
185     size_t          base_length = MAX_OID_LEN;
186 
187     memset(base, 0, MAX_OID_LEN * sizeof(oid));
188 
189     if (!snmp_parse_oid(mibnodename, base, &base_length)) {
190         snmp_perror(mibnodename);
191         fprintf(stderr, "couldn't find mib node %s, giving up\n",
192                 mibnodename);
193 #if HAVE_CURSES_H
194         endwin();
195 #endif
196         exit(1);
197     }
198 
199     if (base_length + indexlen > sizeof(base) / sizeof(base[0])) {
200         fprintf(stderr, "internal error for %s, giving up\n", mibnodename);
201         exit(1);
202     }
203 
204     if (index && indexlen) {
205         memcpy(&(base[base_length]), index, indexlen * sizeof(oid));
206         base_length += indexlen;
207     }
208     DEBUGMSGTL(("add", "created: "));
209     DEBUGMSGOID(("add", base, base_length));
210     DEBUGMSG(("add", "\n"));
211     snmp_add_null_var(pdu, base, base_length);
212 
213     return base_length;
214 }
215 
216 netsnmp_variable_list *
collect_procs(netsnmp_session * ss,netsnmp_pdu * pdu,oid * base,size_t base_length)217 collect_procs(netsnmp_session *ss, netsnmp_pdu *pdu,
218         oid * base, size_t base_length)
219 {
220     netsnmp_pdu    *response;
221     int             running = 1;
222     netsnmp_variable_list *saved = NULL, **vlpp = &saved;
223     int             status;
224 
225     while (running) {
226         /*
227          * gotta catch em all, gotta catch em all!
228          */
229         status = snmp_synch_response(ss, pdu, &response);
230         if (status != STAT_SUCCESS || !response) {
231             snmp_sess_perror(progname, ss);
232 #if HAVE_CURSES_H
233             endwin();
234 #endif
235             exit(1);
236         }
237         if (response->errstat != SNMP_ERR_NOERROR) {
238             fprintf(stderr, "%s: Error in packet: %s\n", progname,
239                     snmp_errstring(response->errstat));
240 #if HAVE_CURSES_H
241             endwin();
242 #endif
243             exit(1);
244         }
245         if (snmp_oid_compare(response->variables->name,
246                              SNMP_MIN(base_length,
247                                       response->variables->name_length),
248                              base, base_length) != 0)
249             running = 0;
250         else if (response->variables->type == SNMP_NOSUCHINSTANCE ||
251                     response->variables->type == SNMP_NOSUCHOBJECT ||
252                 response->variables->type == SNMP_ENDOFMIBVIEW)
253             running = 0;
254         else {
255             /*
256              * get response
257              */
258             *vlpp = response->variables;
259             (*vlpp)->next_variable = NULL;      /* shouldn't be any, but just in case */
260 
261             /*
262              * create the next request
263              */
264             pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
265             snmp_add_null_var(pdu, (*vlpp)->name, (*vlpp)->name_length);
266 
267             /*
268              * finish loop setup
269              */
270             vlpp = &((*vlpp)->next_variable);
271             response->variables = NULL; /* ahh, forget about it */
272         }
273         snmp_free_pdu(response);
274     }
275     return saved;
276 }
277 
278 
279 int
collect_perf(netsnmp_session * ss,struct hrSWRunTable ** fproc)280 collect_perf(netsnmp_session *ss, struct hrSWRunTable **fproc)
281 {
282     netsnmp_pdu    *pdu;
283     netsnmp_pdu    *response;
284     netsnmp_variable_list *vlp;
285     oid             base[MAX_OID_LEN];
286     size_t          base_length;
287     int status, count = 0;
288     struct hrSWRunTable *procs = malloc(sizeof(struct hrSWRunTable));
289 
290     pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
291     base_length =
292         add(pdu, "HOST-RESOURCES-MIB:hrSWRunIndex", NULL, 0);
293     memcpy(base, pdu->variables->name, base_length * sizeof(oid));
294 
295     vlp = collect_procs(ss, pdu, base, base_length);
296 
297     while (vlp) {
298         size_t len;
299         struct hrSWRunTable proc;
300         netsnmp_variable_list *vlp2;
301 
302         pdu = snmp_pdu_create(SNMP_MSG_GET);
303 
304         add(pdu, "HOST-RESOURCES-MIB:hrSWRunName",
305             &vlp->name[base_length], vlp->name_length - base_length);
306         add(pdu, "HOST-RESOURCES-MIB:hrSWRunID",
307             &vlp->name[base_length], vlp->name_length - base_length);
308         add(pdu, "HOST-RESOURCES-MIB:hrSWRunPath",
309             &vlp->name[base_length], vlp->name_length - base_length);
310         add(pdu, "HOST-RESOURCES-MIB:hrSWRunParameters",
311             &vlp->name[base_length], vlp->name_length - base_length);
312         add(pdu, "HOST-RESOURCES-MIB:hrSWRunType",
313             &vlp->name[base_length], vlp->name_length - base_length);
314         add(pdu, "HOST-RESOURCES-MIB:hrSWRunStatus",
315             &vlp->name[base_length], vlp->name_length - base_length);
316         add(pdu, "HOST-RESOURCES-MIB:hrSWRunPerfCPU",
317             &vlp->name[base_length], vlp->name_length - base_length);
318         add(pdu, "HOST-RESOURCES-MIB:hrSWRunPerfMem",
319             &vlp->name[base_length], vlp->name_length - base_length);
320 
321         response = NULL;
322         status = snmp_synch_response(ss, pdu, &response);
323         if (status != STAT_SUCCESS || !response) {
324             snmp_sess_perror(progname, ss);
325 #if HAVE_CURSES_H
326             endwin();
327 #endif
328             exit(1);
329         }
330         if (response->errstat != SNMP_ERR_NOERROR) {
331             vlp = vlp->next_variable;
332             continue;
333         }
334 
335         memset(&proc, 0, sizeof(proc));
336 
337         proc.hrSWRunIndex = vlp->name[base_length];
338 
339         vlp2 = response->variables;
340         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
341             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
342         len = vlp2->val_len;
343         proc.hrSWRunName = malloc(len+1);
344         memcpy(proc.hrSWRunName, vlp2->val.string, len);
345         proc.hrSWRunName[len] = '\0';
346 
347         vlp2 = vlp2->next_variable;
348         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
349             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
350         proc.hrSWRunID = *vlp2->val.integer;
351 
352         vlp2 = vlp2->next_variable;
353         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
354             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
355         len = vlp2->val_len;
356         proc.hrSWRunPath = malloc(len+1);
357         memcpy(proc.hrSWRunPath, vlp2->val.string, len);
358         proc.hrSWRunPath[len] = '\0';
359 
360         vlp2 = vlp2->next_variable;
361         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
362             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
363         len = vlp2->val_len;
364         proc.hrSWRunParameters = malloc(len+1);
365         memcpy(proc.hrSWRunParameters, vlp2->val.string, len);
366         proc.hrSWRunParameters[len] = '\0';
367 
368         vlp2 = vlp2->next_variable;
369         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
370             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
371         proc.hrSWRunType = *vlp2->val.integer;
372 
373         vlp2 = vlp2->next_variable;
374         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
375             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
376         proc.hrSWRunStatus = *vlp2->val.integer;
377 
378         vlp2 = vlp2->next_variable;
379         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
380             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
381         proc.hrSWRunPerfCPU = *vlp2->val.integer;
382 
383         vlp2 = vlp2->next_variable;
384         if (vlp2->type == SNMP_NOSUCHINSTANCE ||
385             vlp2->type == SNMP_NOSUCHOBJECT) goto next;
386         proc.hrSWRunPerfMem = *vlp2->val.integer;
387 
388         count++;
389         procs = realloc(procs, count*sizeof(procs[0]));
390         procs[count-1] = proc;
391 
392         snmp_free_pdu(response);
393         vlp2 = vlp;
394         vlp = vlp->next_variable;
395         free(vlp2);
396         continue;
397 
398 next:
399         if (proc.hrSWRunName) free(proc.hrSWRunName);
400         if (proc.hrSWRunPath) free(proc.hrSWRunPath);
401         if (proc.hrSWRunParameters) free(proc.hrSWRunParameters);
402         snmp_free_pdu(response);
403         vlp2 = vlp;
404         vlp = vlp->next_variable;
405         free(vlp2);
406     }
407     *fproc = procs;
408     return count;
409 }
410 
411 
free_perf(struct hrSWRunTable * procs,int nproc)412 void free_perf(struct hrSWRunTable *procs, int nproc)
413 {
414     int i;
415     for (i = 0; i < nproc; i++) {
416         struct hrSWRunTable *proc = procs+i;
417         if (proc->hrSWRunName) free(proc->hrSWRunName);
418         if (proc->hrSWRunPath) free(proc->hrSWRunPath);
419         if (proc->hrSWRunParameters) free(proc->hrSWRunParameters);
420     }
421     free(procs);
422 }
423 
424 
collect_cpu(netsnmp_session * ss,struct cpuStats * cpu)425 int collect_cpu(netsnmp_session *ss, struct cpuStats *cpu)
426 {
427     netsnmp_pdu    *pdu;
428     netsnmp_pdu    *response;
429     int status;
430     int ret = 0;
431 
432     pdu = snmp_pdu_create(SNMP_MSG_GET);
433     add(pdu, "UCD-SNMP-MIB:ssCpuRawUser.0", NULL, 0);
434     add(pdu, "UCD-SNMP-MIB:ssCpuRawNice.0", NULL, 0);
435     add(pdu, "UCD-SNMP-MIB:ssCpuRawSystem.0", NULL, 0);
436     add(pdu, "UCD-SNMP-MIB:ssCpuRawIdle.0", NULL, 0);
437     add(pdu, "UCD-SNMP-MIB:ssCpuRawWait.0", NULL, 0);
438     add(pdu, "UCD-SNMP-MIB:ssCpuRawKernel.0", NULL, 0);
439     add(pdu, "UCD-SNMP-MIB:ssCpuRawInterrupt.0", NULL, 0);
440     add(pdu, "UCD-SNMP-MIB:ssCpuRawSoftIRQ.0", NULL, 0);
441     add(pdu, "UCD-SNMP-MIB:ssCpuRawSteal.0", NULL, 0);
442     add(pdu, "UCD-SNMP-MIB:ssCpuRawGuest.0", NULL, 0);
443     add(pdu, "UCD-SNMP-MIB:ssCpuRawGuestNice.0", NULL, 0);
444 
445     status = snmp_synch_response(ss, pdu, &response);
446     memset(cpu, 0, sizeof(*cpu));
447     if (status != STAT_SUCCESS || !response ||
448             response->errstat != SNMP_ERR_NOERROR) {
449         goto out;
450     }
451     else {
452         netsnmp_variable_list *vlp = response->variables;
453         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
454         cpu->user = *vlp->val.integer;
455         vlp = vlp->next_variable;
456         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
457         cpu->nice = *vlp->val.integer;
458         vlp = vlp->next_variable;
459         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
460         cpu->system = *vlp->val.integer;
461         vlp = vlp->next_variable;
462         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
463         cpu->idle = *vlp->val.integer;
464         vlp = vlp->next_variable;
465         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
466         cpu->wait = *vlp->val.integer;
467         vlp = vlp->next_variable;
468         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
469         cpu->kernel = *vlp->val.integer;
470         vlp = vlp->next_variable;
471 
472         ret = 1;
473 
474         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
475         cpu->intr = *vlp->val.integer;
476         vlp = vlp->next_variable;
477         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
478         cpu->softintr = *vlp->val.integer;
479         vlp = vlp->next_variable;
480         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
481         cpu->steal = *vlp->val.integer;
482         vlp = vlp->next_variable;
483         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
484         cpu->guest = *vlp->val.integer;
485         vlp = vlp->next_variable;
486         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
487         cpu->guestnice = *vlp->val.integer;
488     }
489 out:
490     if (response) snmp_free_pdu(response);
491     return ret;
492 }
493 
494 
collect_mem(netsnmp_session * ss,struct memStats * mem)495 int collect_mem(netsnmp_session *ss, struct memStats *mem)
496 {
497     netsnmp_pdu    *pdu;
498     netsnmp_pdu    *response;
499     int status;
500     int ret = 0;
501 
502     pdu = snmp_pdu_create(SNMP_MSG_GET);
503     add(pdu, "UCD-SNMP-MIB:memTotalSwap.0", NULL, 0);
504     add(pdu, "UCD-SNMP-MIB:memAvailSwap.0", NULL, 0);
505     add(pdu, "UCD-SNMP-MIB:memTotalReal.0", NULL, 0);
506     add(pdu, "UCD-SNMP-MIB:memAvailReal.0", NULL, 0);
507     add(pdu, "UCD-SNMP-MIB:memShared.0", NULL, 0);
508     add(pdu, "UCD-SNMP-MIB:memBuffer.0", NULL, 0);
509     add(pdu, "UCD-SNMP-MIB:memCached.0", NULL, 0);
510 
511     status = snmp_synch_response(ss, pdu, &response);
512     memset(mem, 0, sizeof(*mem));
513     if (status != STAT_SUCCESS || !response ||
514             response->errstat != SNMP_ERR_NOERROR) {
515         goto out;
516     }
517     else {
518         netsnmp_variable_list *vlp = response->variables;
519         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
520         mem->totalSwap = *vlp->val.integer;
521         vlp = vlp->next_variable;
522         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
523         mem->availSwap = *vlp->val.integer;
524         vlp = vlp->next_variable;
525         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
526         mem->totalReal = *vlp->val.integer;
527         vlp = vlp->next_variable;
528         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
529         mem->availReal = *vlp->val.integer;
530         vlp = vlp->next_variable;
531 
532         ret = 1;
533 
534         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
535         mem->shared = *vlp->val.integer;
536         vlp = vlp->next_variable;
537         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
538         mem->buffer = *vlp->val.integer;
539         vlp = vlp->next_variable;
540         if (vlp->type == SNMP_NOSUCHOBJECT) goto out;
541         mem->cached = *vlp->val.integer;
542     }
543 out:
544     if (response) snmp_free_pdu(response);
545     return ret;
546 }
547 
548 
format_centisec(char * buf,size_t len,unsigned long csec)549 char *format_centisec(char *buf, size_t len, unsigned long csec)
550 {
551     long sec, min, hour, day;
552 
553     day = csec / 100 / 3600 / 24;
554     csec -= day * 100 * 3600 * 24;
555     hour = csec / 100 / 3600;
556     csec -= hour * 100 * 3600;
557     min = csec / 100 / 60;
558     csec -= min * 100 * 60;
559     sec = csec / 100;
560     csec -= sec * 100;
561 
562     if (day)
563         snprintf(buf, len, "%ldd%02ld:%02ld:%02ld.%02lu", day, hour, min, sec, csec);
564     else if (hour)
565         snprintf(buf, len, "%ld:%02ld:%02ld.%02lu", hour, min, sec, csec);
566     else if (min)
567         snprintf(buf, len, "%ld:%02ld.%02lu", min, sec, csec);
568     else
569         snprintf(buf, len, "%ld.%02lu", sec, csec);
570     return buf;
571 }
572 
573 
format_sec(char * buf,size_t len,unsigned long csec)574 char *format_sec(char *buf, size_t len, unsigned long csec)
575 {
576     long sec, min, hour, day;
577 
578     day = csec / 100 / 3600 / 24;
579     csec -= day * 100 * 3600 * 24;
580     hour = csec / 100 / 3600;
581     csec -= hour * 100 * 3600;
582     min = csec / 100 / 60;
583     csec -= min * 100 * 60;
584     sec = csec / 100;
585     csec -= sec * 100;
586 
587     if (day)
588         snprintf(buf, len, "%ldd%02ld:%02ld:%02ld", day, hour, min, sec);
589     else if (hour)
590         snprintf(buf, len, "%ld:%02ld:%02ld.%02lu", hour, min, sec, csec);
591     else if (min)
592         snprintf(buf, len, "%ld:%02ld.%02lu", min, sec, csec);
593     else
594         snprintf(buf, len, "%ld.%02lu", sec, csec);
595     return buf;
596 }
597 
598 
format_humanmem(char * buf,size_t len,unsigned long mem)599 char *format_humanmem(char *buf, size_t len, unsigned long mem)
600 {
601     if (mem >= 1024*1024)
602         snprintf(buf, len, "%4.2fGB", (float)mem/(1024*1024));
603     else if (mem >= 1024)
604         snprintf(buf, len, "%4.2fMB", (float)mem/1024);
605     else
606         snprintf(buf, len, "%4.2fkB", (float)mem);
607     return buf;
608 }
609 
610 
cpucomp(const void * v1,const void * v2)611 int cpucomp(const void *v1, const void *v2)
612 {
613     const struct hrSWRunTable *p1 = v1, *p2 = v2;
614     return p2->hrSWRunPerfCPUInc - p1->hrSWRunPerfCPUInc;
615 }
616 
617 
memcomp(const void * v1,const void * v2)618 int memcomp(const void *v1, const void *v2)
619 {
620     const struct hrSWRunTable *p1 = v1, *p2 = v2;
621     return p2->hrSWRunPerfMem - p1->hrSWRunPerfMem;
622 }
623 
624 
totcomp(const void * v1,const void * v2)625 int totcomp(const void *v1, const void *v2)
626 {
627     const struct hrSWRunTable *p1 = v1, *p2 = v2;
628     return p2->hrSWRunPerfCPU - p1->hrSWRunPerfCPU;
629 }
630 
631 
pidcomp(const void * v1,const void * v2)632 int pidcomp(const void *v1, const void *v2)
633 {
634     const struct hrSWRunTable *p1 = v1, *p2 = v2;
635     return p1->hrSWRunIndex - p2->hrSWRunIndex;
636 }
637 
638 
639 int
snmpps(int argc,char * argv[])640 snmpps(int argc, char *argv[])
641 {
642     netsnmp_session session, *ss;
643     int             arg;
644     struct hrSWRunTable *procs;
645     int             count, pinx = 0;
646 
647     /*
648      * get the common command line arguments
649      */
650     switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
651     case NETSNMP_PARSE_ARGS_ERROR:
652         exit(1);
653     case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
654         exit(0);
655     case NETSNMP_PARSE_ARGS_ERROR_USAGE:
656         usage();
657         exit(1);
658     default:
659         break;
660     }
661 
662     if (arg != argc) {
663         fprintf(stderr, "snmpps: extra argument: %s\n", argv[arg]);
664         exit(1);
665     }
666 
667     SOCK_STARTUP;
668 
669     /*
670      * Open an SNMP session.
671      */
672     ss = snmp_open(&session);
673     if (ss == NULL) {
674         /*
675          * diagnose snmp_open errors with the input netsnmp_session pointer
676          */
677         snmp_sess_perror("snmpps", &session);
678         SOCK_CLEANUP;
679         exit(1);
680     }
681 
682     count = collect_perf(ss, &procs);
683     if (count == 0) {
684         fprintf(stderr, "snmpps: no processes found\n");
685         exit(1);
686     }
687 
688     switch (topsort) {
689     case 'm':
690         qsort(procs, count, sizeof(procs[0]), memcomp);
691         break;
692     case 't':
693         qsort(procs, count, sizeof(procs[0]), totcomp);
694         break;
695     }
696 
697     printf("%7s %4s %6s %10s %11s %-10s\n",
698         "Index", "Type", "Status", "Memory", "CPU", "Command");
699 
700     while (pinx < count) {
701         struct hrSWRunTable *proc = procs+pinx;
702         const char *hr_status, *hr_type;
703         char b1[15], b2[20];
704 
705         switch (proc->hrSWRunType) {
706         case 1: hr_type = "Unkn"; break;
707         case 2: hr_type = "Os"; break;
708         case 3: hr_type = "Drvr"; break;
709         case 4: hr_type = "Appl"; break;
710         default: hr_type = "?"; break;
711         }
712 
713         switch (proc->hrSWRunStatus) {
714         case 1: hr_status = "Run"; break;
715         case 2: hr_status = "Wait"; break;
716         case 3: hr_status = "Event"; break;
717         case 4: hr_status = "Inval"; break;
718         default: hr_status = "?"; break;
719         }
720 
721         printf("%7lu %4s %6s %10s %11.11s %s %s\n",
722                proc->hrSWRunIndex,
723                hr_type,
724                hr_status,
725                format_humanmem(b1, sizeof b1, proc->hrSWRunPerfMem),
726                format_centisec(b2, sizeof b2, proc->hrSWRunPerfCPU),
727                command_path && proc->hrSWRunPath[0] ? proc->hrSWRunPath : proc->hrSWRunName,
728                command_args ? proc->hrSWRunParameters : "");
729 
730         pinx++;
731     }
732 
733     snmp_close(ss);
734     SOCK_CLEANUP;
735     return 0;
736 }
737 
738 
739 #if HAVE_CURSES_H
endtop(int sig)740 static void endtop(int sig)
741 {
742     endwin();
743     exit(1);
744 }
745 
746 
snmptop(int argc,char ** argv)747 int snmptop(int argc, char **argv)
748 {
749     netsnmp_session session, *ss;
750     int             arg;
751     struct hrSWRunTable *oproc;
752     int             ocount = 0;
753     int             show_idle = 1;
754     int             show_os = 1;
755     char            ch;
756     struct cpuStats oldCpu;
757     struct memStats mem;
758     int             has_cpu, has_mem;
759 
760     /*
761      * get the common command line arguments
762      */
763     switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
764     case NETSNMP_PARSE_ARGS_ERROR:
765         exit(1);
766     case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
767         exit(0);
768     case NETSNMP_PARSE_ARGS_ERROR_USAGE:
769         usage();
770         exit(1);
771     default:
772         break;
773     }
774 
775     if (arg != argc) {
776         fprintf(stderr, "snmptop: extra argument: %s\n", argv[arg]);
777         exit(1);
778     }
779 
780     SOCK_STARTUP;
781 
782     /*
783      * Open an SNMP session.
784      */
785     ss = snmp_open(&session);
786     if (ss == NULL) {
787         /*
788          * diagnose snmp_open errors with the input netsnmp_session pointer
789          */
790         snmp_sess_perror("snmptop", &session);
791         SOCK_CLEANUP;
792         exit(1);
793     }
794 
795     ocount = collect_perf(ss, &oproc);
796     if (ocount == 0) {
797         fprintf(stderr, "snmptop: no processes found\n");
798         exit(1);
799     }
800 
801     collect_cpu(ss, &oldCpu);
802 
803     signal(SIGINT, endtop);
804     initscr();
805     cbreak();
806     noecho();
807     nonl();
808     halfdelay(50);
809 
810     while ((ch = getch()) != 'q') {
811         int ncount;
812         struct hrSWRunTable *nproc;
813         int oinx = 0, ninx = 0, line = 0;
814         netsnmp_pdu    *pdu;
815         netsnmp_pdu    *response = NULL;
816         int status;
817         time_t clock;
818         struct tm *ptm;
819         char uptime[40];
820         char timestr[40];
821         char b1[15], b2[15], b3[15], b4[15];
822         struct cpuStats newCpu;
823 
824         if (ch == 'c' || ch == 'm' || ch == 'n' || ch == 't') topsort = ch;
825         if (ch == 'i') show_idle = !show_idle;
826         if (ch == 'o') show_os = !show_os;
827         if (ch == 'a') command_args = !command_args;
828         if (ch == 'p') command_path = !command_path;
829 
830         ncount = collect_perf(ss, &nproc);
831 
832         while (oinx < ocount && ninx < ncount) {
833             if (oproc[oinx].hrSWRunIndex == nproc[ninx].hrSWRunIndex) {
834                 nproc[ninx].hrSWRunPerfCPUInc = nproc[ninx].hrSWRunPerfCPU-oproc[oinx].hrSWRunPerfCPU;
835                 ninx++;
836                 oinx++;
837             }
838             else if (nproc[oinx].hrSWRunIndex < oproc[ninx].hrSWRunIndex)
839                 oinx++;
840             else {
841                 nproc[ninx].hrSWRunPerfCPUInc = nproc[ninx].hrSWRunPerfCPU;
842                 ninx++;
843             }
844         }
845         while (ninx < ncount) {
846             nproc[ninx].hrSWRunPerfCPUInc = nproc[ninx].hrSWRunPerfCPU;
847             ninx++;
848         }
849 
850         switch (topsort) {
851         case 'c':
852             qsort(nproc, ncount, sizeof(nproc[0]), cpucomp);
853             break;
854         case 'm':
855             qsort(nproc, ncount, sizeof(nproc[0]), memcomp);
856             break;
857         case 't':
858             qsort(nproc, ncount, sizeof(nproc[0]), totcomp);
859             break;
860         }
861 
862         has_cpu = collect_cpu(ss, &newCpu);
863         has_mem = collect_mem(ss, &mem);
864 
865         pdu = snmp_pdu_create(SNMP_MSG_GET);
866         add(pdu, "HOST-RESOURCES-MIB:hrSystemUptime.0", NULL, 0);
867         status = snmp_synch_response(ss, pdu, &response);
868         if (status != STAT_SUCCESS || !response ||
869                 response->errstat != SNMP_ERR_NOERROR) {
870             uptime[0] = '\0';
871         }
872         else {
873             netsnmp_variable_list *vlp = response->variables;
874             if (vlp->type == SNMP_NOSUCHINSTANCE) abort();
875             uptime_string_n(*vlp->val.integer, uptime, sizeof(uptime));
876         }
877         snmp_free_pdu(response);
878 
879         clock = time(NULL);
880         ptm = localtime(&clock);
881         strftime(timestr, sizeof(timestr), "%H:%M:%S", ptm);
882 
883         clear();
884         move(0, 0);
885         printw("%s %s%s", session.peername, uptime[0] ? "up " : "", uptime);
886         move(0, COLS-strlen(timestr)-1);
887         printw("%s", timestr);
888         if (has_cpu) {
889             struct cpuStats deltaCpu;
890             u_long sumCpu;
891 
892             deltaCpu.user = newCpu.user - oldCpu.user;
893             deltaCpu.nice = newCpu.nice - oldCpu.nice;
894             deltaCpu.system = newCpu.system - oldCpu.system;
895             deltaCpu.idle = newCpu.idle - oldCpu.idle;
896             deltaCpu.wait = newCpu.wait - oldCpu.wait;
897             deltaCpu.kernel = newCpu.kernel - oldCpu.kernel;
898             deltaCpu.intr = newCpu.intr - oldCpu.intr;
899             deltaCpu.softintr = newCpu.softintr - oldCpu.softintr;
900             deltaCpu.steal = newCpu.steal - oldCpu.steal;
901             deltaCpu.guest = newCpu.guest - oldCpu.guest;
902             deltaCpu.guestnice = newCpu.guestnice - oldCpu.guestnice;
903             oldCpu = newCpu;
904             sumCpu = deltaCpu.user + deltaCpu.nice
905                 + deltaCpu.system + deltaCpu.idle
906                 + deltaCpu.wait + deltaCpu.kernel + deltaCpu.steal
907                 + deltaCpu.intr + deltaCpu.softintr
908                 + deltaCpu.guest + deltaCpu.guestnice;
909 
910             printw("\nCPU%%: %4.1fUs %4.1fSy %4.1fId %3.1fWa %3.1fNi %3.1fKe %3.1fHi %3.1fSi %3.1fSt %3.1fGu %3.1fGN",
911                 (float)deltaCpu.user*100/sumCpu,
912                 (float)deltaCpu.system*100/sumCpu,
913                 (float)deltaCpu.idle*100/sumCpu,
914                 (float)deltaCpu.wait*100/sumCpu,
915                 (float)deltaCpu.nice*100/sumCpu,
916                 (float)deltaCpu.kernel*100/sumCpu,
917                 (float)deltaCpu.intr*100/sumCpu,
918                 (float)deltaCpu.softintr*100/sumCpu,
919                 (float)deltaCpu.steal*100/sumCpu,
920                 (float)deltaCpu.guest*100/sumCpu,
921                 (float)deltaCpu.guestnice*100/sumCpu);
922             line++;
923         }
924 
925         if (has_mem) {
926             printw("\nMem:  %10s Total %10s Used %10s Free %10s Buffer",
927                 format_humanmem(b1, sizeof b1, mem.totalReal),
928                 format_humanmem(b2, sizeof b2, mem.totalReal-mem.availReal),
929                 format_humanmem(b3, sizeof b3, mem.availReal),
930                 format_humanmem(b4, sizeof b4, mem.buffer));
931             line++;
932             printw("\nSwap: %10s Total %10s Used %10s Free %10s Cached",
933                 format_humanmem(b1, sizeof b1, mem.totalSwap),
934                 format_humanmem(b2, sizeof b2, mem.totalSwap-mem.availSwap),
935                 format_humanmem(b3, sizeof b3, mem.availSwap),
936                 format_humanmem(b4, sizeof b4, mem.cached));
937             line++;
938         }
939 
940         printw("\n%7s %4s %6s %10s %11s %5s %-10s",
941             "Index", "Type", "Status", "Memory", "Total CPU", "%CPU", "Command");
942         line++;
943         ninx = 0;
944         while (line < LINES && ninx < ncount) {
945             struct hrSWRunTable *proc = nproc+ninx;
946             const char *hr_status, *hr_type;
947 
948             ninx++;
949             if (proc->hrSWRunPerfCPUInc == 0 && !show_idle)
950                 continue;
951             if (proc->hrSWRunType != 4 && !show_os)
952                 continue;
953 
954             line++;
955 
956             switch (proc->hrSWRunType) {
957             case 1: hr_type = "Unkn"; break;
958             case 2: hr_type = "Os"; break;
959             case 3: hr_type = "Drvr"; break;
960             case 4: hr_type = "Appl"; break;
961             default: hr_type = "?"; break;
962             }
963 
964             switch (proc->hrSWRunStatus) {
965             case 1: hr_status = "Run"; break;
966             case 2: hr_status = "Wait"; break;
967             case 3: hr_status = "Event"; break;
968             case 4: hr_status = "Inval"; break;
969             default: hr_status = "?"; break;
970             }
971 
972             printw("\n%7lu %4s %6s %10s %11s %5.1f %s %s",
973                    proc->hrSWRunIndex,
974                    hr_type,
975                    hr_status,
976                    format_humanmem(b1, sizeof b1, proc->hrSWRunPerfMem),
977                    format_sec(b2,sizeof b2, proc->hrSWRunPerfCPU),
978                    (float)proc->hrSWRunPerfCPUInc/5,
979                    command_path && proc->hrSWRunPath[0] ? proc->hrSWRunPath : proc->hrSWRunName,
980                    command_args ? proc->hrSWRunParameters : "");
981         }
982         refresh();
983 
984         qsort(nproc, ncount, sizeof(nproc[0]), pidcomp);
985         free_perf(oproc, ocount);
986         oproc = nproc;
987         ocount = ncount;
988     }
989     endwin();
990 
991     free_perf(oproc, ocount);
992 
993     snmp_close(ss);
994     SOCK_CLEANUP;
995     return 0;
996 }
997 #else
snmptop(int argc,char ** argv)998 int snmptop(int argc, char **argv)
999 {
1000     fprintf(stderr, "%s: curses not detected during configure\n", progname);
1001     return 1;
1002 }
1003 #endif
1004 
1005 
main(int argc,char ** argv)1006 int main(int argc, char **argv)
1007 {
1008     progname = strrchr(argv[0], '/');
1009     if (progname) progname++;
1010     else progname = argv[0];
1011     if (strncmp(progname, "lt-", 3) == 0) progname += 3;
1012 
1013     if (strcmp(progname, "snmpps") == 0) return snmpps(argc, argv);
1014     if (strcmp(progname, "snmptop") == 0) return snmptop(argc, argv);
1015     fprintf(stderr, "%s: unknown prognam name\n", progname);
1016     exit(1);
1017 }
1018