diff options
author | Joshua Watt <JPEWhacker@gmail.com> | 2023-08-18 07:27:51 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2023-08-24 16:49:38 +0100 |
commit | 871a4ac6e7e814242db4f90fc4d8ae92d72d7460 (patch) | |
tree | db15d000a28fd70829c6eac978082c16d55671a8 /bitbake/lib/bb/acl.py | |
parent | 8087c261b06efbdc581a5eae85d52b5d004b4a01 (diff) | |
download | poky-871a4ac6e7e814242db4f90fc4d8ae92d72d7460.tar.gz |
bitbake: lib/bb: Add xattr and acl libraries
Adds Python wrappers around the xattr API from libc and the ACL API from
libacl.
(Bitbake rev: 538011256964d0253f8e3ab7ff1d6fd62c7c2f89)
Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/acl.py')
-rwxr-xr-x | bitbake/lib/bb/acl.py | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/bitbake/lib/bb/acl.py b/bitbake/lib/bb/acl.py new file mode 100755 index 0000000000..0f41b275cf --- /dev/null +++ b/bitbake/lib/bb/acl.py | |||
@@ -0,0 +1,215 @@ | |||
1 | #! /usr/bin/env python3 | ||
2 | # | ||
3 | # Copyright 2023 by Garmin Ltd. or its subsidiaries | ||
4 | # | ||
5 | # SPDX-License-Identifier: MIT | ||
6 | |||
7 | |||
8 | import sys | ||
9 | import ctypes | ||
10 | import os | ||
11 | import errno | ||
12 | import pwd | ||
13 | import grp | ||
14 | |||
15 | libacl = ctypes.CDLL("libacl.so.1", use_errno=True) | ||
16 | |||
17 | |||
18 | ACL_TYPE_ACCESS = 0x8000 | ||
19 | ACL_TYPE_DEFAULT = 0x4000 | ||
20 | |||
21 | ACL_FIRST_ENTRY = 0 | ||
22 | ACL_NEXT_ENTRY = 1 | ||
23 | |||
24 | ACL_UNDEFINED_TAG = 0x00 | ||
25 | ACL_USER_OBJ = 0x01 | ||
26 | ACL_USER = 0x02 | ||
27 | ACL_GROUP_OBJ = 0x04 | ||
28 | ACL_GROUP = 0x08 | ||
29 | ACL_MASK = 0x10 | ||
30 | ACL_OTHER = 0x20 | ||
31 | |||
32 | ACL_READ = 0x04 | ||
33 | ACL_WRITE = 0x02 | ||
34 | ACL_EXECUTE = 0x01 | ||
35 | |||
36 | acl_t = ctypes.c_void_p | ||
37 | acl_entry_t = ctypes.c_void_p | ||
38 | acl_permset_t = ctypes.c_void_p | ||
39 | acl_perm_t = ctypes.c_uint | ||
40 | |||
41 | acl_tag_t = ctypes.c_int | ||
42 | |||
43 | libacl.acl_free.argtypes = [acl_t] | ||
44 | |||
45 | |||
46 | def acl_free(acl): | ||
47 | libacl.acl_free(acl) | ||
48 | |||
49 | |||
50 | libacl.acl_get_file.restype = acl_t | ||
51 | libacl.acl_get_file.argtypes = [ctypes.c_char_p, ctypes.c_uint] | ||
52 | |||
53 | |||
54 | def acl_get_file(path, typ): | ||
55 | acl = libacl.acl_get_file(os.fsencode(path), typ) | ||
56 | if acl is None: | ||
57 | err = ctypes.get_errno() | ||
58 | raise OSError(err, os.strerror(err), str(path)) | ||
59 | |||
60 | return acl | ||
61 | |||
62 | |||
63 | libacl.acl_get_entry.argtypes = [acl_t, ctypes.c_int, ctypes.c_void_p] | ||
64 | |||
65 | |||
66 | def acl_get_entry(acl, entry_id): | ||
67 | entry = acl_entry_t() | ||
68 | ret = libacl.acl_get_entry(acl, entry_id, ctypes.byref(entry)) | ||
69 | if ret < 0: | ||
70 | err = ctypes.get_errno() | ||
71 | raise OSError(err, os.strerror(err)) | ||
72 | |||
73 | if ret == 0: | ||
74 | return None | ||
75 | |||
76 | return entry | ||
77 | |||
78 | |||
79 | libacl.acl_get_tag_type.argtypes = [acl_entry_t, ctypes.c_void_p] | ||
80 | |||
81 | |||
82 | def acl_get_tag_type(entry_d): | ||
83 | tag = acl_tag_t() | ||
84 | ret = libacl.acl_get_tag_type(entry_d, ctypes.byref(tag)) | ||
85 | if ret < 0: | ||
86 | err = ctypes.get_errno() | ||
87 | raise OSError(err, os.strerror(err)) | ||
88 | return tag.value | ||
89 | |||
90 | |||
91 | libacl.acl_get_qualifier.restype = ctypes.c_void_p | ||
92 | libacl.acl_get_qualifier.argtypes = [acl_entry_t] | ||
93 | |||
94 | |||
95 | def acl_get_qualifier(entry_d): | ||
96 | ret = libacl.acl_get_qualifier(entry_d) | ||
97 | if ret is None: | ||
98 | err = ctypes.get_errno() | ||
99 | raise OSError(err, os.strerror(err)) | ||
100 | return ctypes.c_void_p(ret) | ||
101 | |||
102 | |||
103 | libacl.acl_get_permset.argtypes = [acl_entry_t, ctypes.c_void_p] | ||
104 | |||
105 | |||
106 | def acl_get_permset(entry_d): | ||
107 | permset = acl_permset_t() | ||
108 | ret = libacl.acl_get_permset(entry_d, ctypes.byref(permset)) | ||
109 | if ret < 0: | ||
110 | err = ctypes.get_errno() | ||
111 | raise OSError(err, os.strerror(err)) | ||
112 | |||
113 | return permset | ||
114 | |||
115 | |||
116 | libacl.acl_get_perm.argtypes = [acl_permset_t, acl_perm_t] | ||
117 | |||
118 | |||
119 | def acl_get_perm(permset_d, perm): | ||
120 | ret = libacl.acl_get_perm(permset_d, perm) | ||
121 | if ret < 0: | ||
122 | err = ctypes.get_errno() | ||
123 | raise OSError(err, os.strerror(err)) | ||
124 | return bool(ret) | ||
125 | |||
126 | |||
127 | class Entry(object): | ||
128 | def __init__(self, tag, qualifier, mode): | ||
129 | self.tag = tag | ||
130 | self.qualifier = qualifier | ||
131 | self.mode = mode | ||
132 | |||
133 | def __str__(self): | ||
134 | typ = "" | ||
135 | qual = "" | ||
136 | if self.tag == ACL_USER: | ||
137 | typ = "user" | ||
138 | qual = pwd.getpwuid(self.qualifier).pw_name | ||
139 | elif self.tag == ACL_GROUP: | ||
140 | typ = "group" | ||
141 | qual = grp.getgrgid(self.qualifier).gr_name | ||
142 | elif self.tag == ACL_USER_OBJ: | ||
143 | typ = "user" | ||
144 | elif self.tag == ACL_GROUP_OBJ: | ||
145 | typ = "group" | ||
146 | elif self.tag == ACL_MASK: | ||
147 | typ = "mask" | ||
148 | elif self.tag == ACL_OTHER: | ||
149 | typ = "other" | ||
150 | |||
151 | r = "r" if self.mode & ACL_READ else "-" | ||
152 | w = "w" if self.mode & ACL_WRITE else "-" | ||
153 | x = "x" if self.mode & ACL_EXECUTE else "-" | ||
154 | |||
155 | return f"{typ}:{qual}:{r}{w}{x}" | ||
156 | |||
157 | |||
158 | class ACL(object): | ||
159 | def __init__(self, acl): | ||
160 | self.acl = acl | ||
161 | |||
162 | def __del__(self): | ||
163 | acl_free(self.acl) | ||
164 | |||
165 | def entries(self): | ||
166 | entry_id = ACL_FIRST_ENTRY | ||
167 | while True: | ||
168 | entry = acl_get_entry(self.acl, entry_id) | ||
169 | if entry is None: | ||
170 | break | ||
171 | |||
172 | permset = acl_get_permset(entry) | ||
173 | |||
174 | mode = 0 | ||
175 | for m in (ACL_READ, ACL_WRITE, ACL_EXECUTE): | ||
176 | if acl_get_perm(permset, m): | ||
177 | mode |= m | ||
178 | |||
179 | qualifier = None | ||
180 | tag = acl_get_tag_type(entry) | ||
181 | |||
182 | if tag == ACL_USER or tag == ACL_GROUP: | ||
183 | qual = acl_get_qualifier(entry) | ||
184 | qualifier = ctypes.cast(qual, ctypes.POINTER(ctypes.c_int))[0] | ||
185 | |||
186 | yield Entry(tag, qualifier, mode) | ||
187 | |||
188 | entry_id = ACL_NEXT_ENTRY | ||
189 | |||
190 | @classmethod | ||
191 | def from_path(cls, path, typ): | ||
192 | acl = acl_get_file(path, typ) | ||
193 | return cls(acl) | ||
194 | |||
195 | |||
196 | def main(): | ||
197 | import argparse | ||
198 | import pwd | ||
199 | import grp | ||
200 | from pathlib import Path | ||
201 | |||
202 | parser = argparse.ArgumentParser() | ||
203 | parser.add_argument("path", help="File Path", type=Path) | ||
204 | |||
205 | args = parser.parse_args() | ||
206 | |||
207 | acl = ACL.from_path(args.path, ACL_TYPE_ACCESS) | ||
208 | for entry in acl.entries(): | ||
209 | print(str(entry)) | ||
210 | |||
211 | return 0 | ||
212 | |||
213 | |||
214 | if __name__ == "__main__": | ||
215 | sys.exit(main()) | ||