Trying to make a directory from systemd results in a 127 error code

I have the following code:

{
    systemd.user.services.syncdir-setup = {
        Unit = {
            Description = "set up sycDir directory";
        };
        Install = {
            WantedBy = [ "default.target" ];
        };
        Service = {
            ExecStart = "${pkgs.writeShellScript "syncdir-setup" ''
                mkdir -p /home/dob/test_folder
            ''}";
        };
    };
}

However, this results with status failed, (code=exited, status=127). It seems like (search) status code 127 is thrown when something is not executable, or not found. When I change the mkdir command to a simple echo, the service runs without any issue. Hence, it looks like there is some permission issue preventing the service to create a directory.

Has anyone any input on what is required for a service to create directories?

I’m not sure if that is needed for mkdir, but you could try replacing mkdir with the more explicit ${coreutils}/bin/mkdir.

However, I believe the recommended way to create such folders is using systemd-tmpfiles. I think the name is not the best, but it can be used for exactly that, ensure that a folder is created.

You probably want to add a rule like so:

systemd.tmpfiles.rules = [
  "d /home/dob/test_folder 755 root root"
];

Adjust permissions to your liking.

2 Likes

Wonderful. Thank you. That is the way to go. That tmpfiles name did throw my off, but it seems to stick.

However, I have one challenge left. I still need to run mount. This needs to be done as root. So, updated the service to:

Service = {
  User = "root";
  Group = "root";
  ExecStart = "${pkgs.writeShellScript "syncdir-setup" ''
    mount -o bind --source /home/dob/syncDir --target /home/dob/nextcloud/syncDir
  ''}";
};

Note: I have tried with {coreutils}/bin/mount as well.

This failed with “Changing group credentials failed: Operation not permitted”. I have seen this related post, but I do not see what I am missing.

Or, is there a better way to do mounts as well?

UPDATE:

I just discovered systemd.user.mounts, so I will investigate that!

1 Like

Yes, you don’t want to call mount directly, but use mount units. And systemd.mounts is the NixOS way to configure them.

That way, you can also declare dependencies for your unit (in your case, something like RequiresMountsFor=/home/dob/syncDir) so the mounts will run in the correct order.

1 Like

Hi,

for the record mount isn’t included in coreutils but in util-linux

1 Like

Thanks for the heads up. How can I see what utility a package is part of?

Great to hear!

1: NOTHING IS MOUNTED - IS THERE A LOG?

I have been fiddling around with this, trying to achieve a mount. The system builds, but the mount is never actually done. Below is what I have written (info from the manual on What = and Where =). Is there a log somewhere to see some output from systemd trying to do the mount? I did look in /etc/systemd/system to see if I could find traces of a .mount file (as described here). I assume that no .mount file for my mount was found due to the mount failing.

    systemd.user.mounts = {
        syncDir = {
            Unit = {
                Description = "Example description";
            };

            Mount = {
                What = "/home/dob/nextcloud/syncDir";
                Where = "/home/dob/syncDir";
            };
        };
    };

Note, I also saw in the issue in home-manager for supporting mount units that Type = "fuse.bindfs"; was used. Not sure if that is the reason for my mount not working. However, I would love to check some log files, to see what is written there.

NOTE:
I tried looking for errors using journalctl -u syncDir and journalctl --since "1 hour ago", with no luck. I can not see any entries for a failed mount.


2: REQUIRESMOUNTSFOR - SEEMS NIFTY!

I am new to mounting, but I found some info on RequiresMountsFor:

Takes a space-separated list of absolute paths. Automatically adds dependencies of type Requires= and After= for all mount units required to access the specified path.

And, I found a page on mounting the file system in a certain order. So, I guess that means that if I have multiple mounts, I can add RequiresMountsFor = "/home/dob/syncDir"; in the Unit section, for the mounts to depend on this one. Seems nifty.

I don’t know if there is a nixos way do get this information. I usually look at the package content on archlinux.org

https://archlinux.org/packages/core/x86_64/coreutils/
https://archlinux.org/packages/core/x86_64/util-linux/

1 Like

I think there is no systemd.user.mounts but only systemd.mounts. So your settings will just have no effect.

Also, in order to find which package a file is part of, there’s a few methods:

  1. If you have the program installed and available in your shell, you can just use something like realpath $(which mkdir) which will give you: /nix/store/ab5hdxr437ng76bayc5r3crfwm3yds9r-coreutils-full-9.3/bin/coreutils. It says coreutils at the end because all these commands are just symlinks to coreutils. But the important part is the package name directly after the hash.

  2. I like to use nix-locate which allows to search through the contents of all of nixpkgs. I recommend to use it together with the nix-index-database since building the index takes forever otherwise.

2 Likes

Thanks for listing a few ways to find that information.


I use home-manager, so that is why I use systemd.user.mounts instead of just systemd.mounts. The option can be viewed here. It should be defined and work the same way as systemd.mounts.

However, for clarity, as my initial question is solved, I will create a new topic for the mounting problem I am having.

The mounting problem conversation is moved to: