free: handle "cached" value too
[oweals/busybox.git] / procps / free.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini free implementation for busybox
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under GPLv2, see file LICENSE in this source tree.
8  */
9
10 /* getopt not needed */
11
12 //usage:#define free_trivial_usage
13 //usage:       "" IF_DESKTOP("[-b/k/m/g]")
14 //usage:#define free_full_usage "\n\n"
15 //usage:       "Display the amount of free and used system memory"
16 //usage:
17 //usage:#define free_example_usage
18 //usage:       "$ free\n"
19 //usage:       "              total         used         free       shared      buffers\n"
20 //usage:       "  Mem:       257628       248724         8904        59644        93124\n"
21 //usage:       " Swap:       128516         8404       120112\n"
22 //usage:       "Total:       386144       257128       129016\n"
23
24 #include "libbb.h"
25 #ifdef __linux__
26 # include <sys/sysinfo.h>
27 #endif
28
29 struct globals {
30         unsigned mem_unit;
31 #if ENABLE_DESKTOP
32         unsigned unit_steps;
33 # define G_unit_steps G.unit_steps
34 #else
35 # define G_unit_steps 10
36 #endif
37 } FIX_ALIASING;
38 #define G (*(struct globals*)&bb_common_bufsiz1)
39 #define INIT_G() do { } while (0)
40
41
42 static unsigned long long scale(unsigned long d)
43 {
44         return ((unsigned long long)d * G.mem_unit) >> G_unit_steps;
45 }
46
47 static unsigned long parse_cached_kb(void)
48 {
49         char buf[60]; /* actual lines we expect are ~30 chars or less */
50         FILE *fp;
51         unsigned long cached = 0;
52
53         fp = xfopen_for_read("/proc/meminfo");
54         while (fgets(buf, sizeof(buf), fp) != NULL) {
55                 if (sscanf(buf, "Cached: %lu %*s\n", &cached) == 1)
56                         break;
57         }
58         if (ENABLE_FEATURE_CLEAN_UP)
59                 fclose(fp);
60
61         return cached;
62 }
63
64 int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
65 int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
66 {
67         struct sysinfo info;
68         unsigned long long cached;
69
70         INIT_G();
71
72 #if ENABLE_DESKTOP
73         G.unit_steps = 10;
74         if (argv[1] && argv[1][0] == '-') {
75                 switch (argv[1][1]) {
76                 case 'b':
77                         G.unit_steps = 0;
78                         break;
79                 case 'k': /* 2^10 */
80                         /* G.unit_steps = 10; - already is */
81                         break;
82                 case 'm': /* 2^(2*10) */
83                         G.unit_steps = 20;
84                         break;
85                 case 'g': /* 2^(3*10) */
86                         G.unit_steps = 30;
87                         break;
88                 default:
89                         bb_show_usage();
90                 }
91         }
92 #endif
93         printf("       %11s%11s%11s%11s%11s%11s\n"
94         "Mem:   ",
95                 "total",
96                 "used",
97                 "free",
98                 "shared", "buffers", "cached" /* swap and total don't have these columns */
99         );
100
101         sysinfo(&info);
102         /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
103         G.mem_unit = (info.mem_unit ? info.mem_unit : 1);
104         /* Extract cached from /proc/meminfo and convert to mem_units */
105         cached = ((unsigned long long) parse_cached_kb() * 1024) / G.mem_unit;
106
107 #define FIELDS_6 "%11llu%11llu%11llu%11llu%11llu%11llu\n"
108 #define FIELDS_3 (FIELDS_6 + 3*6)
109 #define FIELDS_2 (FIELDS_6 + 4*6)
110
111         printf(FIELDS_6,
112                 scale(info.totalram),                //total
113                 scale(info.totalram - info.freeram), //used
114                 scale(info.freeram),                 //free
115                 scale(info.sharedram),               //shared
116                 scale(info.bufferram),               //buffers
117                 scale(cached)                        //cached
118         );
119         /* Show alternate, more meaningful busy/free numbers by counting
120          * buffer cache as free memory. */
121         printf("-/+ buffers/cache:");
122         cached += info.freeram;
123         cached += info.bufferram;
124         printf(FIELDS_2,
125                 scale(info.totalram - cached), //used
126                 scale(cached)                  //free
127         );
128 #if BB_MMU
129         printf("Swap:  ");
130         printf(FIELDS_3,
131                 scale(info.totalswap),                 //total
132                 scale(info.totalswap - info.freeswap), //used
133                 scale(info.freeswap)                   //free
134         );
135 #endif
136         return EXIT_SUCCESS;
137 }