diff options
-rw-r--r-- | Makefile | 5 | ||||
-rwxr-xr-x | build/cc.sh | 11 | ||||
-rw-r--r-- | build/config.mk | 8 | ||||
-rw-r--r-- | build/deps.mk | 2 | ||||
-rw-r--r-- | build/header.mk | 24 | ||||
-rwxr-xr-x | build/pkgconf.sh | 2 | ||||
-rwxr-xr-x | configure | 153 | ||||
-rw-r--r-- | docs/SECURITY.md | 126 | ||||
-rw-r--r-- | docs/bfs.1 | 8 | ||||
-rw-r--r-- | src/bftw.c | 41 | ||||
-rw-r--r-- | src/color.c | 12 | ||||
-rw-r--r-- | src/exec.c | 2 | ||||
-rw-r--r-- | src/ioq.c | 22 | ||||
-rw-r--r-- | src/parse.c | 11 | ||||
-rw-r--r-- | src/prelude.h | 3 | ||||
-rw-r--r-- | src/version.c | 8 |
16 files changed, 293 insertions, 145 deletions
@@ -215,6 +215,11 @@ check-install:: bin/bfs pkg -not -type d -print -exit 1 ${RM} -r pkg +# Check man page markup +check-man:: + ${MSG} "[LINT] docs/bfs.1" \ + groff -man -rCHECKSTYLE=3 -ww -b -z docs/bfs.1 + ## Cleanup (`make clean`) # Clean all build products diff --git a/build/cc.sh b/build/cc.sh index 45d51ca..23a4c01 100755 --- a/build/cc.sh +++ b/build/cc.sh @@ -5,12 +5,5 @@ # Run the compiler and check if it succeeded -set -eu - -TMP=$(mktemp) -trap 'rm -f "$TMP"' EXIT - -( - set -x - $XCC $XCPPFLAGS $XCFLAGS $XLDFLAGS "$@" $XLDLIBS -o "$TMP" -) +set -eux +$XCC $XCPPFLAGS $XCFLAGS $XLDFLAGS "$@" $XLDLIBS diff --git a/build/config.mk b/build/config.mk index 24873ec..80206c7 100644 --- a/build/config.mk +++ b/build/config.mk @@ -7,7 +7,7 @@ include build/prelude.mk include build/exports.mk # All configuration steps -config: gen/config.mk gen/config.h +config: gen/config.mk .PHONY: config # Makefile fragments generated by `./configure` @@ -18,10 +18,10 @@ MKS := \ gen/pkgs.mk # The main configuration file, which includes the others -gen/config.mk: ${MKS} +gen/config.mk: ${MKS} gen/config.h ${MSG} "[ GEN] $@" @printf '# %s\n' "$@" >$@ - @printf 'include %s\n' ${.ALLSRC} >>$@ + @printf 'include %s\n' ${MKS} >>$@ ${VCAT} gen/config.mk .PHONY: gen/config.mk @@ -57,6 +57,6 @@ gen/pkgs.mk: gen/flags.mk .PHONY: gen/pkgs.mk # Compile-time feature detection -gen/config.h: gen/config.mk +gen/config.h: gen/pkgs.mk @+XMAKEFLAGS="$$MAKEFLAGS" ${MAKE} -sf build/header.mk $@ .PHONY: gen/config.h diff --git a/build/deps.mk b/build/deps.mk index d382f5d..a6ea673 100644 --- a/build/deps.mk +++ b/build/deps.mk @@ -11,7 +11,7 @@ include build/exports.mk gen/deps.mk:: ${MSG} "[ GEN] $@" @printf '# %s\n' "$@" >$@ - @if build/cc.sh -MD -MP -MF /dev/null build/empty.c; then \ + @if build/cc.sh -MD -MP build/empty.c -o gen/.deps.out; then \ printf '_CPPFLAGS += -MD -MP\n'; \ fi >>$@ 2>$@.log ${VCAT} $@ diff --git a/build/header.mk b/build/header.mk index 8b28346..afd04d0 100644 --- a/build/header.mk +++ b/build/header.mk @@ -4,7 +4,10 @@ # Makefile that generates gen/config.h include build/prelude.mk -include gen/config.mk +include gen/vars.mk +include gen/flags.mk +include gen/deps.mk +include gen/pkgs.mk include build/exports.mk # All header fragments we generate @@ -61,9 +64,10 @@ gen/config.h: ${PKG_HEADERS} ${HEADERS} @printf '#define BFS_CONFIG_H\n' >>$@ @cat ${.ALLSRC} >>$@ @printf '#endif // BFS_CONFIG_H\n' >>$@ - @cat ${.ALLSRC:%=%.log} >gen/config.log + @cat gen/cc.log ${.ALLSRC:%=%.log} >gen/config.log ${VCAT} $@ - @printf '%s' "$$CONFIG" | build/embed.sh >gen/config.i + @printf '%s' "$$CONFFLAGS" | build/embed.sh >gen/confflags.i + @printf '%s' "$$XCC" | build/embed.sh >gen/cc.i @printf '%s' "$$XCPPFLAGS" | build/embed.sh >gen/cppflags.i @printf '%s' "$$XCFLAGS" | build/embed.sh >gen/cflags.i @printf '%s' "$$XLDFLAGS" | build/embed.sh >gen/ldflags.i @@ -72,8 +76,18 @@ gen/config.h: ${PKG_HEADERS} ${HEADERS} # The short name of the config test SLUG = ${@:gen/%.h=%} +# The hidden output file name +OUT = ${SLUG:has/%=gen/has/.%.out} -${HEADERS}:: +${HEADERS}: cc @${MKDIR} ${@D} - @build/define-if.sh ${SLUG} build/cc.sh build/${SLUG}.c >$@ 2>$@.log; \ + @build/define-if.sh ${SLUG} build/cc.sh build/${SLUG}.c -o ${OUT} >$@ 2>$@.log; \ build/msg-if.sh "[ CC ] ${SLUG}.c" test $$? -eq 0 +.PHONY: ${HEADERS} + +# Check that the C compiler works at all +cc:: + @build/cc.sh build/empty.c -o gen/.cc.out 2>gen/cc.log; \ + ret=$$?; \ + build/msg-if.sh "[ CC ] build/empty.c" test $$ret -eq 0; \ + exit $$ret diff --git a/build/pkgconf.sh b/build/pkgconf.sh index 244c95d..a8a3341 100755 --- a/build/pkgconf.sh +++ b/build/pkgconf.sh @@ -37,7 +37,7 @@ if [ -z "$MODE" ]; then CFLAGS=$("$0" --cflags "$LIB") || exit 1 LDFLAGS=$("$0" --ldflags "$LIB") || exit 1 LDLIBS=$("$0" --ldlibs "$LIB") || exit 1 - build/cc.sh $CFLAGS $LDFLAGS build/with/$LIB.c $LDLIBS || exit 1 + build/cc.sh $CFLAGS $LDFLAGS "build/with/$LIB.c" $LDLIBS -o "gen/with/.$LIB.out" || exit 1 done fi @@ -7,22 +7,62 @@ set -eu -# Save the ./configure command line for bfs --version -export CONFIG="$0 $*" +# Print the help message +help() { + cat <<EOF +Usage: -# Default to `make` -MAKE="${MAKE:-make}" - -# Pass -j$(nproc) unless MAKEFLAGS is set -if [ "${MAKEFLAGS+y}" ]; then - j="" -else - j="-j$({ nproc || sysctl -n hw.ncpu || getconf _NPROCESSORS_ONLN || echo 1; } 2>/dev/null)" -fi - -# Convert kebab-case to UPPER_CASE -toupper() { - printf '%s' "$1" | tr 'a-z-' 'A-Z_' + \$ $0 [--enable-*|--disable-*] [--with-*|--without-*] [CC=...] [...] + \$ $MAKE $j + +Variables set in the environment or on the command line will be picked up: + + MAKE + The make implementation to use + CC + The C compiler to use + + CPPFLAGS="-I... -D..." + CFLAGS="-W... -f..." + LDFLAGS="-L... -Wl,..." + Preprocessor/compiler/linker flags + + LDLIBS="-l... -l..." + Dynamic libraries to link + + EXTRA_{CPPFLAGS,CFLAGS,LDFLAGS,LDLIBS} + Adds to the default flags, instead of replacing them + +The default flags result in a plain debug build. Other build profiles include: + + --enable-release + Enable optimizations, disable assertions + --enable-{asan,lsan,msan,tsan,ubsan} + Enable sanitizers + --enable-gcov + Enable code coverage instrumentation + +External dependencies are auto-detected by default, but you can build --with or +--without them explicitly: + + --with-libacl --without-libacl + --with-libcap --without-libcap + --with-libselinux --without-libselinux + --with-liburing --without-liburing + --with-oniguruma --without-oniguruma + +Packaging: + + --prefix=/path + Set the installation prefix (default: /usr) + --mandir=/path + Set the man page directory (default: \$PREFIX/share/man) + +This script is a thin wrapper around a makefile-based configuration system. +Any other arguments will be passed directly to the $MAKE invocation, e.g. + + \$ $0 $j V=1 +EOF } # Report an argument parsing error @@ -32,7 +72,26 @@ invalid() { exit 1 } +# Get the number of cores to use +nproc() { + { + command nproc \ + || sysctl -n hw.ncpu \ + || getconf _NPROCESSORS_ONLN \ + || echo 1 + } 2>/dev/null +} + +# Save the ./configure command line for bfs --version +export CONFFLAGS="$*" + +# Default to `make` +MAKE="${MAKE-make}" + +# Parse the command-line arguments for arg; do + shift + # --[(enable|disable|with|without)-]$name[=$value] value="${arg#*=}" name="${arg%%=*}" @@ -80,67 +139,13 @@ for arg; do case "$arg" in -h|--help) - cat <<EOF -Usage: - - \$ $0 [--enable-*|--disable-*] [--with-*|--without-*] [CC=...] [...] - \$ $MAKE $j - -Variables set in the environment or on the command line will be picked up: - - MAKE - The make implementation to use - CC - The C compiler to use - - CPPFLAGS="-I... -D..." - CFLAGS="-W... -f..." - LDFLAGS="-L... -Wl,..." - Preprocessor/compiler/linker flags - - LDLIBS="-l... -l..." - Dynamic libraries to link - - EXTRA_{CPPFLAGS,CFLAGS,LDFLAGS,LDLIBS} - Adds to the default flags, instead of replacing them - -The default flags result in a plain debug build. Other build profiles include: - - --enable-release - Enable optimizations, disable assertions - --enable-{asan,lsan,msan,tsan,ubsan} - Enable sanitizers - --enable-gcov - Enable code coverage instrumentation - -External dependencies are auto-detected by default, but you can build --with or ---without them explicitly: - - --with-libacl --without-libacl - --with-libcap --without-libcap - --with-libselinux --without-libselinux - --with-liburing --without-liburing - --with-oniguruma --without-oniguruma - -Packaging: - - --prefix=/path - Set the installation prefix (default: /usr) - --mandir=/path - Set the man page directory (default: \$PREFIX/share/man) - -This script is a thin wrapper around a makefile-based configuration system. -Any other arguments will be passed directly to the $MAKE invocation, e.g. - - \$ $0 $j V=1 -EOF + help exit 0 ;; --enable-*|--disable-*) case "$name" in release|asan|lsan|msan|tsan|ubsan|lint|gcov) - shift set -- "$@" "$NAME=$yn" ;; *) @@ -152,7 +157,6 @@ EOF --with-*|--without-*) case "$name" in libacl|libcap|libselinux|liburing|oniguruma) - shift set -- "$@" "WITH_$NAME=$yn" ;; *) @@ -162,23 +166,20 @@ EOF ;; --prefix=*|--mandir=*) - shift set -- "$@" "$NAME=$value" ;; --infodir=*|--build=*|--host=*|--target=*) - shift printf 'warning: Ignoring option "%s"\n' "$arg" >&2 ;; MAKE=*) - shift MAKE="$value" ;; # make flag (-j2) or variable (CC=clang) -*|*=*) - continue + set -- "$@" "$arg" ;; *) @@ -196,6 +197,6 @@ for f in Makefile build completions docs src tests; do done # Set MAKEFLAGS to -j$(nproc) if it's unset -export MAKEFLAGS="${MAKEFLAGS-$j}" +export MAKEFLAGS="${MAKEFLAGS--j$(nproc)}" $MAKE -rf build/config.mk "$@" diff --git a/docs/SECURITY.md b/docs/SECURITY.md new file mode 100644 index 0000000..f26efc5 --- /dev/null +++ b/docs/SECURITY.md @@ -0,0 +1,126 @@ +Security +======== + +Threat model +------------ + +`bfs` is a command line program running on multi-user operating systems. +Those other users may be malicious, but `bfs` should not allow them to do anything they couldn't already do. +That includes situations where one user (especially `root`) is running `bfs` on files owned or controlled by another user. + +On the other hand, `bfs` implicitly trusts the user running it. +Anyone with enough control over the command line of `bfs` or any `find`-compatible tool can wreak havoc with dangerous actions like `-exec`, `-delete`, etc. + +> [!CAUTION] +> The only untrusted input that should *ever* be passed on the `bfs` command line are **file paths**. +> It is *always* unsafe to allow *any* other part of the command line to be affected by untrusted input. +> Use the `-f` flag, or `-files0-from`, to ensure that the input is interpreted as a path. + +This still has security implications, incuding: + +- **Information disclosure:** an attacker may learn whether particular files exist by observing `bfs`'s output, exit status, or even side channels like execution time. +- **Denial of service:** large directory trees or slow/network storage may cause `bfs` to consume excessive system resources. + +> [!TIP] +> When in doubt, do not pass any untrusted input to `bfs`. + + +Executing commands +------------------ + +The `-exec` family of actions execute commands, passing the matched paths as arguments. +File names that begin with a dash may be misinterpreted as options, so `bfs` adds a leading `./` in some instances: + +```console +user@host$ bfs -execdir echo {} \; +./-rf +``` + +This might save you from accidentally running `rm -rf` (for example) when you didn't mean to. +This mitigation applies to `-execdir`, but not `-exec`, because the full path typically does not begin with a dash. +But it is possible, so be careful: + +```console +user@host$ bfs -f -rf -exec echo {} \; +-rf +``` + + +Race conditions +--------------- + +Like many programs that interface with the file system, `bfs` can be affected by race conditions—in particular, "[time-of-check to time-of-use](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use)" (TOCTTOU) issues. +For example, + +```console +user@host$ bfs / -user user -exec dangerous_command {} \; +``` + +is not guaranteed to only run `dangerous_command` on files you own, because another user may run + +```console +evil@host$ mv /path/to/file /path/to/exile +evil@host$ mv ~/malicious /path/to/file +``` + +in between checking `-user user` and executing the command. + +> [!WARNING] +> Be careful when running `bfs` on directories that other users have write access to, because they can modify the directory tree while `bfs` is running, leading to unpredictable results and possible TOCTTOU issues. + + +Output sanitization +------------------- + +In general, printing arbitrary data to a terminal may have [security](https://hdm.io/writing/termulation.txt) [implications](https://dgl.cx/2023/09/ansi-terminal-security#vulnerabilities-using-known-replies). +On many platforms, file paths may be completely arbitrary data (except for NUL (`\0`) bytes). +Therefore, when `bfs` is writing output to a terminal, it will escape non-printable characters: + +<pre> +user@host$ touch $'\e[1mBOLD\e[0m' +user@host$ bfs +. +./$'\e[1mBOLD\e[0m' +</pre> + +However, this is fragile as it only applies when outputting directly to a terminal: + +<pre> +user@host$ bfs | grep BOLD +<strong>BOLD</strong> +</pre> + + +Code quality +------------ + +Every correctness issue in `bfs` is a potential security issue, because acting on the wrong path may do arbitrarily bad things. +For example: + +```console +root@host# bfs /etc -name passwd -exec cat {} \; +``` + +should print `/etc/passwd` but not `/etc/shadow`. +`bfs` tries to ensure correct behavior through careful programming practice, an extensive testsuite, and static analysis. + +`bfs` is written in C, which is a memory unsafe language. +Bugs that lead to memory corruption are likely to be exploitable due to the nature of C. +We use [sanitizers](https://github.com/google/sanitizers) to try to detect these bugs. +Fuzzing has also been applied in the past, and deploying continuous fuzzing is a work in progress. + + +Supported versions +------------------ + +`bfs` comes with [no warranty](/LICENSE), and is maintained by [me](https://tavianator.com/) and [other volunteers](https://github.com/tavianator/bfs/graphs/contributors) in our spare time. +In that sense, there are no *supported* versions. +However, as long as I maintain `bfs` I will attempt to address any security issues swiftly. +In general, security fixes will we part of the latest release, though for significant issues I may backport fixes to older release series. + + +Reporting a vulnerability +------------------------- + +If you think you have found a sensitive security issue in `bfs`, you can [report it privately](https://github.com/tavianator/bfs/security/advisories/new). +Or you can [report it publicly](https://github.com/tavianator/bfs/issues/new); I won't judge you. @@ -1,4 +1,4 @@ -.TH BFS 1 +.TH BFS 1 2024-06-17 "bfs 3.3.1" .SH NAME bfs \- breadth-first search for your files .SH SYNOPSIS @@ -45,7 +45,7 @@ For example, .RE .fi .PP -will print the all the paths that are either .txt files or symbolic links to .txt files. +will print all the paths that are either .txt files or symbolic links to .txt files. .B \-and is implied between two consecutive expressions, so this is equivalent: .PP @@ -71,7 +71,7 @@ will also accept .I \-N or .IR +N . -.IR \-N +.I \-N means "less than .IR N ," and @@ -917,7 +917,7 @@ Finds broken symbolic links. .TP .B bfs \-name config \-exclude \-name .git Finds all files named -.BR config, +.BR config , skipping every .B .git directory. @@ -1529,11 +1529,28 @@ static bool bftw_pop_file(struct bftw_state *state) { return bftw_pop(state, &state->fileq); } +/** Add a path component to the path. */ +static void bftw_prepend_path(char *path, size_t nameoff, size_t namelen, const char *name) { + if (nameoff > 0) { + path[nameoff - 1] = '/'; + } + memcpy(path + nameoff, name, namelen); +} + /** Build the path to the current file. */ static int bftw_build_path(struct bftw_state *state, const char *name) { const struct bftw_file *file = state->file; - size_t pathlen = file ? file->nameoff + file->namelen : 0; + size_t nameoff, namelen; + if (name) { + nameoff = file ? bftw_child_nameoff(file) : 0; + namelen = strlen(name); + } else { + nameoff = file->nameoff; + namelen = file->namelen; + } + + size_t pathlen = nameoff + namelen; if (dstresize(&state->path, pathlen) != 0) { state->error = errno; return -1; @@ -1546,11 +1563,11 @@ static int bftw_build_path(struct bftw_state *state, const char *name) { } // Build the path backwards + if (name) { + bftw_prepend_path(state->path, nameoff, namelen, name); + } while (file && file != ancestor) { - if (file->nameoff > 0) { - state->path[file->nameoff - 1] = '/'; - } - memcpy(state->path + file->nameoff, file->name, file->namelen); + bftw_prepend_path(state->path, file->nameoff, file->namelen, file->name); if (ancestor && ancestor->depth == file->depth) { ancestor = ancestor->parent; @@ -1559,20 +1576,6 @@ static int bftw_build_path(struct bftw_state *state, const char *name) { } state->previous = state->file; - - if (name) { - if (pathlen > 0 && state->path[pathlen - 1] != '/') { - if (dstrapp(&state->path, '/') != 0) { - state->error = errno; - return -1; - } - } - if (dstrcat(&state->path, name) != 0) { - state->error = errno; - return -1; - } - } - return 0; } diff --git a/src/color.c b/src/color.c index 81f28bb..701a89c 100644 --- a/src/color.c +++ b/src/color.c @@ -583,7 +583,7 @@ static int parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) { break; } - if (dstrncpy(&key, chunk, equals - chunk) != 0) { + if (dstrxcpy(&key, chunk, equals - chunk) != 0) { goto fail; } if (unescape(&value, equals + 1, ':', &next) != 0) { @@ -968,7 +968,7 @@ static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, if (path == ftwbuf->path) { if (ftwbuf->depth == 0) { at_fd = AT_FDCWD; - at_path = dstrndup(path, max); + at_path = dstrxdup(path, max); } else { // The parent must have existed to get here goto out; @@ -977,13 +977,13 @@ static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, // We're in print_link_target(), so resolve relative to the link's parent directory at_fd = ftwbuf->at_fd; if (at_fd == (int)AT_FDCWD && path[0] != '/') { - at_path = dstrndup(ftwbuf->path, ftwbuf->nameoff); - if (at_path && dstrncat(&at_path, path, max) != 0) { + at_path = dstrxdup(ftwbuf->path, ftwbuf->nameoff); + if (at_path && dstrxcat(&at_path, path, max) != 0) { ret = -1; goto out_path; } } else { - at_path = dstrndup(path, max); + at_path = dstrxdup(path, max); } } @@ -1206,7 +1206,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { for (const char *i = format; *i; ++i) { size_t verbatim = strcspn(i, "%$"); - if (dstrncat(&cfile->buffer, i, verbatim) != 0) { + if (dstrxcat(&cfile->buffer, i, verbatim) != 0) { return -1; } i += verbatim; @@ -234,7 +234,7 @@ static char *bfs_exec_format_arg(char *arg, const char *path) { char *last = arg; do { - if (dstrncat(&ret, last, match - last) != 0) { + if (dstrxcat(&ret, last, match - last) != 0) { goto err; } if (dstrcat(&ret, path) != 0) { @@ -313,9 +313,11 @@ static void ioq_slot_wake(struct ioqq *ioqq, ioq_slot *slot) { cond_broadcast(&monitor->cond); } -/** Branch-free (slot & IOQ_SKIP) ? ~IOQ_BLOCKED : 0 */ -static uintptr_t ioq_skip_mask(uintptr_t slot) { - return -(slot >> IOQ_SKIP_BIT) << 1; +/** Branch-free ((slot & IOQ_SKIP) ? skip : full) & ~IOQ_BLOCKED */ +static uintptr_t ioq_slot_blend(uintptr_t slot, uintptr_t skip, uintptr_t full) { + uintptr_t mask = -(slot >> IOQ_SKIP_BIT); + uintptr_t ret = (skip & mask) | (full & ~mask); + return ret & ~IOQ_BLOCKED; } /** Push an entry into a slot. */ @@ -323,19 +325,18 @@ static bool ioq_slot_push(struct ioqq *ioqq, ioq_slot *slot, struct ioq_ent *ent uintptr_t prev = load(slot, relaxed); while (true) { - size_t skip_mask = ioq_skip_mask(prev); - size_t full_mask = ~skip_mask & ~IOQ_BLOCKED; - if (prev & full_mask) { + uintptr_t full = ioq_slot_blend(prev, 0, prev); + if (full) { // full(ptr) → wait prev = ioq_slot_wait(ioqq, slot, prev); continue; } // empty → full(ptr) - uintptr_t next = ((uintptr_t)ent >> 1) & full_mask; + uintptr_t next = (uintptr_t)ent >> 1; // skip(1) → empty // skip(n) → skip(n - 1) - next |= (prev - IOQ_SKIP_ONE) & skip_mask; + next = ioq_slot_blend(prev, prev - IOQ_SKIP_ONE, next); if (compare_exchange_weak(slot, &prev, next, release, relaxed)) { break; @@ -357,9 +358,8 @@ static struct ioq_ent *ioq_slot_pop(struct ioqq *ioqq, ioq_slot *slot, bool bloc // skip(n) → skip(n + 1) // full(ptr) → full(ptr - 1) uintptr_t next = prev + IOQ_SKIP_ONE; - // skip(n) → ~IOQ_BLOCKED // full(ptr) → 0 - next &= ioq_skip_mask(next); + next = ioq_slot_blend(next, next, 0); if (block && next) { prev = ioq_slot_wait(ioqq, slot, prev); @@ -378,7 +378,7 @@ static struct ioq_ent *ioq_slot_pop(struct ioqq *ioqq, ioq_slot *slot, bool bloc // empty → 0 // skip(n) → 0 // full(ptr) → ptr - prev &= ioq_skip_mask(~prev); + prev = ioq_slot_blend(prev, 0, prev); return (struct ioq_ent *)(prev << 1); } diff --git a/src/parse.c b/src/parse.c index a626391..86ce72c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -2961,11 +2961,12 @@ static struct bfs_expr *parse_version(struct bfs_parser *parser, int arg1, int a printf("Copyright © Tavian Barnes and the bfs contributors\n"); printf("No rights reserved (https://opensource.org/license/0BSD)\n\n"); - printf("CONFIG := %s\n", bfs_config); - printf("CPPFLAGS := %s\n", bfs_cppflags); - printf("CFLAGS := %s\n", bfs_cflags); - printf("LDFLAGS := %s\n", bfs_ldflags); - printf("LDLIBS := %s\n", bfs_ldlibs); + printf("CONFFLAGS := %s\n", bfs_confflags); + printf("CC := %s\n", bfs_cc); + printf("CPPFLAGS := %s\n", bfs_cppflags); + printf("CFLAGS := %s\n", bfs_cflags); + printf("LDFLAGS := %s\n", bfs_ldflags); + printf("LDLIBS := %s\n", bfs_ldlibs); printf("\n%s\n", BFS_HOMEPAGE); diff --git a/src/prelude.h b/src/prelude.h index faa84ec..34ce803 100644 --- a/src/prelude.h +++ b/src/prelude.h @@ -40,7 +40,8 @@ // when the version number changes extern const char bfs_version[]; -extern const char bfs_config[]; +extern const char bfs_confflags[]; +extern const char bfs_cc[]; extern const char bfs_cppflags[]; extern const char bfs_cflags[]; extern const char bfs_ldflags[]; diff --git a/src/version.c b/src/version.c index e2d4c87..8383350 100644 --- a/src/version.c +++ b/src/version.c @@ -7,8 +7,12 @@ const char bfs_version[] = { #include "version.i" }; -const char bfs_config[] = { -#include "config.i" +const char bfs_confflags[] = { +#include "confflags.i" +}; + +const char bfs_cc[] = { +#include "cc.i" }; const char bfs_cppflags[] = { |