busybox/procps/free.c
<<
>>
Prefs
   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//config:config FREE
  10//config:       bool "free"
  11//config:       default y
  12//config:       select PLATFORM_LINUX #sysinfo()
  13//config:       help
  14//config:         free displays the total amount of free and used physical and swap
  15//config:         memory in the system, as well as the buffers used by the kernel.
  16//config:         The shared memory column should be ignored; it is obsolete.
  17
  18//applet:IF_FREE(APPLET(free, BB_DIR_USR_BIN, BB_SUID_DROP))
  19
  20//kbuild:lib-$(CONFIG_FREE) += free.o
  21
  22//usage:#define free_trivial_usage
  23//usage:       "" IF_DESKTOP("[-b/k/m/g]")
  24//usage:#define free_full_usage "\n\n"
  25//usage:       "Display the amount of free and used system memory"
  26//usage:
  27//usage:#define free_example_usage
  28//usage:       "$ free\n"
  29//usage:       "              total         used         free       shared      buffers\n"
  30//usage:       "  Mem:       257628       248724         8904        59644        93124\n"
  31//usage:       " Swap:       128516         8404       120112\n"
  32//usage:       "Total:       386144       257128       129016\n"
  33
  34#include "libbb.h"
  35#include "common_bufsiz.h"
  36#ifdef __linux__
  37# include <sys/sysinfo.h>
  38#endif
  39
  40struct globals {
  41        unsigned mem_unit;
  42#if ENABLE_DESKTOP
  43        unsigned unit_steps;
  44# define G_unit_steps G.unit_steps
  45#else
  46# define G_unit_steps 10
  47#endif
  48} FIX_ALIASING;
  49#define G (*(struct globals*)bb_common_bufsiz1)
  50#define INIT_G() do { setup_common_bufsiz(); } while (0)
  51
  52
  53static unsigned long long scale(unsigned long d)
  54{
  55        return ((unsigned long long)d * G.mem_unit) >> G_unit_steps;
  56}
  57
  58static unsigned long parse_cached_kb(void)
  59{
  60        char buf[60]; /* actual lines we expect are ~30 chars or less */
  61        FILE *fp;
  62        unsigned long cached = 0;
  63
  64        fp = xfopen_for_read("/proc/meminfo");
  65        while (fgets(buf, sizeof(buf), fp) != NULL) {
  66                if (sscanf(buf, "Cached: %lu %*s\n", &cached) == 1)
  67                        break;
  68        }
  69        if (ENABLE_FEATURE_CLEAN_UP)
  70                fclose(fp);
  71
  72        return cached;
  73}
  74
  75int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  76int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
  77{
  78        struct sysinfo info;
  79        unsigned long long cached;
  80
  81        INIT_G();
  82
  83#if ENABLE_DESKTOP
  84        G.unit_steps = 10;
  85        if (argv[1] && argv[1][0] == '-') {
  86                switch (argv[1][1]) {
  87                case 'b':
  88                        G.unit_steps = 0;
  89                        break;
  90                case 'k': /* 2^10 */
  91                        /* G.unit_steps = 10; - already is */
  92                        break;
  93                case 'm': /* 2^(2*10) */
  94                        G.unit_steps = 20;
  95                        break;
  96                case 'g': /* 2^(3*10) */
  97                        G.unit_steps = 30;
  98                        break;
  99                default:
 100                        bb_show_usage();
 101                }
 102        }
 103#endif
 104        printf("       %11s%11s%11s%11s%11s%11s\n"
 105        "Mem:   ",
 106                "total",
 107                "used",
 108                "free",
 109                "shared", "buffers", "cached" /* swap and total don't have these columns */
 110        );
 111
 112        sysinfo(&info);
 113        /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
 114        G.mem_unit = (info.mem_unit ? info.mem_unit : 1);
 115        /* Extract cached from /proc/meminfo and convert to mem_units */
 116        cached = ((unsigned long long) parse_cached_kb() * 1024) / G.mem_unit;
 117
 118#define FIELDS_6 "%11llu%11llu%11llu%11llu%11llu%11llu\n"
 119#define FIELDS_3 (FIELDS_6 + 3*6)
 120#define FIELDS_2 (FIELDS_6 + 4*6)
 121
 122        printf(FIELDS_6,
 123                scale(info.totalram),                //total
 124                scale(info.totalram - info.freeram), //used
 125                scale(info.freeram),                 //free
 126                scale(info.sharedram),               //shared
 127                scale(info.bufferram),               //buffers
 128                scale(cached)                        //cached
 129        );
 130        /* Show alternate, more meaningful busy/free numbers by counting
 131         * buffer cache as free memory. */
 132        printf("-/+ buffers/cache:");
 133        cached += info.freeram;
 134        cached += info.bufferram;
 135        printf(FIELDS_2,
 136                scale(info.totalram - cached), //used
 137                scale(cached)                  //free
 138        );
 139#if BB_MMU
 140        printf("Swap:  ");
 141        printf(FIELDS_3,
 142                scale(info.totalswap),                 //total
 143                scale(info.totalswap - info.freeswap), //used
 144                scale(info.freeswap)                   //free
 145        );
 146#endif
 147        return EXIT_SUCCESS;
 148}
 149