#!/usr/bin/env bash # binbox: Creates a multi-binary script that self-contains the input scripts. # Symlinking to the resulting binary with the name of one of the original scripts will trigger # said script. The idea is similar to `busybox`. LD_INTERNAL=1 . $(dirname $(realpath $0))/daisy.source args=$@ function help() { echo "$LD_BIN is a utility that allows you to generate busybox-style combined binaries." echo "It only supports shell scripts compatible with \`bash\`." echo "To access the original functionality of an input binary, you can either use a symlink or" echo "call the function like so: 'combi-bin input-bin ." echo "" echo "> Usage:" echo "Creating boxed binary: $LD_BIN -o <-s source files> <-p include files verbatim> -i INPUT_BINS ..." echo " Unpacking a boxed binary: $LD_BIN -e " echo "View this screen: $LD_BIN " exit 0 } if [[ $@ == '' ]]; then help fi # Define some building blocks case_p1="case $BINARY in" case_pm1=" $OPTION)" case_pm2=" exec $OTPION_fn" case_pm3=" ;;" case_cm1=" *)" case_cm2=" exec help_fn" case_cm3=" ;;" case_p2="esac" func_p1="function $OPTION_fn() {" func_p2=" exit($?)" func_p3="}" basic_p1="BINARY=$0" # Start parsing args inputs=() output="" inputs=() output="" includes=() sources=() args=("$@") i=0 b=0 s=0 p=0 while [ $i -lt $# ]; do case "${args[$i]}" in -i) ((i++)) while [ $i -lt $# ] && [[ ! "${args[$i]}" =~ ^- ]]; do file="${args[$i]}" ((i++)) if [[ -e "$file" ]]; then inputs+=("$file") ((b++)) else echo "WARNING: Missing input binary: \"$file\"." echo "Module will NOT be available!" fi done continue ;; -s) ((i++)) while [ $i -lt $# ] && [[ ! "${args[$i]}" =~ ^- ]]; do file="${args[$i]}" ((i++)) if [[ -e "$file" ]]; then sources+=("$file") ((s++)) else echo "WARNING: Missing input source: \"$file\"." echo "File will NOT be sourced!" fi done continue ;; -p) ((i++)) while [ $i -lt $# ] && [[ ! "${args[$i]}" =~ ^- ]]; do file="${args[$i]}" ((i++)) if [[ -e "$file" ]]; then includes+=("$file") ((p++)) else echo "WARNING: Missing input include: \"$file\"." echo "File will NOT be included!" fi done continue ;; -o) ((i++)) output="${args[$i]}" ;; esac ((i++)) done echo "Input binaries: ${inputs[*]}" echo "Include files: ${includes[*]}" echo "Source files: ${sources[*]}" echo "Output binary: $output" if [[ "$output" == "" ]]; then echo "Missing output file!" exit 1 fi function add() { echo "$@" >> "$output" } function add_nn() { echo -n "$@" >> "$output" } rm -rf "$output" # Now to construct the binary # >>> Section 1, includes add "#!/usr/bin/env bash" add "# Multi-call binary generated by LACKADAISICAL binbox" add "# $output information:" add "# Contained modules: ${inputs[*]}" add "# Files included verbatim: ${includes[*]}" add "# Files sourced: ${sources[*]}" add "# Symlink to this binary with the module name to invoke it, or" add "# use '$output ' to do the same." for f in "${sources[@]}"; do add ". $f" done for f in "${includes[@]}"; do add "" add "# Included file $f" add "$(cat "$f")" done add "readarray -t all_funcs < <(declare -F | awk '{print \$3}')" # >>> Section 2: Modules for f in "${inputs[@]}"; do add "# Module '$f':" add "function $f()" add "{" add "$(cat "$f" | grep -v "#!")" add "}" done # >>> Section 3: Module selection add "" add "################################################################################" add "# END OF INCLUDED MODULES ######################################################" add "################################################################################" add "" add "# Array of modules as well as array of functions." # Add a static list of modules with a no-newline add add_nn "modules=(" for f in "${inputs[@]}"; do add_nn "\"$f\" " done add ")" add 'mapfile -t funcs < <(printf "%s\n" "${all_funcs[@]}" "${modules[@]}" "${modules[@]}" | sort | uniq -u)' add "" add "# Check the export switches (-m and -f)" add "" add "symed=1" add "binself=\$(basename \$0)" add "boxfile=\"$(basename $output)\"" add "" add "if [[ \$binself == \$boxfile ]]; then" add " symed=0" add " if [[ \$# -eq 0 ]]; then" add " echo '$(basename $output): Multi-call binary generated by lackadaisical binbox.'" add " echo 'Use switch \"-m\" to generate symlinks of modules in the current directory,'" add " echo 'or use switch \"-f\" to generate symlinks of all available functions.'" add " echo ''" add " echo 'Exported modules:'" add " for mod in \"\${modules[@]}\"; do" add " echo \"- \$mod\"" add " done" add " echo ''" add " echo 'Other functions:'" add " for func in \"\${funcs[@]}\"; do" add " echo \"- \$func\"" add " done" add " exit 0" add " fi" add "fi" add "" add "if [[ \$symed -eq 0 ]]; then" add " eval \$@" add " exit \$?" add "fi" add "" add "if [[ \$symed -eq 1 ]]; then" add " eval \$(basename \$0) \$@" add "fi" chmod +x "$output"