resticprofile icon indicating copy to clipboard operation
resticprofile copied to clipboard

Source & stdin-from-command: true does not play well together

Open qraynaud opened this issue 6 months ago β€’ 4 comments

I tried the following:

profiles:
  test:
    backup:
      source:
        - sh
        - -c
        - echo toto
      stdin-from-command: true

And when executing resticprofile backup@test I get the following logs:

2025/06/30 10:00:11 using configuration file: profiles.yaml
2025/06/30 10:00:11 profile 'test': initializing repository (if not existing)
2025/06/30 10:00:11 profile 'test': starting 'backup'
repository 041b0f7f opened (version 2, compression level auto)
using parent snapshot aa77c642
[0:00] 100.00%  2 / 2 index files loaded
subprocess sh: sh: can't open './-c': No such file or directory
error: failed to save /stdin: Fatal: command failed: exit status 2
Fatal: unable to save snapshot: failed to save /stdin: Fatal: command failed: exit status 2
2025/06/30 10:00:12 backup on profile 'test': exit status 1

It seems like -c is replaced by ./-c and thus that source is interpreted as containing paths even when this flag is set to true. Setting stdin-from-command should prevent any path resolving on source.

qraynaud avatar Jun 30 '25 08:06 qraynaud

I think it might not be explained in the documentation, but the way you use this flag is like that instead:

profiles:
  test:
    backup:
      stdin-from-command: "sh -c echo toto"

creativeprojects avatar Jun 30 '25 17:06 creativeprojects

Are you not confusing it with stdin-command? This is the one I’m using right now but I would prefer the syntax I gave because it’s cleanier for complex commands like docker exec or sh -c since you don’t have to play with escaping as much.

The documentation clearly states that stdin-from-command is a boolean (which corresponds to the equivalent restic flag): | stdin-from-command | true / false | false | interpret arguments as command to execute and store its stdout. restic >= 0.17.0 |

I think:

profiles:
  test:
    backup:
      stdin-command: "sh -c 'echo toto'"

Produces:

sh -c 'echo toto' | restic backup --stdin

While:

profiles:
  test:
    backup:
      source:
        - sh
        - -c
        - echo toto
      stdin-from-command: true

Should produce:

restic backup --stdin-from-command -- sh -c 'echo toto'

Am I wrong?

qraynaud avatar Jul 01 '25 14:07 qraynaud

Are you not confusing it with stdin-command?

My apologies, I totally mixed up both commands. My brain is non-functional after work these days πŸ˜†

Your idea is interesting. It simply doesn't work because the option wasn't available at the time the configuration file was designed πŸ˜›

The other issue here (that you don't really see) is that restic is already called via sh -c (to allow for * completion the exact same way as executing the command line in a shell) which makes character escaping very complicated 😒

I'll have a look at it though πŸ‘πŸ»

creativeprojects avatar Jul 04 '25 19:07 creativeprojects

After thinking even more about this, I think that maybe you could just bypass everything you coded now for handling source when stdin-from-command is true (so just give every argument "as is") in this case. I think that would work nicely since a glob in there would be given to the command. You could add to the documentation that globs can only be used with explicits sh -c or "identical" commands.

That would allow you to either drop the sh -c call to invoke restic or to simply escape every argument so that sh -c does not interpret any (whichever is the easier solution).

qraynaud avatar Aug 03 '25 14:08 qraynaud