Packaging a debian application which outputs logs to a child directory of its binary's path

Hello all,

I have been trying to package Splashtop (a remote desktop application) and have almost got it working.

The application is proving quite annoying to package because it generates logging information in a directory which is a level deeper than its binary. For example:

            \__ app-binary
            \__ log
                  \__  Foo.log

When the application is run, it starts writing to the Foo.log file which it will not be able to do because /nix/store is a RO path. Annoyingly, the application doesn’t provide me with a way to define the output path for its logs.

I have attempted to make this work using the buildFHSUserEnv and it almost works if I simply initialise the env using flake.nix and then manually run the binary from a writable location as a nasty workaround but a proper solution would be really helpful.

Would anyone be able to give me any suggestions or hints as to how I can achieve this?


Have you tried making log a symlink to some directory you can assume is always there such as /var/tmp/?

I’d also recommend you make an upstream bug report. The app should not log relative to its binary, that’s never sane.

Riffing on this: what about ln -s log/Foo.log /dev/stdout :smiling_imp:

1 Like

After you’ve found a solution it would be helpful to update Packaging / Binaries / Wrong file paths which doesn’t yet cover this scenario.

Thanks for the suggestions folks! @Atemu I did try something slightly similar however not what you suggested. How would you work around the Permission Denied errors though?
I am not able to create any directories/files in /var . I managed to create a directory in /tmp and link that but I think that path is invalid at runtime.

Following is what my flake.nix looks like. Please bear with me, I am still very much a nix noob :slight_smile:

If anyone has any suggestions or improvements (in addition to a solution :smiley: ) please let me know!

  description = "";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = {
    flake-utils.lib.eachSystem ["x86_64-linux" "aarch64-linux"] (system:
      with nixpkgs.legacyPackages.${system}; let
        pkg_name = "splashtop-business";
        pkg_version = "";
        pkgs = nixpkgs.legacyPackages.${system};
        splashtop-unwrapped = pkgs.stdenv.mkDerivation {
          pname = pkg_name;
          version = pkg_version;

          nativeBuildInputs = [dpkg];

          src = pkgs.fetchzip {
            url = "${pkg_name}_Ubuntu_v${pkg_version}_amd64.tar.gz";
            sha256 = "YiwhsgtzeIR4RPs9pK4tnf2jj7vAA7P5tz7xHGEkPcs=";
            stripRoot = false;

          dontBuild = true;
          dontConfigure = true;
          dontFixup = true;

          installPhase = ''
            mkdir $out
            dpkg -x ${pkg_name}_Ubuntu_amd64.deb $out/
            mkdir -p /tmp/${pkg_name}/log
            touch /tmp/${pkg_name}/log/${pkg_name}.log
            mkdir -p $out/opt/${pkg_name}
            ln -s /tmp/${pkg_name}/log $out/opt/${pkg_name}/log
      in {
        formatter = pkgs.alejandra;
        packages = {
          default = pkgs.buildFHSUserEnv {
            name = pkg_name;
            targetPkgs = pkgs: (
              with pkgs;
                ++ (with libsForQt5; [

            passthru = {
              inherit splashtop-unwrapped;

            # runScript = "bash";
            runScript = "${bash}/bin/bash ${
              writeText "splashtop-wrapper"

Hmm…not sure how I feel about this :smiley:

However, did try it out of curiosity/frustration but how does this also circumvent the Permission Denied or File Exists error?

You’d use /var/tmp/ as I suggested which is publicly writable. In the ideal case, the app would then create the log file at /var/tmp/Foo.log through the symlink. Not certain that actually works but that’s the theory at least.

You could wrap the executable using makeWrapper to create the directory/file whenever the application is ran.

I’d rather try @bme’s suggestion though, you probably want stdout logging anyways.

So did it work? What are you asking? Every process has a fd for stdout. That fd is exposed by /proc/$pid/fd/1. /proc/self/ is a special entry in the proc file system accessible by any process to see it’s own entry in procfs. /dev/stdout is just a symlink into that.

❯ ls -la /dev/stdout 
lrwxrwxrwx 1 root root 15 Jan 13 09:56 /dev/stdout -> /proc/self/fd/1

So hopefully the solution that I am proposing is obvious: symlink any stupid log files this program wants to create to /dev/stdout which always exists for every process and you are golden.

Stupid demo:

~                                                                                                20:45:3
❯ ln -s /dev/stdout log

~                                                                                                20:45:3
❯ echo beep >log

Thanks, yes it actually works :smiley:

I was doing it incorrectly the first time around and decided to simply copy the binary in a tmp directory and execute it from there which worked. I did not really like it though.

The second time around I read your comment again and realised I had done what you suggested incorrectly :sweat_smile:

Today has been quite productive thanks for all your suggestions!

1 Like

I had a brief look at this as I use splashtop to help out immediate family and it’s extremely concerning to say the least.

The fact that splashtop makes these kinds of fundamental mistakes in addition to the included script which uses a fixed location under /tmp and helpfully recommends running as root makes me question all their other engineering practices.

I guess I need to look for an alternative now.

1 Like