Build the rsync command as an argument list
The rsync command was built as a string and split with shlex.split, so paths containing quotes broke it, and the key file path in the -e command was split on spaces. Pass each path as its own argument, and quote the key file and user name inside the -e command, which rsync splits itself.
This commit is contained in:
@@ -552,24 +552,27 @@ class Backup:
|
||||
|
||||
logger.info('Copying files. This may take a long time...')
|
||||
|
||||
if self._last_backup == '':
|
||||
rsync = f'/usr/bin/rsync {self.options} --exclude-from={self._exclude_path} ' +\
|
||||
f'--files-from={self._inputs_path} / "{self._server}{self._output_dir}"'
|
||||
else:
|
||||
rsync = f'/usr/bin/rsync {self.options} --link-dest="{self._last_backup}" --exclude-from=' +\
|
||||
f'{self._exclude_path} --files-from={self._inputs_path} / "{self._server}{self._output_dir}"'
|
||||
# Build the argument list directly, so paths with spaces or quotes are passed unchanged
|
||||
args = ['/usr/bin/rsync', *self.options.split()]
|
||||
|
||||
if self._last_backup != '':
|
||||
args.append(f'--link-dest={self._last_backup}')
|
||||
|
||||
args.extend([f'--exclude-from={self._exclude_path}', f'--files-from={self._inputs_path}',
|
||||
'/', f'{self._server}{self._output_dir}'])
|
||||
|
||||
# rsync splits the -e command itself, so quote the parts that may contain spaces
|
||||
if self.ssh_keyfile is not None:
|
||||
rsync = f'{rsync} -e \'ssh -i {self.ssh_keyfile} -o StrictHostKeyChecking=accept-new\''
|
||||
ssh = f'ssh -i {shlex.quote(self.ssh_keyfile)} -o StrictHostKeyChecking=accept-new'
|
||||
elif self._password_auth and which('sshpass'):
|
||||
rsync = f'{rsync} -e \'sshpass -e ssh -l {self.ssh_user} -o StrictHostKeyChecking=accept-new\''
|
||||
ssh = f'sshpass -e ssh -l {shlex.quote(self.ssh_user)} -o StrictHostKeyChecking=accept-new'
|
||||
else:
|
||||
rsync = f'{rsync} -e \'ssh -o StrictHostKeyChecking=accept-new\''
|
||||
ssh = 'ssh -o StrictHostKeyChecking=accept-new'
|
||||
|
||||
args.extend(['-e', ssh])
|
||||
|
||||
if self._remote and self.remote_sudo:
|
||||
rsync = f'{rsync} --rsync-path="sudo rsync"'
|
||||
|
||||
args = shlex.split(rsync)
|
||||
args.append('--rsync-path=sudo rsync')
|
||||
|
||||
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=STDOUT, shell=False) as p:
|
||||
output: Union[bytes, List[str]]
|
||||
|
||||
Reference in New Issue
Block a user