1

I'm trying to execute a .sh script from within a .Net Core service daemon and getting weird behavior. The purpose of the script is to create an encrypted container, format it, set some settings, then mount it.

I'm using .Net Core version 3.1.4 on Raspbian on a Raspberry Pi 4.

The problem: I have the below script which creates the container, formats it, sets the settings, then attempts to mount it. It all seems to work fine but the last command, mount call, never actually works. The mount point is not valid.

The kicker: After the script is run via the service, if I open a terminal and issue the mount command there manully, it mounts correctly. I can then goto that mount point and it shows ~10GB of space available meaning it's using the container.

Note: Make sure the script is chmod +x when testing. Also you'll need cryptsetup installed to work.

Thoughts:

I'm not sure if some environment or PATH variables are missing for the shell script to properly function. Since this is a service, I can edit the Unit to include this information, if I knew what it was.

In previous attempts at issuing bash commands, I've had to set the DISPLAY variable like below for it to work correctly (because of needing to work with the desktop). For this issue that doesn't seem to matter but if I need to set the script as executable, then this command is uses as an example

string chmodArgs = string.Format("DISPLAY=:0.0; export DISPLAY && chmod +x {0}", scriptPath);
chmodArgs = string.Format("-c \"{0}\"", chmodArgs);

I'd like to see if someone can take the below and test on their end to confirm and possibly help come up with a solution. Thanks!

#!/bin/bash

#       variables
#       s0f4e7n4r4h8x4j4
#       /usr/sbin/content1
#       content1
#       /mnt/content1
#       10240

#       change the size of M to what the size of container should be
echo "Allocating 10240MB..."
fallocate -l 10240M /usr/sbin/content1
sleep 1

#       using echo with -n passes in the password required for cryptsetup command.  The dash at the end tells cryptsetup to read in from console
echo "Formatting..."
echo -n s0f4e7n4r4h8x4j4 | cryptsetup luksFormat /usr/sbin/content1 - 
sleep 1

echo "Opening..."
echo -n s0f4e7n4r4h8x4j4 | cryptsetup luksOpen /usr/sbin/content1 content1 - 
sleep 1

#       create without journaling
echo "Creating filesystem..."
mkfs.ext4 -O ^has_journal /dev/mapper/content1
sleep 1

#       enable writeback mode
echo "Tuning..."
tune2fs -o journal_data_writeback /dev/mapper/content1
sleep 1

if [ ! -d "/mnt/content1" ]; then
  echo "Creating directory..."
  mkdir -p /mnt/content1
  sleep 1
fi

#       mount with no access time to stop unnecessary writes to disk for just access
echo "Mounting..."
mount /dev/mapper/content1 /mnt/content1 -o noatime
sleep 1

This is how I'm executing the script in .Net

var proc = new System.Diagnostics.Process {
    StartInfo =
        {
            FileName = pathToScript,
            WorkingDirectory = workingDir,
            Arguments = args,
            UseShellExecute = false
        }
};

if (proc.Start())
{
    while (!proc.HasExited)
    {
        System.Threading.Thread.Sleep(33);
    }
}

The Unit file use for service daemon

[Unit]
Description=Service name

[Service]
ExecStart=/bin/bash -c 'PATH=/sbin/dotnet:$PATH exec dotnet myservice.dll'
WorkingDirectory=/sbin/myservice/
User=root
Group=root
Restart=on-failure
SyslogIdentifier=my-service
PrivateTmp=true

[Install]
WantedBy=multi-user.target
ScottN
  • 1,490
  • 2
  • 20
  • 34

1 Answers1

0

The problem was not being able to run the mount command from within a service directly. From extensive trial and error, even printing verbose of the mount command would show that there was NO errors and it would NOT be mounted. Very misleading to not provide some failure message for users.

Solution is to create a Unit file "service" to handle the mount/umount. Below explains with a link to the inspiring article that brought me here.

Step 1: Create the Unit File

The key is the .mount file needs to be named in a pattern that matches the Where= in the Unit file. So if you're mounting /mnt/content1, your file would be:

sudo nano /etc/systemd/system/mnt-content1.mount

Here is the Unit file details I used.

[Unit]
Description=Mount Content (/mnt/content1)
DefaultDependencies=no
Conflicts=umount.target
Before=local-fs.target umount.target
After=swap.target

[Mount]
What=/dev/mapper/content1
Where=/mnt/content1
Type=ext4
Options=noatime

[Install]
WantedBy=multi-user.target

Step 2: Reload systemctl

systemctl daemon-reload

Final steps:

You can now issue start/stop on the new "service" that is dedicated just to mount and unmount. This will not auto mount on reboot, if you need that you'll need to enable the service to do such.

systemctl start mnt-content1.mount
systemctl stop mnt-content1.mount

Article: https://www.golinuxcloud.com/mount-filesystem-without-fstab-systemd-rhel-8/

ScottN
  • 1,490
  • 2
  • 20
  • 34