creative packaging in nixpkgs

21 jun 2015

saleae logic analyzer

just discovered an interesting hack for the logic analyzer [1] software worth sharing! this is about tricking proprietary software:

theory: if programmers don’t understand the concept of storing files in $HOME but instead depend on writing data to the same directory as the binary is in, you are basically doomed on pretty much every linux distribution, as this cannot be packaged by definition. in such situation you can only copy the whole program into your $HOME or some place else you have write permissions on.

the situation on nixos is even worse, since deploying proprietary software requires you to use nix by altering the interpreter and RPATH of the binary and also installing it into the read only nix-store. using patchelf as i’ve done in the FTL posting [4] is hacky, complicated and brings stateful breakages on updates as the dependencies are not seen by the nix garbage collector.

however, Bjørn Forsman made a very cool hack:

  1. first he patch the software, see [2]:

    # Patch it
    patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/Logic"
    patchelf --set-rpath "${stdenv.cc.cc}/lib:${stdenv.cc.cc}/lib64:${libPath}:\$ORIGIN/Analyzers:\$ORIGIN" "$out/Logic"
  2. then a prepares a shared library:

    gcc -shared -fPIC -DOUT=\"$out\" "${./preload.c}" -o "$out/lib/preload.so" -ldl
  3. finally he creates a wrapper script:

    # Make wrapper script that uses the LD_PRELOAD library
    mkdir -p "$out/bin"
    cat > "$out/bin/saleae-logic" << EOF
    #!${stdenv.shell}
    export LD_PRELOAD="$out/lib/preload.so"
    exec "$out/Logic" "\$@"
    EOF
    chmod a+x "$out"/bin/saleae-logic
  4. the wrapper [3] basically filters fopen and fopen64:

    FILE *fopen(const char *pathname, const char *mode) {...}
    FILE *fopen64(const char *pathname, const char *mode) {...}
  5. and finally replaces ‘/Settings/settings.xml’ with ‘%s/.saleae-logic-settings.xml’ when it is in the stream!

    new_path = pathname;
    if (strcmp(OUT "/Settings/settings.xml", pathname) == 0) {
        snprintf(buffer, PATH_MAX, "%s/.saleae-logic-settings.xml", homepath);
        buffer[PATH_MAX-1] = '\0';
        new_path = buffer;
    }

this is just amazing!

article source