From 5edd17c4c2a17e7e964f360d83de39e66ea6865b Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 00:57:31 +0200 Subject: 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 0130499a993d..7fe382a5e486 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"; -- cgit v1.2.3 From de1f53b84d5f9549730693aa1e33f69069477395 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 01:11:06 +0200 Subject: Add make-c-wrapper.sh for creating binary executable wrappers --- pkgs/build-support/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 000000000000..2c67d9ab16e6 --- /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\";" -- cgit v1.2.3 From eef4fa82c169d00b0b05f1c3ac2b1081b968c9e7 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 01:47:40 +0200 Subject: 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 2c67d9ab16e6..6f024b3356c3 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))]}" -- cgit v1.2.3 From 131ed20b2f8b937e0ff0fffae1dcde8d699ce0e1 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 01:56:05 +0200 Subject: 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 6f024b3356c3..e018e4f161d7 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//\"/'\"'} -- cgit v1.2.3 From e8cedf381914d28e162810f567216f8c00f87edc Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 27 May 2021 02:04:12 +0200 Subject: 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 e018e4f161d7..55afe9fcf2a2 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))]}" -- cgit v1.2.3 From 8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 1 Jun 2021 01:02:08 +0200 Subject: 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 +++++++++++++++++++++ pkgs/build-support/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 000000000000..b77aca60a01d --- /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 55afe9fcf2a2..000000000000 --- 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\";" -- cgit v1.2.3 From 1d6428140194b5bac68266ca11a441ed6f63571c Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Tue, 1 Jun 2021 01:25:22 +0200 Subject: 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 b77aca60a01d..33310948333a --- 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 "$@" -- cgit v1.2.3 From dcba4171d4a7150cbaf90cae7a3e12a8381067a7 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 23 Aug 2021 23:44:57 +0200 Subject: 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 33310948333a..f19edd483cfa 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" '}' +} -- cgit v1.2.3 From b58c857bfbce8af9b5c100ea2f483c5a228f35d6 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Thu, 26 Aug 2021 14:36:30 +0200 Subject: Switch to using strlen in concat3Fn. Make sure uses-variables are local to improve purity of makeCWrapper. Refactor --- pkgs/build-support/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 f19edd483cfa..0c72508520a4 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];' -- cgit v1.2.3 From b62216a2118a9b5771206eb88a1fc1dfb6fcb382 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 17:43:23 +0200 Subject: 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 0c72508520a4..1b0ff385cf95 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); +} +" } -- cgit v1.2.3 From ac99a6ff9889fa12184aab82642e0e1b4c4d64b0 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 18:19:53 +0200 Subject: 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 974595bb1192..cbb01ce2c537 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; -- cgit v1.2.3 From d930fecc3cb3f10d8de52c31916063659448f64b Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 18:51:09 +0200 Subject: Return an #error macro if the wrong number of arguments are supplied --- pkgs/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 1b0ff385cf95..6c4e47c3ea33 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}" -- cgit v1.2.3 From 3df841bb99e3e96bcd8c52c19246d74c5e05deee Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Fri, 1 Oct 2021 18:57:26 +0200 Subject: Make error messages more consistent --- pkgs/build-support/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 6c4e47c3ea33..d7a8a31121d4 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 -- cgit v1.2.3 From adef70ce7c964e0d1d9d961783036541323b06a7 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 4 Oct 2021 14:29:22 +0200 Subject: 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. --- pkgs/build-support/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 d7a8a31121d4..abc0e10631e8 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 -- cgit v1.2.3 From b7d36b8d597df1a9d799fa9d6d8d55137a525570 Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 4 Oct 2021 22:35:09 +0200 Subject: 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 ++++++ pkgs/test/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 b9f05bdff8d0..acf639b4a46e 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 000000000000..70d43e0bec08 --- /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 000000000000..8e3e1f2987b5 --- /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 000000000000..de366c519630 --- /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 000000000000..925fdf1ccfb4 --- /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 000000000000..0b9f7e5abea2 --- /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 000000000000..89f1f496b349 --- /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 000000000000..a0408b5a9089 --- /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 000000000000..914fd851bb7e --- /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 000000000000..865d76fe34e2 --- /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 -- cgit v1.2.3 From 4b833cc141172f88e563692f2458253212d1cf1a Mon Sep 17 00:00:00 2001 From: Tobias Bergkvist Date: Mon, 4 Oct 2021 22:38:14 +0200 Subject: EditorConfig: Switch from tabs to spaces --- pkgs/test/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 a0408b5a9089..80e880e11e48 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 -- cgit v1.2