0

I am developing a backup python program, one of the modules makes a rsync backup of a remote folder into my local device.

This is the part of the code where I have the problem:

            try:
                process = subprocess.Popen(
                    ['sshpass',
                    '-p',
                    password,
                    'rsync',
                    '-avz',
                    '-e',
                    'ssh -o StrictHostKeyChecking=no',
                    '-p',
                    port,
                    '{}@{}:{}'.format(user, host, folder),
                    dest_folder],
                    stdout=subprocess.PIPE
                )
                output = process.communicate()[0]
                if int(process.returncode) != 0:
                    print('Command failed. Return code : {}'.format(process.returncode))
                    exit(1)
                return output
            except Exception as e:
                print(e)
                exit(1)

The shown error is:

Unexpected remote arg: debian@12.345.67.89:/folder1/folder2/
rsync error: syntax or usage error (code 1) at main.c(1372) [sender=3.1.3]
Command failed. Return code : 1

I believe that the problem is with the array in Popen. If I run the single command in bash I rsync successfully.

What should I change from subprocess.Popen array?

  • Maybe you shouldn't use subprocess. You could use something like spur. – xilpex Apr 09 '20 at 02:10
  • That error means rsync is seeing more than two arguments parse as filenames. – Charles Duffy Apr 09 '20 at 03:27
  • Using `-e` and `-p` together doesn't make sense. Use `'-e', 'ssh -o Port={port} -o StringHostKeyChecking=no'.format(port=port)` – Charles Duffy Apr 09 '20 at 03:28
  • Beyond that, it'd be good to verify that `dest_folder` looks like a folder to rsync. Among other things, that means it can't contain a `:`. – Charles Duffy Apr 09 '20 at 03:29
  • Anyhow -- if you want to compare against a working command line, the first place to start is generating a command line that's a 100% match for your array. In this case, I'd suggest logging (and including in the question) `print(' '.join(shlex.quote(arg) for arg in argument_list))`, and the result of running same as a shell command,where `argument_list` is the list you're passing to `subprocess.Popen`. – Charles Duffy Apr 09 '20 at 03:32
  • @Xilpex, `subprocess` with `shell=False` just invokes the operating system's `execve()` interface. That's the same thing a shell calls after it parsed an external command, forked a subprocess for it, performed redirections and is ready to let the external command take over control. Thus, if something can't be made to work with `subprocess`, it can't be made to work at all. – Charles Duffy Apr 09 '20 at 03:33

1 Answers1

1

This is caused by -p flag being consumed by rsync rather than ssh, and as such the destination effectively is set to port.

The -e argument of rsync takes exactly one parameter. That means that only 'ssh -o StrictHostKeyChecking=no' will be passed as an argument. Unluckily for you, -p is an actual flag of rsync, and as such it's processed without error. It means 'preserve permissions'. This means that rather than setting port to use with ssh, you're passing a flag to rsync, and the next parameter gets interpreted as a destination.

You can fix it by changing

 'ssh -o StrictHostKeyChecking=no',
 '-p',
 port,

to simply

 'ssh -o StrictHostKeyChecking=no -p {}'.format(port),
Shumatsu
  • 150
  • 9