1 /*
2    A colorful `free' clone with graphs and such.
3 */
4 /*
5  * Copyright (c) 2004, 2005, 2009, 2013, 2014  Roy Keene
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 #if defined(HAVE_LIBSTATGRAB) && !defined(HAVE_LIBSTATGRAB_H)
32 #undef HAVE_LIBSTATGRAB
33 #endif
34 #include <assert.h>
35 #include <stdint.h>
36 
37 #ifndef HAVE_LIBSTATGRAB
38 #include <linux/kernel.h>
39 #include <sys/sysinfo.h>
40 #ifndef PROC_MEMINFO
41 #define PROC_MEMINFO "/proc/meminfo"
42 #endif
43 #else
44 #include <statgrab.h>
45 #endif
46 #include <string.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #ifndef NO_GETOPT
51 #include <getopt.h>
52 #endif
53 #define BARLEN 35
54 #define HEADERLEN 14
55 #define VERSION "0.9.3"
56 
57 extern char *optarg;
58 extern int optind, opterr, optopt;
59 
60 struct freecolor_meminfo {
61 	uint64_t totalram;  /* Total usable main memory size */
62 	uint64_t freeram;   /* Available memory size */
63 	uint64_t sharedram; /* Amount of shared memory */
64 	uint64_t bufferram; /* Memory used by buffers */
65 	uint64_t cachedram; /* Memory used for I/O cache */
66 	uint64_t totalswap; /* Total swap space size */
67 	uint64_t freeswap;  /* swap space still available */
68 };
69 
bargraph(double percent,double secondper,char marks[BARLEN+HEADERLEN+1],int usefull)70 void bargraph(double percent, double secondper, char marks[BARLEN + HEADERLEN + 1], int usefull) {
71 	char percentone[BARLEN + 1], percenttwo[BARLEN + 1], remain[BARLEN + 1];
72 	unsigned int numberofmarks, numofmarkstwo, remainnum;
73 
74 	numberofmarks=(int) ((double) (BARLEN * (percent / 100)));
75 
76 	assert(numberofmarks <= BARLEN);
77 
78 	if (!usefull) {
79 		numofmarkstwo = (int) ((double) (BARLEN * (secondper / 100)));
80 	} else {
81 		numofmarkstwo = (BARLEN - numberofmarks);
82 	}
83 
84 	assert(numofmarkstwo <= BARLEN);
85 
86 	remainnum = BARLEN - (numberofmarks + numofmarkstwo);
87 
88 	assert(remainnum <= BARLEN);
89 
90 	memset(percentone, '#', numberofmarks);
91 	memset(percenttwo, '%', numofmarkstwo);
92 	memset(remain, '.', remainnum);
93 
94 	percentone[numberofmarks] = 0;
95 	percenttwo[numofmarkstwo] = 0;
96 
97 	remain[remainnum] = 0;
98 
99 	snprintf(marks, BARLEN + HEADERLEN + 1, "%s\033[1;31m%s\033[1;37m%s", percentone, percenttwo, remain);
100 
101 	return;
102 }
103 
104 #ifndef HAVE_LIBSTATGRAB
105 /*
106   Extracted alot from sysinfo.c (part of the procps package?) by
107   Michael K. Johnson <johnsonm@redhat.com>
108 */
get_meminfo(char searchfor[12])109 unsigned long get_meminfo(char searchfor[12]) {
110 	FILE *fd;
111 	unsigned long value = 0, results = 0;
112 	char buffer[256];
113 	char fieldname[12];
114 
115 	fd = fopen(PROC_MEMINFO, "r");
116 	if (fd == NULL) {
117 		return(0);
118 	}
119 
120 	while (!feof(fd)) {
121 		fgets(buffer, sizeof(buffer), fd);
122 		sscanf(buffer,"%11s%lu",fieldname,&value);
123 		if (strcmp(fieldname, searchfor) == 0) {
124 			results+=(value*1024);
125 		}
126 	}
127 
128 	fclose(fd);
129 
130 	return(results);
131 }
132 
get_all_meminfo(struct freecolor_meminfo * retval)133 int get_all_meminfo(struct freecolor_meminfo *retval) {
134 	struct sysinfo sinfo;
135 	uint64_t meminfo_cached;
136 	uint64_t multiplier;
137 
138 	meminfo_cached = get_meminfo("Cached:");
139 	sysinfo(&sinfo);
140 
141 #ifdef HAVE_SYSINFO_MEM_UNIT
142 	multiplier = sinfo.mem_unit;
143 #else
144 	multiplier = 1;
145 #endif
146 
147 	retval->totalram  = sinfo.totalram * multiplier;
148 	retval->freeram   = sinfo.freeram * multiplier;
149 	retval->sharedram = sinfo.sharedram * multiplier;
150 	retval->bufferram = sinfo.bufferram * multiplier;
151 	retval->totalswap = sinfo.totalswap * multiplier;
152 	retval->freeswap  = sinfo.freeswap * multiplier;
153 
154 	retval->cachedram = meminfo_cached;
155 
156 	return(0);
157 }
158 #else
get_all_meminfo(struct freecolor_meminfo * retval)159 int get_all_meminfo(struct freecolor_meminfo *retval) {
160 	static int init_called = 0;
161 	sg_mem_stats *mem_stats;
162 	sg_swap_stats *swap_stats;
163 
164 	if (init_called == 0) {
165 		init_called = 1;
166 
167 		sg_init(0);
168 
169 #ifdef HAVE_STATGRAB_DROP_PRIVILEGES
170 		/* Drop setuid/setgid privileges. */
171 		if (sg_drop_privileges() != 0) {
172 			perror("Error. Failed to drop privileges");
173 			return(-1);
174 		}
175 #endif
176 	}
177 
178 	mem_stats = sg_get_mem_stats(NULL);
179 	swap_stats = sg_get_swap_stats(NULL);
180 
181 	if (mem_stats == NULL || swap_stats == NULL) {
182 		return(-1);
183 	}
184 
185 	retval->totalram  = mem_stats->total;
186 	retval->freeram   = mem_stats->free;
187 	retval->cachedram = mem_stats->cache;
188 	retval->sharedram = 0;
189 	retval->bufferram = 0;
190 	retval->totalswap = swap_stats->total;
191 	retval->freeswap  = swap_stats->free;
192 
193 #ifdef HAVE_SG_FREE_MEM_STATS
194 	sg_free_mem_stats(mem_stats);
195 #endif
196 #ifdef HAVE_SG_FREE_SWAP_STATS
197 	sg_free_swap_stats(swap_stats);
198 #endif
199 
200 	return(0);
201 }
202 #endif
203 
main(int argc,char ** argv)204 int main(int argc, char **argv) {
205 	struct freecolor_meminfo sinfo;
206 	uint64_t cachedbuffer, divisor;
207 	double percentram, percentswap, percentbuffer, percentused, percentfree;
208 	double ramfree, ramtotal, swapfree, swaptotal, doloop, totaltotal;
209 	char realbarchart[BARLEN  +HEADERLEN + 1], swapbarchart[BARLEN + HEADERLEN + 1], totalbarchart[BARLEN + HEADERLEN + 1];
210 	int i, dototals, doold, linestoup;
211 	int gam_ret;
212 
213 	/* Set defaults */
214 	divisor = 1024;
215 	doold = 0;
216 	linestoup = 2;
217 	dototals = 0;
218 	doloop = 0;
219 
220 	/* Get arguments */
221 #ifdef NO_GETOPT
222 	for (i=1;i<argc;i++) {
223 		if (argv[i][0] != '-') {
224 			break;
225 		}
226 
227 		switch(argv[i][1]) {
228 			case 's' :
229 				if (argc > (i+1)) {
230 					doloop=atof(argv[i+1]); i++;
231 				}
232 				break;
233 #else
234 	while ((i=getopt(argc, argv, "obkmVs:t")) != -1) {
235 		switch(i) {
236 			case 's' :
237 				doloop=atof(optarg);
238 				break;
239 #endif /* NO_GETOPT */
240 			case 'b' : divisor=1; break;
241 			case 'k' : divisor=1024; break;
242 			case 'm' : divisor=1048576; break;
243 			case 'V' : printf("freecolor version %s\n", VERSION); return(0);
244 			case 't' : dototals=1; linestoup++; break;
245 			case 'o' : doold=1; linestoup++; break;
246 			case '?' :  printf("usage: %s [-b|-k|-m] [-o] [-t] [-s delay] [-V]\n",argv[0]); return(1);
247 			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);
248 		}
249   	}
250 
251 	/* Display information */
252 	while(1) {
253 		gam_ret = get_all_meminfo(&sinfo);
254 		if (gam_ret < 0) {
255 			fprintf(stderr, "Error getting memory information.\n");
256 
257 			return(1);
258 		}
259 
260 		ramtotal  = sinfo.totalram;
261 		ramfree   = sinfo.freeram;
262 		swapfree  = sinfo.freeswap;
263 		swaptotal = sinfo.totalswap;
264 
265 		totaltotal   = sinfo.totalram + sinfo.totalswap;
266 		cachedbuffer = sinfo.bufferram + sinfo.cachedram;
267 
268 		percentram    = (double) ((ramfree / ramtotal) * 100);
269 		percentbuffer = (double) ((cachedbuffer / ramtotal) * 100);
270 		percentfree   = (double) (((sinfo.freeram + sinfo.freeswap + cachedbuffer) / totaltotal) * 100);
271 		percentused   = (int) (100 - ((int) percentfree));
272 
273 		if (swaptotal!=0) {
274 			percentswap = (double) (( swapfree / swaptotal) * 100);
275 		} else {
276 			percentswap = 0;
277 		}
278 
279 		bargraph(percentswap, 0, swapbarchart, 0);
280 		bargraph(percentram, percentbuffer, realbarchart, 0);
281 		bargraph((int) percentfree,(int) percentused, totalbarchart,1);
282 
283 		if (!doold) {
284 			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",
285 			    realbarchart,
286 			    (int) (percentram + percentbuffer),
287 			    (unsigned long) ((ramfree + cachedbuffer) / divisor),
288 			    (unsigned long) (ramtotal / divisor)
289 			);
290 
291 			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",
292 			    swapbarchart,
293 			     (int) percentswap,
294 			     (unsigned long) (swapfree / divisor),
295 			     (unsigned long) (swaptotal/divisor)
296 			);
297 
298 			if (dototals) {
299 				printf("Total     : \033[1;30m[\033[1;32m%s\033[1;30m]\033[1;37m \033[0m(%lu=%lu+%lu)\n",
300 				    totalbarchart,
301 				    (unsigned long) ((sinfo.totalram + sinfo.totalswap) / divisor),
302 				    (unsigned long) ((sinfo.freeram + sinfo.freeswap) / divisor),
303 				    (unsigned long) ((totaltotal - ((sinfo.freeram + sinfo.freeswap + cachedbuffer))) / divisor)
304 				);
305 			}
306 		} else {
307 			printf("             total       used       free     shared    buffers     cached\n");
308 			printf("Mem:  %12lu %10lu %10lu %10lu %10lu %10lu\n",
309 			    (unsigned long) (sinfo.totalram / divisor),
310 			    (unsigned long) ((sinfo.totalram - sinfo.freeram) / divisor),
311 			    (unsigned long) (sinfo.freeram / divisor),
312 			    (unsigned long) (sinfo.sharedram / divisor),
313 			    (unsigned long) (sinfo.bufferram / divisor),
314 			    (unsigned long) (cachedbuffer / divisor)
315 			);
316 
317 			printf("Swap: %12lu %10lu %10lu\n",
318 			    (unsigned long) (sinfo.totalswap / divisor),
319 			    (unsigned long) ((sinfo.totalswap - sinfo.freeswap) / divisor),
320 			    (unsigned long) (sinfo.freeswap / divisor)
321 			);
322 
323 			if (dototals) {
324 				printf("Total: %11lu = (%8lu (used) + %8lu (free))\n",
325 				    (unsigned long) (totaltotal / divisor),
326 				    (unsigned long) ((((long) totaltotal) - ((sinfo.freeram+sinfo.freeswap))) / divisor),
327 				    (unsigned long) ((sinfo.freeram+sinfo.freeswap+((unsigned long) cachedbuffer)) / divisor)
328 				);
329 			}
330 		}
331 
332 		if (doloop==0) {
333 			break;
334 		}
335 
336 		usleep(doloop * 1000000);
337 		printf("\033[%iA", linestoup);
338 	}
339 
340 	return(0);
341 }
342