/*
A colorful `free' clone with graphs and such.
-- Roy Keene [200819992000] rkeene@suspend.net
Bug 230819992230: freecolor segfaults if swapping is off. (fixed,
reported by shammack@goldinc.com).
Warn 260919991600: Warning about returning a local variable fixed (
Jakob Erikson <jakov@quicknet.se>).
Annoy 270819990700: Made the code for the "-o" option neater.
Bug 270819990700: Fixed support for unknown options
(Rene <renec@zorro.pangea.ca)
Annoy 270819990800: Fixed display of buffed and cached memmory.
(Rene <renec@zorro.pangea.ca)
Annoy 270819991030: Fixed the ugly bargraph(), now its less ugly, but
but still not very good.
Annoy 270819992100: Fixed the (less) ugly bargraph(), now it doesnt look
so bad.
Feature 161019991640: Added Total Free/Total Used to "-t" option.
*/
/*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following condition
* is met:
* 1. Redistributions of source code must retain the following disclaimer,
* and this list of conditions.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* JUHA PIRKOLA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(HAVE_LIBSTATGRAB) && !defined(HAVE_LIBSTATGRAB_H)
#undef HAVE_LIBSTATGRAB
#endif
#ifndef HAVE_LIBSTATGRAB
#include <linux/kernel.h>
#include <sys/sysinfo.h>
#include <linux/sys.h>
#ifndef PROC_MEMINFO
#define PROC_MEMINFO "/proc/meminfo"
#endif
#else
#include <statgrab.h>
#endif
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef NO_GETOPT
#include <getopt.h>
#endif
#define BARLEN 35
#define HEADERLEN 14
#define VERSION "0.8.7"
extern char *optarg;
extern int optind, opterr, optopt;
void bargraph(float percent, float secondper, char marks[BARLEN+HEADERLEN+1],int usefull) {
char percentone[BARLEN+1], percenttwo[BARLEN+1], remain[BARLEN+1];
unsigned int numberofmarks, numofmarkstwo, remainnum;
numberofmarks=(int) ((float) (BARLEN*(percent/100)));
if (!usefull) numofmarkstwo=(int) ((float) (BARLEN*(secondper/100))); else numofmarkstwo=(BARLEN-numberofmarks);
remainnum=BARLEN-(numberofmarks+numofmarkstwo);
memset(percentone, '#', numberofmarks);
memset(percenttwo, '%', numofmarkstwo);
memset(remain, '.', remainnum);
percentone[numberofmarks]=0;
percenttwo[numofmarkstwo]=0;
remain[remainnum]=0;
snprintf(marks, BARLEN+HEADERLEN+1, "%s\033[1;31m%s\033[1;37m%s", percentone, percenttwo, remain);
return;
}
#ifndef HAVE_LIBSTATGRAB
/*
Extracted alot from sysinfo.c (part of the procps package?) by
Michael K. Johnson <johnsonm@redhat.com>
*/
unsigned long get_meminfo(char searchfor[12]) {
FILE *fd;
unsigned long value=0, results=0;
char buffer[256]; /* Paranoia, reallly big buffer. */
char feildname[12];
if ((fd=fopen(PROC_MEMINFO, "r"))==NULL) return(0);
while (!feof(fd)) {
fgets(buffer, sizeof(buffer), fd);
sscanf(buffer,"%11s%lu",feildname,&value);
if (strcmp(feildname,searchfor)==0) results+=(value*1024);
}
fclose(fd);
return(results);
}
#endif
int main(int argc, char *argv[]) {
float percentram, percentswap, percentbuffer, percentused, percentfree;
float ramfree, ramtotal, swapfree, swaptotal, doloop=0, cachedbuffer, totaltotal;
char realbarchart[BARLEN+HEADERLEN+1], swapbarchart[BARLEN+HEADERLEN+1], totalbarchart[BARLEN+HEADERLEN+1];
int i, dototals=0, doold=0, linestoup=2;
unsigned long meminfo_cached, divisor=1024;
#ifndef HAVE_LIBSTATGRAB
struct sysinfo sinfo;
meminfo_cached=get_meminfo("Cached:");
#else
sg_mem_stats *mem_stats=NULL;
sg_swap_stats *swap_stats=NULL;
struct systeminfo_st {
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
} sinfo;
sg_init();
#ifdef HAVE_STATGRAB_DROP_PRIVILEGES
/* Drop setuid/setgid privileges. */
if (sg_drop_privileges() != 0) {
perror("Error. Failed to drop privileges");
return 1;
}
#endif
#endif
#ifdef NO_GETOPT
for (i=1;i<argc;i++) {
if (argv[i][0]=='-') {
switch(argv[i][1]) {
case 's' :
if (argc>(i+1)) { doloop=atof(argv[i+1]); i++; }
break;
#else
while ((i=getopt(argc, argv, "obkmVs:t")) != -1) {
if (i=='?') { printf("usage: %s [-b|-k|-m] [-o] [-t] [-s delay] [-V]\n",argv[0]); return(1); }
switch(i) {
case 's' :
doloop=atof(optarg);
break;
#endif
case 'b' : divisor=1; break;
case 'k' : divisor=1024; break;
case 'm' : divisor=1048576; break;
case 'V' : printf("freecolor version %s\n", VERSION); return(0);
case 't' : dototals=1; linestoup++; break;
case 'o' : doold=1; linestoup++; break;
#ifdef NO_GETOPT
default : printf("%s: illegal option -- %c\n",argv[0],argv[i][1]); printf("usage: %s [-b|-k|-m] [-t] [-s delay] [-V]\n",argv[0]); return(1);
}
}
}
#else
}
}
#endif
while(1) {
#ifndef HAVE_LIBSTATGRAB
sysinfo(&sinfo);
#else
if(((mem_stats=sg_get_mem_stats()) == NULL) || (swap_stats=sg_get_swap_stats()) == NULL) {
printf("Couldn't get memory information, exiting.\n");
return(-1);
}
meminfo_cached=mem_stats->cache;
sinfo.totalram=mem_stats->total;
sinfo.freeram=mem_stats->free;
sinfo.sharedram=0;
sinfo.bufferram=0;
sinfo.totalswap=swap_stats->total;
sinfo.freeswap=swap_stats->free;
#endif
ramtotal=sinfo.totalram;
cachedbuffer=sinfo.bufferram+meminfo_cached;
ramfree=sinfo.freeram;
swapfree=sinfo.freeswap;
swaptotal=sinfo.totalswap;
totaltotal=(sinfo.totalram+sinfo.totalswap);
percentram=(float) ((ramfree / ramtotal)*100);
percentbuffer=(float) ((cachedbuffer/ramtotal)*100);
percentfree=(float) (((sinfo.freeram+sinfo.freeswap+meminfo_cached+sinfo.bufferram)/totaltotal)*100);
percentused=(int) (100-((int) percentfree));
if (!(swaptotal==0)) { percentswap=(float) ((swapfree/swaptotal)*100); } else { percentswap=0; }
bargraph(percentswap,0,swapbarchart,0);
bargraph(percentram,percentbuffer,realbarchart,0);
bargraph((int) percentfree,(int) percentused,totalbarchart,1);
if (!doold) {
printf("Physical : \033[1;30m[\033[1;32m%s\033[1;30m]\033[1;37m %i\033[0;31m%%\033[0m\t(%lu/%lu)\n", realbarchart ,(int) (percentram+percentbuffer), (unsigned long) (ramfree+cachedbuffer)/divisor, (unsigned long) ramtotal/divisor);
printf("Swap : \033[1;30m[\033[1;32m%s\033[1;30m]\033[1;37m %i\033[0;31m%%\033[0m\t(%lu/%lu)\n",swapbarchart ,(int) percentswap,(unsigned long) swapfree/divisor, (unsigned long) swaptotal/divisor);
if (dototals)
printf("Total : \033[1;30m[\033[1;32m%s\033[1;30m]\033[1;37m \033[0m(%lu=%lu+%lu)\n", totalbarchart, (unsigned long) (sinfo.totalram+sinfo.totalswap)/divisor,(unsigned long) ((sinfo.freeram+sinfo.freeswap)/divisor), (unsigned long) ((totaltotal-((sinfo.freeram+sinfo.freeswap+cachedbuffer)))/divisor));
} else {
printf(" total used free shared buffers cached\n");
printf("Mem: %12lu %10lu %10lu %10lu %10lu %10lu\n",(sinfo.totalram/divisor), (sinfo.totalram-sinfo.freeram)/divisor, (sinfo.freeram/divisor), (sinfo.sharedram/divisor), (sinfo.bufferram/divisor), (((unsigned long) cachedbuffer)/divisor));
printf("Swap: %12lu %10lu %10lu\n",(sinfo.totalswap/divisor), ((sinfo.totalswap-sinfo.freeswap)/divisor), (sinfo.freeswap/divisor));
if (dototals) printf("Total: %11lu = (%8lu (used) + %8lu (free))\n",(long) totaltotal/divisor,(((long) totaltotal)-((sinfo.freeram+sinfo.freeswap)))/divisor,(sinfo.freeram+sinfo.freeswap+((unsigned long) cachedbuffer))/divisor);
}
if (doloop==0) { return(0); } else { usleep(doloop*1000000); printf("\033[%iA",linestoup); }
}
return(0);
}