From 5edd17c4c2a17e7e964f360d83de39e66ea6865b Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 00:57:31 +0200 Subject: [PATCH 01/48] Add bergkvist to maintainer list --- maintainers/maintainer-list.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 0130499a993d7..7fe382a5e486f 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -1228,6 +1228,12 @@ githubId = 251106; name = "Daniel Bergey"; }; + bergkvist = { + email = "tobias@bergkv.ist"; + github = "bergkvist"; + githubId = 410028; + name = "Tobias Bergkvist"; + }; betaboon = { email = "betaboon@0x80.ninja"; github = "betaboon"; From de1f53b84d5f9549730693aa1e33f69069477395 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 01:11:06 +0200 Subject: [PATCH 02/48] Add make-c-wrapper.sh for creating binary executable wrappers --- .../setup-hooks/make-c-wrapper.sh | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 pkgs/build-support/setup-hooks/make-c-wrapper.sh diff --git a/pkgs/build-support/setup-hooks/make-c-wrapper.sh b/pkgs/build-support/setup-hooks/make-c-wrapper.sh new file mode 100644 index 0000000000000..2c67d9ab16e6d --- /dev/null +++ b/pkgs/build-support/setup-hooks/make-c-wrapper.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# make-c-wrapper.sh EXECUTABLE ARGS +# +# ARGS: +# --argv0 NAME : set name of executed process to NAME +# (defaults to EXECUTABLE) +# --set VAR VAL : add VAR with value VAL to the executable’s +# environment +# --set-default VAR VAL : like --set, but only adds VAR if not already set in +# the environment +# --unset VAR : remove VAR from the environment +# +# To debug a binary wrapper after you compiled it, use the `strings` command + +escape_string_literal() { + # We need to make sure that special characters are escaped + # before trying to create C string literals + result=${1//$'\\'/$'\\\\'} + result=${result//\"/'\"'} + result=${result//$'\n'/"\n"} + result=${result//$'\r'/"\r"} +} + +escape_string_literal "$1" +executable="${result}" +args=("$@") + +printf "%s\n" "#include " +printf "%s\n" "#include " +printf "\n%s\n" "int main(int argc, char **argv) {" +for ((n = 1; n < ${#args[*]}; n += 1)); do + p="${args[$n]}" + if [[ "$p" == "--set" ]]; then + escape_string_literal "${args[$((n + 1))]}" + key="${result}" + escape_string_literal "${args[$((n + 2))]}" + value="${result}" + n=$((n + 2)) + printf "%s\n" " putenv(\"${key}=${value}\");" + docs="${docs:+$docs$'\n'}putenv(\"${key}=${value}\");" + elif [[ "$p" == "--set-default" ]]; then + escape_string_literal "${args[$((n + 1))]}" + key="${result}" + escape_string_literal "${args[$((n + 2))]}" + value="${result}" + n=$((n + 2)) + printf "%s\n" " setenv(\"${key}\", \"${value}\", 0);" + docs="${docs:+$docs$'\n'}setenv(\"${key}=${value}\", 0);" + elif [[ "$p" == "--unset" ]]; then + escape_string_literal "${args[$((n + 1))]}" + key="${result}" + printf "%s\n" " unsetenv(\"$key\");" + docs="${docs:+$docs$'\n'}unsetenv(\"${key}=${value}\", 0);" + n=$((n + 1)) + elif [[ "$p" == "--argv0" ]]; then + escape_string_literal "${args[$((n + 1))]}" + argv0="${result}" + n=$((n + 1)) + else + # Using an error macro, we will make sure the compiler gives an understandable error message + printf "%s\n" " #error make-c-wrapper.sh did not understand argument ${p}" + fi +done +printf "%s\n" " argv[0] = \"${argv0:-${executable}}\";" +printf "%s\n" " return execv(\"${executable}\", argv);" +printf "%s\n" "}" + +docs="${docs:+$docs$'\n'}argv[0] = \"${argv0:-${executable}}\";" +docs="${docs:+$docs$'\n'}execv(\"${executable}\", argv);" +docs="----------"$'\n'"This binary wrapper (created from generated C-code) is configured with the following settings:${docs:+$'\n'$docs}" +escape_string_literal "$docs" +docs=$result +printf "\n%s\n" "const char* DOCS = \"$docs\";" From eef4fa82c169d00b0b05f1c3ac2b1081b968c9e7 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 01:47:40 +0200 Subject: [PATCH 03/48] make-c-wrapper: Fix typo in generated code documentation --- pkgs/build-support/setup-hooks/make-c-wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-c-wrapper.sh b/pkgs/build-support/setup-hooks/make-c-wrapper.sh index 2c67d9ab16e6d..6f024b3356c3c 100644 --- a/pkgs/build-support/setup-hooks/make-c-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-c-wrapper.sh @@ -50,7 +50,7 @@ for ((n = 1; n < ${#args[*]}; n += 1)); do escape_string_literal "${args[$((n + 1))]}" key="${result}" printf "%s\n" " unsetenv(\"$key\");" - docs="${docs:+$docs$'\n'}unsetenv(\"${key}=${value}\", 0);" + docs="${docs:+$docs$'\n'}unsetenv(\"${key}=${value}\");" n=$((n + 1)) elif [[ "$p" == "--argv0" ]]; then escape_string_literal "${args[$((n + 1))]}" From 131ed20b2f8b937e0ff0fffae1dcde8d699ce0e1 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 01:56:05 +0200 Subject: [PATCH 04/48] make-c-wrapper: Remove trailing whitespace (editorconfig) --- pkgs/build-support/setup-hooks/make-c-wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-c-wrapper.sh b/pkgs/build-support/setup-hooks/make-c-wrapper.sh index 6f024b3356c3c..e018e4f161d7c 100644 --- a/pkgs/build-support/setup-hooks/make-c-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-c-wrapper.sh @@ -13,7 +13,7 @@ # To debug a binary wrapper after you compiled it, use the `strings` command escape_string_literal() { - # We need to make sure that special characters are escaped + # We need to make sure that special characters are escaped # before trying to create C string literals result=${1//$'\\'/$'\\\\'} result=${result//\"/'\"'} From e8cedf381914d28e162810f567216f8c00f87edc Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 02:04:12 +0200 Subject: [PATCH 05/48] make-c-wrapper: Fix typo in generated documentation --- pkgs/build-support/setup-hooks/make-c-wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-c-wrapper.sh b/pkgs/build-support/setup-hooks/make-c-wrapper.sh index e018e4f161d7c..55afe9fcf2a27 100644 --- a/pkgs/build-support/setup-hooks/make-c-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-c-wrapper.sh @@ -50,7 +50,7 @@ for ((n = 1; n < ${#args[*]}; n += 1)); do escape_string_literal "${args[$((n + 1))]}" key="${result}" printf "%s\n" " unsetenv(\"$key\");" - docs="${docs:+$docs$'\n'}unsetenv(\"${key}=${value}\");" + docs="${docs:+$docs$'\n'}unsetenv(\"${key}\");" n=$((n + 1)) elif [[ "$p" == "--argv0" ]]; then escape_string_literal "${args[$((n + 1))]}" From 8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 1 Jun 2021 01:02:08 +0200 Subject: [PATCH 06/48] Rename make-c-wrapper.sh to make-binary-wrapper.sh. Refactor to match style of other setup-hooks. Add compilation step with gcc. Embed the entire generated source code into the binary for troubleshooting. --- .../setup-hooks/make-binary-wrapper.sh | 108 ++++++++++++++++++ .../setup-hooks/make-c-wrapper.sh | 73 ------------ 2 files changed, 108 insertions(+), 73 deletions(-) create mode 100755 pkgs/build-support/setup-hooks/make-binary-wrapper.sh delete mode 100644 pkgs/build-support/setup-hooks/make-c-wrapper.sh diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh new file mode 100755 index 0000000000000..b77aca60a01de --- /dev/null +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -0,0 +1,108 @@ +# Generate a binary executable wrapper for wrapping an executable. +# The binary is compiled from generated C-code using gcc. +# makeBinaryWrapper EXECUTABLE OUT_PATH ARGS + +# ARGS: +# --argv0 NAME : set name of executed process to NAME +# (defaults to EXECUTABLE) +# --set VAR VAL : add VAR with value VAL to the executable’s +# environment +# --set-default VAR VAL : like --set, but only adds VAR if not already set in +# the environment +# --unset VAR : remove VAR from the environment +# +# To troubleshoot a binary wrapper after you compiled it, +# use the `strings` command or open the binary file in a text editor. +makeBinaryWrapper() { + makeDocumentedCWrapper "$1" "${@:3}" | gcc -x c -o "$2" - +} + +# Generate source code for the wrapper in such a way that the wrapper source code +# will still be readable even after compilation +# makeDocumentedCWrapper EXECUTABLE ARGS +# ARGS: same as makeBinaryWrapper +makeDocumentedCWrapper() { + local src=$(makeCWrapper "$@") + local docs=$(documentationString "$src") + printf "%s\n" "$src" + printf "\n%s\n" "$docs" +} + +# makeCWrapper EXECUTABLE ARGS +# ARGS: same as makeBinaryWrapper +makeCWrapper() { + local argv0 n params cmd + local executable=$(escapeStringLiteral "$1") + local params=("$@") + + printf "%s\n" "#include " + printf "%s\n" "#include " + printf "\n%s\n" "int main(int argc, char **argv) {" + + for ((n = 1; n < ${#params[*]}; n += 1)); do + p="${params[$n]}" + if [[ "$p" == "--set" ]]; then + cmd=$(setEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") + n=$((n + 2)) + printf "%s\n" " $cmd" + elif [[ "$p" == "--set-default" ]]; then + cmd=$(setDefaultEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") + n=$((n + 2)) + printf "%s\n" " $cmd" + elif [[ "$p" == "--unset" ]]; then + cmd=$(unsetEnv "${params[$((n + 1))]}") + printf "%s\n" " $cmd" + n=$((n + 1)) + elif [[ "$p" == "--argv0" ]]; then + argv0=$(escapeStringLiteral "${params[$((n + 1))]}") + n=$((n + 1)) + else + # Using an error macro, we will make sure the compiler gives an understandable error message + printf "%s\n" " #error makeCWrapper did not understand argument ${p}" + fi + done + + printf "%s\n" " argv[0] = \"${argv0:-${executable}}\";" + printf "%s\n" " return execv(\"${executable}\", argv);" + printf "%s\n" "}" +} + +# setEnv KEY VALUE +setEnv() { + local key=$(escapeStringLiteral "$1") + local value=$(escapeStringLiteral "$2") + printf "%s" "putenv(\"${key}=${value}\");" +} + +# setDefaultEnv KEY VALUE +setDefaultEnv() { + local key=$(escapeStringLiteral "$1") + local value=$(escapeStringLiteral "$2") + printf "%s" "setenv(\"$key\", \"$value\", 0);" +} + +# unsetEnv KEY +unsetEnv() { + local key=$(escapeStringLiteral "$1") + printf "%s" "unsetenv(\"$key\");" +} + +# Put the entire source code into const char* SOURCE_CODE to make it readable after compilation. +# documentationString SOURCE_CODE +documentationString() { + local docs=$(escapeStringLiteral $'\n----------\n// This binary wrapper was compiled from the following generated C-code:\n'"$1"$'\n----------\n') + printf "%s" "const char * SOURCE_CODE = \"$docs\";" +} + +# Makes it safe to insert STRING within quotes in a C String Literal. +# escapeStringLiteral STRING +escapeStringLiteral() { + local result + result=${1//$'\\'/$'\\\\'} + result=${result//\"/'\"'} + result=${result//$'\n'/"\n"} + result=${result//$'\r'/"\r"} + printf "%s" "$result" +} + +makeBinaryWrapper "$@" diff --git a/pkgs/build-support/setup-hooks/make-c-wrapper.sh b/pkgs/build-support/setup-hooks/make-c-wrapper.sh deleted file mode 100644 index 55afe9fcf2a27..0000000000000 --- a/pkgs/build-support/setup-hooks/make-c-wrapper.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# make-c-wrapper.sh EXECUTABLE ARGS -# -# ARGS: -# --argv0 NAME : set name of executed process to NAME -# (defaults to EXECUTABLE) -# --set VAR VAL : add VAR with value VAL to the executable’s -# environment -# --set-default VAR VAL : like --set, but only adds VAR if not already set in -# the environment -# --unset VAR : remove VAR from the environment -# -# To debug a binary wrapper after you compiled it, use the `strings` command - -escape_string_literal() { - # We need to make sure that special characters are escaped - # before trying to create C string literals - result=${1//$'\\'/$'\\\\'} - result=${result//\"/'\"'} - result=${result//$'\n'/"\n"} - result=${result//$'\r'/"\r"} -} - -escape_string_literal "$1" -executable="${result}" -args=("$@") - -printf "%s\n" "#include " -printf "%s\n" "#include " -printf "\n%s\n" "int main(int argc, char **argv) {" -for ((n = 1; n < ${#args[*]}; n += 1)); do - p="${args[$n]}" - if [[ "$p" == "--set" ]]; then - escape_string_literal "${args[$((n + 1))]}" - key="${result}" - escape_string_literal "${args[$((n + 2))]}" - value="${result}" - n=$((n + 2)) - printf "%s\n" " putenv(\"${key}=${value}\");" - docs="${docs:+$docs$'\n'}putenv(\"${key}=${value}\");" - elif [[ "$p" == "--set-default" ]]; then - escape_string_literal "${args[$((n + 1))]}" - key="${result}" - escape_string_literal "${args[$((n + 2))]}" - value="${result}" - n=$((n + 2)) - printf "%s\n" " setenv(\"${key}\", \"${value}\", 0);" - docs="${docs:+$docs$'\n'}setenv(\"${key}=${value}\", 0);" - elif [[ "$p" == "--unset" ]]; then - escape_string_literal "${args[$((n + 1))]}" - key="${result}" - printf "%s\n" " unsetenv(\"$key\");" - docs="${docs:+$docs$'\n'}unsetenv(\"${key}\");" - n=$((n + 1)) - elif [[ "$p" == "--argv0" ]]; then - escape_string_literal "${args[$((n + 1))]}" - argv0="${result}" - n=$((n + 1)) - else - # Using an error macro, we will make sure the compiler gives an understandable error message - printf "%s\n" " #error make-c-wrapper.sh did not understand argument ${p}" - fi -done -printf "%s\n" " argv[0] = \"${argv0:-${executable}}\";" -printf "%s\n" " return execv(\"${executable}\", argv);" -printf "%s\n" "}" - -docs="${docs:+$docs$'\n'}argv[0] = \"${argv0:-${executable}}\";" -docs="${docs:+$docs$'\n'}execv(\"${executable}\", argv);" -docs="----------"$'\n'"This binary wrapper (created from generated C-code) is configured with the following settings:${docs:+$'\n'$docs}" -escape_string_literal "$docs" -docs=$result -printf "\n%s\n" "const char* DOCS = \"$docs\";" From 1d6428140194b5bac68266ca11a441ed6f63571c Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 1 Jun 2021 01:25:22 +0200 Subject: [PATCH 07/48] Remove line at the bottom of make-binary-wrapper that executes makeBinaryWrapper "$@" --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 2 -- 1 file changed, 2 deletions(-) mode change 100755 => 100644 pkgs/build-support/setup-hooks/make-binary-wrapper.sh diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh old mode 100755 new mode 100644 index b77aca60a01de..33310948333ac --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -104,5 +104,3 @@ escapeStringLiteral() { result=${result//$'\r'/"\r"} printf "%s" "$result" } - -makeBinaryWrapper "$@" From dcba4171d4a7150cbaf90cae7a3e12a8381067a7 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 23 Aug 2021 23:44:57 +0200 Subject: [PATCH 08/48] Add support for --add-flags, --prefix and --suffix --- .../setup-hooks/make-binary-wrapper.sh | 124 +++++++++++++++--- 1 file changed, 109 insertions(+), 15 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 33310948333ac..f19edd483cfa8 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -4,17 +4,21 @@ # ARGS: # --argv0 NAME : set name of executed process to NAME -# (defaults to EXECUTABLE) +# (otherwise it’s called …-wrapped) # --set VAR VAL : add VAR with value VAL to the executable’s # environment # --set-default VAR VAL : like --set, but only adds VAR if not already set in # the environment # --unset VAR : remove VAR from the environment -# +# --add-flags FLAGS : add FLAGS to invocation of executable + +# --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP +# --suffix + # To troubleshoot a binary wrapper after you compiled it, # use the `strings` command or open the binary file in a text editor. makeBinaryWrapper() { - makeDocumentedCWrapper "$1" "${@:3}" | gcc -x c -o "$2" - + makeDocumentedCWrapper "$1" "${@:3}" | gcc -Os -x c -o "$2" - } # Generate source code for the wrapper in such a way that the wrapper source code @@ -31,27 +35,39 @@ makeDocumentedCWrapper() { # makeCWrapper EXECUTABLE ARGS # ARGS: same as makeBinaryWrapper makeCWrapper() { - local argv0 n params cmd + local argv0 n params cmd main flagsBefore flags local executable=$(escapeStringLiteral "$1") local params=("$@") - printf "%s\n" "#include " - printf "%s\n" "#include " - printf "\n%s\n" "int main(int argc, char **argv) {" - for ((n = 1; n < ${#params[*]}; n += 1)); do p="${params[$n]}" if [[ "$p" == "--set" ]]; then cmd=$(setEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") + main="$main $cmd"$'\n' n=$((n + 2)) - printf "%s\n" " $cmd" elif [[ "$p" == "--set-default" ]]; then cmd=$(setDefaultEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") + main="$main $cmd"$'\n' n=$((n + 2)) - printf "%s\n" " $cmd" elif [[ "$p" == "--unset" ]]; then cmd=$(unsetEnv "${params[$((n + 1))]}") - printf "%s\n" " $cmd" + main="$main $cmd"$'\n' + n=$((n + 1)) + elif [[ "$p" == "--prefix" ]]; then + cmd=$(setEnvPrefix "${params[$((n + 1))]}" "${params[$((n + 2))]}" "${params[$((n + 3))]}") + main="$main $cmd"$'\n' + uses_prefix=1 + uses_concat3=1 + n=$((n + 3)) + elif [[ "$p" == "--suffix" ]]; then + cmd=$(setEnvSuffix "${params[$((n + 1))]}" "${params[$((n + 2))]}" "${params[$((n + 3))]}") + main="$main $cmd"$'\n' + uses_suffix=1 + uses_concat3=1 + n=$((n + 3)) + elif [[ "$p" == "--add-flags" ]]; then + flags="${params[$((n + 1))]}" + flagsBefore="$flagsBefore $flags" n=$((n + 1)) elif [[ "$p" == "--argv0" ]]; then argv0=$(escapeStringLiteral "${params[$((n + 1))]}") @@ -61,17 +77,63 @@ makeCWrapper() { printf "%s\n" " #error makeCWrapper did not understand argument ${p}" fi done + [ -z ${flagsBefore+"1"} ] || { + flagsBefore=("$flagsBefore") + main="$main"$'\n'$(addFlags $flagsBefore)$'\n'$'\n' + } - printf "%s\n" " argv[0] = \"${argv0:-${executable}}\";" - printf "%s\n" " return execv(\"${executable}\", argv);" - printf "%s\n" "}" + main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' + main="$main return execv(\"${executable}\", argv);"$'\n' + + printf "%s\n" "#include " + printf "%s\n" "#include " + [ -z "$uses_concat3" ] || printf "\n%s\n" "$(concat3Fn)" + [ -z "$uses_prefix" ] || printf "\n%s\n" "$(setEnvPrefixFn)" + [ -z "$uses_suffix" ] || printf "\n%s\n" "$(setEnvSuffixFn)" + printf "\n%s" "int main(int argc, char **argv) {" + printf "\n%s" "$main" + printf "%s" "}" +} + +addFlags() { + local result n flag flags + local var="argv_tmp" + flags=("$@") + for ((n = 0; n < ${#flags[*]}; n += 1)); do + flag=$(escapeStringLiteral "${flags[((n))]}") + result="$result $var[$((n+1))] = \"$flag\";"$'\n' + done + printf " %s\n" "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));" + printf " %s\n" "$var[0] = argv[0];" + printf "%s" "$result" + printf " %s\n" "for (int i = 1; i < argc; ++i) {" + printf " %s\n" " $var[$n + i] = argv[i];" + printf " %s\n" "}" + printf " %s\n" "$var[$n + argc] = NULL;" + printf " %s\n" "argv = $var;" +} + +# prefix ENV SEP VAL +setEnvPrefix() { + local env=$(escapeStringLiteral "$1") + local sep=$(escapeStringLiteral "$2") + local val=$(escapeStringLiteral "$3") + printf "%s" "set_env_prefix(\"$env\", \"$sep\", \"$val\");" +} + +# suffix ENV SEP VAL +setEnvSuffix() { + local env=$(escapeStringLiteral "$1") + local sep=$(escapeStringLiteral "$2") + local val=$(escapeStringLiteral "$3") + printf "%s" "set_env_suffix(\"$env\", \"$sep\", \"$val\");" } # setEnv KEY VALUE setEnv() { local key=$(escapeStringLiteral "$1") local value=$(escapeStringLiteral "$2") - printf "%s" "putenv(\"${key}=${value}\");" + printf "%s" "putenv(\"$key=$value\");" } # setDefaultEnv KEY VALUE @@ -104,3 +166,35 @@ escapeStringLiteral() { result=${result//$'\r'/"\r"} printf "%s" "$result" } + +concat3Fn() { + printf "%s\n" 'char *concat3(char *x, char *y, char *z) {' + printf "%s\n" ' int xn = 0; while(x[++xn]);' + printf "%s\n" ' int yn = 0; while(y[++yn]);' + printf "%s\n" ' int zn = 0; while(z[++zn]);' + printf "%s\n" ' char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));' + printf "%s\n" ' for (int i = 0; i < xn; ++i) res[i] = x[i];' + printf "%s\n" ' for (int i = 0; i < yn; ++i) res[xn+i] = y[i];' + printf "%s\n" ' for (int i = 0; i < zn; ++i) res[xn+yn+i] = z[i];' + printf "%s\n" " res[xn+yn+zn] = '\0';" + printf "%s\n" ' return res;' + printf "%s\n" '}' +} + +setEnvPrefixFn() { + printf "%s\n" 'void set_env_prefix(char *env, char *sep, char *val) {' + printf "%s\n" ' char *existing = getenv(env);' + printf "%s\n" ' if (existing) val = concat3(val, sep, existing);' + printf "%s\n" ' setenv(env, val, 1);' + printf "%s\n" ' if (existing) free(val);' + printf "%s\n" '}' +} + +setEnvSuffixFn() { + printf "%s\n" 'void set_env_suffix(char *env, char *sep, char *val) {' + printf "%s\n" ' char *existing = getenv(env);' + printf "%s\n" ' if (existing) val = concat3(existing, sep, val);' + printf "%s\n" ' setenv(env, val, 1);' + printf "%s\n" ' if (existing) free(val);' + printf "%s\n" '}' +} From b58c857bfbce8af9b5c100ea2f483c5a228f35d6 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 26 Aug 2021 14:36:30 +0200 Subject: [PATCH 09/48] Switch to using strlen in concat3Fn. Make sure uses-variables are local to improve purity of makeCWrapper. Refactor --- .../setup-hooks/make-binary-wrapper.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index f19edd483cfa8..0c72508520a49 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -36,6 +36,7 @@ makeDocumentedCWrapper() { # ARGS: same as makeBinaryWrapper makeCWrapper() { local argv0 n params cmd main flagsBefore flags + local uses_prefix uses_suffix uses_concat3 local executable=$(escapeStringLiteral "$1") local params=("$@") @@ -77,22 +78,19 @@ makeCWrapper() { printf "%s\n" " #error makeCWrapper did not understand argument ${p}" fi done - [ -z ${flagsBefore+"1"} ] || { - flagsBefore=("$flagsBefore") - main="$main"$'\n'$(addFlags $flagsBefore)$'\n'$'\n' - } - + [ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n' main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' main="$main return execv(\"${executable}\", argv);"$'\n' printf "%s\n" "#include " printf "%s\n" "#include " + [ -z "$uses_concat3" ] || printf "%s\n" "#include " [ -z "$uses_concat3" ] || printf "\n%s\n" "$(concat3Fn)" [ -z "$uses_prefix" ] || printf "\n%s\n" "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf "\n%s\n" "$(setEnvSuffixFn)" printf "\n%s" "int main(int argc, char **argv) {" printf "\n%s" "$main" - printf "%s" "}" + printf "%s\n" "}" } addFlags() { @@ -100,7 +98,7 @@ addFlags() { local var="argv_tmp" flags=("$@") for ((n = 0; n < ${#flags[*]}; n += 1)); do - flag=$(escapeStringLiteral "${flags[((n))]}") + flag=$(escapeStringLiteral "${flags[$n]}") result="$result $var[$((n+1))] = \"$flag\";"$'\n' done printf " %s\n" "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));" @@ -169,9 +167,9 @@ escapeStringLiteral() { concat3Fn() { printf "%s\n" 'char *concat3(char *x, char *y, char *z) {' - printf "%s\n" ' int xn = 0; while(x[++xn]);' - printf "%s\n" ' int yn = 0; while(y[++yn]);' - printf "%s\n" ' int zn = 0; while(z[++zn]);' + printf "%s\n" ' int xn = strlen(x);' + printf "%s\n" ' int yn = strlen(y);' + printf "%s\n" ' int zn = strlen(z);' printf "%s\n" ' char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));' printf "%s\n" ' for (int i = 0; i < xn; ++i) res[i] = x[i];' printf "%s\n" ' for (int i = 0; i < yn; ++i) res[xn+i] = y[i];' From b62216a2118a9b5771206eb88a1fc1dfb6fcb382 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 17:43:23 +0200 Subject: [PATCH 10/48] Fix shellcheck warnings. Use single quotes for printf format strings. Switch to strncpy in concat3. Use multiline strings to print C functions. Switch from if/elif to case. --- .../setup-hooks/make-binary-wrapper.sh | 234 ++++++++++-------- 1 file changed, 127 insertions(+), 107 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 0c72508520a49..1b0ff385cf95e 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -26,132 +26,146 @@ makeBinaryWrapper() { # makeDocumentedCWrapper EXECUTABLE ARGS # ARGS: same as makeBinaryWrapper makeDocumentedCWrapper() { - local src=$(makeCWrapper "$@") - local docs=$(documentationString "$src") - printf "%s\n" "$src" - printf "\n%s\n" "$docs" + local src docs + src=$(makeCWrapper "$@") + docs=$(documentationString "$src") + printf '%s\n\n' "$src" + printf '%s\n' "$docs" } # makeCWrapper EXECUTABLE ARGS # ARGS: same as makeBinaryWrapper makeCWrapper() { - local argv0 n params cmd main flagsBefore flags - local uses_prefix uses_suffix uses_concat3 - local executable=$(escapeStringLiteral "$1") - local params=("$@") - + local argv0 n params cmd main flagsBefore flags executable params + executable=$(escapeStringLiteral "$1") + params=("$@") for ((n = 1; n < ${#params[*]}; n += 1)); do - p="${params[$n]}" - if [[ "$p" == "--set" ]]; then - cmd=$(setEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") - main="$main $cmd"$'\n' - n=$((n + 2)) - elif [[ "$p" == "--set-default" ]]; then - cmd=$(setDefaultEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}") - main="$main $cmd"$'\n' - n=$((n + 2)) - elif [[ "$p" == "--unset" ]]; then - cmd=$(unsetEnv "${params[$((n + 1))]}") - main="$main $cmd"$'\n' - n=$((n + 1)) - elif [[ "$p" == "--prefix" ]]; then - cmd=$(setEnvPrefix "${params[$((n + 1))]}" "${params[$((n + 2))]}" "${params[$((n + 3))]}") - main="$main $cmd"$'\n' - uses_prefix=1 - uses_concat3=1 - n=$((n + 3)) - elif [[ "$p" == "--suffix" ]]; then - cmd=$(setEnvSuffix "${params[$((n + 1))]}" "${params[$((n + 2))]}" "${params[$((n + 3))]}") - main="$main $cmd"$'\n' - uses_suffix=1 - uses_concat3=1 - n=$((n + 3)) - elif [[ "$p" == "--add-flags" ]]; then - flags="${params[$((n + 1))]}" - flagsBefore="$flagsBefore $flags" - n=$((n + 1)) - elif [[ "$p" == "--argv0" ]]; then - argv0=$(escapeStringLiteral "${params[$((n + 1))]}") - n=$((n + 1)) - else - # Using an error macro, we will make sure the compiler gives an understandable error message - printf "%s\n" " #error makeCWrapper did not understand argument ${p}" - fi + p="${params[n]}" + case $p in + --set) + cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}") + main="$main $cmd"$'\n' + n=$((n + 2)) + ;; + --set-default) + cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") + main="$main $cmd"$'\n' + n=$((n + 2)) + ;; + --unset) + cmd=$(unsetEnv "${params[n + 1]}") + main="$main $cmd"$'\n' + n=$((n + 1)) + ;; + --prefix) + cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") + main="$main $cmd"$'\n' + uses_prefix=1 + uses_concat3=1 + n=$((n + 3)) + ;; + --suffix) + cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") + main="$main $cmd"$'\n' + uses_suffix=1 + uses_concat3=1 + n=$((n + 3)) + ;; + --add-flags) + flags="${params[n + 1]}" + flagsBefore="$flagsBefore $flags" + n=$((n + 1)) + ;; + --argv0) + argv0=$(escapeStringLiteral "${params[n + 1]}") + n=$((n + 1)) + ;; + *) # Using an error macro, we will make sure the compiler gives an understandable error message + printf '%s\n' " #error makeCWrapper did not understand argument ${p}" + ;; + esac done + # shellcheck disable=SC2086 [ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n' main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' main="$main return execv(\"${executable}\", argv);"$'\n' - printf "%s\n" "#include " - printf "%s\n" "#include " - [ -z "$uses_concat3" ] || printf "%s\n" "#include " - [ -z "$uses_concat3" ] || printf "\n%s\n" "$(concat3Fn)" - [ -z "$uses_prefix" ] || printf "\n%s\n" "$(setEnvPrefixFn)" - [ -z "$uses_suffix" ] || printf "\n%s\n" "$(setEnvSuffixFn)" - printf "\n%s" "int main(int argc, char **argv) {" - printf "\n%s" "$main" - printf "%s\n" "}" + printf '%s\n' "#include " + printf '%s\n' "#include " + [ -z "$uses_concat3" ] || printf '%s\n' "#include " + [ -z "$uses_concat3" ] || printf '\n%s\n' "$(concat3Fn)" + [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" + [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" + printf '\n%s' "int main(int argc, char **argv) {" + printf '\n%s' "$main" + printf '%s\n' "}" } addFlags() { - local result n flag flags - local var="argv_tmp" + local result n flag flags var + var="argv_tmp" flags=("$@") for ((n = 0; n < ${#flags[*]}; n += 1)); do flag=$(escapeStringLiteral "${flags[$n]}") - result="$result $var[$((n+1))] = \"$flag\";"$'\n' + result="$result ${var}[$((n+1))] = \"$flag\";"$'\n' done - printf " %s\n" "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));" - printf " %s\n" "$var[0] = argv[0];" - printf "%s" "$result" - printf " %s\n" "for (int i = 1; i < argc; ++i) {" - printf " %s\n" " $var[$n + i] = argv[i];" - printf " %s\n" "}" - printf " %s\n" "$var[$n + argc] = NULL;" - printf " %s\n" "argv = $var;" + printf ' %s\n' "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));" + printf ' %s\n' "${var}[0] = argv[0];" + printf '%s' "$result" + printf ' %s\n' "for (int i = 1; i < argc; ++i) {" + printf ' %s\n' " ${var}[$n + i] = argv[i];" + printf ' %s\n' "}" + printf ' %s\n' "${var}[$n + argc] = NULL;" + printf ' %s\n' "argv = $var;" } # prefix ENV SEP VAL setEnvPrefix() { - local env=$(escapeStringLiteral "$1") - local sep=$(escapeStringLiteral "$2") - local val=$(escapeStringLiteral "$3") - printf "%s" "set_env_prefix(\"$env\", \"$sep\", \"$val\");" + local env sep val + env=$(escapeStringLiteral "$1") + sep=$(escapeStringLiteral "$2") + val=$(escapeStringLiteral "$3") + printf '%s' "set_env_prefix(\"$env\", \"$sep\", \"$val\");" } # suffix ENV SEP VAL setEnvSuffix() { - local env=$(escapeStringLiteral "$1") - local sep=$(escapeStringLiteral "$2") - local val=$(escapeStringLiteral "$3") - printf "%s" "set_env_suffix(\"$env\", \"$sep\", \"$val\");" + local env sep val + env=$(escapeStringLiteral "$1") + sep=$(escapeStringLiteral "$2") + val=$(escapeStringLiteral "$3") + printf '%s' "set_env_suffix(\"$env\", \"$sep\", \"$val\");" } # setEnv KEY VALUE setEnv() { - local key=$(escapeStringLiteral "$1") - local value=$(escapeStringLiteral "$2") - printf "%s" "putenv(\"$key=$value\");" + local key value + key=$(escapeStringLiteral "$1") + value=$(escapeStringLiteral "$2") + printf '%s' "putenv(\"$key=$value\");" } # setDefaultEnv KEY VALUE setDefaultEnv() { - local key=$(escapeStringLiteral "$1") - local value=$(escapeStringLiteral "$2") - printf "%s" "setenv(\"$key\", \"$value\", 0);" + local key value + key=$(escapeStringLiteral "$1") + value=$(escapeStringLiteral "$2") + printf '%s' "setenv(\"$key\", \"$value\", 0);" } # unsetEnv KEY unsetEnv() { - local key=$(escapeStringLiteral "$1") - printf "%s" "unsetenv(\"$key\");" + local key + key=$(escapeStringLiteral "$1") + printf '%s' "unsetenv(\"$key\");" } # Put the entire source code into const char* SOURCE_CODE to make it readable after compilation. # documentationString SOURCE_CODE documentationString() { - local docs=$(escapeStringLiteral $'\n----------\n// This binary wrapper was compiled from the following generated C-code:\n'"$1"$'\n----------\n') - printf "%s" "const char * SOURCE_CODE = \"$docs\";" + local docs + docs=$(escapeStringLiteral $'\n----------\n// This binary wrapper was compiled from the following generated C-code:\n'"$1"$'\n----------\n') + printf '%s' "const char * SOURCE_CODE = \"$docs\";" } # Makes it safe to insert STRING within quotes in a C String Literal. @@ -162,37 +176,43 @@ escapeStringLiteral() { result=${result//\"/'\"'} result=${result//$'\n'/"\n"} result=${result//$'\r'/"\r"} - printf "%s" "$result" + printf '%s' "$result" } concat3Fn() { - printf "%s\n" 'char *concat3(char *x, char *y, char *z) {' - printf "%s\n" ' int xn = strlen(x);' - printf "%s\n" ' int yn = strlen(y);' - printf "%s\n" ' int zn = strlen(z);' - printf "%s\n" ' char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));' - printf "%s\n" ' for (int i = 0; i < xn; ++i) res[i] = x[i];' - printf "%s\n" ' for (int i = 0; i < yn; ++i) res[xn+i] = y[i];' - printf "%s\n" ' for (int i = 0; i < zn; ++i) res[xn+yn+i] = z[i];' - printf "%s\n" " res[xn+yn+zn] = '\0';" - printf "%s\n" ' return res;' - printf "%s\n" '}' + printf '%s' "\ +char *concat3(char *x, char *y, char *z) { + int xn = strlen(x); + int yn = strlen(y); + int zn = strlen(z); + char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + strncpy(res, x, xn); + strncpy(res + xn, y, yn); + strncpy(res + xn + yn, z, zn); + res[xn + yn + zn] = '\0'; + return res; +} +" } setEnvPrefixFn() { - printf "%s\n" 'void set_env_prefix(char *env, char *sep, char *val) {' - printf "%s\n" ' char *existing = getenv(env);' - printf "%s\n" ' if (existing) val = concat3(val, sep, existing);' - printf "%s\n" ' setenv(env, val, 1);' - printf "%s\n" ' if (existing) free(val);' - printf "%s\n" '}' + printf '%s' "\ +void set_env_prefix(char *env, char *sep, char *val) { + char *existing = getenv(env); + if (existing) val = concat3(val, sep, existing); + setenv(env, val, 1); + if (existing) free(val); +} +" } setEnvSuffixFn() { - printf "%s\n" 'void set_env_suffix(char *env, char *sep, char *val) {' - printf "%s\n" ' char *existing = getenv(env);' - printf "%s\n" ' if (existing) val = concat3(existing, sep, val);' - printf "%s\n" ' setenv(env, val, 1);' - printf "%s\n" ' if (existing) free(val);' - printf "%s\n" '}' + printf '%s' "\ +void set_env_suffix(char *env, char *sep, char *val) { + char *existing = getenv(env); + if (existing) val = concat3(existing, sep, val); + setenv(env, val, 1); + if (existing) free(val); +} +" } From ac99a6ff9889fa12184aab82642e0e1b4c4d64b0 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 18:19:53 +0200 Subject: [PATCH 11/48] Add makeBinaryWrapper to pkgs/top-level/all-packages.nix --- pkgs/top-level/all-packages.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 974595bb1192f..cbb01ce2c5370 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -606,6 +606,8 @@ in makeWrapper = makeSetupHook { deps = [ dieHook ]; substitutions = { shell = targetPackages.runtimeShell; }; } ../build-support/setup-hooks/make-wrapper.sh; + makeBinaryWrapper = makeSetupHook { } ../build-support/setup-hooks/make-binary-wrapper.sh; + makeModulesClosure = { kernel, firmware, rootModules, allowMissing ? false }: callPackage ../build-support/kernel/modules-closure.nix { inherit kernel firmware rootModules allowMissing; From d930fecc3cb3f10d8de52c31916063659448f64b Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 18:51:09 +0200 Subject: [PATCH 12/48] Return an #error macro if the wrong number of arguments are supplied --- .../build-support/setup-hooks/make-binary-wrapper.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 1b0ff385cf95e..6c4e47c3ea33e 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -36,26 +36,30 @@ makeDocumentedCWrapper() { # makeCWrapper EXECUTABLE ARGS # ARGS: same as makeBinaryWrapper makeCWrapper() { - local argv0 n params cmd main flagsBefore flags executable params + local argv0 n params cmd main flagsBefore flags executable params length executable=$(escapeStringLiteral "$1") params=("$@") - for ((n = 1; n < ${#params[*]}; n += 1)); do + length=${#params[*]} + for ((n = 1; n < length; n += 1)); do p="${params[n]}" case $p in --set) cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' n=$((n + 2)) + [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 2 arguments" ;; --set-default) cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' n=$((n + 2)) + [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 2 arguments" ;; --unset) cmd=$(unsetEnv "${params[n + 1]}") main="$main $cmd"$'\n' n=$((n + 1)) + [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 1 argument" ;; --prefix) cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") @@ -63,6 +67,7 @@ makeCWrapper() { uses_prefix=1 uses_concat3=1 n=$((n + 3)) + [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 3 arguments" ;; --suffix) cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") @@ -70,15 +75,18 @@ makeCWrapper() { uses_suffix=1 uses_concat3=1 n=$((n + 3)) + [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 3 arguments" ;; --add-flags) flags="${params[n + 1]}" flagsBefore="$flagsBefore $flags" n=$((n + 1)) + [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 1 argument" ;; --argv0) argv0=$(escapeStringLiteral "${params[n + 1]}") n=$((n + 1)) + [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 1 argument" ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message printf '%s\n' " #error makeCWrapper did not understand argument ${p}" From 3df841bb99e3e96bcd8c52c19246d74c5e05deee Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 18:57:26 +0200 Subject: [PATCH 13/48] Make error messages more consistent --- .../setup-hooks/make-binary-wrapper.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 6c4e47c3ea33e..d7a8a31121d44 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -47,19 +47,19 @@ makeCWrapper() { cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' n=$((n + 2)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 2 arguments" + [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 2 arguments" ;; --set-default) cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' n=$((n + 2)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 2 arguments" + [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 2 arguments" ;; --unset) cmd=$(unsetEnv "${params[n + 1]}") main="$main $cmd"$'\n' n=$((n + 1)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 1 argument" + [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 1 argument" ;; --prefix) cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") @@ -67,7 +67,7 @@ makeCWrapper() { uses_prefix=1 uses_concat3=1 n=$((n + 3)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 3 arguments" + [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 3 arguments" ;; --suffix) cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") @@ -75,21 +75,21 @@ makeCWrapper() { uses_suffix=1 uses_concat3=1 n=$((n + 3)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 3 arguments" + [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 3 arguments" ;; --add-flags) flags="${params[n + 1]}" flagsBefore="$flagsBefore $flags" n=$((n + 1)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 1 argument" + [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 1 argument" ;; --argv0) argv0=$(escapeStringLiteral "${params[n + 1]}") n=$((n + 1)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeBinaryWrapper: $p takes 1 argument" + [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 1 argument" ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message - printf '%s\n' " #error makeCWrapper did not understand argument ${p}" + printf '%s\n' " #error makeCWrapper: Unknown argument '$p'" ;; esac done From adef70ce7c964e0d1d9d961783036541323b06a7 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 4 Oct 2021 14:29:22 +0200 Subject: [PATCH 14/48] Specify uses_prefix, uses_suffix and uses_concat3 as local vars. Make sure errors in makeCWrapper are located next to the line with the issue. --- .../setup-hooks/make-binary-wrapper.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index d7a8a31121d44..abc0e10631e80 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -37,6 +37,7 @@ makeDocumentedCWrapper() { # ARGS: same as makeBinaryWrapper makeCWrapper() { local argv0 n params cmd main flagsBefore flags executable params length + local uses_prefix uses_suffix uses_concat3 executable=$(escapeStringLiteral "$1") params=("$@") length=${#params[*]} @@ -47,19 +48,19 @@ makeCWrapper() { cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' n=$((n + 2)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 2 arguments" + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' ;; --set-default) cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' n=$((n + 2)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 2 arguments" + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' ;; --unset) cmd=$(unsetEnv "${params[n + 1]}") main="$main $cmd"$'\n' n=$((n + 1)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 1 argument" + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' ;; --prefix) cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") @@ -67,7 +68,7 @@ makeCWrapper() { uses_prefix=1 uses_concat3=1 n=$((n + 3)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 3 arguments" + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' ;; --suffix) cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") @@ -75,21 +76,21 @@ makeCWrapper() { uses_suffix=1 uses_concat3=1 n=$((n + 3)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 3 arguments" + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' ;; --add-flags) flags="${params[n + 1]}" flagsBefore="$flagsBefore $flags" n=$((n + 1)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 1 argument" + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' ;; --argv0) argv0=$(escapeStringLiteral "${params[n + 1]}") n=$((n + 1)) - [ $n -ge "$length" ] && printf '%s\n' " #error makeCWrapper: $p takes 1 argument" + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message - printf '%s\n' " #error makeCWrapper: Unknown argument '$p'" + main="$main #error makeCWrapper: Uknown argument ${p}"$'\n' ;; esac done From b7d36b8d597df1a9d799fa9d6d8d55137a525570 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 4 Oct 2021 22:35:09 +0200 Subject: [PATCH 15/48] Add golden tests for make-binary-wrapper. To run tests after cloning on linux, use the following: nix-build pkgs/top-level/release.nix -A tests.make-binary-wrapper.x86_64-linux --- pkgs/test/default.nix | 2 + pkgs/test/make-binary-wrapper/add-flags.c | 23 +++++++ pkgs/test/make-binary-wrapper/argv0.c | 10 +++ pkgs/test/make-binary-wrapper/basic.c | 9 +++ pkgs/test/make-binary-wrapper/combination.c | 58 ++++++++++++++++ pkgs/test/make-binary-wrapper/default.nix | 69 +++++++++++++++++++ pkgs/test/make-binary-wrapper/env.c | 17 +++++ .../make-binary-wrapper/golden-test-utils.sh | 44 ++++++++++++ pkgs/test/make-binary-wrapper/prefix.c | 33 +++++++++ pkgs/test/make-binary-wrapper/suffix.c | 33 +++++++++ 10 files changed, 298 insertions(+) create mode 100644 pkgs/test/make-binary-wrapper/add-flags.c create mode 100644 pkgs/test/make-binary-wrapper/argv0.c create mode 100644 pkgs/test/make-binary-wrapper/basic.c create mode 100644 pkgs/test/make-binary-wrapper/combination.c create mode 100644 pkgs/test/make-binary-wrapper/default.nix create mode 100644 pkgs/test/make-binary-wrapper/env.c create mode 100644 pkgs/test/make-binary-wrapper/golden-test-utils.sh create mode 100644 pkgs/test/make-binary-wrapper/prefix.c create mode 100644 pkgs/test/make-binary-wrapper/suffix.c diff --git a/pkgs/test/default.nix b/pkgs/test/default.nix index b9f05bdff8d01..acf639b4a46ea 100644 --- a/pkgs/test/default.nix +++ b/pkgs/test/default.nix @@ -35,6 +35,8 @@ with pkgs; macOSSierraShared = callPackage ./macos-sierra-shared {}; + make-binary-wrapper = callPackage ./make-binary-wrapper { inherit makeBinaryWrapper; }; + cross = callPackage ./cross {}; rustCustomSysroot = callPackage ./rust-sysroot {}; diff --git a/pkgs/test/make-binary-wrapper/add-flags.c b/pkgs/test/make-binary-wrapper/add-flags.c new file mode 100644 index 0000000000000..70d43e0bec081 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/add-flags.c @@ -0,0 +1,23 @@ +// makeCWrapper /send/me/flags \ + --add-flags "-x -y -z" \ + --add-flags -abc + +#include +#include + +int main(int argc, char **argv) { + char **argv_tmp = malloc(sizeof(*argv_tmp) * (5 + argc)); + argv_tmp[0] = argv[0]; + argv_tmp[1] = "-x"; + argv_tmp[2] = "-y"; + argv_tmp[3] = "-z"; + argv_tmp[4] = "-abc"; + for (int i = 1; i < argc; ++i) { + argv_tmp[4 + i] = argv[i]; + } + argv_tmp[4 + argc] = NULL; + argv = argv_tmp; + + argv[0] = "/send/me/flags"; + return execv("/send/me/flags", argv); +} \ No newline at end of file diff --git a/pkgs/test/make-binary-wrapper/argv0.c b/pkgs/test/make-binary-wrapper/argv0.c new file mode 100644 index 0000000000000..8e3e1f2987b5b --- /dev/null +++ b/pkgs/test/make-binary-wrapper/argv0.c @@ -0,0 +1,10 @@ +// makeCWrapper /path/to/some/executable \ + --argv0 alternative-name + +#include +#include + +int main(int argc, char **argv) { + argv[0] = "alternative-name"; + return execv("/path/to/some/executable", argv); +} diff --git a/pkgs/test/make-binary-wrapper/basic.c b/pkgs/test/make-binary-wrapper/basic.c new file mode 100644 index 0000000000000..de366c5196306 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/basic.c @@ -0,0 +1,9 @@ +// makeCWrapper /path/to/executable + +#include +#include + +int main(int argc, char **argv) { + argv[0] = "/path/to/executable"; + return execv("/path/to/executable", argv); +} diff --git a/pkgs/test/make-binary-wrapper/combination.c b/pkgs/test/make-binary-wrapper/combination.c new file mode 100644 index 0000000000000..925fdf1ccfb4a --- /dev/null +++ b/pkgs/test/make-binary-wrapper/combination.c @@ -0,0 +1,58 @@ +// makeCWrapper /path/to/executable \ + --argv0 my-wrapper \ + --set-default MESSAGE HELLO \ + --prefix PATH : /usr/bin/ \ + --suffix PATH : /usr/local/bin/ \ + --add-flags "-x -y -z" \ + --set MESSAGE2 WORLD + +#include +#include +#include + +char *concat3(char *x, char *y, char *z) { + int xn = strlen(x); + int yn = strlen(y); + int zn = strlen(z); + char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + strncpy(res, x, xn); + strncpy(res + xn, y, yn); + strncpy(res + xn + yn, z, zn); + res[xn + yn + zn] = '\0'; + return res; +} + +void set_env_prefix(char *env, char *sep, char *val) { + char *existing = getenv(env); + if (existing) val = concat3(val, sep, existing); + setenv(env, val, 1); + if (existing) free(val); +} + +void set_env_suffix(char *env, char *sep, char *val) { + char *existing = getenv(env); + if (existing) val = concat3(existing, sep, val); + setenv(env, val, 1); + if (existing) free(val); +} + +int main(int argc, char **argv) { + setenv("MESSAGE", "HELLO", 0); + set_env_prefix("PATH", ":", "/usr/bin/"); + set_env_suffix("PATH", ":", "/usr/local/bin/"); + putenv("MESSAGE2=WORLD"); + + char **argv_tmp = malloc(sizeof(*argv_tmp) * (4 + argc)); + argv_tmp[0] = argv[0]; + argv_tmp[1] = "-x"; + argv_tmp[2] = "-y"; + argv_tmp[3] = "-z"; + for (int i = 1; i < argc; ++i) { + argv_tmp[3 + i] = argv[i]; + } + argv_tmp[3 + argc] = NULL; + argv = argv_tmp; + + argv[0] = "my-wrapper"; + return execv("/path/to/executable", argv); +} diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix new file mode 100644 index 0000000000000..0b9f7e5abea2e --- /dev/null +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -0,0 +1,69 @@ +{ lib, stdenv, runCommand, makeBinaryWrapper }: + +let + makeGoldenTest = { name, filename }: stdenv.mkDerivation { + name = name; + dontUnpack = true; + buildInputs = [ makeBinaryWrapper ]; + phases = [ "installPhase" ]; + installPhase = '' + source ${./golden-test-utils.sh} + mkdir -p $out/bin + command=$(getInputCommand "${filename}") + eval "$command" > "$out/bin/result" + ''; + passthru = { + assertion = '' + source ${./golden-test-utils.sh} + contents=$(getOutputText "${filename}") + echo "$contents" | diff $out/bin/result - + ''; + }; + }; + tests = { + add-flags = makeGoldenTest { name = "add-flags"; filename = ./add-flags.c; }; + argv0 = makeGoldenTest { name = "argv0"; filename = ./argv0.c; }; + basic = makeGoldenTest { name = "basic"; filename = ./basic.c; }; + combination = makeGoldenTest { name = "combination"; filename = ./combination.c; }; + env = makeGoldenTest { name = "env"; filename = ./env.c; }; + prefix = makeGoldenTest { name = "prefix"; filename = ./prefix.c; }; + suffix = makeGoldenTest { name = "suffix"; filename = ./suffix.c; }; + }; +in runCommand "make-binary-wrapper-test" { + passthru = tests; + meta.platforms = lib.platforms.all; +} '' + validate() { + local name=$1 + local testout=$2 + local assertion=$3 + + echo -n "... $name: " >&2 + + local rc=0 + (out=$testout eval "$assertion") || rc=1 + + if [ "$rc" -eq 0 ]; then + echo "yes" >&2 + else + echo "no" >&2 + fi + + return "$rc" + } + + echo "checking whether makeCWrapper works properly... ">&2 + + fail= + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (_: test: '' + validate "${test.name}" "${test}" ${lib.escapeShellArg test.assertion} || fail=1 + '') tests)} + + if [ "$fail" ]; then + echo "failed" + exit 1 + else + echo "succeeded" + touch $out + fi +'' diff --git a/pkgs/test/make-binary-wrapper/env.c b/pkgs/test/make-binary-wrapper/env.c new file mode 100644 index 0000000000000..89f1f496b3497 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/env.c @@ -0,0 +1,17 @@ +// makeCWrapper /hello/world \ + --set PART1 HELLO \ + --set-default PART2 WORLD \ + --unset SOME_OTHER_VARIABLE \ + --set PART3 $'"!!\n"' + +#include +#include + +int main(int argc, char **argv) { + putenv("PART1=HELLO"); + setenv("PART2", "WORLD", 0); + unsetenv("SOME_OTHER_VARIABLE"); + putenv("PART3=\"!!\n\""); + argv[0] = "/hello/world"; + return execv("/hello/world", argv); +} \ No newline at end of file diff --git a/pkgs/test/make-binary-wrapper/golden-test-utils.sh b/pkgs/test/make-binary-wrapper/golden-test-utils.sh new file mode 100644 index 0000000000000..a0408b5a90896 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/golden-test-utils.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Split a generated C-file into the command used to generate it, +# and the outputted code itself. + +# This is useful because it allows input and output to be inside the same file + +# How it works: +# - The first line needs to start with '//' (and becomes the command). +# - Whitespace/padding between the comment and the generated code is ignored +# - To write a command using multiple lines, end each line with backslash (\) + +# Count the number of lines before the output text starts +# commandLineCount FILE +commandLineCount() { + local n state + n=0 + state="init" + while IFS="" read -r p || [ -n "$p" ]; do + case $state in + init) + if [[ $p =~ ^//.*\\$ ]]; then state="comment" + elif [[ $p =~ ^//.* ]]; then state="padding" + else break + fi + ;; + comment) [[ ! $p =~ ^.*\\$ ]] && state="padding";; + padding) [ -n "${p// }" ] && break;; + esac + n=$((n+1)) + done < "$1" + printf '%s' "$n" +} + +# getInputCommand FILE +getInputCommand() { + n=$(commandLineCount "$1") + head -n "$n" "$1" | awk '{ if (NR == 1) print substr($0, 3); else print $0 }' +} + +# getOutputText FILE +getOutputText() { + n=$(commandLineCount "$1") + sed "1,${n}d" "$1" +} diff --git a/pkgs/test/make-binary-wrapper/prefix.c b/pkgs/test/make-binary-wrapper/prefix.c new file mode 100644 index 0000000000000..914fd851bb7e7 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/prefix.c @@ -0,0 +1,33 @@ +// makeCWrapper /path/to/executable \ + --prefix PATH : /usr/bin/ \ + --prefix PATH : /usr/local/bin/ + +#include +#include +#include + +char *concat3(char *x, char *y, char *z) { + int xn = strlen(x); + int yn = strlen(y); + int zn = strlen(z); + char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + strncpy(res, x, xn); + strncpy(res + xn, y, yn); + strncpy(res + xn + yn, z, zn); + res[xn + yn + zn] = '\0'; + return res; +} + +void set_env_prefix(char *env, char *sep, char *val) { + char *existing = getenv(env); + if (existing) val = concat3(val, sep, existing); + setenv(env, val, 1); + if (existing) free(val); +} + +int main(int argc, char **argv) { + set_env_prefix("PATH", ":", "/usr/bin/"); + set_env_prefix("PATH", ":", "/usr/local/bin/"); + argv[0] = "/path/to/executable"; + return execv("/path/to/executable", argv); +} \ No newline at end of file diff --git a/pkgs/test/make-binary-wrapper/suffix.c b/pkgs/test/make-binary-wrapper/suffix.c new file mode 100644 index 0000000000000..865d76fe34e2a --- /dev/null +++ b/pkgs/test/make-binary-wrapper/suffix.c @@ -0,0 +1,33 @@ +// makeCWrapper /path/to/executable \ + --suffix PATH : /usr/bin/ \ + --suffix PATH : /usr/local/bin/ + +#include +#include +#include + +char *concat3(char *x, char *y, char *z) { + int xn = strlen(x); + int yn = strlen(y); + int zn = strlen(z); + char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + strncpy(res, x, xn); + strncpy(res + xn, y, yn); + strncpy(res + xn + yn, z, zn); + res[xn + yn + zn] = '\0'; + return res; +} + +void set_env_suffix(char *env, char *sep, char *val) { + char *existing = getenv(env); + if (existing) val = concat3(existing, sep, val); + setenv(env, val, 1); + if (existing) free(val); +} + +int main(int argc, char **argv) { + set_env_suffix("PATH", ":", "/usr/bin/"); + set_env_suffix("PATH", ":", "/usr/local/bin/"); + argv[0] = "/path/to/executable"; + return execv("/path/to/executable", argv); +} \ No newline at end of file From 4b833cc141172f88e563692f2458253212d1cf1a Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 4 Oct 2021 22:38:14 +0200 Subject: [PATCH 16/48] EditorConfig: Switch from tabs to spaces --- .../make-binary-wrapper/golden-test-utils.sh | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkgs/test/make-binary-wrapper/golden-test-utils.sh b/pkgs/test/make-binary-wrapper/golden-test-utils.sh index a0408b5a90896..80e880e11e485 100644 --- a/pkgs/test/make-binary-wrapper/golden-test-utils.sh +++ b/pkgs/test/make-binary-wrapper/golden-test-utils.sh @@ -12,23 +12,23 @@ # Count the number of lines before the output text starts # commandLineCount FILE commandLineCount() { - local n state - n=0 - state="init" - while IFS="" read -r p || [ -n "$p" ]; do - case $state in - init) - if [[ $p =~ ^//.*\\$ ]]; then state="comment" - elif [[ $p =~ ^//.* ]]; then state="padding" - else break - fi - ;; - comment) [[ ! $p =~ ^.*\\$ ]] && state="padding";; - padding) [ -n "${p// }" ] && break;; - esac - n=$((n+1)) - done < "$1" - printf '%s' "$n" + local n state + n=0 + state="init" + while IFS="" read -r p || [ -n "$p" ]; do + case $state in + init) + if [[ $p =~ ^//.*\\$ ]]; then state="comment" + elif [[ $p =~ ^//.* ]]; then state="padding" + else break + fi + ;; + comment) [[ ! $p =~ ^.*\\$ ]] && state="padding";; + padding) [ -n "${p// }" ] && break;; + esac + n=$((n+1)) + done < "$1" + printf '%s' "$n" } # getInputCommand FILE From a45c5db39128019ca0d37f3cca1cfa7450e9a894 Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Sat, 2 Oct 2021 01:19:29 +0300 Subject: [PATCH 17/48] makeBinaryWrapper: Assert $1 is executable --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 10 ++++++++++ pkgs/top-level/all-packages.nix | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index abc0e10631e80..3948db7e4eeab 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -1,3 +1,12 @@ +# Assert that FILE exists and is executable +# +# assertExecutable FILE +assertExecutable() { + local file="$1" + [[ -f "$file" && -x "$file" ]] || \ + die "Cannot wrap '$file' because it is not an executable file" +} + # Generate a binary executable wrapper for wrapping an executable. # The binary is compiled from generated C-code using gcc. # makeBinaryWrapper EXECUTABLE OUT_PATH ARGS @@ -39,6 +48,7 @@ makeCWrapper() { local argv0 n params cmd main flagsBefore flags executable params length local uses_prefix uses_suffix uses_concat3 executable=$(escapeStringLiteral "$1") + assertExecutable "$1" params=("$@") length=${#params[*]} for ((n = 1; n < length; n += 1)); do diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index cbb01ce2c5370..0e1dd457d8405 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -606,7 +606,9 @@ in makeWrapper = makeSetupHook { deps = [ dieHook ]; substitutions = { shell = targetPackages.runtimeShell; }; } ../build-support/setup-hooks/make-wrapper.sh; - makeBinaryWrapper = makeSetupHook { } ../build-support/setup-hooks/make-binary-wrapper.sh; + makeBinaryWrapper = makeSetupHook { + deps = [ dieHook ]; + } ../build-support/setup-hooks/make-binary-wrapper.sh; makeModulesClosure = { kernel, firmware, rootModules, allowMissing ? false }: callPackage ../build-support/kernel/modules-closure.nix { From c310cb0d941cfaaf265e895f41b97db19eb9c69d Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Sat, 2 Oct 2021 01:20:25 +0300 Subject: [PATCH 18/48] makeBinaryWrapper: add wrapProgramBinary (like wrapProgram) --- .../setup-hooks/make-binary-wrapper.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 3948db7e4eeab..c8a8aef36097e 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -30,6 +30,23 @@ makeBinaryWrapper() { makeDocumentedCWrapper "$1" "${@:3}" | gcc -Os -x c -o "$2" - } +# Syntax: wrapProgramBinary +wrapProgramBinary() { + local prog="$1" + local hidden + + assertExecutable "$prog" + + hidden="$(dirname "$prog")/.$(basename "$prog")"-wrapped + while [ -e "$hidden" ]; do + hidden="${hidden}_" + done + mv "$prog" "$hidden" + # Silence warning about unexpanded $0: + # shellcheck disable=SC2016 + makeBinaryWrapper "$hidden" "$prog" --argv0 '$0' "${@:2}" +} + # Generate source code for the wrapper in such a way that the wrapper source code # will still be readable even after compilation # makeDocumentedCWrapper EXECUTABLE ARGS From ba86a1916b483c50f85e32c0ac1547bae06f498f Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Sat, 2 Oct 2021 01:20:41 +0300 Subject: [PATCH 19/48] makeBinaryWrapper: Document --- doc/stdenv/stdenv.chapter.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index b23c50e836445..55e9ae48fb16b 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -774,7 +774,7 @@ The standard environment provides a number of useful functions. ### `makeWrapper` \ \ \ {#fun-makeWrapper} -Constructs a wrapper for a program with various possible arguments. For example: +A setup-hook that can be added to a derivation's inputs. It adds a `makeWrapper` bash function that constructs a wrapper for a program with various possible arguments. For example: ```bash # adds `FOOBAR=baz` to `$out/bin/foo`’s environment @@ -790,6 +790,14 @@ There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/bui `wrapProgram` is a convenience function you probably want to use most of the time. +### `makeBinaryWrapper` \ \ \ {#fun-makeBinaryWrapper} + +A setup-hook very similar to `makeWrapper`, only it creates a tiny compiled wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). The arguments it accepts are similar to those of `makeWrapper` and they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh`. + +Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less ` - by scrolling past the binary data you should be able to see the C code that generated the executable and there see the environment variables that were injected into the wrapper. + +Similarly to `wrapProgram`, the `makeBinaryWrapper` setup-hook provides a `wrapProgramBinary` with similar command line arguments. + ### `substitute` \ \ \ {#fun-substitute} Performs string substitution on the contents of \, writing the result to \. The substitutions in \ are of the following form: @@ -865,7 +873,13 @@ someVar=$(stripHash $name) Convenience function for `makeWrapper` that automatically creates a sane wrapper file. It takes all the same arguments as `makeWrapper`, except for `--argv0`. -It cannot be applied multiple times, since it will overwrite the wrapper file. +It cannot be applied multiple times, since it will overwrite the wrapper file and you will end up with double wrapping. + +### `wrapProgramBinary` \ \ {#fun-wrapProgramBinary} + +Convenience function for `makeWrapperBinary` that automatically creates a sane wrapper file. It takes all the same arguments as `makeBinaryWrapper`, except for `--argv0`. + +It cannot be applied multiple times, since it will overwrite the wrapper file and you will end up with double wrapping. ## Package setup hooks {#ssec-setup-hooks} From 1218b82bce915e2cde8820b13768ed00d7e84b53 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 19 Oct 2021 14:37:05 +0200 Subject: [PATCH 20/48] Move assertExecutable from makeCWrapper to makeBinaryWrapper to ensure that makeCWrapper is a pure function --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index c8a8aef36097e..bb9b5f453d196 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -27,6 +27,7 @@ assertExecutable() { # To troubleshoot a binary wrapper after you compiled it, # use the `strings` command or open the binary file in a text editor. makeBinaryWrapper() { + assertExecutable "$1" makeDocumentedCWrapper "$1" "${@:3}" | gcc -Os -x c -o "$2" - } @@ -65,7 +66,6 @@ makeCWrapper() { local argv0 n params cmd main flagsBefore flags executable params length local uses_prefix uses_suffix uses_concat3 executable=$(escapeStringLiteral "$1") - assertExecutable "$1" params=("$@") length=${#params[*]} for ((n = 1; n < length; n += 1)); do From 6517e5b10f901fb4e41fbf8a5a8b2456ae03c3bc Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Tue, 19 Oct 2021 17:33:02 +0300 Subject: [PATCH 21/48] Improve explenations for wrap*Program --- doc/stdenv/stdenv.chapter.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 55e9ae48fb16b..031880fbc687c 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -871,15 +871,15 @@ someVar=$(stripHash $name) ### `wrapProgram` \ \ {#fun-wrapProgram} -Convenience function for `makeWrapper` that automatically creates a sane wrapper file. It takes all the same arguments as `makeWrapper`, except for `--argv0`. +Convenience function for `makeWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--argv0`. -It cannot be applied multiple times, since it will overwrite the wrapper file and you will end up with double wrapping. +If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided. ### `wrapProgramBinary` \ \ {#fun-wrapProgramBinary} -Convenience function for `makeWrapperBinary` that automatically creates a sane wrapper file. It takes all the same arguments as `makeBinaryWrapper`, except for `--argv0`. +Convenience function for `makeBinaryWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeBinaryWrapper`, except for `--argv0`. -It cannot be applied multiple times, since it will overwrite the wrapper file and you will end up with double wrapping. +If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided. ## Package setup hooks {#ssec-setup-hooks} From 7cca19a46a1803320df1a8d43ca669dcf9e87e84 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 19 Oct 2021 09:25:24 -0700 Subject: [PATCH 22/48] Set strictDeps = true in makeGoldenTest Co-authored-by: Robert Hensing --- pkgs/test/make-binary-wrapper/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index 0b9f7e5abea2e..c30d430d3aba9 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -4,6 +4,7 @@ let makeGoldenTest = { name, filename }: stdenv.mkDerivation { name = name; dontUnpack = true; + strictDeps = true; buildInputs = [ makeBinaryWrapper ]; phases = [ "installPhase" ]; installPhase = '' From a95a7a22be0c0768df613c4c74981374259665d6 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 19 Oct 2021 18:35:42 +0200 Subject: [PATCH 23/48] Switch from buildInputs to nativeBuildInpuits in makeGoldenTest --- pkgs/test/make-binary-wrapper/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index c30d430d3aba9..72e7fb094a482 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -5,7 +5,7 @@ let name = name; dontUnpack = true; strictDeps = true; - buildInputs = [ makeBinaryWrapper ]; + nativeBuildInputs = [ makeBinaryWrapper ]; phases = [ "installPhase" ]; installPhase = '' source ${./golden-test-utils.sh} From eb048d8fe26e029d662ee9300ff87c616baf2076 Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Wed, 20 Oct 2021 08:58:17 +0300 Subject: [PATCH 24/48] Rephrase makeWrapper setup-hook --- doc/stdenv/stdenv.chapter.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 031880fbc687c..71caddd8aa4dd 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -774,7 +774,7 @@ The standard environment provides a number of useful functions. ### `makeWrapper` \ \ \ {#fun-makeWrapper} -A setup-hook that can be added to a derivation's inputs. It adds a `makeWrapper` bash function that constructs a wrapper for a program with various possible arguments. For example: +Constructs a wrapper for a program with various possible arguments. It is defined as part of a setup-hook by the same name, so to use it you have to add `makeWrapper` to your `nativeBuildInputs`. Here's a usage example: ```bash # adds `FOOBAR=baz` to `$out/bin/foo`’s environment @@ -792,7 +792,7 @@ There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/bui ### `makeBinaryWrapper` \ \ \ {#fun-makeBinaryWrapper} -A setup-hook very similar to `makeWrapper`, only it creates a tiny compiled wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). The arguments it accepts are similar to those of `makeWrapper` and they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh`. +A setup-hook very similar to `makeWrapper`, only it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). The arguments it accepts are similar to those of `makeWrapper` and they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh`. Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less ` - by scrolling past the binary data you should be able to see the C code that generated the executable and there see the environment variables that were injected into the wrapper. From 3a014be2f2230b3228e122b7c74fb7561b495195 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 9 Nov 2021 02:55:26 +0100 Subject: [PATCH 25/48] Assert that malloc does not return a NULL pointer for better error messages + to satisfy static analysis tools. --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 8 +++++++- pkgs/test/make-binary-wrapper/add-flags.c | 2 ++ pkgs/test/make-binary-wrapper/combination.c | 3 +++ pkgs/test/make-binary-wrapper/prefix.c | 2 ++ pkgs/test/make-binary-wrapper/suffix.c | 2 ++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index bb9b5f453d196..d7b888292d581 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -64,7 +64,7 @@ makeDocumentedCWrapper() { # ARGS: same as makeBinaryWrapper makeCWrapper() { local argv0 n params cmd main flagsBefore flags executable params length - local uses_prefix uses_suffix uses_concat3 + local uses_prefix uses_suffix uses_concat3 uses_assert executable=$(escapeStringLiteral "$1") params=("$@") length=${#params[*]} @@ -94,6 +94,7 @@ makeCWrapper() { main="$main $cmd"$'\n' uses_prefix=1 uses_concat3=1 + uses_assert=1 n=$((n + 3)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' ;; @@ -102,12 +103,14 @@ makeCWrapper() { main="$main $cmd"$'\n' uses_suffix=1 uses_concat3=1 + uses_assert=1 n=$((n + 3)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' ;; --add-flags) flags="${params[n + 1]}" flagsBefore="$flagsBefore $flags" + uses_assert=1 n=$((n + 1)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' ;; @@ -129,6 +132,7 @@ makeCWrapper() { printf '%s\n' "#include " printf '%s\n' "#include " [ -z "$uses_concat3" ] || printf '%s\n' "#include " + [ -z "$uses_assert" ] || printf '%s\n' "#include " [ -z "$uses_concat3" ] || printf '\n%s\n' "$(concat3Fn)" [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" @@ -146,6 +150,7 @@ addFlags() { result="$result ${var}[$((n+1))] = \"$flag\";"$'\n' done printf ' %s\n' "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));" + printf ' %s\n' "assert($var != NULL);" printf ' %s\n' "${var}[0] = argv[0];" printf '%s' "$result" printf ' %s\n' "for (int i = 1; i < argc; ++i) {" @@ -222,6 +227,7 @@ char *concat3(char *x, char *y, char *z) { int yn = strlen(y); int zn = strlen(z); char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + assert(res != NULL); strncpy(res, x, xn); strncpy(res + xn, y, yn); strncpy(res + xn + yn, z, zn); diff --git a/pkgs/test/make-binary-wrapper/add-flags.c b/pkgs/test/make-binary-wrapper/add-flags.c index 70d43e0bec081..fccd5aa9402a7 100644 --- a/pkgs/test/make-binary-wrapper/add-flags.c +++ b/pkgs/test/make-binary-wrapper/add-flags.c @@ -4,9 +4,11 @@ #include #include +#include int main(int argc, char **argv) { char **argv_tmp = malloc(sizeof(*argv_tmp) * (5 + argc)); + assert(argv_tmp != NULL); argv_tmp[0] = argv[0]; argv_tmp[1] = "-x"; argv_tmp[2] = "-y"; diff --git a/pkgs/test/make-binary-wrapper/combination.c b/pkgs/test/make-binary-wrapper/combination.c index 925fdf1ccfb4a..5e4e1168f4a02 100644 --- a/pkgs/test/make-binary-wrapper/combination.c +++ b/pkgs/test/make-binary-wrapper/combination.c @@ -9,12 +9,14 @@ #include #include #include +#include char *concat3(char *x, char *y, char *z) { int xn = strlen(x); int yn = strlen(y); int zn = strlen(z); char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + assert(res != NULL); strncpy(res, x, xn); strncpy(res + xn, y, yn); strncpy(res + xn + yn, z, zn); @@ -43,6 +45,7 @@ int main(int argc, char **argv) { putenv("MESSAGE2=WORLD"); char **argv_tmp = malloc(sizeof(*argv_tmp) * (4 + argc)); + assert(argv_tmp != NULL); argv_tmp[0] = argv[0]; argv_tmp[1] = "-x"; argv_tmp[2] = "-y"; diff --git a/pkgs/test/make-binary-wrapper/prefix.c b/pkgs/test/make-binary-wrapper/prefix.c index 914fd851bb7e7..fa333013cd02e 100644 --- a/pkgs/test/make-binary-wrapper/prefix.c +++ b/pkgs/test/make-binary-wrapper/prefix.c @@ -5,12 +5,14 @@ #include #include #include +#include char *concat3(char *x, char *y, char *z) { int xn = strlen(x); int yn = strlen(y); int zn = strlen(z); char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + assert(res != NULL); strncpy(res, x, xn); strncpy(res + xn, y, yn); strncpy(res + xn + yn, z, zn); diff --git a/pkgs/test/make-binary-wrapper/suffix.c b/pkgs/test/make-binary-wrapper/suffix.c index 865d76fe34e2a..a299f1fa0bd66 100644 --- a/pkgs/test/make-binary-wrapper/suffix.c +++ b/pkgs/test/make-binary-wrapper/suffix.c @@ -5,12 +5,14 @@ #include #include #include +#include char *concat3(char *x, char *y, char *z) { int xn = strlen(x); int yn = strlen(y); int zn = strlen(z); char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); + assert(res != NULL); strncpy(res, x, xn); strncpy(res + xn, y, yn); strncpy(res + xn + yn, z, zn); From 4e55d34535ae278b6130cba43edab6fd6c95e67d Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Wed, 1 Dec 2021 22:49:20 +0100 Subject: [PATCH 26/48] Add assertValidEnvName and check that variable name is valid during code generation. Add assert_success, and assert that setenv/unsetenv succeeds to crash if they don't --- .../setup-hooks/make-binary-wrapper.sh | 28 +++++++++++++++---- pkgs/test/make-binary-wrapper/combination.c | 9 ++++-- pkgs/test/make-binary-wrapper/default.nix | 1 + pkgs/test/make-binary-wrapper/env.c | 7 +++-- pkgs/test/make-binary-wrapper/invalid-env.c | 18 ++++++++++++ pkgs/test/make-binary-wrapper/prefix.c | 7 +++-- pkgs/test/make-binary-wrapper/suffix.c | 5 +++- 7 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 pkgs/test/make-binary-wrapper/invalid-env.c diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index d7b888292d581..90b9576740b15 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -64,7 +64,7 @@ makeDocumentedCWrapper() { # ARGS: same as makeBinaryWrapper makeCWrapper() { local argv0 n params cmd main flagsBefore flags executable params length - local uses_prefix uses_suffix uses_concat3 uses_assert + local uses_prefix uses_suffix uses_assert uses_assert_success uses_concat3 executable=$(escapeStringLiteral "$1") params=("$@") length=${#params[*]} @@ -80,12 +80,14 @@ makeCWrapper() { --set-default) cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' + uses_assert_success=1 n=$((n + 2)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' ;; --unset) cmd=$(unsetEnv "${params[n + 1]}") main="$main $cmd"$'\n' + uses_assert_success=1 n=$((n + 1)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' ;; @@ -94,6 +96,7 @@ makeCWrapper() { main="$main $cmd"$'\n' uses_prefix=1 uses_concat3=1 + uses_assert_success=1 uses_assert=1 n=$((n + 3)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' @@ -103,6 +106,7 @@ makeCWrapper() { main="$main $cmd"$'\n' uses_suffix=1 uses_concat3=1 + uses_assert_success=1 uses_assert=1 n=$((n + 3)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' @@ -133,6 +137,8 @@ makeCWrapper() { printf '%s\n' "#include " [ -z "$uses_concat3" ] || printf '%s\n' "#include " [ -z "$uses_assert" ] || printf '%s\n' "#include " + [ -z "$uses_assert_success" ] || printf '%s\n' "#include " + [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0)" [ -z "$uses_concat3" ] || printf '\n%s\n' "$(concat3Fn)" [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" @@ -167,6 +173,7 @@ setEnvPrefix() { sep=$(escapeStringLiteral "$2") val=$(escapeStringLiteral "$3") printf '%s' "set_env_prefix(\"$env\", \"$sep\", \"$val\");" + assertValidEnvName "$1" } # suffix ENV SEP VAL @@ -176,6 +183,7 @@ setEnvSuffix() { sep=$(escapeStringLiteral "$2") val=$(escapeStringLiteral "$3") printf '%s' "set_env_suffix(\"$env\", \"$sep\", \"$val\");" + assertValidEnvName "$1" } # setEnv KEY VALUE @@ -184,6 +192,7 @@ setEnv() { key=$(escapeStringLiteral "$1") value=$(escapeStringLiteral "$2") printf '%s' "putenv(\"$key=$value\");" + assertValidEnvName "$1" } # setDefaultEnv KEY VALUE @@ -191,14 +200,16 @@ setDefaultEnv() { local key value key=$(escapeStringLiteral "$1") value=$(escapeStringLiteral "$2") - printf '%s' "setenv(\"$key\", \"$value\", 0);" + printf '%s' "assert_success(setenv(\"$key\", \"$value\", 0));" + assertValidEnvName "$1" } # unsetEnv KEY unsetEnv() { local key key=$(escapeStringLiteral "$1") - printf '%s' "unsetenv(\"$key\");" + printf '%s' "assert_success(unsetenv(\"$key\"));" + assertValidEnvName "$1" } # Put the entire source code into const char* SOURCE_CODE to make it readable after compilation. @@ -220,6 +231,13 @@ escapeStringLiteral() { printf '%s' "$result" } +assertValidEnvName() { + case "$1" in + *=*) printf '\n%s\n' " #error Illegal environment variable name \`$1\` (cannot contain \`=\`)";; + "") printf '\n%s\n' " #error Environment variable name can't be empty.";; + esac +} + concat3Fn() { printf '%s' "\ char *concat3(char *x, char *y, char *z) { @@ -242,7 +260,7 @@ setEnvPrefixFn() { void set_env_prefix(char *env, char *sep, char *val) { char *existing = getenv(env); if (existing) val = concat3(val, sep, existing); - setenv(env, val, 1); + assert_success(setenv(env, val, 1)); if (existing) free(val); } " @@ -253,7 +271,7 @@ setEnvSuffixFn() { void set_env_suffix(char *env, char *sep, char *val) { char *existing = getenv(env); if (existing) val = concat3(existing, sep, val); - setenv(env, val, 1); + assert_success(setenv(env, val, 1)); if (existing) free(val); } " diff --git a/pkgs/test/make-binary-wrapper/combination.c b/pkgs/test/make-binary-wrapper/combination.c index 5e4e1168f4a02..a4082ac4aea05 100644 --- a/pkgs/test/make-binary-wrapper/combination.c +++ b/pkgs/test/make-binary-wrapper/combination.c @@ -10,6 +10,9 @@ #include #include #include +#include + +#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) char *concat3(char *x, char *y, char *z) { int xn = strlen(x); @@ -27,19 +30,19 @@ char *concat3(char *x, char *y, char *z) { void set_env_prefix(char *env, char *sep, char *val) { char *existing = getenv(env); if (existing) val = concat3(val, sep, existing); - setenv(env, val, 1); + assert_success(setenv(env, val, 1)); if (existing) free(val); } void set_env_suffix(char *env, char *sep, char *val) { char *existing = getenv(env); if (existing) val = concat3(existing, sep, val); - setenv(env, val, 1); + assert_success(setenv(env, val, 1)); if (existing) free(val); } int main(int argc, char **argv) { - setenv("MESSAGE", "HELLO", 0); + assert_success(setenv("MESSAGE", "HELLO", 0)); set_env_prefix("PATH", ":", "/usr/bin/"); set_env_suffix("PATH", ":", "/usr/local/bin/"); putenv("MESSAGE2=WORLD"); diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index 72e7fb094a482..1972b03da25ba 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -29,6 +29,7 @@ let env = makeGoldenTest { name = "env"; filename = ./env.c; }; prefix = makeGoldenTest { name = "prefix"; filename = ./prefix.c; }; suffix = makeGoldenTest { name = "suffix"; filename = ./suffix.c; }; + invalid-env = makeGoldenTest { name = "invalid-env"; filename = ./invalid-env.c; }; }; in runCommand "make-binary-wrapper-test" { passthru = tests; diff --git a/pkgs/test/make-binary-wrapper/env.c b/pkgs/test/make-binary-wrapper/env.c index 89f1f496b3497..a1b50b1c3630c 100644 --- a/pkgs/test/make-binary-wrapper/env.c +++ b/pkgs/test/make-binary-wrapper/env.c @@ -6,11 +6,14 @@ #include #include +#include + +#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) int main(int argc, char **argv) { putenv("PART1=HELLO"); - setenv("PART2", "WORLD", 0); - unsetenv("SOME_OTHER_VARIABLE"); + assert_success(setenv("PART2", "WORLD", 0)); + assert_success(unsetenv("SOME_OTHER_VARIABLE")); putenv("PART3=\"!!\n\""); argv[0] = "/hello/world"; return execv("/hello/world", argv); diff --git a/pkgs/test/make-binary-wrapper/invalid-env.c b/pkgs/test/make-binary-wrapper/invalid-env.c new file mode 100644 index 0000000000000..02f7cd01a5944 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/invalid-env.c @@ -0,0 +1,18 @@ +// makeCWrapper /bad/env/example \ + --set "=" "TEST1" \ + --set-default "" "TEST2" + +#include +#include +#include + +#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) + +int main(int argc, char **argv) { + putenv("==TEST1"); + #error Illegal environment variable name `=` (cannot contain `=`) + assert_success(setenv("", "TEST2", 0)); + #error Environment variable name can't be empty. + argv[0] = "/bad/env/example"; + return execv("/bad/env/example", argv); +} \ No newline at end of file diff --git a/pkgs/test/make-binary-wrapper/prefix.c b/pkgs/test/make-binary-wrapper/prefix.c index fa333013cd02e..8f7dd9b679c45 100644 --- a/pkgs/test/make-binary-wrapper/prefix.c +++ b/pkgs/test/make-binary-wrapper/prefix.c @@ -6,6 +6,9 @@ #include #include #include +#include + +#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) char *concat3(char *x, char *y, char *z) { int xn = strlen(x); @@ -23,7 +26,7 @@ char *concat3(char *x, char *y, char *z) { void set_env_prefix(char *env, char *sep, char *val) { char *existing = getenv(env); if (existing) val = concat3(val, sep, existing); - setenv(env, val, 1); + assert_success(setenv(env, val, 1)); if (existing) free(val); } @@ -32,4 +35,4 @@ int main(int argc, char **argv) { set_env_prefix("PATH", ":", "/usr/local/bin/"); argv[0] = "/path/to/executable"; return execv("/path/to/executable", argv); -} \ No newline at end of file +} diff --git a/pkgs/test/make-binary-wrapper/suffix.c b/pkgs/test/make-binary-wrapper/suffix.c index a299f1fa0bd66..17160465b41e1 100644 --- a/pkgs/test/make-binary-wrapper/suffix.c +++ b/pkgs/test/make-binary-wrapper/suffix.c @@ -6,6 +6,9 @@ #include #include #include +#include + +#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) char *concat3(char *x, char *y, char *z) { int xn = strlen(x); @@ -23,7 +26,7 @@ char *concat3(char *x, char *y, char *z) { void set_env_suffix(char *env, char *sep, char *val) { char *existing = getenv(env); if (existing) val = concat3(existing, sep, val); - setenv(env, val, 1); + assert_success(setenv(env, val, 1)); if (existing) free(val); } From 97d62a90f5ba28d6f16f40d20a679862394be8c2 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Wed, 1 Dec 2021 22:56:18 +0100 Subject: [PATCH 27/48] Switch from exit(1) to abort() in assert_success --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 2 +- pkgs/test/make-binary-wrapper/combination.c | 2 +- pkgs/test/make-binary-wrapper/env.c | 2 +- pkgs/test/make-binary-wrapper/invalid-env.c | 2 +- pkgs/test/make-binary-wrapper/prefix.c | 2 +- pkgs/test/make-binary-wrapper/suffix.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 90b9576740b15..29b7c2d845e14 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -138,7 +138,7 @@ makeCWrapper() { [ -z "$uses_concat3" ] || printf '%s\n' "#include " [ -z "$uses_assert" ] || printf '%s\n' "#include " [ -z "$uses_assert_success" ] || printf '%s\n' "#include " - [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0)" + [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)" [ -z "$uses_concat3" ] || printf '\n%s\n' "$(concat3Fn)" [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" diff --git a/pkgs/test/make-binary-wrapper/combination.c b/pkgs/test/make-binary-wrapper/combination.c index a4082ac4aea05..c476b24394d84 100644 --- a/pkgs/test/make-binary-wrapper/combination.c +++ b/pkgs/test/make-binary-wrapper/combination.c @@ -12,7 +12,7 @@ #include #include -#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) +#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) char *concat3(char *x, char *y, char *z) { int xn = strlen(x); diff --git a/pkgs/test/make-binary-wrapper/env.c b/pkgs/test/make-binary-wrapper/env.c index a1b50b1c3630c..fa2e6fc4dd294 100644 --- a/pkgs/test/make-binary-wrapper/env.c +++ b/pkgs/test/make-binary-wrapper/env.c @@ -8,7 +8,7 @@ #include #include -#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) +#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) int main(int argc, char **argv) { putenv("PART1=HELLO"); diff --git a/pkgs/test/make-binary-wrapper/invalid-env.c b/pkgs/test/make-binary-wrapper/invalid-env.c index 02f7cd01a5944..bad647bd13a28 100644 --- a/pkgs/test/make-binary-wrapper/invalid-env.c +++ b/pkgs/test/make-binary-wrapper/invalid-env.c @@ -6,7 +6,7 @@ #include #include -#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) +#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) int main(int argc, char **argv) { putenv("==TEST1"); diff --git a/pkgs/test/make-binary-wrapper/prefix.c b/pkgs/test/make-binary-wrapper/prefix.c index 8f7dd9b679c45..8ca0ad94a6d70 100644 --- a/pkgs/test/make-binary-wrapper/prefix.c +++ b/pkgs/test/make-binary-wrapper/prefix.c @@ -8,7 +8,7 @@ #include #include -#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) +#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) char *concat3(char *x, char *y, char *z) { int xn = strlen(x); diff --git a/pkgs/test/make-binary-wrapper/suffix.c b/pkgs/test/make-binary-wrapper/suffix.c index 17160465b41e1..31059c86e7a8e 100644 --- a/pkgs/test/make-binary-wrapper/suffix.c +++ b/pkgs/test/make-binary-wrapper/suffix.c @@ -8,7 +8,7 @@ #include #include -#define assert_success(e) do { if ((e) < 0) { perror(#e); exit(1); } } while (0) +#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) char *concat3(char *x, char *y, char *z) { int xn = strlen(x); From 3997e9de6794e3227aa0c852647abda42d8a8fe6 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Wed, 1 Dec 2021 23:07:30 +0100 Subject: [PATCH 28/48] Switch from malloc to calloc in addFlags --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 2 +- pkgs/test/make-binary-wrapper/add-flags.c | 2 +- pkgs/test/make-binary-wrapper/combination.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 29b7c2d845e14..659a0293703ec 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -155,7 +155,7 @@ addFlags() { flag=$(escapeStringLiteral "${flags[$n]}") result="$result ${var}[$((n+1))] = \"$flag\";"$'\n' done - printf ' %s\n' "char **$var = malloc(sizeof(*$var) * ($((n+1)) + argc));" + printf ' %s\n' "char **$var = calloc($((n+1)) + argc, sizeof(*$var));" printf ' %s\n' "assert($var != NULL);" printf ' %s\n' "${var}[0] = argv[0];" printf '%s' "$result" diff --git a/pkgs/test/make-binary-wrapper/add-flags.c b/pkgs/test/make-binary-wrapper/add-flags.c index fccd5aa9402a7..20d3b7508c05c 100644 --- a/pkgs/test/make-binary-wrapper/add-flags.c +++ b/pkgs/test/make-binary-wrapper/add-flags.c @@ -7,7 +7,7 @@ #include int main(int argc, char **argv) { - char **argv_tmp = malloc(sizeof(*argv_tmp) * (5 + argc)); + char **argv_tmp = calloc(5 + argc, sizeof(*argv_tmp)); assert(argv_tmp != NULL); argv_tmp[0] = argv[0]; argv_tmp[1] = "-x"; diff --git a/pkgs/test/make-binary-wrapper/combination.c b/pkgs/test/make-binary-wrapper/combination.c index c476b24394d84..4ab44281ef143 100644 --- a/pkgs/test/make-binary-wrapper/combination.c +++ b/pkgs/test/make-binary-wrapper/combination.c @@ -47,7 +47,7 @@ int main(int argc, char **argv) { set_env_suffix("PATH", ":", "/usr/local/bin/"); putenv("MESSAGE2=WORLD"); - char **argv_tmp = malloc(sizeof(*argv_tmp) * (4 + argc)); + char **argv_tmp = calloc(4 + argc, sizeof(*argv_tmp)); assert(argv_tmp != NULL); argv_tmp[0] = argv[0]; argv_tmp[1] = "-x"; From a1e62262bc5b1a7a3f528b48369e88846ba5cd3f Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Wed, 1 Dec 2021 23:27:26 +0100 Subject: [PATCH 29/48] Replace concat3 with asprintf in set_env_prefix and set_env_suffix. --- .../setup-hooks/make-binary-wrapper.sh | 64 +++++++++---------- pkgs/test/make-binary-wrapper/combination.c | 41 ++++++------ pkgs/test/make-binary-wrapper/prefix.c | 28 +++----- pkgs/test/make-binary-wrapper/suffix.c | 30 ++++----- 4 files changed, 70 insertions(+), 93 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 659a0293703ec..f507f8c70cf8f 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -64,7 +64,7 @@ makeDocumentedCWrapper() { # ARGS: same as makeBinaryWrapper makeCWrapper() { local argv0 n params cmd main flagsBefore flags executable params length - local uses_prefix uses_suffix uses_assert uses_assert_success uses_concat3 + local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf executable=$(escapeStringLiteral "$1") params=("$@") length=${#params[*]} @@ -80,6 +80,7 @@ makeCWrapper() { --set-default) cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") main="$main $cmd"$'\n' + uses_stdio=1 uses_assert_success=1 n=$((n + 2)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' @@ -87,6 +88,7 @@ makeCWrapper() { --unset) cmd=$(unsetEnv "${params[n + 1]}") main="$main $cmd"$'\n' + uses_stdio=1 uses_assert_success=1 n=$((n + 1)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' @@ -95,7 +97,8 @@ makeCWrapper() { cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") main="$main $cmd"$'\n' uses_prefix=1 - uses_concat3=1 + uses_asprintf=1 + uses_stdio=1 uses_assert_success=1 uses_assert=1 n=$((n + 3)) @@ -105,7 +108,8 @@ makeCWrapper() { cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") main="$main $cmd"$'\n' uses_suffix=1 - uses_concat3=1 + uses_asprintf=1 + uses_stdio=1 uses_assert_success=1 uses_assert=1 n=$((n + 3)) @@ -133,15 +137,14 @@ makeCWrapper() { main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' main="$main return execv(\"${executable}\", argv);"$'\n' + [ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */" printf '%s\n' "#include " printf '%s\n' "#include " - [ -z "$uses_concat3" ] || printf '%s\n' "#include " - [ -z "$uses_assert" ] || printf '%s\n' "#include " - [ -z "$uses_assert_success" ] || printf '%s\n' "#include " + [ -z "$uses_assert" ] || printf '%s\n' "#include " + [ -z "$uses_stdio" ] || printf '%s\n' "#include " [ -z "$uses_assert_success" ] || printf '\n%s\n' "#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)" - [ -z "$uses_concat3" ] || printf '\n%s\n' "$(concat3Fn)" - [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" - [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" + [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" + [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" printf '\n%s' "int main(int argc, char **argv) {" printf '\n%s' "$main" printf '%s\n' "}" @@ -238,41 +241,34 @@ assertValidEnvName() { esac } -concat3Fn() { - printf '%s' "\ -char *concat3(char *x, char *y, char *z) { - int xn = strlen(x); - int yn = strlen(y); - int zn = strlen(z); - char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); - assert(res != NULL); - strncpy(res, x, xn); - strncpy(res + xn, y, yn); - strncpy(res + xn + yn, z, zn); - res[xn + yn + zn] = '\0'; - return res; -} -" -} - setEnvPrefixFn() { printf '%s' "\ -void set_env_prefix(char *env, char *sep, char *val) { +void set_env_prefix(char *env, char *sep, char *prefix) { char *existing = getenv(env); - if (existing) val = concat3(val, sep, existing); - assert_success(setenv(env, val, 1)); - if (existing) free(val); + if (existing) { + char *val; + assert_success(asprintf(&val, \"%s%s%s\", prefix, sep, existing)); + assert_success(setenv(env, val, 1)); + free(val); + } else { + assert_success(setenv(env, prefix, 1)); + } } " } setEnvSuffixFn() { printf '%s' "\ -void set_env_suffix(char *env, char *sep, char *val) { +void set_env_suffix(char *env, char *sep, char *suffix) { char *existing = getenv(env); - if (existing) val = concat3(existing, sep, val); - assert_success(setenv(env, val, 1)); - if (existing) free(val); + if (existing) { + char *val; + assert_success(asprintf(&val, \"%s%s%s\", existing, sep, suffix)); + assert_success(setenv(env, val, 1)); + free(val); + } else { + assert_success(setenv(env, suffix, 1)); + } } " } diff --git a/pkgs/test/make-binary-wrapper/combination.c b/pkgs/test/make-binary-wrapper/combination.c index 4ab44281ef143..bb35d0d99f314 100644 --- a/pkgs/test/make-binary-wrapper/combination.c +++ b/pkgs/test/make-binary-wrapper/combination.c @@ -6,39 +6,36 @@ --add-flags "-x -y -z" \ --set MESSAGE2 WORLD +#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include -#include #include #include #define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) -char *concat3(char *x, char *y, char *z) { - int xn = strlen(x); - int yn = strlen(y); - int zn = strlen(z); - char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); - assert(res != NULL); - strncpy(res, x, xn); - strncpy(res + xn, y, yn); - strncpy(res + xn + yn, z, zn); - res[xn + yn + zn] = '\0'; - return res; -} - -void set_env_prefix(char *env, char *sep, char *val) { +void set_env_prefix(char *env, char *sep, char *prefix) { char *existing = getenv(env); - if (existing) val = concat3(val, sep, existing); - assert_success(setenv(env, val, 1)); - if (existing) free(val); + if (existing) { + char *val; + assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing)); + assert_success(setenv(env, val, 1)); + free(val); + } else { + assert_success(setenv(env, prefix, 1)); + } } -void set_env_suffix(char *env, char *sep, char *val) { +void set_env_suffix(char *env, char *sep, char *suffix) { char *existing = getenv(env); - if (existing) val = concat3(existing, sep, val); - assert_success(setenv(env, val, 1)); - if (existing) free(val); + if (existing) { + char *val; + assert_success(asprintf(&val, "%s%s%s", existing, sep, suffix)); + assert_success(setenv(env, val, 1)); + free(val); + } else { + assert_success(setenv(env, suffix, 1)); + } } int main(int argc, char **argv) { diff --git a/pkgs/test/make-binary-wrapper/prefix.c b/pkgs/test/make-binary-wrapper/prefix.c index 8ca0ad94a6d70..de431168bffc0 100644 --- a/pkgs/test/make-binary-wrapper/prefix.c +++ b/pkgs/test/make-binary-wrapper/prefix.c @@ -2,32 +2,24 @@ --prefix PATH : /usr/bin/ \ --prefix PATH : /usr/local/bin/ +#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include -#include #include #include #define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) -char *concat3(char *x, char *y, char *z) { - int xn = strlen(x); - int yn = strlen(y); - int zn = strlen(z); - char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); - assert(res != NULL); - strncpy(res, x, xn); - strncpy(res + xn, y, yn); - strncpy(res + xn + yn, z, zn); - res[xn + yn + zn] = '\0'; - return res; -} - -void set_env_prefix(char *env, char *sep, char *val) { +void set_env_prefix(char *env, char *sep, char *prefix) { char *existing = getenv(env); - if (existing) val = concat3(val, sep, existing); - assert_success(setenv(env, val, 1)); - if (existing) free(val); + if (existing) { + char *val; + assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing)); + assert_success(setenv(env, val, 1)); + free(val); + } else { + assert_success(setenv(env, prefix, 1)); + } } int main(int argc, char **argv) { diff --git a/pkgs/test/make-binary-wrapper/suffix.c b/pkgs/test/make-binary-wrapper/suffix.c index 31059c86e7a8e..3fcb338a61045 100644 --- a/pkgs/test/make-binary-wrapper/suffix.c +++ b/pkgs/test/make-binary-wrapper/suffix.c @@ -2,32 +2,24 @@ --suffix PATH : /usr/bin/ \ --suffix PATH : /usr/local/bin/ +#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include -#include #include #include #define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) -char *concat3(char *x, char *y, char *z) { - int xn = strlen(x); - int yn = strlen(y); - int zn = strlen(z); - char *res = malloc(sizeof(*res)*(xn + yn + zn + 1)); - assert(res != NULL); - strncpy(res, x, xn); - strncpy(res + xn, y, yn); - strncpy(res + xn + yn, z, zn); - res[xn + yn + zn] = '\0'; - return res; -} - -void set_env_suffix(char *env, char *sep, char *val) { +void set_env_suffix(char *env, char *sep, char *suffix) { char *existing = getenv(env); - if (existing) val = concat3(existing, sep, val); - assert_success(setenv(env, val, 1)); - if (existing) free(val); + if (existing) { + char *val; + assert_success(asprintf(&val, "%s%s%s", existing, sep, suffix)); + assert_success(setenv(env, val, 1)); + free(val); + } else { + assert_success(setenv(env, suffix, 1)); + } } int main(int argc, char **argv) { @@ -35,4 +27,4 @@ int main(int argc, char **argv) { set_env_suffix("PATH", ":", "/usr/local/bin/"); argv[0] = "/path/to/executable"; return execv("/path/to/executable", argv); -} \ No newline at end of file +} From e3c94f3d6b23a31b9a1b9dd6ba492b17cd23e57a Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 2 Dec 2021 02:07:17 +0100 Subject: [PATCH 30/48] Use cc instead of gcc in makeBinaryWrapper --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index f507f8c70cf8f..2a05dfaf4e69d 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -28,7 +28,7 @@ assertExecutable() { # use the `strings` command or open the binary file in a text editor. makeBinaryWrapper() { assertExecutable "$1" - makeDocumentedCWrapper "$1" "${@:3}" | gcc -Os -x c -o "$2" - + makeDocumentedCWrapper "$1" "${@:3}" | cc -Os -x c -o "$2" - } # Syntax: wrapProgramBinary From a47286f0a048f22d7f40bd1fc912914962d05e91 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 2 Dec 2021 02:29:00 +0100 Subject: [PATCH 31/48] Add argument --inherit-argv0 to replace use case `--argv0 '$0'`. Fix wrapProgramBinary by using this new argument --- .../setup-hooks/make-binary-wrapper.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 2a05dfaf4e69d..7642a23986420 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -14,6 +14,8 @@ assertExecutable() { # ARGS: # --argv0 NAME : set name of executed process to NAME # (otherwise it’s called …-wrapped) +# --inherit-argv0 : the executable inherits argv0 from the wrapper. +# (use instead of --argv0 '$0') # --set VAR VAL : add VAR with value VAL to the executable’s # environment # --set-default VAR VAL : like --set, but only adds VAR if not already set in @@ -45,7 +47,7 @@ wrapProgramBinary() { mv "$prog" "$hidden" # Silence warning about unexpanded $0: # shellcheck disable=SC2016 - makeBinaryWrapper "$hidden" "$prog" --argv0 '$0' "${@:2}" + makeBinaryWrapper "$hidden" "$prog" --inherit-argv0 "${@:2}" } # Generate source code for the wrapper in such a way that the wrapper source code @@ -63,7 +65,7 @@ makeDocumentedCWrapper() { # makeCWrapper EXECUTABLE ARGS # ARGS: same as makeBinaryWrapper makeCWrapper() { - local argv0 n params cmd main flagsBefore flags executable params length + local argv0 inherit_argv0 n params cmd main flagsBefore flags executable params length local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf executable=$(escapeStringLiteral "$1") params=("$@") @@ -124,9 +126,14 @@ makeCWrapper() { ;; --argv0) argv0=$(escapeStringLiteral "${params[n + 1]}") + inherit_argv0= n=$((n + 1)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' ;; + --inherit-argv0) + # Whichever comes last of --argv0 and --inherit-argv0 wins + inherit_argv0=1 + ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message main="$main #error makeCWrapper: Uknown argument ${p}"$'\n' ;; @@ -134,7 +141,7 @@ makeCWrapper() { done # shellcheck disable=SC2086 [ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n' - main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' + [ -z "$inherit_argv0" ] && main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' main="$main return execv(\"${executable}\", argv);"$'\n' [ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */" From 64da82731d44371a88625af875848482b3b436bc Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 2 Dec 2021 03:39:25 +0100 Subject: [PATCH 32/48] Add new argument: --chdir DIR (alternative to --run "cd DIR" in makeWrapper) --- .../setup-hooks/make-binary-wrapper.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 7642a23986420..fa02d59ef46a5 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -21,6 +21,7 @@ assertExecutable() { # --set-default VAR VAL : like --set, but only adds VAR if not already set in # the environment # --unset VAR : remove VAR from the environment +# --chdir DIR : change working directory (use instead of --run "cd DIR") # --add-flags FLAGS : add FLAGS to invocation of executable # --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP @@ -117,6 +118,14 @@ makeCWrapper() { n=$((n + 3)) [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' ;; + --chdir) + cmd=$(changeDir "${params[n + 1]}") + main="$main $cmd"$'\n' + uses_stdio=1 + uses_assert_success=1 + n=$((n + 1)) + [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + ;; --add-flags) flags="${params[n + 1]}" flagsBefore="$flagsBefore $flags" @@ -176,6 +185,13 @@ addFlags() { printf ' %s\n' "argv = $var;" } +# chdir DIR +changeDir() { + local dir + dir=$(escapeStringLiteral "$1") + printf '%s' "assert_success(chdir(\"$dir\"));" +} + # prefix ENV SEP VAL setEnvPrefix() { local env sep val From d8375fbccb2d8f7b8279374fa84645494e1a0942 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 2 Dec 2021 04:03:36 +0100 Subject: [PATCH 33/48] Add tests for `--inherit-argv0` and `--chdir DIR` --- pkgs/test/make-binary-wrapper/chdir.c | 14 ++++++++++++++ pkgs/test/make-binary-wrapper/default.nix | 10 ++++++---- pkgs/test/make-binary-wrapper/inherit-argv0.c | 9 +++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 pkgs/test/make-binary-wrapper/chdir.c create mode 100644 pkgs/test/make-binary-wrapper/inherit-argv0.c diff --git a/pkgs/test/make-binary-wrapper/chdir.c b/pkgs/test/make-binary-wrapper/chdir.c new file mode 100644 index 0000000000000..ff1f91a03babd --- /dev/null +++ b/pkgs/test/make-binary-wrapper/chdir.c @@ -0,0 +1,14 @@ +// makeCWrapper /path/to/executable \ + --chdir /usr/local/bin + +#include +#include +#include + +#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) + +int main(int argc, char **argv) { + assert_success(chdir("/usr/local/bin")); + argv[0] = "/path/to/executable"; + return execv("/path/to/executable", argv); +} \ No newline at end of file diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index 1972b03da25ba..eddab15fd31d9 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -22,14 +22,16 @@ let }; }; tests = { - add-flags = makeGoldenTest { name = "add-flags"; filename = ./add-flags.c; }; - argv0 = makeGoldenTest { name = "argv0"; filename = ./argv0.c; }; basic = makeGoldenTest { name = "basic"; filename = ./basic.c; }; - combination = makeGoldenTest { name = "combination"; filename = ./combination.c; }; + argv0 = makeGoldenTest { name = "argv0"; filename = ./argv0.c; }; + inherit_argv0 = makeGoldenTest { name = "inherit-argv0"; filename = ./inherit-argv0.c; }; env = makeGoldenTest { name = "env"; filename = ./env.c; }; + invalid_env = makeGoldenTest { name = "invalid-env"; filename = ./invalid-env.c; }; prefix = makeGoldenTest { name = "prefix"; filename = ./prefix.c; }; suffix = makeGoldenTest { name = "suffix"; filename = ./suffix.c; }; - invalid-env = makeGoldenTest { name = "invalid-env"; filename = ./invalid-env.c; }; + add_flags = makeGoldenTest { name = "add-flags"; filename = ./add-flags.c; }; + chdir = makeGoldenTest { name = "chdir"; filename = ./chdir.c; }; + combination = makeGoldenTest { name = "combination"; filename = ./combination.c; }; }; in runCommand "make-binary-wrapper-test" { passthru = tests; diff --git a/pkgs/test/make-binary-wrapper/inherit-argv0.c b/pkgs/test/make-binary-wrapper/inherit-argv0.c new file mode 100644 index 0000000000000..71e12d9b024a5 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/inherit-argv0.c @@ -0,0 +1,9 @@ +// makeCWrapper /path/to/executable \ + --inherit-argv0 + +#include +#include + +int main(int argc, char **argv) { + return execv("/path/to/executable", argv); +} \ No newline at end of file From 2b103ab8a131e54b750d90ec0cc9ff86741a6c4b Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Thu, 2 Dec 2021 10:43:47 +0200 Subject: [PATCH 34/48] Remove TODO in documentation --- doc/stdenv/stdenv.chapter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 71caddd8aa4dd..91e59bbce48ed 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -792,7 +792,7 @@ There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/bui ### `makeBinaryWrapper` \ \ \ {#fun-makeBinaryWrapper} -A setup-hook very similar to `makeWrapper`, only it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). The arguments it accepts are similar to those of `makeWrapper` and they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh`. +A setup-hook very similar to `makeWrapper`, only it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). The arguments it accepts are similar to those of `makeWrapper` and they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh`. Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less ` - by scrolling past the binary data you should be able to see the C code that generated the executable and there see the environment variables that were injected into the wrapper. From 2b5a2d4a8e8e41a283767088443845913c3ab340 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 7 Dec 2021 01:50:38 +0100 Subject: [PATCH 35/48] Switch to embedding input arguments instead of generated C code in binary. --- .../setup-hooks/make-binary-wrapper.sh | 95 ++++++++++++++++--- 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index fa02d59ef46a5..5080d0065aac3 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -51,14 +51,14 @@ wrapProgramBinary() { makeBinaryWrapper "$hidden" "$prog" --inherit-argv0 "${@:2}" } -# Generate source code for the wrapper in such a way that the wrapper source code +# Generate source code for the wrapper in such a way that the wrapper inputs # will still be readable even after compilation # makeDocumentedCWrapper EXECUTABLE ARGS # ARGS: same as makeBinaryWrapper makeDocumentedCWrapper() { local src docs src=$(makeCWrapper "$@") - docs=$(documentationString "$src") + docs=$(docstring "$@") printf '%s\n\n' "$src" printf '%s\n' "$docs" } @@ -66,7 +66,7 @@ makeDocumentedCWrapper() { # makeCWrapper EXECUTABLE ARGS # ARGS: same as makeBinaryWrapper makeCWrapper() { - local argv0 inherit_argv0 n params cmd main flagsBefore flags executable params length + local argv0 inherit_argv0 n params cmd main flagsBefore flags executable length local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf executable=$(escapeStringLiteral "$1") params=("$@") @@ -238,14 +238,6 @@ unsetEnv() { assertValidEnvName "$1" } -# Put the entire source code into const char* SOURCE_CODE to make it readable after compilation. -# documentationString SOURCE_CODE -documentationString() { - local docs - docs=$(escapeStringLiteral $'\n----------\n// This binary wrapper was compiled from the following generated C-code:\n'"$1"$'\n----------\n') - printf '%s' "const char * SOURCE_CODE = \"$docs\";" -} - # Makes it safe to insert STRING within quotes in a C String Literal. # escapeStringLiteral STRING escapeStringLiteral() { @@ -295,3 +287,84 @@ void set_env_suffix(char *env, char *sep, char *suffix) { } " } + +# Embed a C string which shows up as readable text in the compiled binary wrapper +# documentationString ARGS +docstring() { + printf '%s' "const char * DOCSTRING = \"$(escapeStringLiteral " + + +# ------------------------------------------------------------------------------------ +# The C-code for this binary wrapper has been generated using the following command: + + +makeCWrapper $(formatArgs "$@") + + +# (Use \`nix-shell -p makeBinaryWrapper\` to get access to makeCWrapper in your shell) +# ------------------------------------------------------------------------------------ + + +")\";" +} + +# formatArgs EXECUTABLE ARGS +formatArgs() { + printf '%s' "$1" + shift + while [ $# -gt 0 ]; do + case "$1" in + --set) + formatArgsLine 2 "$@" + shift 2 + ;; + --set-default) + formatArgsLine 2 "$@" + shift 2 + ;; + --unset) + formatArgsLine 1 "$@" + shift 1 + ;; + --prefix) + formatArgsLine 3 "$@" + shift 3 + ;; + --suffix) + formatArgsLine 3 "$@" + shift 3 + ;; + --chdir) + formatArgsLine 1 "$@" + shift 1 + ;; + --add-flags) + formatArgsLine 1 "$@" + shift 1 + ;; + --argv0) + formatArgsLine 1 "$@" + shift 1 + ;; + --inherit-argv0) + formatArgsLine 0 "$@" + ;; + esac + shift + done + printf '%s\n' "" +} + +# formatArgsLine ARG_COUNT ARGS +formatArgsLine() { + local ARG_COUNT LENGTH + ARG_COUNT=$1 + LENGTH=$# + shift + printf '%s' $' \\\n '"$1" + shift + while [ "$ARG_COUNT" -gt $((LENGTH - $# - 2)) ]; do + printf ' %s' "${1@Q}" + shift + done +} From 7cf1aa102a513ad7df9c6e6c0e57254b2f44efaf Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 7 Dec 2021 17:42:54 +0100 Subject: [PATCH 36/48] Separate out indentation responsibility to indent4 in makeCWrapper using awk. Generated code no longer needs to worry about its own indent level in the output. --- .../setup-hooks/make-binary-wrapper.sh | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 5080d0065aac3..ec60f9ba7223f 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -76,82 +76,82 @@ makeCWrapper() { case $p in --set) cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' n=$((n + 2)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 2 arguments"$'\n' ;; --set-default) cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_stdio=1 uses_assert_success=1 n=$((n + 2)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 2 arguments"$'\n' ;; --unset) cmd=$(unsetEnv "${params[n + 1]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_stdio=1 uses_assert_success=1 n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --prefix) cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_prefix=1 uses_asprintf=1 uses_stdio=1 uses_assert_success=1 uses_assert=1 n=$((n + 3)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 3 arguments"$'\n' ;; --suffix) cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_suffix=1 uses_asprintf=1 uses_stdio=1 uses_assert_success=1 uses_assert=1 n=$((n + 3)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 3 arguments"$'\n' ;; --chdir) cmd=$(changeDir "${params[n + 1]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_stdio=1 uses_assert_success=1 n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --add-flags) flags="${params[n + 1]}" flagsBefore="$flagsBefore $flags" uses_assert=1 n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --argv0) argv0=$(escapeStringLiteral "${params[n + 1]}") inherit_argv0= n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --inherit-argv0) # Whichever comes last of --argv0 and --inherit-argv0 wins inherit_argv0=1 ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message - main="$main #error makeCWrapper: Uknown argument ${p}"$'\n' + main="$main#error makeCWrapper: Uknown argument ${p}"$'\n' ;; esac done # shellcheck disable=SC2086 [ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n' - [ -z "$inherit_argv0" ] && main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' - main="$main return execv(\"${executable}\", argv);"$'\n' + [ -z "$inherit_argv0" ] && main="${main}argv[0] = \"${argv0:-${executable}}\";"$'\n' + main="${main}return execv(\"${executable}\", argv);"$'\n' [ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */" printf '%s\n' "#include " @@ -162,8 +162,8 @@ makeCWrapper() { [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" printf '\n%s' "int main(int argc, char **argv) {" - printf '\n%s' "$main" - printf '%s\n' "}" + printf '\n%s' "$(indent4 "$main")" + printf '\n%s\n' "}" } addFlags() { @@ -172,17 +172,17 @@ addFlags() { flags=("$@") for ((n = 0; n < ${#flags[*]}; n += 1)); do flag=$(escapeStringLiteral "${flags[$n]}") - result="$result ${var}[$((n+1))] = \"$flag\";"$'\n' + result="$result${var}[$((n+1))] = \"$flag\";"$'\n' done - printf ' %s\n' "char **$var = calloc($((n+1)) + argc, sizeof(*$var));" - printf ' %s\n' "assert($var != NULL);" - printf ' %s\n' "${var}[0] = argv[0];" + printf '%s\n' "char **$var = calloc($((n+1)) + argc, sizeof(*$var));" + printf '%s\n' "assert($var != NULL);" + printf '%s\n' "${var}[0] = argv[0];" printf '%s' "$result" - printf ' %s\n' "for (int i = 1; i < argc; ++i) {" - printf ' %s\n' " ${var}[$n + i] = argv[i];" - printf ' %s\n' "}" - printf ' %s\n' "${var}[$n + argc] = NULL;" - printf ' %s\n' "argv = $var;" + printf '%s\n' "for (int i = 1; i < argc; ++i) {" + printf '%s\n' " ${var}[$n + i] = argv[i];" + printf '%s\n' "}" + printf '%s\n' "${var}[$n + argc] = NULL;" + printf '%s\n' "argv = $var;" } # chdir DIR @@ -249,10 +249,16 @@ escapeStringLiteral() { printf '%s' "$result" } +# Indents every non-empty line by 4 spaces. To avoid trailing whitespace, we don't indent empty lines +# indent4 TEXT_BLOCK +indent4() { + printf '%s' "$1" | awk '{ if ($0 != "") { print " "$0 } else { print $0 }}' +} + assertValidEnvName() { case "$1" in - *=*) printf '\n%s\n' " #error Illegal environment variable name \`$1\` (cannot contain \`=\`)";; - "") printf '\n%s\n' " #error Environment variable name can't be empty.";; + *=*) printf '\n%s\n' "#error Illegal environment variable name \`$1\` (cannot contain \`=\`)";; + "") printf '\n%s\n' "#error Environment variable name can't be empty.";; esac } From f3b16a6b5d9d027f2a5d7f732378b90495c8bcdf Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Wed, 8 Dec 2021 10:25:23 +0000 Subject: [PATCH 37/48] Fix typo in make-binary-wrapper --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index fa02d59ef46a5..ba9efa05191a3 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -144,7 +144,7 @@ makeCWrapper() { inherit_argv0=1 ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message - main="$main #error makeCWrapper: Uknown argument ${p}"$'\n' + main="$main #error makeCWrapper: Unknown argument ${p}"$'\n' ;; esac done From 32d566e1b9d9ff55ec5b013d5420419649780e0d Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Wed, 8 Dec 2021 18:59:38 +0200 Subject: [PATCH 38/48] wrapProgramBinary -> binaryWrapProgram --- doc/stdenv/stdenv.chapter.md | 4 ++-- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 91e59bbce48ed..bd9d9e1e36892 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -796,7 +796,7 @@ A setup-hook very similar to `makeWrapper`, only it creates a tiny _compiled_ wr Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less ` - by scrolling past the binary data you should be able to see the C code that generated the executable and there see the environment variables that were injected into the wrapper. -Similarly to `wrapProgram`, the `makeBinaryWrapper` setup-hook provides a `wrapProgramBinary` with similar command line arguments. +Similarly to `wrapProgram`, the `makeBinaryWrapper` setup-hook provides a `binaryWrapProgram` with similar command line arguments. ### `substitute` \ \ \ {#fun-substitute} @@ -875,7 +875,7 @@ Convenience function for `makeWrapper` that replaces `<\executable\>` with a wra If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided. -### `wrapProgramBinary` \ \ {#fun-wrapProgramBinary} +### `binaryWrapProgram` \ \ {#fun-binaryWrapProgram} Convenience function for `makeBinaryWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeBinaryWrapper`, except for `--argv0`. diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index ec60f9ba7223f..d4d4163c4b754 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -34,8 +34,8 @@ makeBinaryWrapper() { makeDocumentedCWrapper "$1" "${@:3}" | cc -Os -x c -o "$2" - } -# Syntax: wrapProgramBinary -wrapProgramBinary() { +# Syntax: binaryWrapProgram +binaryWrapProgram() { local prog="$1" local hidden From 2bc7345064f5fc454282f044589e9f4b288257d4 Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Tue, 7 Dec 2021 17:39:38 +0000 Subject: [PATCH 39/48] Add golden effects test --- pkgs/test/make-binary-wrapper/add-flags.c | 6 +- .../make-binary-wrapper/add-flags.cmdline | 2 + pkgs/test/make-binary-wrapper/add-flags.env | 6 + pkgs/test/make-binary-wrapper/argv0.c | 5 +- pkgs/test/make-binary-wrapper/argv0.cmdline | 1 + pkgs/test/make-binary-wrapper/argv0.env | 2 + pkgs/test/make-binary-wrapper/basic.c | 6 +- pkgs/test/make-binary-wrapper/basic.cmdline | 0 pkgs/test/make-binary-wrapper/basic.env | 2 + pkgs/test/make-binary-wrapper/chdir.c | 11 +- pkgs/test/make-binary-wrapper/chdir.cmdline | 1 + pkgs/test/make-binary-wrapper/chdir.env | 2 + pkgs/test/make-binary-wrapper/combination.c | 10 +- .../make-binary-wrapper/combination.cmdline | 6 + pkgs/test/make-binary-wrapper/combination.env | 8 ++ pkgs/test/make-binary-wrapper/default.nix | 113 ++++++++---------- pkgs/test/make-binary-wrapper/env.c | 12 +- pkgs/test/make-binary-wrapper/env.cmdline | 4 + pkgs/test/make-binary-wrapper/env.env | 6 + pkgs/test/make-binary-wrapper/envcheck.c | 22 ++++ .../make-binary-wrapper/golden-test-utils.sh | 44 ------- pkgs/test/make-binary-wrapper/inherit-argv0.c | 7 +- .../make-binary-wrapper/inherit-argv0.cmdline | 1 + .../make-binary-wrapper/inherit-argv0.env | 2 + pkgs/test/make-binary-wrapper/invalid-env.c | 10 +- .../make-binary-wrapper/invalid-env.cmdline | 2 + pkgs/test/make-binary-wrapper/prefix.c | 8 +- pkgs/test/make-binary-wrapper/prefix.cmdline | 2 + pkgs/test/make-binary-wrapper/prefix.env | 3 + pkgs/test/make-binary-wrapper/suffix.c | 8 +- pkgs/test/make-binary-wrapper/suffix.cmdline | 2 + pkgs/test/make-binary-wrapper/suffix.env | 3 + 32 files changed, 145 insertions(+), 172 deletions(-) create mode 100644 pkgs/test/make-binary-wrapper/add-flags.cmdline create mode 100644 pkgs/test/make-binary-wrapper/add-flags.env create mode 100644 pkgs/test/make-binary-wrapper/argv0.cmdline create mode 100644 pkgs/test/make-binary-wrapper/argv0.env create mode 100644 pkgs/test/make-binary-wrapper/basic.cmdline create mode 100644 pkgs/test/make-binary-wrapper/basic.env create mode 100644 pkgs/test/make-binary-wrapper/chdir.cmdline create mode 100644 pkgs/test/make-binary-wrapper/chdir.env create mode 100644 pkgs/test/make-binary-wrapper/combination.cmdline create mode 100644 pkgs/test/make-binary-wrapper/combination.env create mode 100644 pkgs/test/make-binary-wrapper/env.cmdline create mode 100644 pkgs/test/make-binary-wrapper/env.env create mode 100644 pkgs/test/make-binary-wrapper/envcheck.c delete mode 100644 pkgs/test/make-binary-wrapper/golden-test-utils.sh create mode 100644 pkgs/test/make-binary-wrapper/inherit-argv0.cmdline create mode 100644 pkgs/test/make-binary-wrapper/inherit-argv0.env create mode 100644 pkgs/test/make-binary-wrapper/invalid-env.cmdline create mode 100644 pkgs/test/make-binary-wrapper/prefix.cmdline create mode 100644 pkgs/test/make-binary-wrapper/prefix.env create mode 100644 pkgs/test/make-binary-wrapper/suffix.cmdline create mode 100644 pkgs/test/make-binary-wrapper/suffix.env diff --git a/pkgs/test/make-binary-wrapper/add-flags.c b/pkgs/test/make-binary-wrapper/add-flags.c index 20d3b7508c05c..7ce682c6be647 100644 --- a/pkgs/test/make-binary-wrapper/add-flags.c +++ b/pkgs/test/make-binary-wrapper/add-flags.c @@ -1,7 +1,3 @@ -// makeCWrapper /send/me/flags \ - --add-flags "-x -y -z" \ - --add-flags -abc - #include #include #include @@ -22,4 +18,4 @@ int main(int argc, char **argv) { argv[0] = "/send/me/flags"; return execv("/send/me/flags", argv); -} \ No newline at end of file +} diff --git a/pkgs/test/make-binary-wrapper/add-flags.cmdline b/pkgs/test/make-binary-wrapper/add-flags.cmdline new file mode 100644 index 0000000000000..f840c772e3494 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/add-flags.cmdline @@ -0,0 +1,2 @@ + --add-flags "-x -y -z" \ + --add-flags -abc diff --git a/pkgs/test/make-binary-wrapper/add-flags.env b/pkgs/test/make-binary-wrapper/add-flags.env new file mode 100644 index 0000000000000..9b8d1fb9f6a5d --- /dev/null +++ b/pkgs/test/make-binary-wrapper/add-flags.env @@ -0,0 +1,6 @@ +CWD=SUBST_CWD +SUBST_ARGV0 +-x +-y +-z +-abc diff --git a/pkgs/test/make-binary-wrapper/argv0.c b/pkgs/test/make-binary-wrapper/argv0.c index 8e3e1f2987b5b..70c36889dc890 100644 --- a/pkgs/test/make-binary-wrapper/argv0.c +++ b/pkgs/test/make-binary-wrapper/argv0.c @@ -1,10 +1,7 @@ -// makeCWrapper /path/to/some/executable \ - --argv0 alternative-name - #include #include int main(int argc, char **argv) { argv[0] = "alternative-name"; - return execv("/path/to/some/executable", argv); + return execv("/send/me/flags", argv); } diff --git a/pkgs/test/make-binary-wrapper/argv0.cmdline b/pkgs/test/make-binary-wrapper/argv0.cmdline new file mode 100644 index 0000000000000..1cadce8312a44 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/argv0.cmdline @@ -0,0 +1 @@ + --argv0 alternative-name diff --git a/pkgs/test/make-binary-wrapper/argv0.env b/pkgs/test/make-binary-wrapper/argv0.env new file mode 100644 index 0000000000000..04c13d32ee6d6 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/argv0.env @@ -0,0 +1,2 @@ +CWD=SUBST_CWD +alternative-name diff --git a/pkgs/test/make-binary-wrapper/basic.c b/pkgs/test/make-binary-wrapper/basic.c index de366c5196306..1c1266181377a 100644 --- a/pkgs/test/make-binary-wrapper/basic.c +++ b/pkgs/test/make-binary-wrapper/basic.c @@ -1,9 +1,7 @@ -// makeCWrapper /path/to/executable - #include #include int main(int argc, char **argv) { - argv[0] = "/path/to/executable"; - return execv("/path/to/executable", argv); + argv[0] = "/send/me/flags"; + return execv("/send/me/flags", argv); } diff --git a/pkgs/test/make-binary-wrapper/basic.cmdline b/pkgs/test/make-binary-wrapper/basic.cmdline new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/pkgs/test/make-binary-wrapper/basic.env b/pkgs/test/make-binary-wrapper/basic.env new file mode 100644 index 0000000000000..b0da31959447c --- /dev/null +++ b/pkgs/test/make-binary-wrapper/basic.env @@ -0,0 +1,2 @@ +CWD=SUBST_CWD +SUBST_ARGV0 diff --git a/pkgs/test/make-binary-wrapper/chdir.c b/pkgs/test/make-binary-wrapper/chdir.c index ff1f91a03babd..c67c695b1c3b9 100644 --- a/pkgs/test/make-binary-wrapper/chdir.c +++ b/pkgs/test/make-binary-wrapper/chdir.c @@ -1,6 +1,3 @@ -// makeCWrapper /path/to/executable \ - --chdir /usr/local/bin - #include #include #include @@ -8,7 +5,7 @@ #define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) int main(int argc, char **argv) { - assert_success(chdir("/usr/local/bin")); - argv[0] = "/path/to/executable"; - return execv("/path/to/executable", argv); -} \ No newline at end of file + assert_success(chdir("/tmp/foo")); + argv[0] = "/send/me/flags"; + return execv("/send/me/flags", argv); +} diff --git a/pkgs/test/make-binary-wrapper/chdir.cmdline b/pkgs/test/make-binary-wrapper/chdir.cmdline new file mode 100644 index 0000000000000..15235f20621c8 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/chdir.cmdline @@ -0,0 +1 @@ + --chdir /tmp/foo diff --git a/pkgs/test/make-binary-wrapper/chdir.env b/pkgs/test/make-binary-wrapper/chdir.env new file mode 100644 index 0000000000000..db129d68af741 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/chdir.env @@ -0,0 +1,2 @@ +CWD=/tmp/foo +SUBST_ARGV0 diff --git a/pkgs/test/make-binary-wrapper/combination.c b/pkgs/test/make-binary-wrapper/combination.c index bb35d0d99f314..e9ce5f1d72440 100644 --- a/pkgs/test/make-binary-wrapper/combination.c +++ b/pkgs/test/make-binary-wrapper/combination.c @@ -1,11 +1,3 @@ -// makeCWrapper /path/to/executable \ - --argv0 my-wrapper \ - --set-default MESSAGE HELLO \ - --prefix PATH : /usr/bin/ \ - --suffix PATH : /usr/local/bin/ \ - --add-flags "-x -y -z" \ - --set MESSAGE2 WORLD - #define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include @@ -57,5 +49,5 @@ int main(int argc, char **argv) { argv = argv_tmp; argv[0] = "my-wrapper"; - return execv("/path/to/executable", argv); + return execv("/send/me/flags", argv); } diff --git a/pkgs/test/make-binary-wrapper/combination.cmdline b/pkgs/test/make-binary-wrapper/combination.cmdline new file mode 100644 index 0000000000000..fb3861235c8b4 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/combination.cmdline @@ -0,0 +1,6 @@ + --argv0 my-wrapper \ + --set-default MESSAGE HELLO \ + --prefix PATH : /usr/bin/ \ + --suffix PATH : /usr/local/bin/ \ + --add-flags "-x -y -z" \ + --set MESSAGE2 WORLD diff --git a/pkgs/test/make-binary-wrapper/combination.env b/pkgs/test/make-binary-wrapper/combination.env new file mode 100644 index 0000000000000..886420c01d1ea --- /dev/null +++ b/pkgs/test/make-binary-wrapper/combination.env @@ -0,0 +1,8 @@ +MESSAGE=HELLO +PATH=/usr/bin/:/usr/local/bin/ +MESSAGE2=WORLD +CWD=SUBST_CWD +my-wrapper +-x +-y +-z diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index eddab15fd31d9..6f3b3ef4ae12b 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -1,73 +1,54 @@ -{ lib, stdenv, runCommand, makeBinaryWrapper }: +{ lib, coreutils, python3, gcc, writeText, writeScript, runCommand, makeBinaryWrapper }: let - makeGoldenTest = { name, filename }: stdenv.mkDerivation { - name = name; - dontUnpack = true; - strictDeps = true; - nativeBuildInputs = [ makeBinaryWrapper ]; - phases = [ "installPhase" ]; - installPhase = '' - source ${./golden-test-utils.sh} - mkdir -p $out/bin - command=$(getInputCommand "${filename}") - eval "$command" > "$out/bin/result" - ''; - passthru = { - assertion = '' - source ${./golden-test-utils.sh} - contents=$(getOutputText "${filename}") - echo "$contents" | diff $out/bin/result - - ''; - }; - }; - tests = { - basic = makeGoldenTest { name = "basic"; filename = ./basic.c; }; - argv0 = makeGoldenTest { name = "argv0"; filename = ./argv0.c; }; - inherit_argv0 = makeGoldenTest { name = "inherit-argv0"; filename = ./inherit-argv0.c; }; - env = makeGoldenTest { name = "env"; filename = ./env.c; }; - invalid_env = makeGoldenTest { name = "invalid-env"; filename = ./invalid-env.c; }; - prefix = makeGoldenTest { name = "prefix"; filename = ./prefix.c; }; - suffix = makeGoldenTest { name = "suffix"; filename = ./suffix.c; }; - add_flags = makeGoldenTest { name = "add-flags"; filename = ./add-flags.c; }; - chdir = makeGoldenTest { name = "chdir"; filename = ./chdir.c; }; - combination = makeGoldenTest { name = "combination"; filename = ./combination.c; }; - }; -in runCommand "make-binary-wrapper-test" { - passthru = tests; - meta.platforms = lib.platforms.all; -} '' - validate() { - local name=$1 - local testout=$2 - local assertion=$3 - - echo -n "... $name: " >&2 - - local rc=0 - (out=$testout eval "$assertion") || rc=1 - - if [ "$rc" -eq 0 ]; then - echo "yes" >&2 + env = { nativeBuildInputs = [ makeBinaryWrapper gcc ]; }; + envCheck = runCommand "envcheck" env '' + cc -o $out ${./envcheck.c} + ''; + makeGoldenTest = testname: runCommand "test-wrapper_${testname}" env '' + mkdir -p /tmp/foo + + params=$(<"${./.}/${testname}.cmdline") + eval "makeCWrapper /send/me/flags $params" > wrapper.c + + diff wrapper.c "${./.}/${testname}.c" + + if [ -f "${./.}/${testname}.env" ]; then + eval "makeBinaryWrapper ${envCheck} wrapped $params" + env -i ./wrapped > env.txt + sed "s#SUBST_ARGV0#${envCheck}#;s#SUBST_CWD#$PWD#" \ + "${./.}/${testname}.env" > golden-env.txt + if ! diff env.txt golden-env.txt; then + echo "env/argv should be:" + cat golden-env.txt + echo "env/argv output is:" + cat env.txt + exit 1 + fi else - echo "no" >&2 + # without a golden env, we expect the wrapper compilation to fail + ! eval "makeBinaryWrapper ${envCheck} wrapped $params" &> error.txt fi - return "$rc" - } - - echo "checking whether makeCWrapper works properly... ">&2 - - fail= + cp wrapper.c $out + ''; + tests = let + names = [ + "add-flags" + "argv0" + "basic" + "chdir" + "combination" + "env" + "inherit-argv0" + "invalid-env" + "prefix" + "suffix" + ]; + f = name: lib.nameValuePair name (makeGoldenTest name); + in builtins.listToAttrs (builtins.map f names); +in writeText "make-binary-wrapper-test" '' ${lib.concatStringsSep "\n" (lib.mapAttrsToList (_: test: '' - validate "${test.name}" "${test}" ${lib.escapeShellArg test.assertion} || fail=1 + "${test.name}" "${test}" '') tests)} - - if [ "$fail" ]; then - echo "failed" - exit 1 - else - echo "succeeded" - touch $out - fi -'' +'' // tests diff --git a/pkgs/test/make-binary-wrapper/env.c b/pkgs/test/make-binary-wrapper/env.c index fa2e6fc4dd294..7e0422dee3bdc 100644 --- a/pkgs/test/make-binary-wrapper/env.c +++ b/pkgs/test/make-binary-wrapper/env.c @@ -1,9 +1,3 @@ -// makeCWrapper /hello/world \ - --set PART1 HELLO \ - --set-default PART2 WORLD \ - --unset SOME_OTHER_VARIABLE \ - --set PART3 $'"!!\n"' - #include #include #include @@ -15,6 +9,6 @@ int main(int argc, char **argv) { assert_success(setenv("PART2", "WORLD", 0)); assert_success(unsetenv("SOME_OTHER_VARIABLE")); putenv("PART3=\"!!\n\""); - argv[0] = "/hello/world"; - return execv("/hello/world", argv); -} \ No newline at end of file + argv[0] = "/send/me/flags"; + return execv("/send/me/flags", argv); +} diff --git a/pkgs/test/make-binary-wrapper/env.cmdline b/pkgs/test/make-binary-wrapper/env.cmdline new file mode 100644 index 0000000000000..3c89f33e2dceb --- /dev/null +++ b/pkgs/test/make-binary-wrapper/env.cmdline @@ -0,0 +1,4 @@ + --set PART1 HELLO \ + --set-default PART2 WORLD \ + --unset SOME_OTHER_VARIABLE \ + --set PART3 $'"!!\n"' diff --git a/pkgs/test/make-binary-wrapper/env.env b/pkgs/test/make-binary-wrapper/env.env new file mode 100644 index 0000000000000..c7661e165e09e --- /dev/null +++ b/pkgs/test/make-binary-wrapper/env.env @@ -0,0 +1,6 @@ +PART1=HELLO +PART2=WORLD +PART3="!! +" +CWD=SUBST_CWD +SUBST_ARGV0 diff --git a/pkgs/test/make-binary-wrapper/envcheck.c b/pkgs/test/make-binary-wrapper/envcheck.c new file mode 100644 index 0000000000000..848fbdaa80f26 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/envcheck.c @@ -0,0 +1,22 @@ +#include +#include +#include + +int main(int argc, char **argv, char **envp) { + for (char **env = envp; *env != 0; ++env) { + puts(*env); + } + + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) { + printf("CWD=%s\n", cwd); + } else { + perror("getcwd() error"); + return 1; + } + + for (int i=0; i < argc; ++i) { + puts(argv[i]); + } + return 0; +} diff --git a/pkgs/test/make-binary-wrapper/golden-test-utils.sh b/pkgs/test/make-binary-wrapper/golden-test-utils.sh deleted file mode 100644 index 80e880e11e485..0000000000000 --- a/pkgs/test/make-binary-wrapper/golden-test-utils.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# Split a generated C-file into the command used to generate it, -# and the outputted code itself. - -# This is useful because it allows input and output to be inside the same file - -# How it works: -# - The first line needs to start with '//' (and becomes the command). -# - Whitespace/padding between the comment and the generated code is ignored -# - To write a command using multiple lines, end each line with backslash (\) - -# Count the number of lines before the output text starts -# commandLineCount FILE -commandLineCount() { - local n state - n=0 - state="init" - while IFS="" read -r p || [ -n "$p" ]; do - case $state in - init) - if [[ $p =~ ^//.*\\$ ]]; then state="comment" - elif [[ $p =~ ^//.* ]]; then state="padding" - else break - fi - ;; - comment) [[ ! $p =~ ^.*\\$ ]] && state="padding";; - padding) [ -n "${p// }" ] && break;; - esac - n=$((n+1)) - done < "$1" - printf '%s' "$n" -} - -# getInputCommand FILE -getInputCommand() { - n=$(commandLineCount "$1") - head -n "$n" "$1" | awk '{ if (NR == 1) print substr($0, 3); else print $0 }' -} - -# getOutputText FILE -getOutputText() { - n=$(commandLineCount "$1") - sed "1,${n}d" "$1" -} diff --git a/pkgs/test/make-binary-wrapper/inherit-argv0.c b/pkgs/test/make-binary-wrapper/inherit-argv0.c index 71e12d9b024a5..e1c2bc926aa72 100644 --- a/pkgs/test/make-binary-wrapper/inherit-argv0.c +++ b/pkgs/test/make-binary-wrapper/inherit-argv0.c @@ -1,9 +1,6 @@ -// makeCWrapper /path/to/executable \ - --inherit-argv0 - #include #include int main(int argc, char **argv) { - return execv("/path/to/executable", argv); -} \ No newline at end of file + return execv("/send/me/flags", argv); +} diff --git a/pkgs/test/make-binary-wrapper/inherit-argv0.cmdline b/pkgs/test/make-binary-wrapper/inherit-argv0.cmdline new file mode 100644 index 0000000000000..0880767998357 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/inherit-argv0.cmdline @@ -0,0 +1 @@ + --inherit-argv0 diff --git a/pkgs/test/make-binary-wrapper/inherit-argv0.env b/pkgs/test/make-binary-wrapper/inherit-argv0.env new file mode 100644 index 0000000000000..c46ca95eefbc7 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/inherit-argv0.env @@ -0,0 +1,2 @@ +CWD=SUBST_CWD +./wrapped diff --git a/pkgs/test/make-binary-wrapper/invalid-env.c b/pkgs/test/make-binary-wrapper/invalid-env.c index bad647bd13a28..4dfd36fb68a0b 100644 --- a/pkgs/test/make-binary-wrapper/invalid-env.c +++ b/pkgs/test/make-binary-wrapper/invalid-env.c @@ -1,7 +1,3 @@ -// makeCWrapper /bad/env/example \ - --set "=" "TEST1" \ - --set-default "" "TEST2" - #include #include #include @@ -13,6 +9,6 @@ int main(int argc, char **argv) { #error Illegal environment variable name `=` (cannot contain `=`) assert_success(setenv("", "TEST2", 0)); #error Environment variable name can't be empty. - argv[0] = "/bad/env/example"; - return execv("/bad/env/example", argv); -} \ No newline at end of file + argv[0] = "/send/me/flags"; + return execv("/send/me/flags", argv); +} diff --git a/pkgs/test/make-binary-wrapper/invalid-env.cmdline b/pkgs/test/make-binary-wrapper/invalid-env.cmdline new file mode 100644 index 0000000000000..a03b001e754e3 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/invalid-env.cmdline @@ -0,0 +1,2 @@ + --set "=" "TEST1" \ + --set-default "" "TEST2" diff --git a/pkgs/test/make-binary-wrapper/prefix.c b/pkgs/test/make-binary-wrapper/prefix.c index de431168bffc0..ea8fbdc64a84e 100644 --- a/pkgs/test/make-binary-wrapper/prefix.c +++ b/pkgs/test/make-binary-wrapper/prefix.c @@ -1,7 +1,3 @@ -// makeCWrapper /path/to/executable \ - --prefix PATH : /usr/bin/ \ - --prefix PATH : /usr/local/bin/ - #define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include @@ -25,6 +21,6 @@ void set_env_prefix(char *env, char *sep, char *prefix) { int main(int argc, char **argv) { set_env_prefix("PATH", ":", "/usr/bin/"); set_env_prefix("PATH", ":", "/usr/local/bin/"); - argv[0] = "/path/to/executable"; - return execv("/path/to/executable", argv); + argv[0] = "/send/me/flags"; + return execv("/send/me/flags", argv); } diff --git a/pkgs/test/make-binary-wrapper/prefix.cmdline b/pkgs/test/make-binary-wrapper/prefix.cmdline new file mode 100644 index 0000000000000..99cebf9503f47 --- /dev/null +++ b/pkgs/test/make-binary-wrapper/prefix.cmdline @@ -0,0 +1,2 @@ + --prefix PATH : /usr/bin/ \ + --prefix PATH : /usr/local/bin/ diff --git a/pkgs/test/make-binary-wrapper/prefix.env b/pkgs/test/make-binary-wrapper/prefix.env new file mode 100644 index 0000000000000..033676457c57c --- /dev/null +++ b/pkgs/test/make-binary-wrapper/prefix.env @@ -0,0 +1,3 @@ +PATH=/usr/local/bin/:/usr/bin/ +CWD=SUBST_CWD +SUBST_ARGV0 diff --git a/pkgs/test/make-binary-wrapper/suffix.c b/pkgs/test/make-binary-wrapper/suffix.c index 3fcb338a61045..d33f86c070ca5 100644 --- a/pkgs/test/make-binary-wrapper/suffix.c +++ b/pkgs/test/make-binary-wrapper/suffix.c @@ -1,7 +1,3 @@ -// makeCWrapper /path/to/executable \ - --suffix PATH : /usr/bin/ \ - --suffix PATH : /usr/local/bin/ - #define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include @@ -25,6 +21,6 @@ void set_env_suffix(char *env, char *sep, char *suffix) { int main(int argc, char **argv) { set_env_suffix("PATH", ":", "/usr/bin/"); set_env_suffix("PATH", ":", "/usr/local/bin/"); - argv[0] = "/path/to/executable"; - return execv("/path/to/executable", argv); + argv[0] = "/send/me/flags"; + return execv("/send/me/flags", argv); } diff --git a/pkgs/test/make-binary-wrapper/suffix.cmdline b/pkgs/test/make-binary-wrapper/suffix.cmdline new file mode 100644 index 0000000000000..95d291f3c169e --- /dev/null +++ b/pkgs/test/make-binary-wrapper/suffix.cmdline @@ -0,0 +1,2 @@ + --suffix PATH : /usr/bin/ \ + --suffix PATH : /usr/local/bin/ diff --git a/pkgs/test/make-binary-wrapper/suffix.env b/pkgs/test/make-binary-wrapper/suffix.env new file mode 100644 index 0000000000000..3ce4cc54de41b --- /dev/null +++ b/pkgs/test/make-binary-wrapper/suffix.env @@ -0,0 +1,3 @@ +PATH=/usr/bin/:/usr/local/bin/ +CWD=SUBST_CWD +SUBST_ARGV0 From e7c70ce5c8cfb139adcbec73ec518031bfc8f211 Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Thu, 9 Dec 2021 12:27:29 +0100 Subject: [PATCH 40/48] Inject gcc path into makewrapper script --- pkgs/test/make-binary-wrapper/default.nix | 4 ++-- pkgs/top-level/all-packages.nix | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index 6f3b3ef4ae12b..04f0059ae153e 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -1,9 +1,9 @@ { lib, coreutils, python3, gcc, writeText, writeScript, runCommand, makeBinaryWrapper }: let - env = { nativeBuildInputs = [ makeBinaryWrapper gcc ]; }; + env = { nativeBuildInputs = [ makeBinaryWrapper ]; }; envCheck = runCommand "envcheck" env '' - cc -o $out ${./envcheck.c} + ${gcc}/bin/cc -o $out ${./envcheck.c} ''; makeGoldenTest = testname: runCommand "test-wrapper_${testname}" env '' mkdir -p /tmp/foo diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 0e1dd457d8405..80e9275f98ed6 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -608,7 +608,9 @@ in makeBinaryWrapper = makeSetupHook { deps = [ dieHook ]; - } ../build-support/setup-hooks/make-binary-wrapper.sh; + } (runCommand "make-binary-wrapper.sh" {} '' + substitute ${../build-support/setup-hooks/make-binary-wrapper.sh} $out --replace " cc " " ${gcc}/bin/cc " + ''); makeModulesClosure = { kernel, firmware, rootModules, allowMissing ? false }: callPackage ../build-support/kernel/modules-closure.nix { From 177f0a6eedcf0b0ab74b845fd7cf77bde0997fbe Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Thu, 9 Dec 2021 11:31:35 +0000 Subject: [PATCH 41/48] make makeWrapper and makeBinaryWrapper drop-in-replaceable --- .../setup-hooks/make-binary-wrapper.sh | 14 +++++++------- pkgs/test/make-binary-wrapper/default.nix | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index ba9efa05191a3..a0c8cf59501e9 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -9,7 +9,7 @@ assertExecutable() { # Generate a binary executable wrapper for wrapping an executable. # The binary is compiled from generated C-code using gcc. -# makeBinaryWrapper EXECUTABLE OUT_PATH ARGS +# makeWrapper EXECUTABLE OUT_PATH ARGS # ARGS: # --argv0 NAME : set name of executed process to NAME @@ -29,13 +29,13 @@ assertExecutable() { # To troubleshoot a binary wrapper after you compiled it, # use the `strings` command or open the binary file in a text editor. -makeBinaryWrapper() { +makeWrapper() { assertExecutable "$1" makeDocumentedCWrapper "$1" "${@:3}" | cc -Os -x c -o "$2" - } -# Syntax: wrapProgramBinary -wrapProgramBinary() { +# Syntax: wrapProgram +wrapProgram() { local prog="$1" local hidden @@ -48,13 +48,13 @@ wrapProgramBinary() { mv "$prog" "$hidden" # Silence warning about unexpanded $0: # shellcheck disable=SC2016 - makeBinaryWrapper "$hidden" "$prog" --inherit-argv0 "${@:2}" + makeWrapper "$hidden" "$prog" --inherit-argv0 "${@:2}" } # Generate source code for the wrapper in such a way that the wrapper source code # will still be readable even after compilation # makeDocumentedCWrapper EXECUTABLE ARGS -# ARGS: same as makeBinaryWrapper +# ARGS: same as makeWrapper makeDocumentedCWrapper() { local src docs src=$(makeCWrapper "$@") @@ -64,7 +64,7 @@ makeDocumentedCWrapper() { } # makeCWrapper EXECUTABLE ARGS -# ARGS: same as makeBinaryWrapper +# ARGS: same as makeWrapper makeCWrapper() { local argv0 inherit_argv0 n params cmd main flagsBefore flags executable params length local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index 04f0059ae153e..c9e045a4d9818 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -14,7 +14,7 @@ let diff wrapper.c "${./.}/${testname}.c" if [ -f "${./.}/${testname}.env" ]; then - eval "makeBinaryWrapper ${envCheck} wrapped $params" + eval "makeWrapper ${envCheck} wrapped $params" env -i ./wrapped > env.txt sed "s#SUBST_ARGV0#${envCheck}#;s#SUBST_CWD#$PWD#" \ "${./.}/${testname}.env" > golden-env.txt @@ -27,7 +27,7 @@ let fi else # without a golden env, we expect the wrapper compilation to fail - ! eval "makeBinaryWrapper ${envCheck} wrapped $params" &> error.txt + ! eval "makeWrapper ${envCheck} wrapped $params" &> error.txt fi cp wrapper.c $out From c42e6741b2e07f7892c4effc71292dea9f1c1254 Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Thu, 9 Dec 2021 16:02:02 +0200 Subject: [PATCH 42/48] Rephrase documentation for both makeWrapper implementations --- doc/stdenv/stdenv.chapter.md | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index bd9d9e1e36892..29987e3d3081a 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -774,7 +774,7 @@ The standard environment provides a number of useful functions. ### `makeWrapper` \ \ \ {#fun-makeWrapper} -Constructs a wrapper for a program with various possible arguments. It is defined as part of a setup-hook by the same name, so to use it you have to add `makeWrapper` to your `nativeBuildInputs`. Here's a usage example: +Constructs a wrapper for a program with various possible arguments. It is defined as part of 2 setup-hooks named `makeWrapper` and `makeBinaryWrapper` that implement the same bash functions. Hence, to use it you have to add `makeWrapper` to your `nativeBuildInputs`. Here's an example usage: ```bash # adds `FOOBAR=baz` to `$out/bin/foo`’s environment @@ -786,17 +786,11 @@ makeWrapper $out/bin/foo $wrapperfile --set FOOBAR baz makeWrapper $out/bin/foo $wrapperfile --prefix PATH : ${lib.makeBinPath [ hello git ]} ``` -There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-wrapper.sh`. +There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-wrapper.sh` for the `makeWrapper` implementation and in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh` for the `makeBinaryWrapper` implementation. -`wrapProgram` is a convenience function you probably want to use most of the time. +`wrapProgram` is a convenience function you probably want to use most of the time, implemented by both `makeWrapper` and `makeBinaryWrapper`. -### `makeBinaryWrapper` \ \ \ {#fun-makeBinaryWrapper} - -A setup-hook very similar to `makeWrapper`, only it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). The arguments it accepts are similar to those of `makeWrapper` and they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh`. - -Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less ` - by scrolling past the binary data you should be able to see the C code that generated the executable and there see the environment variables that were injected into the wrapper. - -Similarly to `wrapProgram`, the `makeBinaryWrapper` setup-hook provides a `binaryWrapProgram` with similar command line arguments. +Using the `makeBinaryWrapper` implementation is usually preferred, as it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less ` - by scrolling past the binary data you should be able to see the shell command that generated the executable and there see the environment variables that were injected into the wrapper. ### `substitute` \ \ \ {#fun-substitute} @@ -871,13 +865,7 @@ someVar=$(stripHash $name) ### `wrapProgram` \ \ {#fun-wrapProgram} -Convenience function for `makeWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--argv0`. - -If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided. - -### `binaryWrapProgram` \ \ {#fun-binaryWrapProgram} - -Convenience function for `makeBinaryWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeBinaryWrapper`, except for `--argv0`. +Convenience function for `makeWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--inherit-argv0` (used by the `makeBinaryWrapper` implementation and `--argv0` (used by both `makeWrapper` and `makeBinaryWrapper` wrapper implementations). If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided. From b7e00ed89ecf726f0860d2e305bbc12ca78398af Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Thu, 9 Dec 2021 15:45:35 +0000 Subject: [PATCH 43/48] make-binary-wrapper: Add -Wall -Werror -Wpedantic --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 7 ++++++- pkgs/test/make-binary-wrapper/default.nix | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index 2b6d316d81eb5..b0ed01de4cfa3 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -31,7 +31,12 @@ assertExecutable() { # use the `strings` command or open the binary file in a text editor. makeWrapper() { assertExecutable "$1" - makeDocumentedCWrapper "$1" "${@:3}" | cc -Os -x c -o "$2" - + makeDocumentedCWrapper "$1" "${@:3}" | \ + cc \ + -Wall -Werror -Wpedantic \ + -Os \ + -x c \ + -o "$2" - } # Syntax: wrapProgram diff --git a/pkgs/test/make-binary-wrapper/default.nix b/pkgs/test/make-binary-wrapper/default.nix index c9e045a4d9818..c5bb6970aac07 100644 --- a/pkgs/test/make-binary-wrapper/default.nix +++ b/pkgs/test/make-binary-wrapper/default.nix @@ -3,7 +3,7 @@ let env = { nativeBuildInputs = [ makeBinaryWrapper ]; }; envCheck = runCommand "envcheck" env '' - ${gcc}/bin/cc -o $out ${./envcheck.c} + ${gcc}/bin/cc -Wall -Werror -Wpedantic -o $out ${./envcheck.c} ''; makeGoldenTest = testname: runCommand "test-wrapper_${testname}" env '' mkdir -p /tmp/foo From 87fcb7b79ec65c246caf65d05fda0c2048a73cb2 Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Thu, 9 Dec 2021 15:46:16 +0000 Subject: [PATCH 44/48] make-binary-wrapper: Add -euo pipefail to bash script --- pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index b0ed01de4cfa3..e9910b2e99b89 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -1,3 +1,6 @@ + +set -euo pipefail + # Assert that FILE exists and is executable # # assertExecutable FILE From d5e028a441ddcac16b380436c98439b769e35355 Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Thu, 9 Dec 2021 15:48:46 +0000 Subject: [PATCH 45/48] make-binary-wrapper: Make CC substitution safer --- .../build-support/setup-hooks/make-binary-wrapper.sh | 2 +- pkgs/top-level/all-packages.nix | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index e9910b2e99b89..abc929cb89dbc 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -35,7 +35,7 @@ assertExecutable() { makeWrapper() { assertExecutable "$1" makeDocumentedCWrapper "$1" "${@:3}" | \ - cc \ + @CC@ \ -Wall -Werror -Wpedantic \ -Os \ -x c \ diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 80e9275f98ed6..1f291fd6c5b96 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -606,11 +606,13 @@ in makeWrapper = makeSetupHook { deps = [ dieHook ]; substitutions = { shell = targetPackages.runtimeShell; }; } ../build-support/setup-hooks/make-wrapper.sh; - makeBinaryWrapper = makeSetupHook { - deps = [ dieHook ]; - } (runCommand "make-binary-wrapper.sh" {} '' - substitute ${../build-support/setup-hooks/make-binary-wrapper.sh} $out --replace " cc " " ${gcc}/bin/cc " - ''); + makeBinaryWrapper = let + script = runCommand "make-binary-wrapper.sh" {} '' + substitute ${../build-support/setup-hooks/make-binary-wrapper.sh} $out \ + --replace " @CC@ " " ${gcc}/bin/cc " + ''; + in + makeSetupHook { deps = [ dieHook ]; } script; makeModulesClosure = { kernel, firmware, rootModules, allowMissing ? false }: callPackage ../build-support/kernel/modules-closure.nix { From bdaa0e2930b71c80ea34fe09ff4f1b1ea8f7ca34 Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Thu, 9 Dec 2021 15:53:51 +0000 Subject: [PATCH 46/48] make-binary-wrapper: Add sanitizer default option --- pkgs/top-level/all-packages.nix | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 1f291fd6c5b96..ce6d8feb0d8e5 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -607,12 +607,19 @@ in ../build-support/setup-hooks/make-wrapper.sh; makeBinaryWrapper = let - script = runCommand "make-binary-wrapper.sh" {} '' - substitute ${../build-support/setup-hooks/make-binary-wrapper.sh} $out \ - --replace " @CC@ " " ${gcc}/bin/cc " - ''; + f = { cc, sanitizers }: let + san = lib.concatMapStringsSep " " (s: "-fsanitize=${s}") sanitizers; + script = runCommand "make-binary-wrapper.sh" {} '' + substitute ${../build-support/setup-hooks/make-binary-wrapper.sh} $out \ + --replace " @CC@ " " ${cc}/bin/cc ${san} " + ''; + in + makeSetupHook { deps = [ dieHook ]; } script; in - makeSetupHook { deps = [ dieHook ]; } script; + lib.makeOverridable f { + cc = gcc; + sanitizers = [ "undefined" "address" ]; + }; makeModulesClosure = { kernel, firmware, rootModules, allowMissing ? false }: callPackage ../build-support/kernel/modules-closure.nix { From ceffea674d8dbe774f451a12fe472a30cc06254f Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Thu, 9 Dec 2021 23:24:13 +0200 Subject: [PATCH 47/48] Small rephrase of wrapProgram documentation Co-authored-by: Julian Stecklina --- doc/stdenv/stdenv.chapter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 29987e3d3081a..79ae4b2b34aad 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -865,7 +865,7 @@ someVar=$(stripHash $name) ### `wrapProgram` \ \ {#fun-wrapProgram} -Convenience function for `makeWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--inherit-argv0` (used by the `makeBinaryWrapper` implementation and `--argv0` (used by both `makeWrapper` and `makeBinaryWrapper` wrapper implementations). +Convenience function for `makeWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--inherit-argv0` (used by the `makeBinaryWrapper` implementation) and `--argv0` (used by both `makeWrapper` and `makeBinaryWrapper` wrapper implementations). If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided. From 39b0aa415c67b6bcaabbb7110344503cc184575a Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 9 Dec 2021 22:57:13 +0100 Subject: [PATCH 48/48] Change default cc from gcc to stdenv.cc.cc to reduce closure size on darwin Co-authored-by: pennae <82953136+pennae@users.noreply.github.com> --- pkgs/top-level/all-packages.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index ce6d8feb0d8e5..3f3dd0342995a 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -617,7 +617,7 @@ in makeSetupHook { deps = [ dieHook ]; } script; in lib.makeOverridable f { - cc = gcc; + cc = stdenv.cc.cc; sanitizers = [ "undefined" "address" ]; };