[howto] call dietpi-sync 1 without user interaction

Hi,
so I setup dietpi-sync.
I want to run this from my own cronjob / script (so not the dietpi build0in daily).

In my cronjob I call /boot/dietpi/dietpi-sync 1

but Although the documentation tells me this is what is needed to run it from a script, what happens is that it is interactive: it starts with a dry-run and then prompts me (read the script) to either sync, display the log or cancel. Same for dietpi-backup.

What is additionally needed is to add the following to the top of your cronjob script that calls the sync / backup:
export G_INTERACTIVE=0

Not sure if this is a bug?
if not, think this is best documented, but for anybody looking for a solution here it is :slight_smile:

I guess something @MichaIng could help with

Did you see this when it was actually called by cron, or when you manually executed the script for testing reasons? cron runs commands without any STDIN attached (by default), in which case G_INTERACTIVE=0 is redundant. But when you execute the same script from console, there is (obviously) some STDIN, in which case dialogs are shown.

This is when running the script NOT from the cron (so in my case for testing purposes). Just tested it via cron and then there is no user interaction.

This means that the dietpi-sync script behaves differently when run from the command line / scripted or from a cron script.

IMO this is not good and leads to confusion (as it did with me :))

If this is intended behavior, the the documentation should be adjusted, as it clearly states:

Scripted run

DietPi-Sync can be run from the command line or from scripts without user interaction by calling it via:
dietpi-sync 1

That is correct. Our scripts, respectively dietpi-globals automatically detects whether it executes within an interactive shell with a STDIN attached and sets G_INTERACTIVE accordingly to skip whiptail menus. This is needed to assure that exactly such hangs are ruled out.

If you want to test scripts for non-interactive environment, than indeed call them with preceding export G_INTERACTIVE=0. Don’t forgot to unset it again, otherwise you cannot call other scripts’ menus anymore :wink:.

But you are right, the docs are not correct. We made the space check in dietpi-backup optional. I think we should do it similarly in dietpi-sync:

  • Make dry run a dedicated menu entry to run a dry run only and test settings that way.
  • Make free space check (which includes a dry run) an option (disabled by default) for the real sync, which then only prompts in interactive environment if the free space check fails.
  • Align with dietpi-backup, i.e. add a dedicated dry run option to dietpi-backup as well.

Fixed for now with: v8.15 · MichaIng/DietPi@4504a93 · GitHub
What I wrote above still makes sense, but is more work.

It was even stranger: With input 1, in case of insufficient free space, the prompt was not shown but the error logged to the log file and the script exited. If the test succeeded, the prompt was shown, but when you selected “Cancel” or hit “ESC”, the sync ran regardless. I think the intention was that the menu is indeed skipped, so now it behaves like that

Yes, I noticed that to and was about to write a ‘bug’ report for this. As I am new to DietPi it takes some more time to investigate if it is indeed a bug or intended behavior :slight_smile:

Will test your PR and report back

@MichaIng
so here are the test results for your pr:

  1. OK: running dietpi-sync and press cancel after dry-run now correctly cancels the sync
  2. NOT OK: Running dietpi-sync 1 still has 2 user interactions that stop the script: 1 > after sync it prompts with an ‘OK’ and after that it 2. prompts with the log file + OK

So not completely successful :slight_smile:

I’m still thinking if we want it like that. In all other cases, the CLI arguments never enable non-interactive runs. Error prompts are still shown, and other prompts possibly as well, depending a little on whether they are embedded within menu selections or not. For consistency, it is correct the way it is: The argument means to skip the menu and do the sync right away (the real sync, not the dry run), in systemd/cron/etc non-interactive environments, this is detected automatically to assure whiptail prompts will never happend in such cases, but to have the same on console, you must export G_INTERACTIVE=1.

Also for testing things, this is not bad, since you have an error handler with details and options to investigate if your run into an error. And also checking the results it would one would probably like to do anyway when testing the sync.

We could refine the docs in this regards, making clear that dietpi-sync 1 just forces the sync, and that /boot/boot/dietpi-sync 1 can be used in cron jobs and systemd units where they are assured to not prompt any whiptail. Not sure yet how/where to document G_INTERACTIVE best. Probably a shared section to link from those individual tool’s sections, which are commonly used in cron jobs etc.

Hi all
Got myself in a similiar situation which i think i need to call dietpi-sync from within a script + cron job. Want to sync /mnt/drive1 fully with /mnt/drive2, althought dietpi_userdata was moved to drive1.

#!/bin/bash

FP_SOURCE='/mnt/drive1'
FP_TARGET='/mnt/drive2'
SYNC_DELETE_MODE=0
SYNC_CRONDAILY=0
SETTINGS_FILE="/boot/dietpi/.dietpi-sync_settings"
SERVICES_TO_STOP=('docker' 'syncthing')

stop_services() {
    for service in "${SERVICES_TO_STOP[@]}"; do
        sudo systemctl stop "$service"
        if [ $? -ne 0 ]; then
            echo "Failed to stop $service. Please check the service name and try again."
            exit 1
        fi
    done
}

start_services() {
    for service in "${SERVICES_TO_STOP[@]}"; do
        sudo systemctl start "$service"
        if [ $? -ne 0 ]; then
            echo "Failed to start $service. Please check the service name and try again."
            # Consider adding more error handling here.
        fi
    done
}

write_setting_file(){
    sudo bash -c "cat > $SETTINGS_FILE << EOF
FP_SOURCE='$FP_SOURCE'
FP_TARGET='$FP_TARGET'
SYNC_DELETE_MODE=$SYNC_DELETE_MODE
SYNC_CRONDAILY=$SYNC_CRONDAILY
EOF"

    sudo chmod 755 "$SETTINGS_FILE"
}

#stop_services
sudo /boot/dietpi/dietpi-services stop

write_setting_file

sudo /boot/dietpi/dietpi-sync 1

#start_services
sudo /boot/dietpi/dietpi-services start

am i forgetting something here ?
thanks in advance :slight_smile:

Hi not sure as to what issue you are facing, but in my script that I start from the daily cron I have the following export in the top of the script:
export G_INTERACTIVE=0

and I run the sync like this:
/boot/dietpi/dietpi-sync 1 > /dev/null

Been running that for more then a yea now without issues.
Hope this helps.

Jap that’s the way

added the export bit aswell as the redirect output but still hangs and needs a keyboard input to proceed

the log output

   2024-02-15_05:07:50 [FAILED] Rsync is already running and failed to stop gracefully

although when calling the same conditions as the dietpi-sync sudo systemctl -q is-active rsync and pgrep '[r]sync', they return none.

that sounds like a concurrent sessions :thinking:

what do you mean by that ? an clue how can i forward inspect the error ?

as i dont understand how can the script fall into the condition if no rsync process is running

found the error
the script name had the ‘rsync’ string in its name
the dietpi-sync condition could upgrade to something like this to exclude the script process itself in those cases

pgrep -x 'rsync' | grep -v "$0" &> /dev/null;
1 Like

Indeed -x just makes sense. The grep pipe is not required since pgrep throws exit code 1 if there was no match. Could you open a PR for this change on GitHub? I fear I forget it before I am home until release later tonight :sweat_smile:.

done :slight_smile:

1 Like

Many thanks! Same change done to dietpi-backup and merged.

EDIT: I just now re-read and understood the purpose of the grep in your example above. It would require to check for the $PPID (parent shell/script process ID) instead, since pgrep prints the PIDs of matching processes, instead of their names. But I think it should be fine when checking for the exact match via -x only, since likely/hopefully no one calls its script exactly rsync.

1 Like