diff options
| -rwxr-xr-x | hosts/vidhar/borg/copy.py | 68 |
1 files changed, 37 insertions, 31 deletions
diff --git a/hosts/vidhar/borg/copy.py b/hosts/vidhar/borg/copy.py index df77e4bb..d4edb09d 100755 --- a/hosts/vidhar/borg/copy.py +++ b/hosts/vidhar/borg/copy.py | |||
| @@ -45,17 +45,10 @@ halo_args = { | |||
| 45 | 45 | ||
| 46 | borg_pwd = getpwnam('borg') | 46 | borg_pwd = getpwnam('borg') |
| 47 | 47 | ||
| 48 | def as_borg(caps=set(), withns=lambda: pass): | 48 | def as_borg(caps=set()): |
| 49 | if caps: | 49 | if caps: |
| 50 | for capset in [cap_permitted, cap_inheritable, cap_effective, cap_ambient]: | 50 | for capset in [cap_permitted, cap_inheritable, cap_effective, cap_ambient]: |
| 51 | capset.add(*caps) | 51 | capset.add(*caps) |
| 52 | |||
| 53 | unshare.unshare(unshare.CLONE_NEWNS) | ||
| 54 | subprocess.run(['mount', '--make-rprivate', '/'], check=True) | ||
| 55 | withns() | ||
| 56 | if os.environ.get('CREDENTIALS_DIRECTORY'): | ||
| 57 | creds_path = pathlib.Path(os.environ['CREDENTIALS_DIRECTORY']).relative_to('/') | ||
| 58 | subprocess.run(['bindfs', '-r', f'--force-user={borg_pwd.pw_uid}', f'--force-group={borg_pwd.pw_gid}', pathlib.Path('/') / creds_path, chroot / creds_path], check=True) | ||
| 59 | 52 | ||
| 60 | os.setgid(borg_pwd.pw_gid) | 53 | os.setgid(borg_pwd.pw_gid) |
| 61 | os.setuid(borg_pwd.pw_uid) | 54 | os.setuid(borg_pwd.pw_uid) |
| @@ -114,29 +107,32 @@ def copy_archive(src_repo_path, dst_repo_path, entry): | |||
| 114 | dir = pathlib.Path('/borg') | 107 | dir = pathlib.Path('/borg') |
| 115 | 108 | ||
| 116 | def preexec_fn(): | 109 | def preexec_fn(): |
| 117 | def withns(): | 110 | unshare.unshare(unshare.CLONE_NEWNS) |
| 118 | chroot = pathlib.Path(tmpdir) / 'chroot' | 111 | subprocess.run(['mount', '--make-rprivate', '/'], check=True) |
| 119 | upper = pathlib.Path(tmpdir) / 'upper' | 112 | chroot = pathlib.Path(tmpdir) / 'chroot' |
| 120 | work = pathlib.Path(tmpdir) / 'work' | 113 | upper = pathlib.Path(tmpdir) / 'upper' |
| 121 | for path in [chroot,upper,work]: | 114 | work = pathlib.Path(tmpdir) / 'work' |
| 122 | path.mkdir() | 115 | for path in [chroot,upper,work]: |
| 123 | subprocess.run(['mount', '-t', 'overlay', 'overlay', '-o', f'lowerdir=/,upperdir={upper},workdir={work}', chroot], check=True) | 116 | path.mkdir() |
| 124 | bindMounts = ['nix', 'run', 'proc', 'dev', 'sys', pathlib.Path(os.path.expanduser('~')).relative_to('/')] | 117 | subprocess.run(['mount', '-t', 'overlay', 'overlay', '-o', f'lowerdir=/,upperdir={upper},workdir={work}', chroot], check=True) |
| 125 | if os.environ.get('BORG_BASE_DIR'): | 118 | bindMounts = ['nix', 'run', 'proc', 'dev', 'sys', pathlib.Path(os.path.expanduser('~')).relative_to('/')] |
| 126 | bindMounts.append(pathlib.Path(os.environ['BORG_BASE_DIR']).relative_to('/')) | 119 | if os.environ.get('BORG_BASE_DIR'): |
| 127 | if not ":" in src_repo_path: | 120 | bindMounts.append(pathlib.Path(os.environ['BORG_BASE_DIR']).relative_to('/')) |
| 128 | bindMounts.append(pathlib.Path(src_repo_path).relative_to('/')) | 121 | if not ":" in src_repo_path: |
| 129 | if 'SSH_AUTH_SOCK' in os.environ: | 122 | bindMounts.append(pathlib.Path(src_repo_path).relative_to('/')) |
| 130 | bindMounts.append(pathlib.Path(os.environ['SSH_AUTH_SOCK']).parent.relative_to('/')) | 123 | if 'SSH_AUTH_SOCK' in os.environ: |
| 131 | for bindMount in bindMounts: | 124 | bindMounts.append(pathlib.Path(os.environ['SSH_AUTH_SOCK']).parent.relative_to('/')) |
| 132 | (chroot / bindMount).mkdir(parents=True,exist_ok=True) | 125 | if 'CREDENTIALS_DIRECTORY' in os.environ: |
| 133 | # print(*['mount', '--bind', pathlib.Path('/') / bindMount, chroot / bindMount], file=stderr) | 126 | bindMounts.append(pathlib.Path(os.environ['CREDENTIALS_DIRECTORY']).parent.relative_to('/')) |
| 134 | subprocess.run(['mount', '--bind', pathlib.Path('/') / bindMount, chroot / bindMount], check=True) | 127 | for bindMount in bindMounts: |
| 135 | os.chroot(chroot) | 128 | (chroot / bindMount).mkdir(parents=True,exist_ok=True) |
| 136 | os.chdir('/') | 129 | # print(*['mount', '--bind', pathlib.Path('/') / bindMount, chroot / bindMount], file=stderr) |
| 137 | dir.mkdir(parents=True,exist_ok=True,mode=750) | 130 | subprocess.run(['mount', '--bind', pathlib.Path('/') / bindMount, chroot / bindMount], check=True) |
| 138 | os.chown(dir, borg_pwd.pw_uid, borg_pwd.pw_gid) | 131 | os.chroot(chroot) |
| 139 | as_borg(withns=withns, caps={Cap.DAC_READ_SEARCH}) | 132 | os.chdir('/') |
| 133 | dir.mkdir(parents=True,exist_ok=True,mode=750) | ||
| 134 | os.chown(dir, borg_pwd.pw_uid, borg_pwd.pw_gid) | ||
| 135 | as_borg(caps={Cap.DAC_READ_SEARCH}) | ||
| 140 | 136 | ||
| 141 | total_size = None | 137 | total_size = None |
| 142 | total_files = None | 138 | total_files = None |
| @@ -245,6 +241,16 @@ def sigterm(signum, frame): | |||
| 245 | 241 | ||
| 246 | def main(): | 242 | def main(): |
| 247 | signal.signal(signal.SIGTERM, sigterm) | 243 | signal.signal(signal.SIGTERM, sigterm) |
| 244 | |||
| 245 | if 'CREDENTIALS_DIRECTORY' in os.environ: | ||
| 246 | for root, dirs, files in os.walk(os.environ['CREDENTIALS_DIRECTORY']): | ||
| 247 | def do_chown(path): | ||
| 248 | os.chown(pathlib.Path(root) / pathlib.Path(path), borg_pwd.pw_uid, borg_pwd.pw_gid) | ||
| 249 | |||
| 250 | for dir in dirs: | ||
| 251 | do_chown(dir) | ||
| 252 | for file in files: | ||
| 253 | do_chown(file) | ||
| 248 | 254 | ||
| 249 | if "::" in args.source: | 255 | if "::" in args.source: |
| 250 | (src_repo_path, _, src_archive) = args.source.partition("::") | 256 | (src_repo_path, _, src_archive) = args.source.partition("::") |
