forked from droserasprout/pacman-fix-permissions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpacman-fix-permissions
executable file
·105 lines (92 loc) · 4.18 KB
/
pacman-fix-permissions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/python
import argparse
from subprocess import run, PIPE, DEVNULL
from os import lstat, chmod, getuid
from os.path import isfile
import logging
import tarfile
logging.basicConfig(level=logging.INFO, format='%(message)s')
logger = logging.getLogger()
if getuid():
logger.error("This script must be run as root.")
quit()
parser = argparse.ArgumentParser()
mods = parser.add_mutually_exclusive_group(required=False)
mods.add_argument('-a', '--all', action='store_true', help='process all installed packages (default)')
mods.add_argument('-p', '--packages', nargs='*', help='list of package names to process', metavar='names')
mods.add_argument('-f', '--filesystem-paths', nargs='*', help='list of filesystem paths to process', metavar='paths')
args = parser.parse_args()
print(args)
if hasattr(args, 'packages') and getattr(args, 'packages') == []:
parser.error('You must pass at least one package name when using -p switch')
if hasattr(args, 'filesystem-paths') and getattr(args, 'f') == []:
parser.error('You must pass at least one filesystem path when using -f switch')
def getTar(pkg):
def _open():
p_arch = '/var/cache/pacman/pkg/{}-{}-{}.pkg.tar.xz'.format(pkg[0], pkg[1], arch)
p_any = '/var/cache/pacman/pkg/{}-{}-{}.pkg.tar.xz'.format(pkg[0], pkg[1], 'any')
if isfile(p_arch):
return tarfile.open(p_arch)
if isfile(p_any):
return tarfile.open(p_any)
return None
arch = run(['uname', '-m'], stdout=PIPE).stdout.decode().rstrip()
pkg = pkg.split()
pkgtar = _open()
if pkgtar is None:
logger.info('=> {} package is missing, downloading'.format(pkg[0]))
run(['pacman', '-Swq', '--noconfirm', pkg[0]], stdout=DEVNULL)
pkgtar = _open()
if pkgtar is None:
raise Exception("Can't open or download '{}' package, check your internet connection".format(pkg[0]))
return pkgtar
def main():
logger.info('==> Upgrading packages that are out-of-date')
res = run(['pacman', '-Fy'])
if res.returncode:
quit()
res = run(['pacman', '-Syyuuq', '--noconfirm'])
if res.returncode:
quit()
logger.info('==> Parsing installed packages list')
if hasattr(args, 'packages') and args.packages:
pkgs = run(['pacman', '-Qn'] + getattr(args, 'packages'), stdout=PIPE).stdout.decode().rstrip().split('\n')
elif hasattr(args, 'filesystem_paths') and args.filesystem_paths:
pkgs = [' '.join(p.rsplit(' ', 2)[1:]) for p in
run(['pacman', '-Qo'] + getattr(args, 'filesystem_paths'), stdout=PIPE).stdout.decode().rstrip().split('\n') if p]
if not pkgs:
quit()
else:
pkgs = run(['pacman', '-Qn'], stdout=PIPE).stdout.decode().rstrip().split('\n')
logger.info('==> Collecting actual filesystem permissions and correct ones from packages')
paths = {}
for i in range(len(pkgs)):
logger.info('({}/{}) {}'.format(i+1, len(pkgs), pkgs[i]))
pkgtar = getTar(pkgs[i])
for f in pkgtar.getmembers():
if f.name not in ['.PKGINFO', '.BUILDINFO', '.MTREE', '.INSTALL', '.CHANGELOG']:
p = '/' + f.name
if p not in paths:
try:
old_mode = int(lstat(p).st_mode & 0o7777)
new_mode = int(f.mode)
if old_mode != new_mode:
paths[p] = {'old_mode': old_mode,
'new_mode': new_mode}
except FileNotFoundError:
logger.error('File not found: {}'.format(p))
if paths:
logger.info('==> Scan completed. Broken permissions in your filesystem:')
for p in paths.keys():
logging.info('{}: {} => {}'.format(p, oct(paths[p]['old_mode']), oct(paths[p]['new_mode'])))
logger.info('==> Apply? (yes/no)')
if input() in ['yes', 'y']:
for p in paths.keys():
chmod(p, paths[p]['new_mode'])
logger.info('==> Done!')
else:
logger.info('==> Done! (no actual changes were made)')
else:
logger.info('==> Your filesystem is fine, no action required')
if __name__ == '__main__':
main()