#!/bin/sh -e
#
# 2014 Daniel Heule  (hda at sfs.biz)
# 2014 Thomas Oettli (otho at sfs.biz)
# Copyright 2017, Philippe Gregoire <pg@pgregoire.xyz>
# 2020 Dennis Camera <dennis.camera at ssrq-sds-fds.ch>
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
# Returns the amount of memory physically installed in the system, or if that
# cannot be determined the amount available to the operating system kernel,
# in kibibytes (kiB).

str2bytes() {
	awk -F' ' '
	$2 ==   "B" || !$2 { print $1 }
	$2 ==  "kB" { printf "%.f\n", ($1 * 1000) }
	$2 ==  "MB" { printf "%.f\n", ($1 * 1000 * 1000) }
	$2 ==  "GB" { printf "%.f\n", ($1 * 1000 * 1000 * 1000) }
	$2 ==  "TB" { printf "%.f\n", ($1 * 1000 * 1000 * 1000 * 1000) }
	$2 == "kiB" { printf "%.f\n", ($1 * 1024) }
	$2 == "MiB" { printf "%.f\n", ($1 * 1024 * 1024) }
	$2 == "GiB" { printf "%.f\n", ($1 * 1024 * 1024 * 1024) }
	$2 == "TiB" { printf "%.f\n", ($1 * 1024 * 1024 * 1024 * 1024) }'
}

bytes2kib() {
	awk '$0 > 0 { printf "%.f\n", ($0 / 1024) }'
}


case $(uname -s)
in
	(Darwin)
		sysctl -n hw.memsize | bytes2kib
		;;
	(FreeBSD)
		sysctl -n hw.realmem | bytes2kib
		;;
	(NetBSD|OpenBSD)
		# NOTE: This reports "usable" memory, not physically installed memory.
		command -p sysctl -n hw.physmem | bytes2kib
		;;
	(SunOS)
		# Make sure that awk from xpg4 is used for the scripts to work
		export PATH="/usr/xpg4/bin:${PATH}"
		prtconf \
		| awk -F ': ' '
		  $1 == "Memory size" { sub(/Megabytes/, "MiB", $2); print $2 }
		  /^$/ { exit }' \
		| str2bytes \
		| bytes2kib
		;;
	(Linux)
		if test -d /sys/devices/system/memory
		then
			# Use memory blocks if the architecture (e.g. x86, PPC64, s390)
			# supports them (they denote physical memory)
			num_mem_blocks=$(cat /sys/devices/system/memory/memory[0-9]*/state | grep -cxF online)
			mem_block_size=$(cat /sys/devices/system/memory/block_size_bytes)

			echo $((num_mem_blocks * 0x$mem_block_size)) | bytes2kib && exit
		fi
		if test -r /proc/meminfo
		then
			# Fall back to meminfo file on other architectures (e.g. ARM, MIPS,
			# PowerPC)
			# NOTE: This is "usable" memory, not physically installed memory.
			awk -F ': +' '$1 == "MemTotal" { sub(/B$/, "iB", $2); print $2 }' /proc/meminfo \
			| str2bytes \
			| bytes2kib
		fi
		;;
	(*)
		printf "Your kernel (%s) is currently not supported by the memory explorer\n" "$(uname -s)" >&2
		printf "Please contribute an implementation for it if you can.\n" >&2
		exit 1
		;;
esac
