/*
A colorful `free' clone with graphs and such.
*/
/*
* Copyright (c) 2004, 2005, 2009, 2013, 2014 Roy Keene
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(HAVE_LIBSTATGRAB) && !defined(HAVE_LIBSTATGRAB_H)
#undef HAVE_LIBSTATGRAB
#endif
#include <assert.h>
#include <stdint.h>
#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.2"
extern char *optarg;
extern int optind, opterr, optopt;
struct freecolor_meminfo {
uint64_t totalram; /* Total usable main memory size */
uint64_t freeram; /* Available memory size */
uint64_t sharedram; /* Amount of shared memory */
uint64_t bufferram; /* Memory used by buffers */
uint64_t cachedram; /* Memory used for I/O cache */
uint64_t totalswap; /* Total swap space size */
uint64_t freeswap; /* swap space still available */
};
void bargraph(double percent, double 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) ((double) (BARLEN * (percent / 100)));
assert(numberofmarks <= BARLEN);
if (!usefull) {
numofmarkstwo = (int) ((double) (BARLEN * (secondper / 100)));
} else {
numofmarkstwo = (BARLEN - numberofmarks);
}
assert(numofmarkstwo <= BARLEN);
remainnum = BARLEN - (numberofmarks + numofmarkstwo);
assert(remainnum <= BARLEN);
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;
uint64_t meminfo_cached;
uint64_t multiplier;
meminfo_cached = get_meminfo("Cached:");
sysinfo(&sinfo);
#ifdef HAVE_SYSINFO_MEM_UNIT
multiplier = sinfo.mem_unit;
#else
multiplier = 1;
#endif
retval->totalram = sinfo.totalram * multiplier;
retval->freeram = sinfo.freeram * multiplier;
retval->sharedram = sinfo.sharedram * multiplier;
retval->bufferram = sinfo.bufferram * multiplier;
retval->totalswap = sinfo.totalswap * multiplier;
retval->freeswap = sinfo.freeswap * multiplier;
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;
uint64_t cachedbuffer, divisor;
double percentram, percentswap, percentbuffer, percentused, percentfree;
double 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 = (double) ((ramfree / ramtotal) * 100);
percentbuffer = (double) ((cachedbuffer / ramtotal) * 100);
percentfree = (double) (((sinfo.freeram + sinfo.freeswap + cachedbuffer) / totaltotal) * 100);
percentused = (int) (100 - ((int) percentfree));
if (swaptotal!=0) {
percentswap = (double) (( 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),
(unsigned long) ((((long) totaltotal) - ((sinfo.freeram+sinfo.freeswap))) / divisor),
(unsigned long) ((sinfo.freeram+sinfo.freeswap+((unsigned long) cachedbuffer)) / divisor)
);
}
}
if (doloop==0) {
break;
}
usleep(doloop * 1000000);
printf("\033[%iA", linestoup);
}
return(0);
}