/* This file is part of GNUnet. Copyright (C) 2008--2013 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ #include "platform.h" #include "gnunet_util_lib.h" /* * File for parsing top-level /proc entities. * Copyright Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm@redhat.com * Copyright 1998-2003 Albert Cahalan * June 2003, Fabian Frederick, disk and slab info * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define BAD_OPEN_MESSAGE \ "Error: /proc must be mounted\n" \ " To mount /proc at boot you need an /etc/fstab line like:\n" \ " proc /proc proc defaults\n" \ " In the meantime, run \"mount proc /proc -t proc\"\n" #define STAT_FILE "/proc/stat" // static int stat_fd = -1; #define UPTIME_FILE "/proc/uptime" // static int uptime_fd = -1; #define LOADAVG_FILE "/proc/loadavg" // static int loadavg_fd = -1; #define MEMINFO_FILE "/proc/meminfo" static int meminfo_fd = -1; #define VMINFO_FILE "/proc/vmstat" // static int vminfo_fd = -1; // As of 2.6.24 /proc/meminfo seems to need 888 on 64-bit, // and would need 1258 if the obsolete fields were there. static char buf[2048]; /* This macro opens filename only if necessary and seeks to 0 so * that successive calls to the functions are more efficient. * It also reads the current contents of the file into the global buf. */ #define FILE_TO_BUF(filename, fd) do { \ static int local_n; \ if (fd == -1 && (fd = open (filename, O_RDONLY)) == -1) { \ fputs (BAD_OPEN_MESSAGE, stderr); \ fflush (NULL); \ _exit (102); \ } \ lseek (fd, 0L, SEEK_SET); \ if ((local_n = read (fd, buf, sizeof buf - 1)) < 0) { \ perror (filename); \ fflush (NULL); \ _exit (103); \ } \ buf[local_n] = '\0'; \ } while (0) /***********************************************************************/ /* * Copyright 1999 by Albert Cahalan; all rights reserved. * This file may be used subject to the terms and conditions of the * GNU Library General Public License Version 2, or any later version * at your option, as published by the Free Software Foundation. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. */ typedef struct mem_table_struct { const char *name; /* memory type name */ unsigned long *slot; /* slot in return struct */ } mem_table_struct; static int compare_mem_table_structs (const void *a, const void *b) { return strcmp (((const mem_table_struct *) a)->name, ((const mem_table_struct *) b) -> name); } /* example data, following junk, with comments added: * * MemTotal: 61768 kB old * MemFree: 1436 kB old * MemShared: 0 kB old (now always zero; not calculated) * Buffers: 1312 kB old * Cached: 20932 kB old * Active: 12464 kB new * Inact_dirty: 7772 kB new * Inact_clean: 2008 kB new * Inact_target: 0 kB new * Inact_laundry: 0 kB new, and might be missing too * HighTotal: 0 kB * HighFree: 0 kB * LowTotal: 61768 kB * LowFree: 1436 kB * SwapTotal: 122580 kB old * SwapFree: 60352 kB old * Inactive: 20420 kB 2.5.41+ * Dirty: 0 kB 2.5.41+ * Writeback: 0 kB 2.5.41+ * Mapped: 9792 kB 2.5.41+ * Slab: 4564 kB 2.5.41+ * Committed_AS: 8440 kB 2.5.41+ * PageTables: 304 kB 2.5.41+ * ReverseMaps: 5738 2.5.41+ * SwapCached: 0 kB 2.5.??+ * HugePages_Total: 220 2.5.??+ * HugePages_Free: 138 2.5.??+ * Hugepagesize: 4096 kB 2.5.??+ */ /* obsolete */ unsigned long kb_main_shared; /* old but still kicking -- the important stuff */ unsigned long kb_main_buffers; unsigned long kb_main_cached; unsigned long kb_main_free; unsigned long kb_main_total; unsigned long kb_swap_free; unsigned long kb_swap_total; /* recently introduced */ unsigned long kb_high_free; unsigned long kb_high_total; unsigned long kb_low_free; unsigned long kb_low_total; /* 2.4.xx era */ unsigned long kb_active; unsigned long kb_inact_laundry; unsigned long kb_inact_dirty; unsigned long kb_inact_clean; unsigned long kb_inact_target; unsigned long kb_swap_cached; /* late 2.4 and 2.6+ only */ /* derived values */ unsigned long kb_swap_used; unsigned long kb_main_used; /* 2.5.41+ */ unsigned long kb_writeback; unsigned long kb_slab; unsigned long nr_reversemaps; unsigned long kb_committed_as; unsigned long kb_dirty; unsigned long kb_inactive; unsigned long kb_mapped; unsigned long kb_pagetables; // seen on a 2.6.x kernel: static unsigned long kb_vmalloc_chunk; static unsigned long kb_vmalloc_total; static unsigned long kb_vmalloc_used; // seen on 2.6.24-rc6-git12 static unsigned long kb_anon_pages; static unsigned long kb_bounce; static unsigned long kb_commit_limit; static unsigned long kb_nfs_unstable; static unsigned long kb_swap_reclaimable; static unsigned long kb_swap_unreclaimable; void meminfo (void) { char namebuf[16]; /* big enough to hold any row name */ mem_table_struct findme = { namebuf, NULL }; mem_table_struct *found; char *head; char *tail; static const mem_table_struct mem_table[] = { { "Active", &kb_active }, // important { "AnonPages", &kb_anon_pages }, { "Bounce", &kb_bounce }, { "Buffers", &kb_main_buffers }, // important { "Cached", &kb_main_cached }, // important { "CommitLimit", &kb_commit_limit }, { "Committed_AS", &kb_committed_as }, { "Dirty", &kb_dirty }, // kB version of vmstat nr_dirty { "HighFree", &kb_high_free }, { "HighTotal", &kb_high_total }, { "Inact_clean", &kb_inact_clean }, { "Inact_dirty", &kb_inact_dirty }, { "Inact_laundry", &kb_inact_laundry }, { "Inact_target", &kb_inact_target }, { "Inactive", &kb_inactive }, // important { "LowFree", &kb_low_free }, { "LowTotal", &kb_low_total }, { "Mapped", &kb_mapped }, // kB version of vmstat nr_mapped { "MemFree", &kb_main_free }, // important { "MemShared", &kb_main_shared }, // important, but now gone! { "MemTotal", &kb_main_total }, // important { "NFS_Unstable", &kb_nfs_unstable }, { "PageTables", &kb_pagetables }, // kB version of vmstat nr_page_table_pages { "ReverseMaps", &nr_reversemaps }, // same as vmstat nr_page_table_pages { "SReclaimable", &kb_swap_reclaimable }, // "swap reclaimable" (dentry and inode structures) { "SUnreclaim", &kb_swap_unreclaimable }, { "Slab", &kb_slab }, // kB version of vmstat nr_slab { "SwapCached", &kb_swap_cached }, { "SwapFree", &kb_swap_free }, // important { "SwapTotal", &kb_swap_total }, // important { "VmallocChunk", &kb_vmalloc_chunk }, { "VmallocTotal", &kb_vmalloc_total }, { "VmallocUsed", &kb_vmalloc_used }, { "Writeback", &kb_writeback }, // kB version of vmstat nr_writeback }; const int mem_table_count = sizeof(mem_table) / sizeof(mem_table_struct); FILE_TO_BUF (MEMINFO_FILE, meminfo_fd); kb_inactive = ~0UL; head = buf; for (;;) { tail = strchr (head, ':'); if (! tail) break; *tail = '\0'; if (strlen (head) >= sizeof(namebuf)) { head = tail + 1; goto nextline; } strcpy (namebuf, head); found = bsearch (&findme, mem_table, mem_table_count, sizeof(mem_table_struct), compare_mem_table_structs ); head = tail + 1; if (! found) goto nextline; *(found->slot) = (unsigned long) strtoull (head, &tail, 10); nextline: tail = strchr (head, '\n'); if (! tail) break; head = tail + 1; } if (! kb_low_total) /* low==main except with large-memory support */ { kb_low_total = kb_main_total; kb_low_free = kb_main_free; } if (kb_inactive == ~0UL) { kb_inactive = kb_inact_dirty + kb_inact_clean + kb_inact_laundry; } kb_swap_used = kb_swap_total - kb_swap_free; kb_main_used = kb_main_total - kb_main_free; }