Browse code

Merge branch 'master' of https://github.com/vmware/photon

archive authored on 2019/08/09 23:30:24
Showing 13 changed files
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
... ...
@@ -32,7 +32,7 @@ datasource_list: [
32 32
 #                  CloudSigma, 
33 33
 #                  Ec2, 
34 34
 #                  CloudStack,
35
-#                  VmxGuestinfo, 
35
+                  VMwareGuestInfo,
36 36
                   None 
37 37
                  ]
38 38
 
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
+
... ...
@@ -1655,6 +1655,7 @@ CONFIG_OF_RESERVED_MEM=y
1655 1655
 CONFIG_OF_RESOLVE=y
1656 1656
 CONFIG_OF_OVERLAY=y
1657 1657
 CONFIG_OF_NUMA=y
1658
+CONFIG_OF_CONFIGFS=y
1658 1659
 # CONFIG_PARPORT is not set
1659 1660
 CONFIG_PNP=y
1660 1661
 # CONFIG_PNP_DEBUG_MESSAGES is not set
... ...
@@ -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