Index: Makefile =================================================================== --- Makefile +++ Makefile @@ -1,590 +1,8 @@ -# # $FreeBSD$ -# -# The user-driven targets are: -# -# universe - *Really* build *everything* (buildworld and -# all kernels on all architectures). -# tinderbox - Same as universe, but presents a list of failed build -# targets and exits with an error if there were any. -# buildworld - Rebuild *everything*, including glue to help do -# upgrades. -# installworld - Install everything built by "buildworld". -# world - buildworld + installworld, no kernel. -# buildkernel - Rebuild the kernel and the kernel-modules. -# installkernel - Install the kernel and the kernel-modules. -# installkernel.debug -# reinstallkernel - Reinstall the kernel and the kernel-modules. -# reinstallkernel.debug -# kernel - buildkernel + installkernel. -# kernel-toolchain - Builds the subset of world necessary to build a kernel -# kernel-toolchains - Build kernel-toolchain for all universe targets. -# doxygen - Build API documentation of the kernel, needs doxygen. -# update - Convenient way to update your source tree(s). -# checkworld - Run test suite on installed world. -# check-old - List obsolete directories/files/libraries. -# check-old-dirs - List obsolete directories. -# check-old-files - List obsolete files. -# check-old-libs - List obsolete libraries. -# delete-old - Delete obsolete directories/files. -# delete-old-dirs - Delete obsolete directories. -# delete-old-files - Delete obsolete files. -# delete-old-libs - Delete obsolete libraries. -# targets - Print a list of supported TARGET/TARGET_ARCH pairs -# for world and kernel targets. -# toolchains - Build a toolchain for all world and kernel targets. -# xdev - xdev-build + xdev-install for the architecture -# specified with XDEV and XDEV_ARCH. -# xdev-build - Build cross-development tools. -# xdev-install - Install cross-development tools. -# xdev-links - Create traditional links in /usr/bin for cc, etc -# native-xtools - Create host binaries that produce target objects -# for use in qemu user-mode jails. -# -# "quick" way to test all kernel builds: -# _jflag=`sysctl -n hw.ncpu` -# _jflag=$(($_jflag * 2)) -# [ $_jflag -gt 12 ] && _jflag=12 -# make universe -DMAKE_JUST_KERNELS JFLAG=-j${_jflag} -# -# This makefile is simple by design. The FreeBSD make automatically reads -# the /usr/share/mk/sys.mk unless the -m argument is specified on the -# command line. By keeping this makefile simple, it doesn't matter too -# much how different the installed mk files are from those in the source -# tree. This makefile executes a child make process, forcing it to use -# the mk files from the source tree which are supposed to DTRT. -# -# Most of the user-driven targets (as listed above) are implemented in -# Makefile.inc1. The exceptions are universe, tinderbox and targets. -# -# If you want to build your system from source be sure that /usr/obj has -# at least 6GB of diskspace available. A complete 'universe' build requires -# about 100GB of space. -# -# For individuals wanting to build from the sources currently on their -# system, the simple instructions are: -# -# 1. `cd /usr/src' (or to the directory containing your source tree). -# 2. Define `HISTORICAL_MAKE_WORLD' variable (see README). -# 3. `make world' -# -# For individuals wanting to upgrade their sources (even if only a -# delta of a few days): -# -# 1. `cd /usr/src' (or to the directory containing your source tree). -# 2. `make buildworld' -# 3. `make buildkernel KERNCONF=YOUR_KERNEL_HERE' (default is GENERIC). -# 4. `make installkernel KERNCONF=YOUR_KERNEL_HERE' (default is GENERIC). -# [steps 3. & 4. can be combined by using the "kernel" target] -# 5. `reboot' (in single user mode: boot -s from the loader prompt). -# 6. `mergemaster -p' -# 7. `make installworld' -# 8. `mergemaster' (you may wish to use -i, along with -U or -F). -# 9. `make delete-old' -# 10. `reboot' -# 11. `make delete-old-libs' (in case no 3rd party program uses them anymore) -# -# See src/UPDATING `COMMON ITEMS' for more complete information. -# -# If TARGET=machine (e.g. powerpc, sparc64, ...) is specified you can -# cross build world for other machine types using the buildworld target, -# and once the world is built you can cross build a kernel using the -# buildkernel target. -# -# Define the user-driven targets. These are listed here in alphabetical -# order, but that's not important. -# -# Targets that begin with underscore are internal targets intended for -# developer convenience only. They are intentionally not documented and -# completely subject to change without notice. -# -# For more information, see the build(7) manual page. -# -# This is included so CC is set to ccache for -V, and COMPILER_TYPE/VERSION -# can be cached for sub-makes. -.if ${MAKE_VERSION} >= 20140620 && defined(.PARSEDIR) -.include -.endif +PROG= prometheus_sysctl_exporter +MAN= prometheus_sysctl_exporter.8 -# Note: we use this awkward construct to be compatible with FreeBSD's -# old make used in 10.0 and 9.2 and earlier. -.if defined(MK_DIRDEPS_BUILD) && ${MK_DIRDEPS_BUILD} == "yes" && \ - !make(showconfig) && !make(print-dir) -# targets/Makefile plays the role of top-level -.include "targets/Makefile" -.else +LIBADD= m -TGTS= all all-man buildenv buildenvvars buildkernel buildworld \ - check check-old check-old-dirs check-old-files check-old-libs \ - checkdpadd checkworld clean cleandepend cleandir cleanworld \ - delete-old delete-old-dirs delete-old-files delete-old-libs \ - depend distribute distributekernel distributekernel.debug \ - distributeworld distrib-dirs distribution doxygen \ - everything hier hierarchy install installcheck installkernel \ - installkernel.debug packagekernel packageworld \ - reinstallkernel reinstallkernel.debug \ - installworld kernel-toolchain libraries lint maninstall \ - obj objlink rerelease showconfig tags toolchain update \ - _worldtmp _legacy _bootstrap-tools _cleanobj _obj \ - _build-tools _cross-tools _includes _libraries \ - build32 distribute32 install32 buildsoft distributesoft installsoft \ - builddtb xdev xdev-build xdev-install \ - xdev-links native-xtools stageworld stagekernel stage-packages \ - create-world-packages create-kernel-packages create-packages \ - packages installconfig real-packages sign-packages package-pkg \ - print-dir test-system-compiler - -# XXX: r156740: This can't work since bsd.subdir.mk is not included ever. -# It will only work for SUBDIR_TARGETS in make.conf. -TGTS+= ${SUBDIR_TARGETS} - -BITGTS= files includes -BITGTS:=${BITGTS} ${BITGTS:S/^/build/} ${BITGTS:S/^/install/} -TGTS+= ${BITGTS} - -# Only some targets are allowed to use meta mode. Others get it -# disabled. In some cases, such as 'install', meta mode can be dangerous -# as a cookie may be used to prevent redundant installations (such as -# for WORLDTMP staging). For DESTDIR=/ we always want to install though. -# For other cases, such as delete-old-libs, meta mode may break -# the interactive tty prompt. The safest route is to just whitelist -# the ones that benefit from it. -META_TGT_WHITELIST+= \ - _* build32 buildfiles buildincludes buildkernel buildsoft \ - buildworld everything kernel-toolchain kernel-toolchains kernel \ - kernels libraries native-xtools showconfig test-system-compiler \ - tinderbox toolchain \ - toolchains universe world worlds xdev xdev-build - -.ORDER: buildworld installworld -.ORDER: buildworld distributeworld -.ORDER: buildworld buildkernel -.ORDER: installworld distribution -.ORDER: installworld installkernel -.ORDER: buildkernel installkernel -.ORDER: buildkernel installkernel.debug -.ORDER: buildkernel reinstallkernel -.ORDER: buildkernel reinstallkernel.debug - -PATH= /sbin:/bin:/usr/sbin:/usr/bin -MAKEOBJDIRPREFIX?= /usr/obj -_MAKEOBJDIRPREFIX!= /usr/bin/env -i PATH=${PATH} MK_AUTO_OBJ=no ${MAKE} \ - ${.MAKEFLAGS:MMAKEOBJDIRPREFIX=*} __MAKE_CONF=${__MAKE_CONF} \ - -f /dev/null -V MAKEOBJDIRPREFIX dummy -.if !empty(_MAKEOBJDIRPREFIX) -.error MAKEOBJDIRPREFIX can only be set in environment, not as a global\ - (in make.conf(5)) or command-line variable. -.endif - -# We often need to use the tree's version of make to build it. -# Choices add to complexity though. -# We cannot blindly use a make which may not be the one we want -# so be exlicit - until all choice is removed. -WANT_MAKE= bmake -.if !empty(.MAKE.MODE:Mmeta) -# 20160604 - support missing-meta,missing-filemon and performance improvements -WANT_MAKE_VERSION= 20160604 -.else -# 20160220 - support .dinclude for FAST_DEPEND. -WANT_MAKE_VERSION= 20160220 -.endif -MYMAKE= ${MAKEOBJDIRPREFIX}${.CURDIR}/make.${MACHINE}/${WANT_MAKE} -.if defined(.PARSEDIR) -HAVE_MAKE= bmake -.else -HAVE_MAKE= fmake -.endif -.if ${HAVE_MAKE} != ${WANT_MAKE} || \ - (defined(WANT_MAKE_VERSION) && ${MAKE_VERSION} < ${WANT_MAKE_VERSION}) -NEED_MAKE_UPGRADE= t -.endif -.if exists(${MYMAKE}) -SUB_MAKE:= ${MYMAKE} -m ${.CURDIR}/share/mk -.elif defined(NEED_MAKE_UPGRADE) -# It may not exist yet but we may cause it to. -# In the case of fmake, upgrade_checks may cause a newer version to be built. -SUB_MAKE= `test -x ${MYMAKE} && echo ${MYMAKE} || echo ${MAKE}` \ - -m ${.CURDIR}/share/mk -.else -SUB_MAKE= ${MAKE} -m ${.CURDIR}/share/mk -.endif - -_MAKE= PATH=${PATH} MAKE_CMD=${MAKE} ${SUB_MAKE} -f Makefile.inc1 \ - TARGET=${_TARGET} TARGET_ARCH=${_TARGET_ARCH} - -# Only allow meta mode for the whitelisted targets. See META_TGT_WHITELIST -# above. -.for _tgt in ${META_TGT_WHITELIST} -.if make(${_tgt}) -_CAN_USE_META_MODE?= yes -.endif -.endfor -.if !defined(_CAN_USE_META_MODE) -_MAKE+= MK_META_MODE=no -.if defined(.PARSEDIR) -.unexport META_MODE -.endif -.elif defined(MK_META_MODE) && ${MK_META_MODE} == "yes" -.if !exists(/dev/filemon) && !defined(NO_FILEMON) && !make(showconfig) -# Require filemon be loaded to provide a working incremental build -.error ${.newline}ERROR: The filemon module (/dev/filemon) is not loaded. \ - ${.newline}ERROR: WITH_META_MODE is enabled but requires filemon for an incremental build. \ - ${.newline}ERROR: 'kldload filemon' or pass -DNO_FILEMON to suppress this error. -.endif # !exists(/dev/filemon) && !defined(NO_FILEMON) -.endif # !defined(_CAN_USE_META_MODE) - -# Guess machine architecture from machine type, and vice versa. -.if !defined(TARGET_ARCH) && defined(TARGET) -_TARGET_ARCH= ${TARGET:S/pc98/i386/:S/arm64/aarch64/} -.elif !defined(TARGET) && defined(TARGET_ARCH) && \ - ${TARGET_ARCH} != ${MACHINE_ARCH} -_TARGET= ${TARGET_ARCH:C/mips(n32|64)?(el)?(hf)?/mips/:C/arm(v6)?(eb)?/arm/:C/aarch64/arm64/:C/powerpc64/powerpc/:C/powerpcspe/powerpc/:C/riscv64(sf)?/riscv/} -.endif -.if defined(TARGET) && !defined(_TARGET) -_TARGET=${TARGET} -.endif -.if defined(TARGET_ARCH) && !defined(_TARGET_ARCH) -_TARGET_ARCH=${TARGET_ARCH} -.endif -# for historical compatibility for xdev targets -.if defined(XDEV) -_TARGET= ${XDEV} -.endif -.if defined(XDEV_ARCH) -_TARGET_ARCH= ${XDEV_ARCH} -.endif -# Otherwise, default to current machine type and architecture. -_TARGET?= ${MACHINE} -_TARGET_ARCH?= ${MACHINE_ARCH} - -.if make(print-dir) -.SILENT: -.endif - -# -# Make sure we have an up-to-date make(1). Only world and buildworld -# should do this as those are the initial targets used for upgrades. -# The user can define ALWAYS_CHECK_MAKE to have this check performed -# for all targets. -# -.if defined(ALWAYS_CHECK_MAKE) || !defined(.PARSEDIR) -${TGTS}: upgrade_checks -.else -buildworld: upgrade_checks -.endif - -# -# Handle the user-driven targets, using the source relative mk files. -# - -tinderbox toolchains kernel-toolchains: .MAKE -${TGTS}: .PHONY .MAKE - ${_+_}@cd ${.CURDIR}; ${_MAKE} ${.TARGET} - -# The historic default "all" target creates files which may cause stale -# or (in the cross build case) unlinkable results. Fail with an error -# when no target is given. The users can explicitly specify "all" -# if they want the historic behavior. -.MAIN: _guard - -_guard: .PHONY - @echo - @echo "Explicit target required. Likely \"${SUBDIR_OVERRIDE:Dall:Ubuildworld}\" is wanted. See build(7)." - @echo - @false - -STARTTIME!= LC_ALL=C date -CHECK_TIME!= find ${.CURDIR}/sys/sys/param.h -mtime -0s ; echo -.if !empty(CHECK_TIME) -.error check your date/time: ${STARTTIME} -.endif - -.if defined(HISTORICAL_MAKE_WORLD) || defined(DESTDIR) -# -# world -# -# Attempt to rebuild and reinstall everything. This target is not to be -# used for upgrading an existing FreeBSD system, because the kernel is -# not included. One can argue that this target doesn't build everything -# then. -# -world: upgrade_checks .PHONY - @echo "--------------------------------------------------------------" - @echo ">>> make world started on ${STARTTIME}" - @echo "--------------------------------------------------------------" -.if target(pre-world) - @echo - @echo "--------------------------------------------------------------" - @echo ">>> Making 'pre-world' target" - @echo "--------------------------------------------------------------" - ${_+_}@cd ${.CURDIR}; ${_MAKE} pre-world -.endif - ${_+_}@cd ${.CURDIR}; ${_MAKE} buildworld - ${_+_}@cd ${.CURDIR}; ${_MAKE} installworld MK_META_MODE=no -.if target(post-world) - @echo - @echo "--------------------------------------------------------------" - @echo ">>> Making 'post-world' target" - @echo "--------------------------------------------------------------" - ${_+_}@cd ${.CURDIR}; ${_MAKE} post-world -.endif - @echo - @echo "--------------------------------------------------------------" - @echo ">>> make world completed on `LC_ALL=C date`" - @echo " (started ${STARTTIME})" - @echo "--------------------------------------------------------------" -.else -world: .PHONY - @echo "WARNING: make world will overwrite your existing FreeBSD" - @echo "installation without also building and installing a new" - @echo "kernel. This can be dangerous. Please read the handbook," - @echo "'Rebuilding world', for how to upgrade your system." - @echo "Define DESTDIR to where you want to install FreeBSD," - @echo "including /, to override this warning and proceed as usual." - @echo "" - @echo "Bailing out now..." - @false -.endif - -# -# kernel -# -# Short hand for `make buildkernel installkernel' -# -kernel: buildkernel installkernel .PHONY - -# -# Perform a few tests to determine if the installed tools are adequate -# for building the world. -# -upgrade_checks: .PHONY -.if defined(NEED_MAKE_UPGRADE) - @${_+_}(cd ${.CURDIR} && ${MAKE} ${WANT_MAKE:S,^f,,}) -.endif - -# -# Upgrade make(1) to the current version using the installed -# headers, libraries and tools. Also, allow the location of -# the system bsdmake-like utility to be overridden. -# -MMAKEENV= MAKEOBJDIRPREFIX=${MYMAKE:H} \ - DESTDIR= \ - INSTALL="sh ${.CURDIR}/tools/install.sh" -MMAKE= ${MMAKEENV} ${MAKE} \ - MAN= -DNO_SHARED \ - -DNO_CPU_CFLAGS -DNO_WERROR \ - -DNO_SUBDIR \ - DESTDIR= PROGNAME=${MYMAKE:T} - -bmake: .PHONY - @echo - @echo "--------------------------------------------------------------" - @echo ">>> Building an up-to-date ${.TARGET}(1)" - @echo "--------------------------------------------------------------" - ${_+_}@cd ${.CURDIR}/usr.bin/${.TARGET}; \ - ${MMAKE} obj; \ - ${MMAKE} depend; \ - ${MMAKE} all; \ - ${MMAKE} install DESTDIR=${MYMAKE:H} BINDIR= - -regress: .PHONY - @echo "'make regress' has been renamed 'make check'" | /usr/bin/fmt - @false - -tinderbox toolchains kernel-toolchains kernels worlds: upgrade_checks - -tinderbox: .PHONY - @cd ${.CURDIR}; ${SUB_MAKE} DOING_TINDERBOX=YES universe - -toolchains: .PHONY - @cd ${.CURDIR}; ${SUB_MAKE} UNIVERSE_TARGET=toolchain universe - -kernel-toolchains: .PHONY - @cd ${.CURDIR}; ${SUB_MAKE} UNIVERSE_TARGET=kernel-toolchain universe - -kernels: .PHONY - @cd ${.CURDIR}; ${SUB_MAKE} UNIVERSE_TARGET=buildkernel universe - -worlds: .PHONY - @cd ${.CURDIR}; ${SUB_MAKE} UNIVERSE_TARGET=buildworld universe - -# -# universe -# -# Attempt to rebuild *everything* for all supported architectures, -# with a reasonable chance of success, regardless of how old your -# existing system is. -# -.if make(universe) || make(universe_kernels) || make(tinderbox) || make(targets) -TARGETS?=amd64 arm arm64 i386 mips pc98 powerpc sparc64 -_UNIVERSE_TARGETS= ${TARGETS} -TARGET_ARCHES_arm?= arm armeb armv6 -TARGET_ARCHES_arm64?= aarch64 -TARGET_ARCHES_mips?= mipsel mips mips64el mips64 mipsn32 mipselhf mipshf mips64elhf mips64hf -TARGET_ARCHES_powerpc?= powerpc powerpc64 powerpcspe -TARGET_ARCHES_pc98?= i386 -.for target in ${TARGETS} -TARGET_ARCHES_${target}?= ${target} -.endfor - -# XXX Remove arm64 from universe if the required binutils package is missing. -# It does not build with the in-tree linker. -.if !exists(/usr/local/aarch64-freebsd/bin/ld) && ${TARGETS:Marm64} -_UNIVERSE_TARGETS:= ${_UNIVERSE_TARGETS:Narm64} -universe: universe_arm64_skip .PHONY -universe_epilogue: universe_arm64_skip .PHONY -universe_arm64_skip: universe_prologue .PHONY - @echo ">> arm64 skipped - install aarch64-binutils port or package to build" -.endif - -.if defined(UNIVERSE_TARGET) -MAKE_JUST_WORLDS= YES -.else -UNIVERSE_TARGET?= buildworld -.endif -KERNSRCDIR?= ${.CURDIR}/sys - -targets: .PHONY - @echo "Supported TARGET/TARGET_ARCH pairs for world and kernel targets" -.for target in ${TARGETS} -.for target_arch in ${TARGET_ARCHES_${target}} - @echo " ${target}/${target_arch}" -.endfor -.endfor - -.if defined(DOING_TINDERBOX) -FAILFILE=${.CURDIR}/_.tinderbox.failed -MAKEFAIL=tee -a ${FAILFILE} -.else -MAKEFAIL=cat -.endif - -universe_prologue: upgrade_checks -universe: universe_prologue -universe_prologue: .PHONY - @echo "--------------------------------------------------------------" - @echo ">>> make universe started on ${STARTTIME}" - @echo "--------------------------------------------------------------" -.if defined(DOING_TINDERBOX) - @rm -f ${FAILFILE} -.endif -.for target in ${_UNIVERSE_TARGETS} -universe: universe_${target} -universe_epilogue: universe_${target} -universe_${target}: universe_${target}_prologue .PHONY -universe_${target}_prologue: universe_prologue .PHONY - @echo ">> ${target} started on `LC_ALL=C date`" -universe_${target}_worlds: .PHONY - -.if !defined(MAKE_JUST_KERNELS) -universe_${target}_done: universe_${target}_worlds .PHONY -.for target_arch in ${TARGET_ARCHES_${target}} -universe_${target}_worlds: universe_${target}_${target_arch} .PHONY -universe_${target}_${target_arch}: universe_${target}_prologue .MAKE .PHONY - @echo ">> ${target}.${target_arch} ${UNIVERSE_TARGET} started on `LC_ALL=C date`" - @(cd ${.CURDIR} && env __MAKE_CONF=/dev/null \ - ${SUB_MAKE} ${JFLAG} ${UNIVERSE_TARGET} \ - TARGET=${target} \ - TARGET_ARCH=${target_arch} \ - > _.${target}.${target_arch}.${UNIVERSE_TARGET} 2>&1 || \ - (echo "${target}.${target_arch} ${UNIVERSE_TARGET} failed," \ - "check _.${target}.${target_arch}.${UNIVERSE_TARGET} for details" | \ - ${MAKEFAIL})) - @echo ">> ${target}.${target_arch} ${UNIVERSE_TARGET} completed on `LC_ALL=C date`" -.endfor -.endif # !MAKE_JUST_KERNELS - -.if !defined(MAKE_JUST_WORLDS) -universe_${target}_done: universe_${target}_kernels .PHONY -universe_${target}_kernels: universe_${target}_worlds .PHONY -universe_${target}_kernels: universe_${target}_prologue .MAKE .PHONY -.if exists(${KERNSRCDIR}/${target}/conf/NOTES) - @(cd ${KERNSRCDIR}/${target}/conf && env __MAKE_CONF=/dev/null \ - ${SUB_MAKE} LINT > ${.CURDIR}/_.${target}.makeLINT 2>&1 || \ - (echo "${target} 'make LINT' failed," \ - "check _.${target}.makeLINT for details"| ${MAKEFAIL})) -.endif - @cd ${.CURDIR}; ${SUB_MAKE} ${.MAKEFLAGS} TARGET=${target} \ - universe_kernels -.endif # !MAKE_JUST_WORLDS - -# Tell the user the worlds and kernels have completed -universe_${target}: universe_${target}_done -universe_${target}_done: - @echo ">> ${target} completed on `LC_ALL=C date`" -.endfor -universe_kernels: universe_kernconfs .PHONY -.if !defined(TARGET) -TARGET!= uname -m -.endif -.if defined(MAKE_ALL_KERNELS) -_THINNER=cat -.else -_THINNER=xargs grep -L "^.NO_UNIVERSE" || true -.endif -KERNCONFS!= cd ${KERNSRCDIR}/${TARGET}/conf && \ - find [[:upper:][:digit:]]*[[:upper:][:digit:]] \ - -type f -maxdepth 0 \ - ! -name DEFAULTS ! -name NOTES | \ - ${_THINNER} -universe_kernconfs: .PHONY -.for kernel in ${KERNCONFS} -TARGET_ARCH_${kernel}!= cd ${KERNSRCDIR}/${TARGET}/conf && \ - config -m ${KERNSRCDIR}/${TARGET}/conf/${kernel} 2> /dev/null | \ - grep -v WARNING: | cut -f 2 -.if empty(TARGET_ARCH_${kernel}) -.error "Target architecture for ${TARGET}/conf/${kernel} unknown. config(8) likely too old." -.endif -universe_kernconfs: universe_kernconf_${TARGET}_${kernel} -universe_kernconf_${TARGET}_${kernel}: .MAKE - @(cd ${.CURDIR} && env __MAKE_CONF=/dev/null \ - ${SUB_MAKE} ${JFLAG} buildkernel \ - TARGET=${TARGET} \ - TARGET_ARCH=${TARGET_ARCH_${kernel}} \ - KERNCONF=${kernel} \ - > _.${TARGET}.${kernel} 2>&1 || \ - (echo "${TARGET} ${kernel} kernel failed," \ - "check _.${TARGET}.${kernel} for details"| ${MAKEFAIL})) -.endfor -universe: universe_epilogue -universe_epilogue: .PHONY - @echo "--------------------------------------------------------------" - @echo ">>> make universe completed on `LC_ALL=C date`" - @echo " (started ${STARTTIME})" - @echo "--------------------------------------------------------------" -.if defined(DOING_TINDERBOX) - @if [ -e ${FAILFILE} ] ; then \ - echo "Tinderbox failed:" ;\ - cat ${FAILFILE} ;\ - exit 1 ;\ - fi -.endif -.endif - -buildLINT: .PHONY - ${MAKE} -C ${.CURDIR}/sys/${_TARGET}/conf LINT - -.if defined(.PARSEDIR) -# This makefile does not run in meta mode -.MAKE.MODE= normal -# Normally the things we run from here don't either. -# Using -DWITH_META_MODE -# we can buildworld with meta files created which are useful -# for debugging, but without any of the rest of a meta mode build. -MK_DIRDEPS_BUILD= no -MK_STAGING= no -# tell meta.autodep.mk to not even think about updating anything. -UPDATE_DEPENDFILE= NO -.if !make(showconfig) -.export MK_DIRDEPS_BUILD MK_STAGING UPDATE_DEPENDFILE -.endif - -.if make(universe) -# we do not want a failure of one branch abort all. -MAKE_JOB_ERROR_TOKEN= no -.export MAKE_JOB_ERROR_TOKEN -.endif -.endif # bmake - -.endif # DIRDEPS_BUILD +.include Index: etc/inetd.conf =================================================================== --- etc/inetd.conf +++ etc/inetd.conf @@ -117,3 +117,7 @@ #netbios-ssn stream tcp nowait root /usr/local/sbin/smbd smbd #netbios-ns dgram udp wait root /usr/local/sbin/nmbd nmbd #swat stream tcp nowait/400 root /usr/local/sbin/swat swat +# +# Example entry for the Prometheus sysctl metrics exporter +# +#prom-sysctl stream tcp nowait nobody /usr/sbin/prometheus_sysctl_exporter prometheus_sysctl_exporter -dh Index: etc/services =================================================================== --- etc/services +++ etc/services @@ -2450,6 +2450,7 @@ aurora 9084/tcp #IBM AURORA Performance Visualizer aurora 9084/udp #IBM AURORA Performance Visualizer jetdirect 9100/tcp #HP JetDirect card +prom-sysctl 9124/tcp #prometheus_sysctl_exporter(8) git 9418/tcp #git pack transfer service git 9418/udp #git pack transfer service man 9535/tcp Index: sbin/sysctl/Makefile =================================================================== --- sbin/sysctl/Makefile +++ sbin/sysctl/Makefile @@ -1,9 +1,8 @@ -# @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -PACKAGE=runtime -PROG= sysctl -WARNS?= 3 -MAN= sysctl.8 +PROG= prometheus_sysctl_exporter +MAN= prometheus_sysctl_exporter.8 + +LIBADD= m .include Index: sbin/sysctl/sysctl.8 =================================================================== --- sbin/sysctl/sysctl.8 +++ sbin/sysctl/sysctl.8 @@ -28,7 +28,7 @@ .\" From: @(#)sysctl.8 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd December 10, 2015 +.Dd December 14, 2016 .Dt SYSCTL 8 .Os .Sh NAME @@ -306,7 +306,8 @@ .Xr sysctl 3 , .Xr loader.conf 5 , .Xr sysctl.conf 5 , -.Xr loader 8 +.Xr loader 8 , +.Xr prometheus_sysctl_exporter 8 .Sh HISTORY A .Nm Index: usr.sbin/Makefile =================================================================== --- usr.sbin/Makefile +++ usr.sbin/Makefile @@ -62,6 +62,7 @@ periodic \ powerd \ procctl \ + prometheus_sysctl_exporter \ pstat \ pw \ pwd_mkdb \ Index: usr.sbin/prometheus_sysctl_exporter/Makefile =================================================================== --- /dev/null +++ usr.sbin/prometheus_sysctl_exporter/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG= prometheus_sysctl_exporter +MAN= prometheus_sysctl_exporter.8 + +LIBADD= m + +.include Index: usr.sbin/prometheus_sysctl_exporter/prometheus_sysctl_exporter.8 =================================================================== --- /dev/null +++ usr.sbin/prometheus_sysctl_exporter/prometheus_sysctl_exporter.8 @@ -0,0 +1,104 @@ +.\" Copyright (c) 2016 Nuxi, https://nuxi.nl/ +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.Dd December 14, 2016 +.Dt PROMETHEUS_SYSCTL_EXPORTER 8 +.Os +.Sh NAME +.Nm prometheus_sysctl_exporter +.Nd print kernel state as Prometheus metrics +.Sh SYNOPSIS +.Nm prometheus_sysctl_exporter +.Op Fl dh +.Op Ar prefix ... +.Sh DESCRIPTION +Prometheus is a monitoring system that gathers metrics from its targets +by fetching them through HTTP GET requests. +Metrics are identified by a name and an optional set of labels. +Sample values are required to be numerical. +.Pp +The +.Nm +utility prints the values of sysctl nodes to standard output, +formatted such that they can be scraped by Prometheus directly. +By default, +it prints metrics for all numerically representable nodes in the sysctl +namespace. +It is also possible to limit output to a smaller number of metrics by +specifying one or more prefixes as arguments. +.Pp +Metrics printed by this utility are named +.Ql sysctl_ , +followed by the name of the sysctl node having its +.Ql .\& +separators replaced by +.Ql _ . +Components on which it is desirable to aggregate (e.g., +names of devices) are omitted from the metric's name, +but are appended as labels instead. +.Pp +There are two different methods for exporting the output of +.Nm +to Prometheus. +The first method is to periodically invoke this utility through +.Xr cron 8 +and store its output in a textfile. +The metrics in this textfile can then be served over HTTP using the +Prometheus node exporter's textfile collector. +The second method is to run this utility through +.Xr inetd 8 . +TCP port 9124 has been allocated for this purpose. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl d +Print descriptions of metrics when available. +.It Fl h +Precede the output with a HTTP response header. +This flag is required when running this utility through +.Xr inetd 8 . +.El +.Sh SEE ALSO +.Xr cron 8 , +.Xr inetd 8 , +.Xr sysctl 8 , +.Xr SYSCTL_ADD_NODE_WITH_LABEL 9 +.Pp +Prometheus project: +.Pa https://prometheus.io/ . +.Pp +Prometheus exposition formats: +.Pa https://prometheus.io/docs/instrumenting/exposition_formats/ . +.Pp +Prometheus node exporter: +.Pa https://github.com/prometheus/node_exporter . +.Pp +Prometheus default port allocations: +.Pa https://github.com/prometheus/prometheus/wiki/Default-port-allocations . +.Sh HISTORY +.Nm +first appeared in +.Fx 12.0 . +.Sh AUTHORS +.An Nuxi : Pa https://nuxi.nl/ . Index: usr.sbin/prometheus_sysctl_exporter/prometheus_sysctl_exporter.c =================================================================== --- /dev/null +++ usr.sbin/prometheus_sysctl_exporter/prometheus_sysctl_exporter.c @@ -0,0 +1,588 @@ +/*- + * Copyright (c) 2016 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Cursor for iterating over all of the system's sysctl OIDs. + */ +struct oid { + int id[CTL_MAXNAME]; + size_t len; +}; + +/* Initializes the cursor to point to start of the tree. */ +static void +oid_get_root(struct oid *o) +{ + + o->id[0] = 1; + o->len = 1; +} + +/* Obtains the OID for a sysctl by name. */ +static void +oid_get_by_name(struct oid *o, const char *name) +{ + + o->len = nitems(o->id); + if (sysctlnametomib(name, o->id, &o->len) != 0) + err(1, "sysctl(%s)", name); +} + +/* Returns whether an OID is placed below another OID. */ +static bool +oid_is_beneath(struct oid *oa, struct oid *ob) +{ + + return (oa->len >= ob->len && + memcmp(oa->id, ob->id, ob->len * sizeof(oa->id[0])) == 0); +} + +/* Advances the cursor to the next OID. */ +static bool +oid_get_next(const struct oid *cur, struct oid *next) +{ + int lookup[CTL_MAXNAME + 2]; + size_t nextsize; + + lookup[0] = 0; + lookup[1] = 2; + memcpy(lookup + 2, cur->id, cur->len * sizeof(lookup[0])); + nextsize = sizeof(next->id); + if (sysctl(lookup, 2 + cur->len, &next->id, &nextsize, 0, 0) != 0) { + if (errno == ENOENT) + return (false); + err(1, "sysctl(next)"); + } + next->len = nextsize / sizeof(next->id[0]); + return (true); +} + +/* + * OID formatting metadata. + */ +struct oidformat { + unsigned int kind; + char format[BUFSIZ]; +}; + +/* Returns whether the OID represents a temperature value. */ +static bool +oidformat_is_temperature(const struct oidformat *of) +{ + + return (of->format[0] == 'I' && of->format[1] == 'K'); +} + +/* Fetches the formatting metadata for an OID. */ +static bool +oid_get_format(const struct oid *o, struct oidformat *of) +{ + int lookup[CTL_MAXNAME + 2]; + size_t oflen; + + lookup[0] = 0; + lookup[1] = 4; + memcpy(lookup + 2, o->id, o->len * sizeof(lookup[0])); + oflen = sizeof(*of); + if (sysctl(lookup, 2 + o->len, of, &oflen, 0, 0) != 0) { + if (errno == ENOENT) + return (false); + err(1, "sysctl(oidfmt)"); + } + return (true); +} + +/* + * Container for holding the value of an OID. + */ +struct oidvalue { + enum { SIGNED, UNSIGNED, FLOAT } type; + union { + intmax_t s; + uintmax_t u; + double f; + } value; +}; + +/* Extracts the value of an OID, converting it to a floating-point number. */ +static double +oidvalue_get_float(const struct oidvalue *ov) +{ + + switch (ov->type) { + case SIGNED: + return (ov->value.s); + case UNSIGNED: + return (ov->value.u); + case FLOAT: + return (ov->value.f); + default: + assert(0 && "Unknown value type"); + } +} + +/* Sets the value of an OID as a signed integer. */ +static void +oidvalue_set_signed(struct oidvalue *ov, intmax_t s) +{ + + ov->type = SIGNED; + ov->value.s = s; +} + +/* Sets the value of an OID as an unsigned integer. */ +static void +oidvalue_set_unsigned(struct oidvalue *ov, uintmax_t u) +{ + + ov->type = UNSIGNED; + ov->value.u = u; +} + +/* Sets the value of an OID as a floating-point number. */ +static void +oidvalue_set_float(struct oidvalue *ov, double f) +{ + + ov->type = FLOAT; + ov->value.f = f; +} + +/* Prints the value of an OID to a file stream. */ +static void +oidvalue_print(const struct oidvalue *ov, FILE *fp) +{ + + switch (ov->type) { + case SIGNED: + fprintf(fp, "%jd", ov->value.s); + break; + case UNSIGNED: + fprintf(fp, "%ju", ov->value.u); + break; + case FLOAT: + switch (fpclassify(ov->value.f)) { + case FP_INFINITE: + if (signbit(ov->value.f)) + fprintf(fp, "-Inf"); + else + fprintf(fp, "+Inf"); + break; + case FP_NAN: + fprintf(fp, "Nan"); + break; + default: + fprintf(fp, "%.2f", ov->value.f); + break; + } + break; + } +} + +/* Fetches the value of an OID. */ +static bool +oid_get_value(const struct oid *o, const struct oidformat *of, + struct oidvalue *ov) +{ + + switch (of->kind & CTLTYPE) { +#define GET_VALUE(ctltype, type) \ + case (ctltype): { \ + type value; \ + size_t valuesize; \ + \ + valuesize = sizeof(value); \ + if (sysctl(o->id, o->len, &value, &valuesize, 0, 0) != 0) \ + return (false); \ + if ((type)-1 > 0) \ + oidvalue_set_unsigned(ov, value); \ + else \ + oidvalue_set_signed(ov, value); \ + break; \ + } + GET_VALUE(CTLTYPE_INT, int); + GET_VALUE(CTLTYPE_UINT, unsigned int); + GET_VALUE(CTLTYPE_LONG, long); + GET_VALUE(CTLTYPE_ULONG, unsigned long); + GET_VALUE(CTLTYPE_S8, int8_t); + GET_VALUE(CTLTYPE_U8, uint8_t); + GET_VALUE(CTLTYPE_S16, int16_t); + GET_VALUE(CTLTYPE_U16, uint16_t); + GET_VALUE(CTLTYPE_S32, int32_t); + GET_VALUE(CTLTYPE_U32, uint32_t); + GET_VALUE(CTLTYPE_S64, int64_t); + GET_VALUE(CTLTYPE_U64, uint64_t); +#undef GET_VALUE + default: + return (false); + } + + /* Convert temperatures from decikelvin to degrees Celcius. */ + if (oidformat_is_temperature(of)) { + double v; + int e; + + v = oidvalue_get_float(ov); + if (v < 0) { + oidvalue_set_float(ov, NAN); + } else { + e = of->format[2] >= '0' && of->format[2] <= '9' ? + of->format[2] - '0' : 1; + oidvalue_set_float(ov, v / pow(10, e) - 273.15); + } + } + return (true); +} + +/* + * The full name of an OID, stored as a series of components. + */ +struct oidname { + struct oid oid; + char name_buf[BUFSIZ]; + size_t name_end[CTL_MAXNAME]; + char label_buf[BUFSIZ]; + size_t label_end[CTL_MAXNAME]; +}; + +/* + * Initializes the OID name object with an empty value. + */ +static void +oidname_init(struct oidname *on) +{ + + on->oid.len = 0; +} + +/* Fetches the name of an OID, partiall reusing the previous results. */ +static void +oid_get_name(const struct oid *o, struct oidname *on) +{ + size_t i, name_start, label_start; + + /* No need to fetch components that we already have. */ + name_start = label_start = 0; + for (i = 0; i < o->len && i < on->oid.len && o->id[i] == on->oid.id[i]; + ++i) { + name_start = on->name_end[i]; + if (on->label_end[i] != 0) + label_start = on->label_end[i]; + } + + /* Fetch the remainder. */ + for (; i < o->len; ++i) { + int lookup[CTL_MAXNAME + 2]; + char buf[BUFSIZ]; + size_t len; + + /* Look up the name of the component. */ + lookup[0] = 0; + lookup[1] = 1; + memcpy(lookup + 2, o->id, (i + 1) * sizeof(lookup[0])); + len = sizeof(buf); + if (sysctl(lookup, 2 + i + 1, buf, &len, 0, 0) == 0) { + char *name; + + name = strrchr(buf, '.'); + if (name == NULL) { + name = buf; + } else { + ++name; + len -= name - buf; + } + + assert(name_start + len <= sizeof(on->name_buf)); + memcpy(on->name_buf + name_start, name, len); + on->name_end[i] = name_start += len; + } else { + err(1, "sysctl(name)"); + } + + /* Look up the optional label, allowing aggregation. */ + lookup[1] = 6; + len = sizeof(buf); + if (sysctl(lookup, 2 + i + 1, buf, &len, 0, 0) == 0) { + assert(label_start + len <= sizeof(on->label_buf)); + memcpy(on->label_buf + label_start, buf, len); + on->label_end[i] = label_start += len; + } else if (errno == ENOENT) { + on->label_end[i] = 0; + } else { + err(1, "sysctl(oidlabel)"); + } + } + on->oid = *o; +} + +/* Prints the name and labels of an OID to a file stream. */ +static void +oidname_print(const struct oidname *on, const struct oidformat *of, + FILE *fp) +{ + const char *name, *label; + size_t i; + char separator; + + /* Print the name of the metric. */ + fprintf(fp, "sysctl"); + name = on->name_buf; + for (i = 0; i < on->oid.len; ++i) { + if (on->label_end[i] == 0) { + assert(name[strspn(name, + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_")] == '\0'); + fprintf(fp, "_%s", name); + } + name = on->name_buf + on->name_end[i]; + } + if (oidformat_is_temperature(of)) + fprintf(fp, "_celcius"); + + /* Print the labels of the metric. */ + label = on->label_buf; + name = on->name_buf; + separator = '{'; + for (i = 0; i < on->oid.len; ++i) { + if (on->label_end[i] != 0) { + assert(name[strspn(name, + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_-")] == '\0'); + assert(label[strspn(label, + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_")] == '\0'); + fprintf(fp, "%c%s=\"%s\"", separator, label, name); + separator = ','; + label = on->label_buf + on->label_end[i]; + } + name = on->name_buf + on->name_end[i]; + } + if (separator != '{') + fputc('}', fp); +} + +/* Returns whether the OID name has any labels associated to it. */ +static bool +oidname_has_labels(const struct oidname *on) +{ + size_t i; + + for (i = 0; i < on->oid.len != 0; ++i) + if (on->label_end[i] != 0) + return (true); + return (false); +} + +/* + * The description of an OID. + */ +struct oiddescription { + char description[BUFSIZ]; +}; + +/* + * Fetches the description of an OID. + */ +static bool +oid_get_description(const struct oid *o, struct oiddescription *od) +{ + int lookup[CTL_MAXNAME + 2]; + char *newline; + size_t odlen; + + lookup[0] = 0; + lookup[1] = 5; + memcpy(lookup + 2, o->id, o->len * sizeof(lookup[0])); + odlen = sizeof(od->description); + if (sysctl(lookup, 2 + o->len, &od->description, &odlen, 0, 0) != 0) { + if (errno == ENOENT) + return (false); + err(1, "sysctl(oiddescr)"); + } + + newline = strchr(od->description, '\n'); + if (newline != NULL) + *newline = '\0'; + + return (*od->description != '\0'); +} + +/* Prints the description of an OID to a file stream. */ +static void +oiddescription_print(const struct oiddescription *od, FILE *fp) +{ + + fprintf(fp, "%s", od->description); +} + +static void +oid_print(const struct oid *o, struct oidname *on, bool print_description, + FILE *fp) +{ + struct oidformat of; + struct oidvalue ov; + struct oiddescription od; + + if (!oid_get_format(o, &of) || !oid_get_value(o, &of, &ov)) + return; + oid_get_name(o, on); + + /* + * Print the line with the description. Prometheus expects a + * single unique description for every metric, which cannot be + * guaranteed by sysctl if labels are present. Omit the + * description if labels are present. + */ + if (print_description && !oidname_has_labels(on) && + oid_get_description(o, &od)) { + fprintf(fp, "# HELP "); + oidname_print(on, &of, fp); + fputc(' ', fp); + oiddescription_print(&od, fp); + fputc('\n', fp); + } + + /* Print the line with the value. */ + oidname_print(on, &of, fp); + fputc(' ', fp); + oidvalue_print(&ov, fp); + fputc('\n', fp); +} + +static void +usage(void) +{ + + fprintf(stderr, + "usage: prometheus_sysctl_exporter [-dh] [prefix ...]\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + struct oidname on; + char *http_buf; + FILE *fp; + size_t http_buflen; + int ch; + bool http_mode, print_descriptions; + + /* Parse command line flags. */ + http_mode = print_descriptions = false; + while ((ch = getopt(argc, argv, "dh")) != -1) { + switch (ch) { + case 'd': + print_descriptions = true; + break; + case 'h': + http_mode = true; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + /* HTTP output: cache metrics in buffer. */ + if (http_mode) { + fp = open_memstream(&http_buf, &http_buflen); + if (fp == NULL) + err(1, "open_memstream"); + } else { + fp = stdout; + } + + oidname_init(&on); + if (argc == 0) { + struct oid o; + + /* Print all OIDs. */ + oid_get_root(&o); + do { + oid_print(&o, &on, print_descriptions, fp); + } while (oid_get_next(&o, &o)); + } else { + int i; + + /* Print only trees provided as arguments. */ + for (i = 0; i < argc; ++i) { + struct oid o, root; + + oid_get_by_name(&root, argv[i]); + o = root; + do { + oid_print(&o, &on, print_descriptions, fp); + } while (oid_get_next(&o, &o) && + oid_is_beneath(&o, &root)); + } + } + + if (http_mode) { + if (ferror(fp) || fclose(fp) != 0) + err(1, "Cannot generate output"); + + /* Print HTTP header and metrics. */ + dprintf(STDOUT_FILENO, + "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-Length: %zu\r\n" + "Content-Type: text/plain; version=0.0.4\r\n" + "\r\n", + http_buflen); + write(STDOUT_FILENO, http_buf, http_buflen); + + /* Drain output. */ + if (shutdown(STDIN_FILENO, SHUT_WR) == 0) { + char buf[1024]; + + while (read(STDIN_FILENO, buf, sizeof(buf)) > 0) { + } + } + } + return (0); +}