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 (2.4 kb)"
  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_NOFORK(free, free, BB_DIR_USR_BIN, BB_SUID_DROP, free))
  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#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/* Because of NOFORK, "globals" are not in global data */
  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/* NOINLINE reduces main() stack usage, which makes code smaller (on x86 at least) */
  56static NOINLINE unsigned long parse_cached_kb(void)
  57{
  58        char buf[60]; /* actual lines we expect are ~30 chars or less */
  59        FILE *fp;
  60        unsigned long cached = 0;
  61
  62        fp = xfopen_for_read("/proc/meminfo");
  63        while (fgets(buf, sizeof(buf), fp) != NULL) {
  64                if (sscanf(buf, "Cached: %lu %*s\n", &cached) == 1)
  65                        break;
  66        }
  67        /* Have to close because of NOFORK */
  68        fclose(fp);
  69
  70        return cached;
  71}
  72
  73int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  74int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
  75{
  76        struct globals G;
  77        struct sysinfo info;
  78        unsigned long long cached;
  79
  80#if ENABLE_DESKTOP
  81        G.unit_steps = 10;
  82        if (argv[1] && argv[1][0] == '-') {
  83                switch (argv[1][1]) {
  84                case 'b':
  85                        G.unit_steps = 0;
  86                        break;
  87                case 'k': /* 2^10 */
  88                        /* G.unit_steps = 10; - already is */
  89                        break;
  90                case 'm': /* 2^(2*10) */
  91                        G.unit_steps = 20;
  92                        break;
  93                case 'g': /* 2^(3*10) */
  94                        G.unit_steps = 30;
  95                        break;
  96                default:
  97                        bb_show_usage();
  98                }
  99        }
 100#endif
 101        printf("       %11s%11s%11s%11s%11s%11s\n"
 102        "Mem:   ",
 103                "total",
 104                "used",
 105                "free",
 106                "shared", "buffers", "cached" /* swap and total don't have these columns */
 107        );
 108
 109        sysinfo(&info);
 110        /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
 111        G.mem_unit = (info.mem_unit ? info.mem_unit : 1);
 112        /* Extract cached from /proc/meminfo and convert to mem_units */
 113        cached = ((unsigned long long) parse_cached_kb() * 1024) / G.mem_unit;
 114
 115#define FIELDS_6 "%11llu%11llu%11llu%11llu%11llu%11llu\n"
 116#define FIELDS_3 (FIELDS_6 + 3*6)
 117#define FIELDS_2 (FIELDS_6 + 4*6)
 118
 119        printf(FIELDS_6,
 120                scale(&G, info.totalram),                //total
 121                scale(&G, info.totalram - info.freeram), //used
 122                scale(&G, info.freeram),                 //free
 123                scale(&G, info.sharedram),               //shared
 124                scale(&G, info.bufferram),               //buffers
 125                scale(&G, cached)                        //cached
 126        );
 127        /* Show alternate, more meaningful busy/free numbers by counting
 128         * buffer cache as free memory. */
 129        printf("-/+ buffers/cache:");
 130        cached += info.freeram;
 131        cached += info.bufferram;
 132        printf(FIELDS_2,
 133                scale(&G, info.totalram - cached), //used
 134                scale(&G, cached)                  //free
 135        );
 136#if BB_MMU
 137        printf("Swap:  ");
 138        printf(FIELDS_3,
 139                scale(&G, info.totalswap),                 //total
 140                scale(&G, info.totalswap - info.freeswap), //used
 141                scale(&G, info.freeswap)                   //free
 142        );
 143#endif
 144        return EXIT_SUCCESS;
 145}
 146