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