1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,470 @@ |
0 |
+diff --git a/cloudinit/sources/DataSourceVMwareGuestInfo.py b/cloudinit/sources/DataSourceVMwareGuestInfo.py |
|
1 |
+index e69de29..59dd685 100644 |
|
2 |
+--- a/cloudinit/sources/DataSourceVMwareGuestInfo.py |
|
3 |
+@@ -0,0 +1,465 @@ |
|
4 |
++# Cloud-Init Datasource for VMware Guestinfo |
|
5 |
++# |
|
6 |
++# Copyright (c) 2018 VMware, Inc. All Rights Reserved. |
|
7 |
++# |
|
8 |
++# This product is licensed to you under the Apache 2.0 license (the "License"). |
|
9 |
++# You may not use this product except in compliance with the Apache 2.0 License. |
|
10 |
++# |
|
11 |
++# This product may include a number of subcomponents with separate copyright |
|
12 |
++# notices and license terms. Your use of these subcomponents is subject to the |
|
13 |
++# terms and conditions of the subcomponent's license, as noted in the LICENSE |
|
14 |
++# file. |
|
15 |
++# |
|
16 |
++# Authors: Anish Swaminathan <anishs@vmware.com> |
|
17 |
++# Andrew Kutz <akutz@vmware.com> |
|
18 |
++# |
|
19 |
++ |
|
20 |
++''' |
|
21 |
++A cloud init datasource for VMware GuestInfo. |
|
22 |
++''' |
|
23 |
++ |
|
24 |
++import base64 |
|
25 |
++import collections |
|
26 |
++import copy |
|
27 |
++from distutils.spawn import find_executable |
|
28 |
++import json |
|
29 |
++import socket |
|
30 |
++import zlib |
|
31 |
++ |
|
32 |
++from cloudinit import log as logging |
|
33 |
++from cloudinit import sources |
|
34 |
++from cloudinit import util |
|
35 |
++from cloudinit import safeyaml |
|
36 |
++ |
|
37 |
++from deepmerge import always_merger |
|
38 |
++import netifaces |
|
39 |
++ |
|
40 |
++LOG = logging.getLogger(__name__) |
|
41 |
++NOVAL = "No value found" |
|
42 |
++VMTOOLSD = find_executable("vmtoolsd") |
|
43 |
++ |
|
44 |
++ |
|
45 |
++class NetworkConfigError(Exception): |
|
46 |
++ ''' |
|
47 |
++ NetworkConfigError is raised when there is an issue getting or |
|
48 |
++ applying network configuration. |
|
49 |
++ ''' |
|
50 |
++ pass |
|
51 |
++ |
|
52 |
++ |
|
53 |
++class DataSourceVMwareGuestInfo(sources.DataSource): |
|
54 |
++ ''' |
|
55 |
++ This cloud-init datasource was designed for use with CentOS 7, |
|
56 |
++ which uses cloud-init 0.7.9. However, this datasource should |
|
57 |
++ work with any Linux distribution for which cloud-init is |
|
58 |
++ avaialble. |
|
59 |
++ The documentation for cloud-init 0.7.9's datasource is |
|
60 |
++ available at http://bit.ly/cloudinit-datasource-0-7-9. The |
|
61 |
++ current documentation for cloud-init is found at |
|
62 |
++ https://cloudinit.readthedocs.io/en/latest/. |
|
63 |
++ Setting the hostname: |
|
64 |
++ The hostname is set by way of the metadata key "local-hostname". |
|
65 |
++ Setting the instance ID: |
|
66 |
++ The instance ID may be set by way of the metadata key "instance-id". |
|
67 |
++ However, if this value is absent then then the instance ID is |
|
68 |
++ read from the file /sys/class/dmi/id/product_uuid. |
|
69 |
++ Configuring the network: |
|
70 |
++ The network is configured by setting the metadata key "network" |
|
71 |
++ with a value consistent with Network Config Versions 1 or 2, |
|
72 |
++ depending on the Linux distro's version of cloud-init: |
|
73 |
++ Network Config Version 1 - http://bit.ly/cloudinit-net-conf-v1 |
|
74 |
++ Network Config Version 2 - http://bit.ly/cloudinit-net-conf-v2 |
|
75 |
++ For example, CentOS 7's official cloud-init package is version |
|
76 |
++ 0.7.9 and does not support Network Config Version 2. However, |
|
77 |
++ this datasource still supports supplying Network Config Version 2 |
|
78 |
++ data as long as the Linux distro's cloud-init package is new |
|
79 |
++ enough to parse the data. |
|
80 |
++ The metadata key "network.encoding" may be used to indicate the |
|
81 |
++ format of the metadata key "network". Valid encodings are base64 |
|
82 |
++ and gzip+base64. |
|
83 |
++ ''' |
|
84 |
++ |
|
85 |
++ dsname = 'VMwareGuestInfo' |
|
86 |
++ |
|
87 |
++ def __init__(self, sys_cfg, distro, paths, ud_proc=None): |
|
88 |
++ sources.DataSource.__init__(self, sys_cfg, distro, paths, ud_proc) |
|
89 |
++ if not VMTOOLSD: |
|
90 |
++ LOG.error("Failed to find vmtoolsd") |
|
91 |
++ |
|
92 |
++ def get_data(self): |
|
93 |
++ """ |
|
94 |
++ This method should really be _get_data in accordance with the most |
|
95 |
++ recent versions of cloud-init. However, because the datasource |
|
96 |
++ supports as far back as cloud-init 0.7.9, get_data is still used. |
|
97 |
++ Because of this the method attempts to do some of the same things |
|
98 |
++ that the get_data functions in newer versions of cloud-init do, |
|
99 |
++ such as calling persist_instance_data. |
|
100 |
++ """ |
|
101 |
++ if not VMTOOLSD: |
|
102 |
++ LOG.error("vmtoolsd is required to fetch guestinfo value") |
|
103 |
++ return False |
|
104 |
++ |
|
105 |
++ # Get the metadata. |
|
106 |
++ self.metadata = load_metadata() |
|
107 |
++ |
|
108 |
++ # Get the user data. |
|
109 |
++ self.userdata_raw = guestinfo('userdata') |
|
110 |
++ |
|
111 |
++ # Get the vendor data. |
|
112 |
++ self.vendordata_raw = guestinfo('vendordata') |
|
113 |
++ |
|
114 |
++ return True |
|
115 |
++ |
|
116 |
++ def setup(self, is_new_instance): |
|
117 |
++ """setup(is_new_instance) |
|
118 |
++ This is called before user-data and vendor-data have been processed. |
|
119 |
++ Unless the datasource has set mode to 'local', then networking |
|
120 |
++ per 'fallback' or per 'network_config' will have been written and |
|
121 |
++ brought up the OS at this point. |
|
122 |
++ """ |
|
123 |
++ |
|
124 |
++ # Get information about the host. |
|
125 |
++ host_info = get_host_info() |
|
126 |
++ LOG.info("got host-info: %s", host_info) |
|
127 |
++ |
|
128 |
++ # Ensure the metadata gets updated with information about the |
|
129 |
++ # host, including the network interfaces, default IP addresses, |
|
130 |
++ # etc. |
|
131 |
++ self.metadata = always_merger.merge(self.metadata, host_info) |
|
132 |
++ |
|
133 |
++ # Persist the instance data for versions of cloud-init that support |
|
134 |
++ # doing so. This occurs here rather than in the get_data call in |
|
135 |
++ # order to ensure that the network interfaces are up and can be |
|
136 |
++ # persisted with the metadata. |
|
137 |
++ try: |
|
138 |
++ self.persist_instance_data() |
|
139 |
++ except AttributeError: |
|
140 |
++ pass |
|
141 |
++ |
|
142 |
++ @property |
|
143 |
++ def network_config(self): |
|
144 |
++ if 'network' in self.metadata: |
|
145 |
++ LOG.debug("using metadata network config") |
|
146 |
++ else: |
|
147 |
++ LOG.debug("using fallback network config") |
|
148 |
++ self.metadata['network'] = { |
|
149 |
++ 'config': self.distro.generate_fallback_config(), |
|
150 |
++ } |
|
151 |
++ return self.metadata['network']['config'] |
|
152 |
++ |
|
153 |
++ def get_instance_id(self): |
|
154 |
++ # Pull the instance ID out of the metadata if present. Otherwise |
|
155 |
++ # read the file /sys/class/dmi/id/product_uuid for the instance ID. |
|
156 |
++ if self.metadata and 'instance-id' in self.metadata: |
|
157 |
++ return self.metadata['instance-id'] |
|
158 |
++ with open('/sys/class/dmi/id/product_uuid', 'r') as id_file: |
|
159 |
++ self.metadata['instance-id'] = str(id_file.read()).rstrip() |
|
160 |
++ return self.metadata['instance-id'] |
|
161 |
++ |
|
162 |
++ |
|
163 |
++def decode(key, enc_type, data): |
|
164 |
++ ''' |
|
165 |
++ decode returns the decoded string value of data |
|
166 |
++ key is a string used to identify the data being decoded in log messages |
|
167 |
++ ---- |
|
168 |
++ In py 2.7: |
|
169 |
++ json.loads method takes string as input |
|
170 |
++ zlib.decompress takes and returns a string |
|
171 |
++ base64.b64decode takes and returns a string |
|
172 |
++ ----- |
|
173 |
++ In py 3.6 and newer: |
|
174 |
++ json.loads method takes bytes or string as input |
|
175 |
++ zlib.decompress takes and returns a bytes |
|
176 |
++ base64.b64decode takes bytes or string and returns bytes |
|
177 |
++ ----- |
|
178 |
++ In py > 3, < 3.6: |
|
179 |
++ json.loads method takes string as input |
|
180 |
++ zlib.decompress takes and returns a bytes |
|
181 |
++ base64.b64decode takes bytes or string and returns bytes |
|
182 |
++ ----- |
|
183 |
++ Given the above conditions the output from zlib.decompress and |
|
184 |
++ base64.b64decode would be bytes with newer python and str in older |
|
185 |
++ version. Thus we would covert the output to str before returning |
|
186 |
++ ''' |
|
187 |
++ LOG.debug("Getting encoded data for key=%s, enc=%s", key, enc_type) |
|
188 |
++ |
|
189 |
++ raw_data = None |
|
190 |
++ if enc_type == "gzip+base64" or enc_type == "gz+b64": |
|
191 |
++ LOG.debug("Decoding %s format %s", enc_type, key) |
|
192 |
++ raw_data = zlib.decompress(base64.b64decode(data), zlib.MAX_WBITS | 16) |
|
193 |
++ elif enc_type == "base64" or enc_type == "b64": |
|
194 |
++ LOG.debug("Decoding %s format %s", enc_type, key) |
|
195 |
++ raw_data = base64.b64decode(data) |
|
196 |
++ else: |
|
197 |
++ LOG.debug("Plain-text data %s", key) |
|
198 |
++ raw_data = data |
|
199 |
++ |
|
200 |
++ if isinstance(raw_data, bytes): |
|
201 |
++ return raw_data.decode('utf-8') |
|
202 |
++ return raw_data |
|
203 |
++ |
|
204 |
++ |
|
205 |
++def get_guestinfo_value(key): |
|
206 |
++ ''' |
|
207 |
++ Returns a guestinfo value for the specified key. |
|
208 |
++ ''' |
|
209 |
++ LOG.debug("Getting guestinfo value for key %s", key) |
|
210 |
++ try: |
|
211 |
++ (stdout, stderr) = util.subp( |
|
212 |
++ [VMTOOLSD, "--cmd", "info-get guestinfo." + key]) |
|
213 |
++ if stderr == NOVAL: |
|
214 |
++ LOG.debug("No value found for key %s", key) |
|
215 |
++ elif not stdout: |
|
216 |
++ LOG.error("Failed to get guestinfo value for key %s", key) |
|
217 |
++ else: |
|
218 |
++ return stdout.rstrip() |
|
219 |
++ except util.ProcessExecutionError as error: |
|
220 |
++ if error.stderr == NOVAL: |
|
221 |
++ LOG.debug("No value found for key %s", key) |
|
222 |
++ else: |
|
223 |
++ util.logexc( |
|
224 |
++ LOG, "Failed to get guestinfo value for key %s: %s", key, error) |
|
225 |
++ except Exception: |
|
226 |
++ util.logexc( |
|
227 |
++ LOG, "Unexpected error while trying to get guestinfo value for key %s", key) |
|
228 |
++ return None |
|
229 |
++ |
|
230 |
++ |
|
231 |
++def guestinfo(key): |
|
232 |
++ ''' |
|
233 |
++ guestinfo returns the guestinfo value for the provided key, decoding |
|
234 |
++ the value when required |
|
235 |
++ ''' |
|
236 |
++ data = get_guestinfo_value(key) |
|
237 |
++ if not data: |
|
238 |
++ return None |
|
239 |
++ enc_type = get_guestinfo_value(key + '.encoding') |
|
240 |
++ return decode('guestinfo.' + key, enc_type, data) |
|
241 |
++ |
|
242 |
++ |
|
243 |
++def load(data): |
|
244 |
++ ''' |
|
245 |
++ load first attempts to unmarshal the provided data as JSON, and if |
|
246 |
++ that fails then attempts to unmarshal the data as YAML. If data is |
|
247 |
++ None then a new dictionary is returned. |
|
248 |
++ ''' |
|
249 |
++ if not data: |
|
250 |
++ return {} |
|
251 |
++ try: |
|
252 |
++ return json.loads(data) |
|
253 |
++ except: |
|
254 |
++ return safeyaml.load(data) |
|
255 |
++ |
|
256 |
++ |
|
257 |
++def load_metadata(): |
|
258 |
++ ''' |
|
259 |
++ load_metadata loads the metadata from the guestinfo data, optionally |
|
260 |
++ decoding the network config when required |
|
261 |
++ ''' |
|
262 |
++ data = load(guestinfo('metadata')) |
|
263 |
++ LOG.debug('loaded metadata %s', data) |
|
264 |
++ |
|
265 |
++ network = None |
|
266 |
++ if 'network' in data: |
|
267 |
++ network = data['network'] |
|
268 |
++ del data['network'] |
|
269 |
++ |
|
270 |
++ network_enc = None |
|
271 |
++ if 'network.encoding' in data: |
|
272 |
++ network_enc = data['network.encoding'] |
|
273 |
++ del data['network.encoding'] |
|
274 |
++ |
|
275 |
++ if network: |
|
276 |
++ LOG.debug('network data found') |
|
277 |
++ if isinstance(network, collections.Mapping): |
|
278 |
++ LOG.debug("network data copied to 'config' key") |
|
279 |
++ network = { |
|
280 |
++ 'config': copy.deepcopy(network) |
|
281 |
++ } |
|
282 |
++ else: |
|
283 |
++ LOG.debug("network data to be decoded %s", network) |
|
284 |
++ dec_net = decode('metadata.network', network_enc, network) |
|
285 |
++ network = { |
|
286 |
++ 'config': load(dec_net), |
|
287 |
++ } |
|
288 |
++ |
|
289 |
++ LOG.debug('network data %s', network) |
|
290 |
++ data['network'] = network |
|
291 |
++ |
|
292 |
++ return data |
|
293 |
++ |
|
294 |
++ |
|
295 |
++def get_datasource_list(depends): |
|
296 |
++ ''' |
|
297 |
++ Return a list of data sources that match this set of dependencies |
|
298 |
++ ''' |
|
299 |
++ return [DataSourceVMwareGuestInfo] |
|
300 |
++ |
|
301 |
++ |
|
302 |
++def get_default_ip_addrs(): |
|
303 |
++ ''' |
|
304 |
++ Returns the default IPv4 and IPv6 addresses based on the device(s) used for |
|
305 |
++ the default route. Please note that None may be returned for either address |
|
306 |
++ family if that family has no default route or if there are multiple |
|
307 |
++ addresses associated with the device used by the default route for a given |
|
308 |
++ address. |
|
309 |
++ ''' |
|
310 |
++ gateways = netifaces.gateways() |
|
311 |
++ if 'default' not in gateways: |
|
312 |
++ return None, None |
|
313 |
++ |
|
314 |
++ default_gw = gateways['default'] |
|
315 |
++ if netifaces.AF_INET not in default_gw and netifaces.AF_INET6 not in default_gw: |
|
316 |
++ return None, None |
|
317 |
++ |
|
318 |
++ ipv4 = None |
|
319 |
++ ipv6 = None |
|
320 |
++ |
|
321 |
++ gw4 = default_gw.get(netifaces.AF_INET) |
|
322 |
++ if gw4: |
|
323 |
++ _, dev4 = gw4 |
|
324 |
++ addr4_fams = netifaces.ifaddresses(dev4) |
|
325 |
++ if addr4_fams: |
|
326 |
++ af_inet4 = addr4_fams.get(netifaces.AF_INET) |
|
327 |
++ if af_inet4: |
|
328 |
++ if len(af_inet4) > 1: |
|
329 |
++ LOG.warn( |
|
330 |
++ "device %s has more than one ipv4 address: %s", dev4, af_inet4) |
|
331 |
++ elif 'addr' in af_inet4[0]: |
|
332 |
++ ipv4 = af_inet4[0]['addr'] |
|
333 |
++ |
|
334 |
++ # Try to get the default IPv6 address by first seeing if there is a default |
|
335 |
++ # IPv6 route. |
|
336 |
++ gw6 = default_gw.get(netifaces.AF_INET6) |
|
337 |
++ if gw6: |
|
338 |
++ _, dev6 = gw6 |
|
339 |
++ addr6_fams = netifaces.ifaddresses(dev6) |
|
340 |
++ if addr6_fams: |
|
341 |
++ af_inet6 = addr6_fams.get(netifaces.AF_INET6) |
|
342 |
++ if af_inet6: |
|
343 |
++ if len(af_inet6) > 1: |
|
344 |
++ LOG.warn( |
|
345 |
++ "device %s has more than one ipv6 address: %s", dev6, af_inet6) |
|
346 |
++ elif 'addr' in af_inet6[0]: |
|
347 |
++ ipv6 = af_inet6[0]['addr'] |
|
348 |
++ |
|
349 |
++ # If there is a default IPv4 address but not IPv6, then see if there is a |
|
350 |
++ # single IPv6 address associated with the same device associated with the |
|
351 |
++ # default IPv4 address. |
|
352 |
++ if ipv4 and not ipv6: |
|
353 |
++ af_inet6 = addr4_fams.get(netifaces.AF_INET6) |
|
354 |
++ if af_inet6: |
|
355 |
++ if len(af_inet6) > 1: |
|
356 |
++ LOG.warn( |
|
357 |
++ "device %s has more than one ipv6 address: %s", dev4, af_inet6) |
|
358 |
++ elif 'addr' in af_inet6[0]: |
|
359 |
++ ipv6 = af_inet6[0]['addr'] |
|
360 |
++ |
|
361 |
++ # If there is a default IPv6 address but not IPv4, then see if there is a |
|
362 |
++ # single IPv4 address associated with the same device associated with the |
|
363 |
++ # default IPv6 address. |
|
364 |
++ if not ipv4 and ipv6: |
|
365 |
++ af_inet4 = addr6_fams.get(netifaces.AF_INET4) |
|
366 |
++ if af_inet4: |
|
367 |
++ if len(af_inet4) > 1: |
|
368 |
++ LOG.warn( |
|
369 |
++ "device %s has more than one ipv4 address: %s", dev6, af_inet4) |
|
370 |
++ elif 'addr' in af_inet4[0]: |
|
371 |
++ ipv4 = af_inet4[0]['addr'] |
|
372 |
++ |
|
373 |
++ return ipv4, ipv6 |
|
374 |
++ |
|
375 |
++ |
|
376 |
++def get_host_info(): |
|
377 |
++ ''' |
|
378 |
++ Returns host information such as the host name and network interfaces. |
|
379 |
++ ''' |
|
380 |
++ |
|
381 |
++ host_info = { |
|
382 |
++ 'network': { |
|
383 |
++ 'interfaces': { |
|
384 |
++ 'by-mac': collections.OrderedDict(), |
|
385 |
++ 'by-ipv4': collections.OrderedDict(), |
|
386 |
++ 'by-ipv6': collections.OrderedDict(), |
|
387 |
++ }, |
|
388 |
++ }, |
|
389 |
++ } |
|
390 |
++ |
|
391 |
++ hostname = socket.getfqdn() |
|
392 |
++ if hostname: |
|
393 |
++ host_info['hostname'] = hostname |
|
394 |
++ host_info['local-hostname'] = hostname |
|
395 |
++ |
|
396 |
++ default_ipv4, default_ipv6 = get_default_ip_addrs() |
|
397 |
++ if default_ipv4: |
|
398 |
++ host_info['local-ipv4'] = default_ipv4 |
|
399 |
++ if default_ipv6: |
|
400 |
++ host_info['local-ipv6'] = default_ipv6 |
|
401 |
++ |
|
402 |
++ by_mac = host_info['network']['interfaces']['by-mac'] |
|
403 |
++ by_ipv4 = host_info['network']['interfaces']['by-ipv4'] |
|
404 |
++ by_ipv6 = host_info['network']['interfaces']['by-ipv6'] |
|
405 |
++ |
|
406 |
++ ifaces = netifaces.interfaces() |
|
407 |
++ for dev_name in ifaces: |
|
408 |
++ addr_fams = netifaces.ifaddresses(dev_name) |
|
409 |
++ af_link = addr_fams.get(netifaces.AF_LINK) |
|
410 |
++ af_inet4 = addr_fams.get(netifaces.AF_INET) |
|
411 |
++ af_inet6 = addr_fams.get(netifaces.AF_INET6) |
|
412 |
++ |
|
413 |
++ mac = None |
|
414 |
++ if af_link and 'addr' in af_link[0]: |
|
415 |
++ mac = af_link[0]['addr'] |
|
416 |
++ |
|
417 |
++ # Do not bother recording localhost |
|
418 |
++ if mac == "00:00:00:00:00:00": |
|
419 |
++ continue |
|
420 |
++ |
|
421 |
++ if mac and (af_inet4 or af_inet6): |
|
422 |
++ key = mac |
|
423 |
++ val = {} |
|
424 |
++ if af_inet4: |
|
425 |
++ val["ipv4"] = af_inet4 |
|
426 |
++ if af_inet6: |
|
427 |
++ val["ipv6"] = af_inet6 |
|
428 |
++ by_mac[key] = val |
|
429 |
++ |
|
430 |
++ if af_inet4: |
|
431 |
++ for ip_info in af_inet4: |
|
432 |
++ key = ip_info['addr'] |
|
433 |
++ if key == '127.0.0.1': |
|
434 |
++ continue |
|
435 |
++ val = copy.deepcopy(ip_info) |
|
436 |
++ del val['addr'] |
|
437 |
++ if mac: |
|
438 |
++ val['mac'] = mac |
|
439 |
++ by_ipv4[key] = val |
|
440 |
++ |
|
441 |
++ if af_inet6: |
|
442 |
++ for ip_info in af_inet6: |
|
443 |
++ key = ip_info['addr'] |
|
444 |
++ if key == '::1': |
|
445 |
++ continue |
|
446 |
++ val = copy.deepcopy(ip_info) |
|
447 |
++ del val['addr'] |
|
448 |
++ if mac: |
|
449 |
++ val['mac'] = mac |
|
450 |
++ by_ipv6[key] = val |
|
451 |
++ |
|
452 |
++ return host_info |
|
453 |
++ |
|
454 |
++ |
|
455 |
++def main(): |
|
456 |
++ ''' |
|
457 |
++ Executed when this file is used as a program. |
|
458 |
++ ''' |
|
459 |
++ metadata = {'network': {'config': {'dhcp': True}}} |
|
460 |
++ host_info = get_host_info() |
|
461 |
++ metadata = always_merger.merge(metadata, host_info) |
|
462 |
++ print(util.json_dumps(metadata)) |
|
463 |
++ |
|
464 |
++ |
|
465 |
++if __name__ == "__main__": |
|
466 |
++ main() |
|
467 |
++ |
|
468 |
++# vi: ts=4 expandtab |
... | ... |
@@ -2,7 +2,7 @@ |
2 | 2 |
|
3 | 3 |
Name: cloud-init |
4 | 4 |
Version: 19.1 |
5 |
-Release: 1%{?dist} |
|
5 |
+Release: 2%{?dist} |
|
6 | 6 |
Summary: Cloud instance init scripts |
7 | 7 |
Group: System Environment/Base |
8 | 8 |
License: GPLv3 |
... | ... |
@@ -13,16 +13,18 @@ Source0: https://launchpad.net/cloud-init/trunk/%{version}/+download/%{na |
13 | 13 |
%define sha1 cloud-init=6de398dd755959dde47c8d6f6e255a0857017c44 |
14 | 14 |
Source1: cloud-photon.cfg |
15 | 15 |
Source2: 99-disable-networking-config.cfg |
16 |
+Source3: dscheck_VMwareGuestInfo |
|
16 | 17 |
|
17 | 18 |
Patch0: photon-distro.patch |
18 | 19 |
Patch2: vca-admin-pwd.patch |
19 | 20 |
Patch3: photon-hosts-template.patch |
20 |
-Patch5: datasource-guestinfo.patch |
|
21 |
+Patch5: DataSourceVMwareGuestInfo.patch |
|
21 | 22 |
Patch6: systemd-service-changes.patch |
22 | 23 |
Patch7: makecheck.patch |
23 | 24 |
Patch8: systemd-resolved-config.patch |
24 | 25 |
Patch9: cloud-init-azureds.patch |
25 | 26 |
Patch10: ds-identity.patch |
27 |
+Patch11: ds-guestinfo-photon.patch |
|
26 | 28 |
|
27 | 29 |
BuildRequires: python3 |
28 | 30 |
BuildRequires: python3-libs |
... | ... |
@@ -60,6 +62,8 @@ Requires: python3-six |
60 | 60 |
Requires: python3-setuptools |
61 | 61 |
Requires: python3-xml |
62 | 62 |
Requires: python3-jsonschema |
63 |
+Requires: python3-deepmerge |
|
64 |
+Requires: python3-netifaces |
|
63 | 65 |
BuildArch: noarch |
64 | 66 |
|
65 | 67 |
%description |
... | ... |
@@ -79,6 +83,7 @@ ssh keys and to let the user run various scripts. |
79 | 79 |
%patch8 -p1 |
80 | 80 |
%patch9 -p1 |
81 | 81 |
%patch10 -p1 |
82 |
+%patch11 -p1 |
|
82 | 83 |
|
83 | 84 |
find systemd -name "cloud*.service*" | xargs sed -i s/StandardOutput=journal+console/StandardOutput=journal/g |
84 | 85 |
|
... | ... |
@@ -97,6 +102,7 @@ cp -p %{SOURCE1} %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg |
97 | 97 |
|
98 | 98 |
# Disable networking config by cloud-init |
99 | 99 |
cp -p %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg.d/ |
100 |
+install -m 755 %{SOURCE3} $RPM_BUILD_ROOT/%{_bindir}/ |
|
100 | 101 |
|
101 | 102 |
%check |
102 | 103 |
easy_install_3=$(ls /usr/bin |grep easy_install |grep 3) |
... | ... |
@@ -143,10 +149,13 @@ rm -rf $RPM_BUILD_ROOT |
143 | 143 |
%{python3_sitelib}/* |
144 | 144 |
%{_bindir}/cloud-init* |
145 | 145 |
%{_bindir}/cloud-id |
146 |
+%{_bindir}/dscheck_VMwareGuestInfo |
|
146 | 147 |
%{_datadir}/bash-completion/completions/cloud-init |
147 | 148 |
%dir /var/lib/cloud |
148 | 149 |
|
149 | 150 |
%changelog |
151 |
+* Tue Jul 23 2019 Keerthana K <keerthanak@vmware.com> 19.1-2 |
|
152 |
+- support for additional features in VMGuestInfo Datasource. |
|
150 | 153 |
* Tue Jun 25 2019 Keerthana K <keerthanak@vmware.com> 19.1-1 |
151 | 154 |
- Upgrade to version 19.1 and fix cloud-init GOS logic. |
152 | 155 |
* Thu Jun 13 2019 Keerthana K <keerthanak@vmware.com> 18.3-4 |
39 | 39 |
deleted file mode 100644 |
... | ... |
@@ -1,149 +0,0 @@ |
1 |
-diff -rupN cloud-init-0.7.9/cloudinit/sources/DataSourceVmxGuestinfo.py cloud-init-0.7.9-new/cloudinit/sources/DataSourceVmxGuestinfo.py |
|
2 |
-+++ cloud-init-0.7.9-new/cloudinit/sources/DataSourceVmxGuestinfo.py 2017-05-08 07:47:27.388662680 -0700 |
|
3 |
-@@ -0,0 +1,145 @@ |
|
4 |
-+# vi: ts=4 expandtab |
|
5 |
-+# |
|
6 |
-+# Copyright (C) 2017 VMware Inc. |
|
7 |
-+# |
|
8 |
-+# Author: Anish Swaminathan <anishs@vmware.com> |
|
9 |
-+# |
|
10 |
-+import os |
|
11 |
-+import base64 |
|
12 |
-+ |
|
13 |
-+from cloudinit import log as logging |
|
14 |
-+from cloudinit import sources |
|
15 |
-+from cloudinit import util |
|
16 |
-+ |
|
17 |
-+from distutils.spawn import find_executable |
|
18 |
-+ |
|
19 |
-+LOG = logging.getLogger(__name__) |
|
20 |
-+ |
|
21 |
-+class DataSourceVmxGuestinfo(sources.DataSource): |
|
22 |
-+ def __init__(self, sys_cfg, distro, paths, ud_proc=None): |
|
23 |
-+ sources.DataSource.__init__(self, sys_cfg, distro, paths, ud_proc) |
|
24 |
-+ self.metadata = {} |
|
25 |
-+ self.userdata_raw = '' |
|
26 |
-+ self.vmtoolsd = find_executable("vmtoolsd") |
|
27 |
-+ if not self.vmtoolsd: |
|
28 |
-+ LOG.error("Failed to find vmtoolsd") |
|
29 |
-+ |
|
30 |
-+ def get_data(self): |
|
31 |
-+ if not self.vmtoolsd: |
|
32 |
-+ LOG.error("vmtoolsd is required to fetch guestinfo value") |
|
33 |
-+ return False |
|
34 |
-+ hostname = self._get_guestinfo_value('hostname') |
|
35 |
-+ if hostname: |
|
36 |
-+ self.distro.set_hostname(hostname) |
|
37 |
-+ ud = self._get_guestinfo_value('userdata') |
|
38 |
-+ if ud: |
|
39 |
-+ LOG.debug("Decoding base64 format guestinfo.userdata") |
|
40 |
-+ self.userdata_raw = base64.b64decode(ud) |
|
41 |
-+ found = True |
|
42 |
-+ dev_index = 0 |
|
43 |
-+ network_settings = '' |
|
44 |
-+ while found: |
|
45 |
-+ key_begin = 'interface.' + str(dev_index) |
|
46 |
-+ key_iname = key_begin + '.name' |
|
47 |
-+ interface_name = self._get_guestinfo_value(key_iname) |
|
48 |
-+ if interface_name: |
|
49 |
-+ network_settings += 'auto ' + interface_name + '\n' |
|
50 |
-+ network_settings += 'iface ' + interface_name |
|
51 |
-+ key_proto = key_begin + '.dhcp' |
|
52 |
-+ dhcp_enabled = self._get_guestinfo_value(key_proto) |
|
53 |
-+ key_address = key_begin + '.address' |
|
54 |
-+ address = self._get_guestinfo_value(key_address) |
|
55 |
-+ bootproto = 'dhcp' |
|
56 |
-+ if dhcp_enabled: |
|
57 |
-+ if dhcp_enabled == 'yes': |
|
58 |
-+ network_settings += ' dhcp\n' |
|
59 |
-+ elif dhcp_enabled == 'no': |
|
60 |
-+ network_settings += ' static\n' |
|
61 |
-+ bootproto = 'static' |
|
62 |
-+ else: |
|
63 |
-+ LOG.warning("Invalid value for yes/no parameter for %s, setting to dhcp", key_proto) |
|
64 |
-+ elif address: |
|
65 |
-+ bootproto = 'static' |
|
66 |
-+ dhcp_enabled == 'no' |
|
67 |
-+ network_settings += ' static\n' |
|
68 |
-+ else: |
|
69 |
-+ dhcp_enabled == 'yes' |
|
70 |
-+ network_settings += ' dhcp\n' |
|
71 |
-+ LOG.debug("Setting network bootproto to dhcp by default") |
|
72 |
-+ key_mac = key_begin + '.mac' |
|
73 |
-+ mac = self._get_guestinfo_value(key_mac) |
|
74 |
-+ if address: |
|
75 |
-+ network_settings += 'address ' + address + '\n' |
|
76 |
-+ if mac: |
|
77 |
-+ network_settings += 'hwaddress ' + mac + '\n' |
|
78 |
-+ key_netmask = key_begin + '.netmask' |
|
79 |
-+ netmask = self._get_guestinfo_value(key_netmask) |
|
80 |
-+ if netmask: |
|
81 |
-+ network_settings += 'netmask ' + netmask + '\n' |
|
82 |
-+ key_dnsserver = 'dns.servers' |
|
83 |
-+ dnsserver = self._get_guestinfo_value(key_dnsserver) |
|
84 |
-+ if dnsserver: |
|
85 |
-+ network_settings += 'dns-nameservers ' |
|
86 |
-+ dnsserver = dnsserver.split(',') |
|
87 |
-+ for d in dnsserver: |
|
88 |
-+ network_settings += d + ' ' |
|
89 |
-+ network_settings += '\n' |
|
90 |
-+ key_dnsdomain = 'dns.domains' |
|
91 |
-+ dnsdomain = self._get_guestinfo_value(key_dnsdomain) |
|
92 |
-+ if dnsdomain: |
|
93 |
-+ network_settings += 'dns-search ' |
|
94 |
-+ dnsdomain = dnsdomain.split(',') |
|
95 |
-+ for d in dnsdomain: |
|
96 |
-+ network_settings += d + ' ' |
|
97 |
-+ network_settings += '\n' |
|
98 |
-+ route_index = 0 |
|
99 |
-+ default_destination_set = False |
|
100 |
-+ while True: |
|
101 |
-+ key_route = key_begin + '.route.' + str(route_index) |
|
102 |
-+ route = self._get_guestinfo_value(key_route) |
|
103 |
-+ if route: |
|
104 |
-+ network_settings += "routes.%s " % (route_index) |
|
105 |
-+ route = route.split(',') |
|
106 |
-+ if len(route) > 2: |
|
107 |
-+ LOG.debug("Route information for %s route in %s device incorrect - ", |
|
108 |
-+ "expected 2 values", route_index, dev_index) |
|
109 |
-+ continue |
|
110 |
-+ elif len(route) == 2: |
|
111 |
-+ network_settings += route[0] + ' ' + route[1] + '\n'# Gateway Destination |
|
112 |
-+ else: #length = 1 |
|
113 |
-+ if not default_destination_set: |
|
114 |
-+ network_settings += route[0] + ' 0.0.0.0/0' + '\n' |
|
115 |
-+ default_destination_set = True |
|
116 |
-+ else: |
|
117 |
-+ LOG.debug("Default destination set previously, not setting route %s", route_index) |
|
118 |
-+ else: |
|
119 |
-+ break |
|
120 |
-+ route_index += 1 |
|
121 |
-+ else: |
|
122 |
-+ found = False |
|
123 |
-+ dev_index += 1 |
|
124 |
-+ self.distro.apply_network(network_settings, False) |
|
125 |
-+ return True |
|
126 |
-+ |
|
127 |
-+ def _get_guestinfo_value(self, key): |
|
128 |
-+ LOG.debug("Getting guestinfo value for key %s", key) |
|
129 |
-+ value = '' |
|
130 |
-+ try: |
|
131 |
-+ (value, _err) = util.subp([self.vmtoolsd, "--cmd", "info-get guestinfo." + key]) |
|
132 |
-+ if _err: |
|
133 |
-+ LOG.error("Failed to get guestinfo value for key %s", key) |
|
134 |
-+ except util.ProcessExecutionError as error: |
|
135 |
-+ util.logexc(LOG,"Failed to get guestinfo value for key %s: %s", key, error) |
|
136 |
-+ except Exception: |
|
137 |
-+ util.logexc(LOG,"Unexpected error while trying to get guestinfo value for key %s", key) |
|
138 |
-+ return value.rstrip() |
|
139 |
-+ |
|
140 |
-+ def get_instance_id(self): |
|
141 |
-+ with open('/sys/class/dmi/id/product_uuid', 'r') as id_file: |
|
142 |
-+ return str(id_file.read()).rstrip() |
|
143 |
-+ |
|
144 |
-+def get_datasource_list(depends): |
|
145 |
-+ """ |
|
146 |
-+ Return a list of data sources that match this set of dependencies |
|
147 |
-+ """ |
|
148 |
-+ return [DataSourceVmxGuestinfo] |
149 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,99 @@ |
0 |
+diff --git a/cloudinit/sources/DataSourceVMwareGuestInfo.py b/cloudinit/sources/DataSourceVMwareGuestInfo.py |
|
1 |
+index e69de29..59dd685 100644 |
|
2 |
+--- a/cloudinit/sources/DataSourceVMwareGuestInfo.py |
|
3 |
+@@ -108,6 +108,94 @@ |
|
4 |
+ # Get the vendor data. |
|
5 |
+ self.vendordata_raw = guestinfo('vendordata') |
|
6 |
+ |
|
7 |
++ hostname = get_guestinfo_value('hostname') |
|
8 |
++ if hostname: |
|
9 |
++ self.distro.set_hostname(hostname) |
|
10 |
++ found = True |
|
11 |
++ dev_index = 0 |
|
12 |
++ network_settings = '' |
|
13 |
++ while found: |
|
14 |
++ key_begin = 'interface.' + str(dev_index) |
|
15 |
++ key_iname = key_begin + '.name' |
|
16 |
++ interface_name = get_guestinfo_value(key_iname) |
|
17 |
++ if interface_name: |
|
18 |
++ network_settings += 'auto ' + interface_name + '\n' |
|
19 |
++ network_settings += 'iface ' + interface_name |
|
20 |
++ key_proto = key_begin + '.dhcp' |
|
21 |
++ dhcp_enabled = get_guestinfo_value(key_proto) |
|
22 |
++ key_address = key_begin + '.address' |
|
23 |
++ address = get_guestinfo_value(key_address) |
|
24 |
++ bootproto = 'dhcp' |
|
25 |
++ if dhcp_enabled: |
|
26 |
++ if dhcp_enabled == 'yes': |
|
27 |
++ network_settings += ' dhcp\n' |
|
28 |
++ elif dhcp_enabled == 'no': |
|
29 |
++ network_settings += ' static\n' |
|
30 |
++ bootproto = 'static' |
|
31 |
++ else: |
|
32 |
++ LOG.warning("Invalid value for yes/no parameter for %s, setting to dhcp", key_proto) |
|
33 |
++ elif address: |
|
34 |
++ bootproto = 'static' |
|
35 |
++ dhcp_enabled == 'no' |
|
36 |
++ network_settings += ' static\n' |
|
37 |
++ else: |
|
38 |
++ dhcp_enabled == 'yes' |
|
39 |
++ network_settings += ' dhcp\n' |
|
40 |
++ LOG.debug("Setting network bootproto to dhcp by default") |
|
41 |
++ key_mac = key_begin + '.mac' |
|
42 |
++ mac = get_guestinfo_value(key_mac) |
|
43 |
++ if address: |
|
44 |
++ network_settings += 'address ' + address + '\n' |
|
45 |
++ if mac: |
|
46 |
++ network_settings += 'hwaddress ' + mac + '\n' |
|
47 |
++ key_netmask = key_begin + '.netmask' |
|
48 |
++ netmask = get_guestinfo_value(key_netmask) |
|
49 |
++ if netmask: |
|
50 |
++ network_settings += 'netmask ' + netmask + '\n' |
|
51 |
++ key_dnsserver = 'dns.servers' |
|
52 |
++ dnsserver = get_guestinfo_value(key_dnsserver) |
|
53 |
++ if dnsserver: |
|
54 |
++ network_settings += 'dns-nameservers ' |
|
55 |
++ dnsserver = dnsserver.split(',') |
|
56 |
++ for d in dnsserver: |
|
57 |
++ network_settings += d + ' ' |
|
58 |
++ network_settings += '\n' |
|
59 |
++ key_dnsdomain = 'dns.domains' |
|
60 |
++ dnsdomain = get_guestinfo_value(key_dnsdomain) |
|
61 |
++ if dnsdomain: |
|
62 |
++ network_settings += 'dns-search ' |
|
63 |
++ dnsdomain = dnsdomain.split(',') |
|
64 |
++ for d in dnsdomain: |
|
65 |
++ network_settings += d + ' ' |
|
66 |
++ network_settings += '\n' |
|
67 |
++ route_index = 0 |
|
68 |
++ default_destination_set = False |
|
69 |
++ while True: |
|
70 |
++ key_route = key_begin + '.route.' + str(route_index) |
|
71 |
++ route = get_guestinfo_value(key_route) |
|
72 |
++ if route: |
|
73 |
++ network_settings += "routes.%s " % (route_index) |
|
74 |
++ route = route.split(',') |
|
75 |
++ if len(route) > 2: |
|
76 |
++ LOG.debug("Route information for %s route in %s device incorrect - ", |
|
77 |
++ "expected 2 values", route_index, dev_index) |
|
78 |
++ continue |
|
79 |
++ elif len(route) == 2: |
|
80 |
++ network_settings += route[0] + ' ' + route[1] + '\n'# Gateway Destination |
|
81 |
++ else: #length = 1 |
|
82 |
++ if not default_destination_set: |
|
83 |
++ network_settings += route[0] + ' 0.0.0.0/0' + '\n' |
|
84 |
++ default_destination_set = True |
|
85 |
++ else: |
|
86 |
++ LOG.debug("Default destination set previously, not setting route %s", route_index) |
|
87 |
++ else: |
|
88 |
++ break |
|
89 |
++ route_index += 1 |
|
90 |
++ else: |
|
91 |
++ found = False |
|
92 |
++ dev_index += 1 |
|
93 |
++ self.distro.apply_network(network_settings, False) |
|
94 |
++ |
|
95 |
+ return True |
|
96 |
+ |
|
97 |
+ def setup(self, is_new_instance): |
0 | 98 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,46 @@ |
0 |
+#!/bin/sh |
|
1 |
+ |
|
2 |
+# Cloud-Init Datasource for VMware Guestinfo |
|
3 |
+# |
|
4 |
+# Copyright (c) 2019 VMware, Inc. All Rights Reserved. |
|
5 |
+# |
|
6 |
+# This product is licensed to you under the Apache 2.0 license (the "License"). |
|
7 |
+# You may not use this product except in compliance with the Apache 2.0 License. |
|
8 |
+# |
|
9 |
+# This product may include a number of subcomponents with separate copyright |
|
10 |
+# notices and license terms. Your use of these subcomponents is subject to the |
|
11 |
+# terms and conditions of the subcomponent's license, as noted in the LICENSE |
|
12 |
+# file. |
|
13 |
+ |
|
14 |
+# |
|
15 |
+# This file should be installed to /usr/bin/dscheck_VMwareGuestInfo |
|
16 |
+# without the ".sh" extension. The extension only exists to make it easier |
|
17 |
+# to identify the file during development. |
|
18 |
+# |
|
19 |
+# This file provides cloud-init's ds-identify program a shell type that |
|
20 |
+# can be resolved with "type dscheck_VMwareGuestInfo" and used to validate |
|
21 |
+# where a datasource is installed and useable. |
|
22 |
+# |
|
23 |
+# Cloud-init's ds-identify program in /usr/lib/cloud-init includes functions |
|
24 |
+# to determine whether or not datasources can be used. Because the program |
|
25 |
+# is a shell script and uses "type dscheck_DATASOURCE_NAME" to determine |
|
26 |
+# if there is a matching bash type that can answer for the datasource, |
|
27 |
+# it's possible to respond with an external script. While other datasources |
|
28 |
+# have functions in ds-identify, the "type" command looks up types both |
|
29 |
+# in Bash's function table as well as script in the PATH. Therefore the |
|
30 |
+# ds-identify program, when looking up whether or not the datasource |
|
31 |
+# VMwareGuestInfo can be used, will defer to this file when it is in the |
|
32 |
+# PATH and named dscheck_VMwareGuestInfo. |
|
33 |
+# |
|
34 |
+ |
|
35 |
+if ! command -v vmtoolsd >/dev/null 2>&1; then |
|
36 |
+ exit 1 |
|
37 |
+fi |
|
38 |
+ |
|
39 |
+if { vmtoolsd --cmd "info-get guestinfo.metadata" || \ |
|
40 |
+ vmtoolsd --cmd "info-get guestinfo.userdata" || \ |
|
41 |
+ vmtoolsd --cmd "info-get guestinfo.vendordata"; } >/dev/null 2>&1; then |
|
42 |
+ exit 0 |
|
43 |
+fi |
|
44 |
+ |
|
45 |
+exit 1 |
0 | 46 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,441 @@ |
0 |
+From c997ff2f4ced80be724c52e1105f75ece966765b Mon Sep 17 00:00:00 2001 |
|
1 |
+From: Pantelis Antoniou <pantelis.antoniou@konsulko.com> |
|
2 |
+Date: Wed, 3 Dec 2014 13:23:28 +0200 |
|
3 |
+Subject: [PATCH] OF: DT-Overlay configfs interface |
|
4 |
+ |
|
5 |
+This is a port of Pantelis Antoniou's v3 port that makes use of the |
|
6 |
+new upstreamed configfs support for binary attributes. |
|
7 |
+ |
|
8 |
+Original commit message: |
|
9 |
+ |
|
10 |
+Add a runtime interface to using configfs for generic device tree overlay |
|
11 |
+usage. With it its possible to use device tree overlays without having |
|
12 |
+to use a per-platform overlay manager. |
|
13 |
+ |
|
14 |
+Please see Documentation/devicetree/configfs-overlays.txt for more info. |
|
15 |
+ |
|
16 |
+Changes since v2: |
|
17 |
+- Removed ifdef CONFIG_OF_OVERLAY (since for now it's required) |
|
18 |
+- Created a documentation entry |
|
19 |
+- Slight rewording in Kconfig |
|
20 |
+ |
|
21 |
+Changes since v1: |
|
22 |
+- of_resolve() -> of_resolve_phandles(). |
|
23 |
+ |
|
24 |
+Originally-signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> |
|
25 |
+Signed-off-by: Phil Elwell <phil@raspberrypi.org> |
|
26 |
+ |
|
27 |
+DT configfs: Fix build errors on other platforms |
|
28 |
+ |
|
29 |
+Signed-off-by: Phil Elwell <phil@raspberrypi.org> |
|
30 |
+ |
|
31 |
+DT configfs: fix build error |
|
32 |
+ |
|
33 |
+There is an error when compiling rpi-4.6.y branch: |
|
34 |
+ CC drivers/of/configfs.o |
|
35 |
+drivers/of/configfs.c:291:21: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types] |
|
36 |
+ .default_groups = of_cfs_def_groups, |
|
37 |
+ ^ |
|
38 |
+drivers/of/configfs.c:291:21: note: (near initialization for 'of_cfs_subsys.su_group.default_groups.next') |
|
39 |
+ |
|
40 |
+The .default_groups is linked list since commit |
|
41 |
+1ae1602de028acaa42a0f6ff18d19756f8e825c6. |
|
42 |
+This commit uses configfs_add_default_group to fix this problem. |
|
43 |
+ |
|
44 |
+Signed-off-by: Slawomir Stepien <sst@poczta.fm> |
|
45 |
+Signed-off-by: Ajay Kaher <akaher@vmware.com> |
|
46 |
+ |
|
47 |
+configfs: New of_overlay API |
|
48 |
+--- |
|
49 |
+ Documentation/devicetree/configfs-overlays.txt | 31 +++ |
|
50 |
+ drivers/of/Kconfig | 7 + |
|
51 |
+ drivers/of/Makefile | 1 + |
|
52 |
+ drivers/of/configfs.c | 310 +++++++++++++++++++++++++ |
|
53 |
+ 4 files changed, 349 insertions(+) |
|
54 |
+ create mode 100644 Documentation/devicetree/configfs-overlays.txt |
|
55 |
+ create mode 100644 drivers/of/configfs.c |
|
56 |
+ |
|
57 |
+diff --git a/Documentation/devicetree/configfs-overlays.txt b/Documentation/devicetree/configfs-overlays.txt |
|
58 |
+new file mode 100644 |
|
59 |
+index 0000000..5fa43e0 |
|
60 |
+--- /dev/null |
|
61 |
+@@ -0,0 +1,31 @@ |
|
62 |
++Howto use the configfs overlay interface. |
|
63 |
++ |
|
64 |
++A device-tree configfs entry is created in /config/device-tree/overlays |
|
65 |
++and and it is manipulated using standard file system I/O. |
|
66 |
++Note that this is a debug level interface, for use by developers and |
|
67 |
++not necessarily something accessed by normal users due to the |
|
68 |
++security implications of having direct access to the kernel's device tree. |
|
69 |
++ |
|
70 |
++* To create an overlay you mkdir the directory: |
|
71 |
++ |
|
72 |
++ # mkdir /config/device-tree/overlays/foo |
|
73 |
++ |
|
74 |
++* Either you echo the overlay firmware file to the path property file. |
|
75 |
++ |
|
76 |
++ # echo foo.dtbo >/config/device-tree/overlays/foo/path |
|
77 |
++ |
|
78 |
++* Or you cat the contents of the overlay to the dtbo file |
|
79 |
++ |
|
80 |
++ # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo |
|
81 |
++ |
|
82 |
++The overlay file will be applied, and devices will be created/destroyed |
|
83 |
++as required. |
|
84 |
++ |
|
85 |
++To remove it simply rmdir the directory. |
|
86 |
++ |
|
87 |
++ # rmdir /config/device-tree/overlays/foo |
|
88 |
++ |
|
89 |
++The rationalle of the dual interface (firmware & direct copy) is that each is |
|
90 |
++better suited to different use patterns. The firmware interface is what's |
|
91 |
++intended to be used by hardware managers in the kernel, while the copy interface |
|
92 |
++make sense for developers (since it avoids problems with namespaces). |
|
93 |
+diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig |
|
94 |
+index ad3fcad..3c808e2 100644 |
|
95 |
+--- a/drivers/of/Kconfig |
|
96 |
+@@ -103,4 +103,11 @@ config OF_OVERLAY |
|
97 |
+ config OF_NUMA |
|
98 |
+ bool |
|
99 |
+ |
|
100 |
++config OF_CONFIGFS |
|
101 |
++ bool "Device Tree Overlay ConfigFS interface" |
|
102 |
++ select CONFIGFS_FS |
|
103 |
++ select OF_OVERLAY |
|
104 |
++ help |
|
105 |
++ Enable a simple user-space driven DT overlay interface. |
|
106 |
++ |
|
107 |
+ endif # OF |
|
108 |
+diff --git a/drivers/of/Makefile b/drivers/of/Makefile |
|
109 |
+index 663a4af..b00a95a 100644 |
|
110 |
+--- a/drivers/of/Makefile |
|
111 |
+@@ -1,6 +1,7 @@ |
|
112 |
+ # SPDX-License-Identifier: GPL-2.0 |
|
113 |
+ obj-y = base.o device.o platform.o property.o |
|
114 |
+ obj-$(CONFIG_OF_KOBJ) += kobj.o |
|
115 |
++obj-$(CONFIG_OF_CONFIGFS) += configfs.o |
|
116 |
+ obj-$(CONFIG_OF_DYNAMIC) += dynamic.o |
|
117 |
+ obj-$(CONFIG_OF_FLATTREE) += fdt.o |
|
118 |
+ obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o |
|
119 |
+diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c |
|
120 |
+new file mode 100644 |
|
121 |
+index 0000000..178f062 |
|
122 |
+--- /dev/null |
|
123 |
+@@ -0,0 +1,310 @@ |
|
124 |
++/* |
|
125 |
++ * Configfs entries for device-tree |
|
126 |
++ * |
|
127 |
++ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com> |
|
128 |
++ * |
|
129 |
++ * This program is free software; you can redistribute it and/or |
|
130 |
++ * modify it under the terms of the GNU General Public License |
|
131 |
++ * as published by the Free Software Foundation; either version |
|
132 |
++ * 2 of the License, or (at your option) any later version. |
|
133 |
++ */ |
|
134 |
++#include <linux/ctype.h> |
|
135 |
++#include <linux/cpu.h> |
|
136 |
++#include <linux/module.h> |
|
137 |
++#include <linux/of.h> |
|
138 |
++#include <linux/of_fdt.h> |
|
139 |
++#include <linux/spinlock.h> |
|
140 |
++#include <linux/slab.h> |
|
141 |
++#include <linux/proc_fs.h> |
|
142 |
++#include <linux/configfs.h> |
|
143 |
++#include <linux/types.h> |
|
144 |
++#include <linux/stat.h> |
|
145 |
++#include <linux/limits.h> |
|
146 |
++#include <linux/file.h> |
|
147 |
++#include <linux/vmalloc.h> |
|
148 |
++#include <linux/firmware.h> |
|
149 |
++#include <linux/sizes.h> |
|
150 |
++ |
|
151 |
++#include "of_private.h" |
|
152 |
++ |
|
153 |
++struct cfs_overlay_item { |
|
154 |
++ struct config_item item; |
|
155 |
++ |
|
156 |
++ char path[PATH_MAX]; |
|
157 |
++ |
|
158 |
++ const struct firmware *fw; |
|
159 |
++ struct device_node *overlay; |
|
160 |
++ int ov_id; |
|
161 |
++ |
|
162 |
++ void *dtbo; |
|
163 |
++ int dtbo_size; |
|
164 |
++}; |
|
165 |
++ |
|
166 |
++static int create_overlay(struct cfs_overlay_item *overlay, void *blob) |
|
167 |
++{ |
|
168 |
++ int err; |
|
169 |
++ |
|
170 |
++ /* unflatten the tree */ |
|
171 |
++ of_fdt_unflatten_tree(blob, NULL, &overlay->overlay); |
|
172 |
++ if (overlay->overlay == NULL) { |
|
173 |
++ pr_err("%s: failed to unflatten tree\n", __func__); |
|
174 |
++ err = -EINVAL; |
|
175 |
++ goto out_err; |
|
176 |
++ } |
|
177 |
++ pr_debug("%s: unflattened OK\n", __func__); |
|
178 |
++ |
|
179 |
++ /* mark it as detached */ |
|
180 |
++ of_node_set_flag(overlay->overlay, OF_DETACHED); |
|
181 |
++ |
|
182 |
++ /* perform resolution */ |
|
183 |
++ err = of_resolve_phandles(overlay->overlay); |
|
184 |
++ if (err != 0) { |
|
185 |
++ pr_err("%s: Failed to resolve tree\n", __func__); |
|
186 |
++ goto out_err; |
|
187 |
++ } |
|
188 |
++ pr_debug("%s: resolved OK\n", __func__); |
|
189 |
++ |
|
190 |
++ err = of_overlay_apply(overlay->overlay, &overlay->ov_id); |
|
191 |
++ if (err < 0) { |
|
192 |
++ pr_err("%s: Failed to create overlay (err=%d)\n", |
|
193 |
++ __func__, err); |
|
194 |
++ goto out_err; |
|
195 |
++ } |
|
196 |
++ |
|
197 |
++out_err: |
|
198 |
++ return err; |
|
199 |
++} |
|
200 |
++ |
|
201 |
++static inline struct cfs_overlay_item *to_cfs_overlay_item( |
|
202 |
++ struct config_item *item) |
|
203 |
++{ |
|
204 |
++ return item ? container_of(item, struct cfs_overlay_item, item) : NULL; |
|
205 |
++} |
|
206 |
++ |
|
207 |
++static ssize_t cfs_overlay_item_path_show(struct config_item *item, |
|
208 |
++ char *page) |
|
209 |
++{ |
|
210 |
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
211 |
++ return sprintf(page, "%s\n", overlay->path); |
|
212 |
++} |
|
213 |
++ |
|
214 |
++static ssize_t cfs_overlay_item_path_store(struct config_item *item, |
|
215 |
++ const char *page, size_t count) |
|
216 |
++{ |
|
217 |
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
218 |
++ const char *p = page; |
|
219 |
++ char *s; |
|
220 |
++ int err; |
|
221 |
++ |
|
222 |
++ /* if it's set do not allow changes */ |
|
223 |
++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0) |
|
224 |
++ return -EPERM; |
|
225 |
++ |
|
226 |
++ /* copy to path buffer (and make sure it's always zero terminated */ |
|
227 |
++ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p); |
|
228 |
++ overlay->path[sizeof(overlay->path) - 1] = '\0'; |
|
229 |
++ |
|
230 |
++ /* strip trailing newlines */ |
|
231 |
++ s = overlay->path + strlen(overlay->path); |
|
232 |
++ while (s > overlay->path && *--s == '\n') |
|
233 |
++ *s = '\0'; |
|
234 |
++ |
|
235 |
++ pr_debug("%s: path is '%s'\n", __func__, overlay->path); |
|
236 |
++ |
|
237 |
++ err = request_firmware(&overlay->fw, overlay->path, NULL); |
|
238 |
++ if (err != 0) |
|
239 |
++ goto out_err; |
|
240 |
++ |
|
241 |
++ err = create_overlay(overlay, (void *)overlay->fw->data); |
|
242 |
++ if (err != 0) |
|
243 |
++ goto out_err; |
|
244 |
++ |
|
245 |
++ return count; |
|
246 |
++ |
|
247 |
++out_err: |
|
248 |
++ |
|
249 |
++ release_firmware(overlay->fw); |
|
250 |
++ overlay->fw = NULL; |
|
251 |
++ |
|
252 |
++ overlay->path[0] = '\0'; |
|
253 |
++ return err; |
|
254 |
++} |
|
255 |
++ |
|
256 |
++static ssize_t cfs_overlay_item_status_show(struct config_item *item, |
|
257 |
++ char *page) |
|
258 |
++{ |
|
259 |
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
260 |
++ |
|
261 |
++ return sprintf(page, "%s\n", |
|
262 |
++ overlay->ov_id >= 0 ? "applied" : "unapplied"); |
|
263 |
++} |
|
264 |
++ |
|
265 |
++CONFIGFS_ATTR(cfs_overlay_item_, path); |
|
266 |
++CONFIGFS_ATTR_RO(cfs_overlay_item_, status); |
|
267 |
++ |
|
268 |
++static struct configfs_attribute *cfs_overlay_attrs[] = { |
|
269 |
++ &cfs_overlay_item_attr_path, |
|
270 |
++ &cfs_overlay_item_attr_status, |
|
271 |
++ NULL, |
|
272 |
++}; |
|
273 |
++ |
|
274 |
++ssize_t cfs_overlay_item_dtbo_read(struct config_item *item, |
|
275 |
++ void *buf, size_t max_count) |
|
276 |
++{ |
|
277 |
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
278 |
++ |
|
279 |
++ pr_debug("%s: buf=%p max_count=%zu\n", __func__, |
|
280 |
++ buf, max_count); |
|
281 |
++ |
|
282 |
++ if (overlay->dtbo == NULL) |
|
283 |
++ return 0; |
|
284 |
++ |
|
285 |
++ /* copy if buffer provided */ |
|
286 |
++ if (buf != NULL) { |
|
287 |
++ /* the buffer must be large enough */ |
|
288 |
++ if (overlay->dtbo_size > max_count) |
|
289 |
++ return -ENOSPC; |
|
290 |
++ |
|
291 |
++ memcpy(buf, overlay->dtbo, overlay->dtbo_size); |
|
292 |
++ } |
|
293 |
++ |
|
294 |
++ return overlay->dtbo_size; |
|
295 |
++} |
|
296 |
++ |
|
297 |
++ssize_t cfs_overlay_item_dtbo_write(struct config_item *item, |
|
298 |
++ const void *buf, size_t count) |
|
299 |
++{ |
|
300 |
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
301 |
++ int err; |
|
302 |
++ |
|
303 |
++ /* if it's set do not allow changes */ |
|
304 |
++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0) |
|
305 |
++ return -EPERM; |
|
306 |
++ |
|
307 |
++ /* copy the contents */ |
|
308 |
++ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL); |
|
309 |
++ if (overlay->dtbo == NULL) |
|
310 |
++ return -ENOMEM; |
|
311 |
++ |
|
312 |
++ overlay->dtbo_size = count; |
|
313 |
++ |
|
314 |
++ err = create_overlay(overlay, overlay->dtbo); |
|
315 |
++ if (err != 0) |
|
316 |
++ goto out_err; |
|
317 |
++ |
|
318 |
++ return count; |
|
319 |
++ |
|
320 |
++out_err: |
|
321 |
++ kfree(overlay->dtbo); |
|
322 |
++ overlay->dtbo = NULL; |
|
323 |
++ overlay->dtbo_size = 0; |
|
324 |
++ |
|
325 |
++ return err; |
|
326 |
++} |
|
327 |
++ |
|
328 |
++CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M); |
|
329 |
++ |
|
330 |
++static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = { |
|
331 |
++ &cfs_overlay_item_attr_dtbo, |
|
332 |
++ NULL, |
|
333 |
++}; |
|
334 |
++ |
|
335 |
++static void cfs_overlay_release(struct config_item *item) |
|
336 |
++{ |
|
337 |
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
338 |
++ |
|
339 |
++ if (overlay->ov_id >= 0) |
|
340 |
++ of_overlay_remove(&overlay->ov_id); |
|
341 |
++ if (overlay->fw) |
|
342 |
++ release_firmware(overlay->fw); |
|
343 |
++ /* kfree with NULL is safe */ |
|
344 |
++ kfree(overlay->dtbo); |
|
345 |
++ kfree(overlay); |
|
346 |
++} |
|
347 |
++ |
|
348 |
++static struct configfs_item_operations cfs_overlay_item_ops = { |
|
349 |
++ .release = cfs_overlay_release, |
|
350 |
++}; |
|
351 |
++ |
|
352 |
++static struct config_item_type cfs_overlay_type = { |
|
353 |
++ .ct_item_ops = &cfs_overlay_item_ops, |
|
354 |
++ .ct_attrs = cfs_overlay_attrs, |
|
355 |
++ .ct_bin_attrs = cfs_overlay_bin_attrs, |
|
356 |
++ .ct_owner = THIS_MODULE, |
|
357 |
++}; |
|
358 |
++ |
|
359 |
++static struct config_item *cfs_overlay_group_make_item( |
|
360 |
++ struct config_group *group, const char *name) |
|
361 |
++{ |
|
362 |
++ struct cfs_overlay_item *overlay; |
|
363 |
++ |
|
364 |
++ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); |
|
365 |
++ if (!overlay) |
|
366 |
++ return ERR_PTR(-ENOMEM); |
|
367 |
++ overlay->ov_id = -1; |
|
368 |
++ |
|
369 |
++ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type); |
|
370 |
++ return &overlay->item; |
|
371 |
++} |
|
372 |
++ |
|
373 |
++static void cfs_overlay_group_drop_item(struct config_group *group, |
|
374 |
++ struct config_item *item) |
|
375 |
++{ |
|
376 |
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
377 |
++ |
|
378 |
++ config_item_put(&overlay->item); |
|
379 |
++} |
|
380 |
++ |
|
381 |
++static struct configfs_group_operations overlays_ops = { |
|
382 |
++ .make_item = cfs_overlay_group_make_item, |
|
383 |
++ .drop_item = cfs_overlay_group_drop_item, |
|
384 |
++}; |
|
385 |
++ |
|
386 |
++static struct config_item_type overlays_type = { |
|
387 |
++ .ct_group_ops = &overlays_ops, |
|
388 |
++ .ct_owner = THIS_MODULE, |
|
389 |
++}; |
|
390 |
++ |
|
391 |
++static struct configfs_group_operations of_cfs_ops = { |
|
392 |
++ /* empty - we don't allow anything to be created */ |
|
393 |
++}; |
|
394 |
++ |
|
395 |
++static struct config_item_type of_cfs_type = { |
|
396 |
++ .ct_group_ops = &of_cfs_ops, |
|
397 |
++ .ct_owner = THIS_MODULE, |
|
398 |
++}; |
|
399 |
++ |
|
400 |
++struct config_group of_cfs_overlay_group; |
|
401 |
++ |
|
402 |
++static struct configfs_subsystem of_cfs_subsys = { |
|
403 |
++ .su_group = { |
|
404 |
++ .cg_item = { |
|
405 |
++ .ci_namebuf = "device-tree", |
|
406 |
++ .ci_type = &of_cfs_type, |
|
407 |
++ }, |
|
408 |
++ }, |
|
409 |
++ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex), |
|
410 |
++}; |
|
411 |
++ |
|
412 |
++static int __init of_cfs_init(void) |
|
413 |
++{ |
|
414 |
++ int ret; |
|
415 |
++ |
|
416 |
++ pr_info("%s\n", __func__); |
|
417 |
++ |
|
418 |
++ config_group_init(&of_cfs_subsys.su_group); |
|
419 |
++ config_group_init_type_name(&of_cfs_overlay_group, "overlays", |
|
420 |
++ &overlays_type); |
|
421 |
++ configfs_add_default_group(&of_cfs_overlay_group, |
|
422 |
++ &of_cfs_subsys.su_group); |
|
423 |
++ |
|
424 |
++ ret = configfs_register_subsystem(&of_cfs_subsys); |
|
425 |
++ if (ret != 0) { |
|
426 |
++ pr_err("%s: failed to register subsys\n", __func__); |
|
427 |
++ goto out; |
|
428 |
++ } |
|
429 |
++ pr_info("%s: OK\n", __func__); |
|
430 |
++out: |
|
431 |
++ return ret; |
|
432 |
++} |
|
433 |
++late_initcall(of_cfs_init); |
|
434 |
+-- |
|
435 |
+2.7.4 |
|
436 |
+ |
0 | 437 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,120 @@ |
0 |
+From d52d91b920d4b6ae17adc42375649f1ae190006b Mon Sep 17 00:00:00 2001 |
|
1 |
+From: Phil Elwell <phil@raspberrypi.org> |
|
2 |
+Date: Thu, 14 Jun 2018 15:07:26 +0100 |
|
3 |
+Subject: [PATCH] of: configfs: Use of_overlay_fdt_apply API call |
|
4 |
+ |
|
5 |
+The published API to the dynamic overlay application mechanism now |
|
6 |
+takes a Flattened Device Tree blob as input so that it can manage the |
|
7 |
+lifetime of the unflattened tree. Conveniently, the new API call - |
|
8 |
+of_overlay_fdt_apply - is virtually a drop-in replacement for |
|
9 |
+create_overlay, which can now be deleted. |
|
10 |
+ |
|
11 |
+Signed-off-by: Phil Elwell <phil@raspberrypi.org> |
|
12 |
+Signed-off-by: Ajay Kaher <akaher@vmware.com> |
|
13 |
+--- |
|
14 |
+ drivers/of/configfs.c | 47 +++++++---------------------------------------- |
|
15 |
+ 1 file changed, 7 insertions(+), 40 deletions(-) |
|
16 |
+ |
|
17 |
+diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c |
|
18 |
+index 178f062..ac04301 100644 |
|
19 |
+--- a/drivers/of/configfs.c |
|
20 |
+@@ -40,41 +40,6 @@ struct cfs_overlay_item { |
|
21 |
+ int dtbo_size; |
|
22 |
+ }; |
|
23 |
+ |
|
24 |
+-static int create_overlay(struct cfs_overlay_item *overlay, void *blob) |
|
25 |
+-{ |
|
26 |
+- int err; |
|
27 |
+- |
|
28 |
+- /* unflatten the tree */ |
|
29 |
+- of_fdt_unflatten_tree(blob, NULL, &overlay->overlay); |
|
30 |
+- if (overlay->overlay == NULL) { |
|
31 |
+- pr_err("%s: failed to unflatten tree\n", __func__); |
|
32 |
+- err = -EINVAL; |
|
33 |
+- goto out_err; |
|
34 |
+- } |
|
35 |
+- pr_debug("%s: unflattened OK\n", __func__); |
|
36 |
+- |
|
37 |
+- /* mark it as detached */ |
|
38 |
+- of_node_set_flag(overlay->overlay, OF_DETACHED); |
|
39 |
+- |
|
40 |
+- /* perform resolution */ |
|
41 |
+- err = of_resolve_phandles(overlay->overlay); |
|
42 |
+- if (err != 0) { |
|
43 |
+- pr_err("%s: Failed to resolve tree\n", __func__); |
|
44 |
+- goto out_err; |
|
45 |
+- } |
|
46 |
+- pr_debug("%s: resolved OK\n", __func__); |
|
47 |
+- |
|
48 |
+- err = of_overlay_apply(overlay->overlay, &overlay->ov_id); |
|
49 |
+- if (err < 0) { |
|
50 |
+- pr_err("%s: Failed to create overlay (err=%d)\n", |
|
51 |
+- __func__, err); |
|
52 |
+- goto out_err; |
|
53 |
+- } |
|
54 |
+- |
|
55 |
+-out_err: |
|
56 |
+- return err; |
|
57 |
+-} |
|
58 |
+- |
|
59 |
+ static inline struct cfs_overlay_item *to_cfs_overlay_item( |
|
60 |
+ struct config_item *item) |
|
61 |
+ { |
|
62 |
+@@ -115,7 +80,8 @@ static ssize_t cfs_overlay_item_path_store(struct config_item *item, |
|
63 |
+ if (err != 0) |
|
64 |
+ goto out_err; |
|
65 |
+ |
|
66 |
+- err = create_overlay(overlay, (void *)overlay->fw->data); |
|
67 |
++ err = of_overlay_fdt_apply((void *)overlay->fw->data, |
|
68 |
++ (u32)overlay->fw->size, &overlay->ov_id); |
|
69 |
+ if (err != 0) |
|
70 |
+ goto out_err; |
|
71 |
+ |
|
72 |
+@@ -136,7 +102,7 @@ static ssize_t cfs_overlay_item_status_show(struct config_item *item, |
|
73 |
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
74 |
+ |
|
75 |
+ return sprintf(page, "%s\n", |
|
76 |
+- overlay->ov_id >= 0 ? "applied" : "unapplied"); |
|
77 |
++ overlay->ov_id > 0 ? "applied" : "unapplied"); |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ CONFIGFS_ATTR(cfs_overlay_item_, path); |
|
81 |
+@@ -188,7 +154,8 @@ ssize_t cfs_overlay_item_dtbo_write(struct config_item *item, |
|
82 |
+ |
|
83 |
+ overlay->dtbo_size = count; |
|
84 |
+ |
|
85 |
+- err = create_overlay(overlay, overlay->dtbo); |
|
86 |
++ err = of_overlay_fdt_apply(overlay->dtbo, overlay->dtbo_size, |
|
87 |
++ &overlay->ov_id); |
|
88 |
+ if (err != 0) |
|
89 |
+ goto out_err; |
|
90 |
+ |
|
91 |
+@@ -198,6 +165,7 @@ ssize_t cfs_overlay_item_dtbo_write(struct config_item *item, |
|
92 |
+ kfree(overlay->dtbo); |
|
93 |
+ overlay->dtbo = NULL; |
|
94 |
+ overlay->dtbo_size = 0; |
|
95 |
++ overlay->ov_id = 0; |
|
96 |
+ |
|
97 |
+ return err; |
|
98 |
+ } |
|
99 |
+@@ -213,7 +181,7 @@ static void cfs_overlay_release(struct config_item *item) |
|
100 |
+ { |
|
101 |
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); |
|
102 |
+ |
|
103 |
+- if (overlay->ov_id >= 0) |
|
104 |
++ if (overlay->ov_id > 0) |
|
105 |
+ of_overlay_remove(&overlay->ov_id); |
|
106 |
+ if (overlay->fw) |
|
107 |
+ release_firmware(overlay->fw); |
|
108 |
+@@ -241,7 +209,6 @@ static struct config_item *cfs_overlay_group_make_item( |
|
109 |
+ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); |
|
110 |
+ if (!overlay) |
|
111 |
+ return ERR_PTR(-ENOMEM); |
|
112 |
+- overlay->ov_id = -1; |
|
113 |
+ |
|
114 |
+ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type); |
|
115 |
+ return &overlay->item; |
|
116 |
+-- |
|
117 |
+2.7.4 |
|
118 |
+ |
... | ... |
@@ -2,7 +2,7 @@ |
2 | 2 |
Summary: Kernel |
3 | 3 |
Name: linux |
4 | 4 |
Version: 4.19.52 |
5 |
-Release: 6%{?kat_build:.%kat_build}%{?dist} |
|
5 |
+Release: 7%{?kat_build:.%kat_build}%{?dist} |
|
6 | 6 |
License: GPLv2 |
7 | 7 |
URL: http://www.kernel.org/ |
8 | 8 |
Group: System Environment/Kernel |
... | ... |
@@ -62,6 +62,10 @@ Patch38: 0001-ipv6_sockglue-Fix-a-missing-check-bug-in-ip6_ra_cont.patch |
62 | 62 |
Patch39: 0001-clk-sunxi-fix-a-missing-check-bug-in-sunxi_divs_clk_.patch |
63 | 63 |
|
64 | 64 |
%ifarch aarch64 |
65 |
+# Rpi of_configfs patches |
|
66 |
+Patch40: 0001-OF-DT-Overlay-configfs-interface.patch |
|
67 |
+Patch41: 0002-of-configfs-Use-of_overlay_fdt_apply-API-call.patch |
|
68 |
+ |
|
65 | 69 |
# NXP LS1012a FRWY patches |
66 | 70 |
Patch51: 0001-staging-fsl_ppfe-eth-header-files-for-pfe-driver.patch |
67 | 71 |
Patch52: 0002-staging-fsl_ppfe-eth-introduce-pfe-driver.patch |
... | ... |
@@ -210,6 +214,10 @@ Kernel Device Tree Blob files for NXP ls1012a FRWY board |
210 | 210 |
%patch39 -p1 |
211 | 211 |
|
212 | 212 |
%ifarch aarch64 |
213 |
+# Rpi of_configfs patches |
|
214 |
+%patch40 -p1 |
|
215 |
+%patch41 -p1 |
|
216 |
+ |
|
213 | 217 |
# NXP FSL_PPFE Driver patches |
214 | 218 |
%patch51 -p1 |
215 | 219 |
%patch52 -p1 |
... | ... |
@@ -467,6 +475,8 @@ ln -sf %{name}-%{uname_r}.cfg /boot/photon.cfg |
467 | 467 |
%endif |
468 | 468 |
|
469 | 469 |
%changelog |
470 |
+* Tue Jul 30 2019 Ajay Kaher <akaher@vmware.com> 4.19.52-7 |
|
471 |
+- Added of_configfs patches to dynamic load Overlays. |
|
470 | 472 |
* Thu Jul 25 2019 Keerthana K <keerthanak@vmware.com> 4.19.52-6 |
471 | 473 |
- Fix postun scriplet. |
472 | 474 |
* Thu Jul 11 2019 Keerthana K <keerthanak@vmware.com> 4.19.52-5 |
473 | 475 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,108 @@ |
0 |
+From dce4683cbbe107a95f1f0d45fabc304acfb5d71a Mon Sep 17 00:00:00 2001 |
|
1 |
+From: Andreas Gruenbacher <agruen@gnu.org> |
|
2 |
+Date: Mon, 15 Jul 2019 16:21:48 +0200 |
|
3 |
+Subject: Don't follow symlinks unless --follow-symlinks is given |
|
4 |
+ |
|
5 |
+* src/inp.c (plan_a, plan_b), src/util.c (copy_to_fd, copy_file, |
|
6 |
+append_to_file): Unless the --follow-symlinks option is given, open files with |
|
7 |
+the O_NOFOLLOW flag to avoid following symlinks. So far, we were only doing |
|
8 |
+that consistently for input files. |
|
9 |
+* src/util.c (create_backup): When creating empty backup files, (re)create them |
|
10 |
+with O_CREAT | O_EXCL to avoid following symlinks in that case as well. |
|
11 |
+--- |
|
12 |
+ src/inp.c | 12 ++++++++++-- |
|
13 |
+ src/util.c | 14 +++++++++++--- |
|
14 |
+ 2 files changed, 21 insertions(+), 5 deletions(-) |
|
15 |
+ |
|
16 |
+diff --git a/src/inp.c b/src/inp.c |
|
17 |
+index 32d0919..22d7473 100644 |
|
18 |
+--- a/src/inp.c |
|
19 |
+@@ -238,8 +238,13 @@ plan_a (char const *filename) |
|
20 |
+ { |
|
21 |
+ if (S_ISREG (instat.st_mode)) |
|
22 |
+ { |
|
23 |
+- int ifd = safe_open (filename, O_RDONLY|binary_transput, 0); |
|
24 |
++ int flags = O_RDONLY | binary_transput; |
|
25 |
+ size_t buffered = 0, n; |
|
26 |
++ int ifd; |
|
27 |
++ |
|
28 |
++ if (! follow_symlinks) |
|
29 |
++ flags |= O_NOFOLLOW; |
|
30 |
++ ifd = safe_open (filename, flags, 0); |
|
31 |
+ if (ifd < 0) |
|
32 |
+ pfatal ("can't open file %s", quotearg (filename)); |
|
33 |
+ |
|
34 |
+@@ -340,6 +345,7 @@ plan_a (char const *filename) |
|
35 |
+ static void |
|
36 |
+ plan_b (char const *filename) |
|
37 |
+ { |
|
38 |
++ int flags = O_RDONLY | binary_transput; |
|
39 |
+ int ifd; |
|
40 |
+ FILE *ifp; |
|
41 |
+ int c; |
|
42 |
+@@ -353,7 +359,9 @@ plan_b (char const *filename) |
|
43 |
+ |
|
44 |
+ if (instat.st_size == 0) |
|
45 |
+ filename = NULL_DEVICE; |
|
46 |
+- if ((ifd = safe_open (filename, O_RDONLY | binary_transput, 0)) < 0 |
|
47 |
++ if (! follow_symlinks) |
|
48 |
++ flags |= O_NOFOLLOW; |
|
49 |
++ if ((ifd = safe_open (filename, flags, 0)) < 0 |
|
50 |
+ || ! (ifp = fdopen (ifd, binary_transput ? "rb" : "r"))) |
|
51 |
+ pfatal ("Can't open file %s", quotearg (filename)); |
|
52 |
+ if (TMPINNAME_needs_removal) |
|
53 |
+diff --git a/src/util.c b/src/util.c |
|
54 |
+index 1cc08ba..fb38307 100644 |
|
55 |
+--- a/src/util.c |
|
56 |
+@@ -388,7 +388,7 @@ create_backup (char const *to, const struct stat *to_st, bool leave_original) |
|
57 |
+ |
|
58 |
+ try_makedirs_errno = ENOENT; |
|
59 |
+ safe_unlink (bakname); |
|
60 |
+- while ((fd = safe_open (bakname, O_CREAT | O_WRONLY | O_TRUNC, 0666)) < 0) |
|
61 |
++ while ((fd = safe_open (bakname, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC, 0666)) < 0) |
|
62 |
+ { |
|
63 |
+ if (errno != try_makedirs_errno) |
|
64 |
+ pfatal ("Can't create file %s", quotearg (bakname)); |
|
65 |
+@@ -579,10 +579,13 @@ create_file (char const *file, int open_flags, mode_t mode, |
|
66 |
+ static void |
|
67 |
+ copy_to_fd (const char *from, int tofd) |
|
68 |
+ { |
|
69 |
++ int from_flags = O_RDONLY | O_BINARY; |
|
70 |
+ int fromfd; |
|
71 |
+ ssize_t i; |
|
72 |
+ |
|
73 |
+- if ((fromfd = safe_open (from, O_RDONLY | O_BINARY, 0)) < 0) |
|
74 |
++ if (! follow_symlinks) |
|
75 |
++ from_flags |= O_NOFOLLOW; |
|
76 |
++ if ((fromfd = safe_open (from, from_flags, 0)) < 0) |
|
77 |
+ pfatal ("Can't reopen file %s", quotearg (from)); |
|
78 |
+ while ((i = read (fromfd, buf, bufsize)) != 0) |
|
79 |
+ { |
|
80 |
+@@ -625,6 +628,8 @@ copy_file (char const *from, char const *to, struct stat *tost, |
|
81 |
+ else |
|
82 |
+ { |
|
83 |
+ assert (S_ISREG (mode)); |
|
84 |
++ if (! follow_symlinks) |
|
85 |
++ to_flags |= O_NOFOLLOW; |
|
86 |
+ tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode, |
|
87 |
+ to_dir_known_to_exist); |
|
88 |
+ copy_to_fd (from, tofd); |
|
89 |
+@@ -640,9 +645,12 @@ copy_file (char const *from, char const *to, struct stat *tost, |
|
90 |
+ void |
|
91 |
+ append_to_file (char const *from, char const *to) |
|
92 |
+ { |
|
93 |
++ int to_flags = O_WRONLY | O_APPEND | O_BINARY; |
|
94 |
+ int tofd; |
|
95 |
+ |
|
96 |
+- if ((tofd = safe_open (to, O_WRONLY | O_BINARY | O_APPEND, 0)) < 0) |
|
97 |
++ if (! follow_symlinks) |
|
98 |
++ to_flags |= O_NOFOLLOW; |
|
99 |
++ if ((tofd = safe_open (to, to_flags, 0)) < 0) |
|
100 |
+ pfatal ("Can't reopen file %s", quotearg (to)); |
|
101 |
+ copy_to_fd (from, tofd); |
|
102 |
+ if (close (tofd) != 0) |
|
103 |
+-- |
|
104 |
+cgit v1.0-41-gc330 |
|
105 |
+ |
0 | 106 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,38 @@ |
0 |
+From 3fcd042d26d70856e826a42b5f93dc4854d80bf0 Mon Sep 17 00:00:00 2001 |
|
1 |
+From: Andreas Gruenbacher <agruen@gnu.org> |
|
2 |
+Date: Fri, 6 Apr 2018 19:36:15 +0200 |
|
3 |
+Subject: Invoke ed directly instead of using the shell |
|
4 |
+ |
|
5 |
+* src/pch.c (do_ed_script): Invoke ed directly instead of using a shell |
|
6 |
+command to avoid quoting vulnerabilities. |
|
7 |
+--- |
|
8 |
+ src/pch.c | 6 ++---- |
|
9 |
+ 1 file changed, 2 insertions(+), 4 deletions(-) |
|
10 |
+ |
|
11 |
+diff --git a/src/pch.c b/src/pch.c |
|
12 |
+index 4fd5a05..16e001a 100644 |
|
13 |
+--- a/src/pch.c |
|
14 |
+@@ -2459,9 +2459,6 @@ do_ed_script (char const *inname, char const *outname, |
|
15 |
+ *outname_needs_removal = true; |
|
16 |
+ copy_file (inname, outname, 0, exclusive, instat.st_mode, true); |
|
17 |
+ } |
|
18 |
+- sprintf (buf, "%s %s%s", editor_program, |
|
19 |
+- verbosity == VERBOSE ? "" : "- ", |
|
20 |
+- outname); |
|
21 |
+ fflush (stdout); |
|
22 |
+ |
|
23 |
+ pid = fork(); |
|
24 |
+@@ -2470,7 +2467,8 @@ do_ed_script (char const *inname, char const *outname, |
|
25 |
+ else if (pid == 0) |
|
26 |
+ { |
|
27 |
+ dup2 (tmpfd, 0); |
|
28 |
+- execl ("/bin/sh", "sh", "-c", buf, (char *) 0); |
|
29 |
++ assert (outname[0] != '!' && outname[0] != '-'); |
|
30 |
++ execlp (editor_program, editor_program, "-", outname, (char *) NULL); |
|
31 |
+ _exit (2); |
|
32 |
+ } |
|
33 |
+ else |
|
34 |
+-- |
|
35 |
+cgit v1.0-41-gc330 |
|
36 |
+ |
... | ... |
@@ -1,7 +1,7 @@ |
1 | 1 |
Summary: Program for modifying or creating files |
2 | 2 |
Name: patch |
3 | 3 |
Version: 2.7.6 |
4 |
-Release: 3%{?dist} |
|
4 |
+Release: 4%{?dist} |
|
5 | 5 |
License: GPLv3+ |
6 | 6 |
URL: http://www.gnu.org/software/%{name} |
7 | 7 |
Source0: ftp://ftp.gnu.org/gnu/patch/%{name}-%{version}.tar.gz |
... | ... |
@@ -9,6 +9,8 @@ Source0: ftp://ftp.gnu.org/gnu/patch/%{name}-%{version}.tar.gz |
9 | 9 |
Patch0: CVE-2018-6951.patch |
10 | 10 |
Patch1: CVE-2018-1000156.patch |
11 | 11 |
Patch2: CVE-2018-6952.patch |
12 |
+patch3: CVE-2019-13636.patch |
|
13 |
+Patch4: CVE-2019-13638.patch |
|
12 | 14 |
Group: Development/Tools |
13 | 15 |
Vendor: VMware, Inc. |
14 | 16 |
Distribution: Photon |
... | ... |
@@ -23,6 +25,8 @@ file typically created by the diff program. |
23 | 23 |
%patch0 -p1 |
24 | 24 |
%patch1 -p1 |
25 | 25 |
%patch2 -p1 |
26 |
+%patch3 -p1 |
|
27 |
+%patch4 -p1 |
|
26 | 28 |
|
27 | 29 |
%build |
28 | 30 |
%configure --disable-silent-rules |
... | ... |
@@ -41,6 +45,8 @@ make %{?_smp_mflags} check |
41 | 41 |
%{_mandir}/*/* |
42 | 42 |
|
43 | 43 |
%changelog |
44 |
+* Thu Aug 08 2019 Shreenidhi Shedi <sshedi@vmware.com> 2.7.6-4 |
|
45 |
+- Apply patch for CVE-2019-13636, CVE-2019-13638 |
|
44 | 46 |
* Mon Nov 19 2018 Siju Maliakkal <smaliakkal@vmware.com> 2.7.6-3 |
45 | 47 |
- Add patches for CVE-2018-6951,CVE-2018-1000156,CVE-2018-6952 |
46 | 48 |
* Tue Oct 2 2018 Michelle Wang <michellew@vmware.com> 2.7.6-2 |