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