1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include "libbb.h"
34#ifdef __linux__
35# include <sys/sysinfo.h>
36#endif
37
38struct globals {
39 unsigned mem_unit;
40#if ENABLE_DESKTOP
41 uint8_t unit_steps;
42# define G_unit_steps g->unit_steps
43#else
44# define G_unit_steps 10
45#endif
46 unsigned long cached_kb, available_kb, reclaimable_kb;
47};
48
49
50static unsigned long long scale(struct globals *g, unsigned long d)
51{
52 return ((unsigned long long)d * g->mem_unit) >> G_unit_steps;
53}
54
55
56static NOINLINE unsigned int parse_meminfo(struct globals *g)
57{
58 char buf[60];
59 FILE *fp;
60 int seen_cached_and_available_and_reclaimable;
61
62 fp = xfopen_for_read("/proc/meminfo");
63 g->cached_kb = g->available_kb = g->reclaimable_kb = 0;
64 seen_cached_and_available_and_reclaimable = 3;
65 while (fgets(buf, sizeof(buf), fp)) {
66 if (sscanf(buf, "Cached: %lu %*s\n", &g->cached_kb) == 1)
67 if (--seen_cached_and_available_and_reclaimable == 0)
68 break;
69 if (sscanf(buf, "MemAvailable: %lu %*s\n", &g->available_kb) == 1)
70 if (--seen_cached_and_available_and_reclaimable == 0)
71 break;
72 if (sscanf(buf, "SReclaimable: %lu %*s\n", &g->reclaimable_kb) == 1)
73 if (--seen_cached_and_available_and_reclaimable == 0)
74 break;
75 }
76
77 fclose(fp);
78
79 return seen_cached_and_available_and_reclaimable == 0;
80}
81
82int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
83int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
84{
85 struct globals G;
86 struct sysinfo info;
87 unsigned long long cached, cached_plus_free, available;
88 int seen_available;
89
90#if ENABLE_DESKTOP
91 G.unit_steps = 10;
92 if (argv[1] && argv[1][0] == '-') {
93 switch (argv[1][1]) {
94 case 'b':
95 G.unit_steps = 0;
96 break;
97 case 'k':
98
99 break;
100 case 'm':
101 G.unit_steps = 20;
102 break;
103 case 'g':
104 G.unit_steps = 30;
105 break;
106 default:
107 bb_show_usage();
108 }
109 }
110#endif
111 printf(" %12s%12s%12s%12s%12s%12s\n"
112 "Mem: ",
113 "total",
114 "used",
115 "free",
116 "shared", "buff/cache", "available"
117 );
118
119 sysinfo(&info);
120
121 seen_available = parse_meminfo(&G);
122 G.mem_unit = (info.mem_unit ? info.mem_unit : 1);
123 available = ((unsigned long long) G.available_kb * 1024) / G.mem_unit;
124 cached = ((unsigned long long) G.cached_kb * 1024) / G.mem_unit;
125 cached += info.bufferram;
126 cached += ((unsigned long long) G.reclaimable_kb * 1024) / G.mem_unit;
127 cached_plus_free = cached + info.freeram;
128
129
130#if 0
131 while (!(G.mem_unit & 1) && G.unit_steps != 0) {
132 G.mem_unit >>= 1;
133 G.unit_steps--;
134
135 }
136#endif
137
138#define FIELDS_6 "%12llu %11llu %11llu %11llu %11llu %11llu\n"
139#define FIELDS_3 (FIELDS_6 + 6 + 7 + 7)
140#define FIELDS_2 (FIELDS_6 + 6 + 7 + 7 + 7)
141
142 printf(FIELDS_6,
143 scale(&G, info.totalram),
144 scale(&G, info.totalram - cached_plus_free),
145 scale(&G, info.freeram),
146 scale(&G, info.sharedram),
147 scale(&G, cached),
148 scale(&G, available)
149 );
150
151
152
153 if (!seen_available) {
154 printf("-/+ buffers/cache: ");
155 printf(FIELDS_2,
156 scale(&G, info.totalram - cached_plus_free),
157 scale(&G, cached_plus_free)
158 );
159 }
160#if BB_MMU
161 printf("Swap: ");
162 printf(FIELDS_3,
163 scale(&G, info.totalswap),
164 scale(&G, info.totalswap - info.freeswap),
165 scale(&G, info.freeswap)
166 );
167#endif
168 return EXIT_SUCCESS;
169}
170