]> granicus.if.org Git - python/commitdiff
Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat.
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 7 Nov 2014 10:23:30 +0000 (12:23 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Fri, 7 Nov 2014 10:23:30 +0000 (12:23 +0200)
Based on patch by Aivars Kalvāns.

1  2 
Lib/test/test_uuid.py
Lib/uuid.py
Misc/NEWS

index 115e66c2160a4501f97afe3e8cdd3a292a8df5d2,10105b00dc7c8dc5e95c9066e03a06b28a42c408..bfa9f973d77b2374a1c3e90d502220be37d3bdc6
@@@ -367,22 -385,22 +385,22 @@@ fake hwadd
  cscotun0  Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
  eth0      Link encap:Ethernet  HWaddr 12:34:56:78:90:ab
  '''
 -        def mock_popen(cmd):
 -            return io.StringIO(data)
 -
 -        if shutil.which('ifconfig') is None:
 -            path = os.pathsep.join(('/sbin', '/usr/sbin'))
 -            if shutil.which('ifconfig', path=path) is None:
 -                self.skipTest('requires ifconfig')
 -
 -        with support.swap_attr(os, 'popen', mock_popen):
 -            mac = uuid._find_mac(
 -                command='ifconfig',
 -                args='',
 -                hw_identifiers=['hwaddr'],
 -                get_index=lambda x: x + 1,
 -            )
 -            self.assertEqual(mac, 0x1234567890ab)
 +
 +        popen = unittest.mock.MagicMock()
 +        popen.stdout = io.BytesIO(data.encode())
 +
 +        with unittest.mock.patch.object(shutil, 'which',
 +                                        return_value='/sbin/ifconfig'):
 +            with unittest.mock.patch.object(subprocess, 'Popen',
 +                                            return_value=popen):
 +                mac = uuid._find_mac(
 +                    command='ifconfig',
-                     arg='',
++                    args='',
 +                    hw_identifiers=[b'hwaddr'],
 +                    get_index=lambda x: x + 1,
 +                )
 +
 +        self.assertEqual(mac, 0x1234567890ab)
  
      @unittest.skipUnless(importable('ctypes'), 'requires ctypes')
      def test_uuid1(self):
diff --cc Lib/uuid.py
index 018bb6f51ba47ae696c1ecdd6920c5cb9bcc210c,83210134903401cfd8e8904f9da763fb28db153e..598aea1956ab1efce563b16797497771eacb6f71
@@@ -304,36 -311,35 +304,40 @@@ class UUID(object)
          if self.variant == RFC_4122:
              return int((self.int >> 76) & 0xf)
  
- def _find_mac(command, arg, hw_identifiers, get_index):
 -def _popen(command, args):
 -    import os, shutil
++def _popen(command, *args):
 +    import os, shutil, subprocess
      executable = shutil.which(command)
      if executable is None:
          path = os.pathsep.join(('/sbin', '/usr/sbin'))
          executable = shutil.which(command, path=path)
          if executable is None:
              return None
 -    # LC_ALL to ensure English output, 2>/dev/null to prevent output on
 -    # stderr (Note: we don't have an example where the words we search for
 -    # are actually localized, but in theory some system could do so.)
 -    cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
 -    return os.popen(cmd)
++    # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output
++    # on stderr (Note: we don't have an example where the words we search
++    # for are actually localized, but in theory some system could do so.)
++    env = dict(os.environ)
++    env['LC_ALL'] = 'C'
++    proc = subprocess.Popen((executable,) + args,
++                            stdout=subprocess.PIPE,
++                            stderr=subprocess.DEVNULL,
++                            env=env)
++    return proc
+ def _find_mac(command, args, hw_identifiers, get_index):
      try:
-         # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output
-         # on stderr (Note: we don't have an example where the words we search
-         # for are actually localized, but in theory some system could do so.)
-         env = dict(os.environ)
-         env['LC_ALL'] = 'C'
-         cmd = [executable]
-         if arg:
-             cmd.append(arg)
-         proc = subprocess.Popen(cmd,
-                                 stdout=subprocess.PIPE,
-                                 stderr=subprocess.DEVNULL,
-                                 env=env)
 -        pipe = _popen(command, args)
 -        if not pipe:
++        proc = _popen(command, *args.split())
++        if not proc:
+             return
 -        with pipe:
 -            for line in pipe:
 +        with proc:
 +            for line in proc.stdout:
-                 words = line.lower().split()
+                 words = line.lower().rstrip().split()
                  for i in range(len(words)):
                      if words[i] in hw_identifiers:
                          try:
-                             return int(
-                                 words[get_index(i)].replace(b':', b''), 16)
+                             word = words[get_index(i)]
 -                            mac = int(word.replace(':', ''), 16)
++                            mac = int(word.replace(b':', b''), 16)
+                             if mac:
+                                 return mac
                          except (ValueError, IndexError):
                              # Virtual interfaces, such as those provided by
                              # VPNs, do not have a colon-delimited MAC address
  
  def _ifconfig_getnode():
      """Get the hardware address on Unix by running ifconfig."""
-     import os
      # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
      for args in ('', '-a', '-av'):
 -        mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
 +        mac = _find_mac('ifconfig', args, [b'hwaddr', b'ether'], lambda i: i+1)
          if mac:
              return mac
  
@@@ -358,16 -364,38 +362,38 @@@ def _arp_getnode()
      ip_addr = socket.gethostbyname(socket.gethostname())
  
      # Try getting the MAC addr from arp based on our IP address (Solaris).
-     mac = _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1)
-     if mac:
-         return mac
 -    return _find_mac('arp', '-an', [ip_addr], lambda i: -1)
++    return _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1)
  
+ def _lanscan_getnode():
+     """Get the hardware address on Unix by running lanscan."""
      # This might work on HP-UX.
-     mac = _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0)
-     if mac:
-         return mac
 -    return _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
++    return _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0)
  
-     return None
+ def _netstat_getnode():
+     """Get the hardware address on Unix by running netstat."""
+     # This might work on AIX, Tru64 UNIX and presumably on IRIX.
+     try:
 -        pipe = _popen('netstat', '-ia')
 -        if not pipe:
++        proc = _popen('netstat', '-ia')
++        if not proc:
+             return
 -        with pipe:
 -            words = pipe.readline().rstrip().split()
++        with proc:
++            words = proc.stdout.readline().rstrip().split()
+             try:
 -                i = words.index('Address')
++                i = words.index(b'Address')
+             except ValueError:
+                 return
 -            for line in pipe:
++            for line in proc.stdout:
+                 try:
+                     words = line.rstrip().split()
+                     word = words[i]
 -                    if len(word) == 17 and word.count(':') == 5:
 -                        mac = int(word.replace(':', ''), 16)
++                    if len(word) == 17 and word.count(b':') == 5:
++                        mac = int(word.replace(b':', b''), 16)
+                         if mac:
+                             return mac
+                 except (ValueError, IndexError):
+                     pass
+     except OSError:
+         pass
  
  def _ipconfig_getnode():
      """Get the hardware address on Windows by running ipconfig.exe."""
diff --cc Misc/NEWS
Simple merge