/*
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>
#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.9.0"
extern char *optarg;
extern int optind, opterr, optopt;
struct freecolor_meminfo {
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 cachedram; /* Memory used for I/O cache */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
};
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];
char fieldname[12];
fd = fopen(PROC_MEMINFO, "r");
if (fd == NULL) {
return(0);
}
while (!feof(fd)) {
fgets(buffer, sizeof(buffer), fd);
sscanf(buffer,"%11s%lu",fieldname,&value);
if (strcmp(fieldname, searchfor) == 0) {
results+=(value*1024);
}
}
fclose(fd);
return(results);
}
int get_all_meminfo(struct freecolor_meminfo *retval) {
struct sysinfo sinfo;
unsigned long meminfo_cached;
meminfo_cached = get_meminfo("Cached:");
sysinfo(&sinfo);
retval->totalram = sinfo.totalram;
retval->freeram = sinfo.freeram;
retval->sharedram = sinfo.sharedram;
retval->bufferram = sinfo.bufferram;
retval->totalswap = sinfo.totalswap;
retval->freeswap = sinfo.freeswap;
retval->cachedram = meminfo_cached;
return(0);
}
#else
int get_all_meminfo(struct freecolor_meminfo *retval) {
static int init_called = 0;
sg_mem_stats *mem_stats;
sg_swap_stats *swap_stats;
if (init_called == 0) {
init_called = 1;
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
}
mem_stats = sg_get_mem_stats();
swap_stats = sg_get_swap_stats();
if (mem_stats == NULL || swap_stats == NULL) {
return(-1);
}
retval->totalram = mem_stats->total;
retval->freeram = mem_stats->free;
retval->cachedram = mem_stats->cache;
retval->sharedram = 0;
retval->bufferram = 0;
retval->totalswap = swap_stats->total;
retval->freeswap = swap_stats->free;
#ifdef HAVE_SG_FREE_MEM_STATS
sg_free_mem_stats(mem_stats);
#endif
#ifdef HAVE_SG_FREE_SWAP_STATS
sg_free_swap_stats(swap_stats);
#endif
return(0);
}
#endif
int main(int argc, char **argv) {
struct freecolor_meminfo sinfo;
unsigned long cachedbuffer, divisor;
float percentram, percentswap, percentbuffer, percentused, percentfree;
float ramfree, ramtotal, swapfree, swaptotal, doloop, totaltotal;
char realbarchart[BARLEN +HEADERLEN + 1], swapbarchart[BARLEN + HEADERLEN + 1], totalbarchart[BARLEN + HEADERLEN + 1];
int i, dototals, doold, linestoup;
int gam_ret;
/* Set defaults */
divisor = 1024;
doold = 0;
linestoup = 2;
dototals = 0;
doloop = 0;
/* Get arguments */
#ifdef NO_GETOPT
for (i=1;i<argc;i++) {
if (argv[i][0] != '-') {
break;
}
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) {
switch(i) {
case 's' :
doloop=atof(optarg);
break;
#endif /* NO_GETOPT */
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;
case '?' : printf("usage: %s [-b|-k|-m] [-o] [-t] [-s delay] [-V]\n",argv[0]); return(1);
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);
}
}
/* Display information */
while(1) {
gam_ret = get_all_meminfo(&sinfo);
if (gam_ret < 0) {
fprintf(stderr, "Error getting memory information.\n");
return(1);
}
ramtotal = sinfo.totalram;
ramfree = sinfo.freeram;
swapfree = sinfo.freeswap;
swaptotal = sinfo.totalswap;
totaltotal = sinfo.totalram + sinfo.totalswap;
cachedbuffer = sinfo.bufferram + sinfo.cachedram;
percentram = (float) ((ramfree / ramtotal) * 100);
percentbuffer = (float) ((cachedbuffer / ramtotal) * 100);
percentfree = (float) (((sinfo.freeram + sinfo.freeswap + cachedbuffer) / 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",
(unsigned long) (sinfo.totalram / divisor),
(unsigned long) ((sinfo.totalram - sinfo.freeram) / divisor),
(unsigned long) (sinfo.freeram / divisor),
(unsigned long) (sinfo.sharedram / divisor),
(unsigned long) (sinfo.bufferram / divisor),
(unsigned long) (cachedbuffer / divisor)
);
printf("Swap: %12lu %10lu %10lu\n",
(unsigned long) (sinfo.totalswap / divisor),
(unsigned long) ((sinfo.totalswap - sinfo.freeswap) / divisor),
(unsigned long) (sinfo.freeswap / divisor)
);
if (dototals) {
printf("Total: %11lu = (%8lu (used) + %8lu (free))\n",
(unsigned long) (totaltotal / divisor),
(((long) totaltotal) - ((sinfo.freeram+sinfo.freeswap))) / divisor,
(sinfo.freeram+sinfo.freeswap+((unsigned long) cachedbuffer)) / divisor
);
}
}
if (doloop==0) {
break;
}
usleep(doloop * 1000000);
printf("\033[%iA", linestoup);
}
return(0);
}