From: Serhiy Storchaka Date: Fri, 7 Nov 2014 10:23:30 +0000 (+0200) Subject: Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. X-Git-Tag: v3.5.0a1~508 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=57b967791a552656f4c21a4af283788269d06d83;p=thirdparty%2FPython%2Fcpython.git Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. Based on patch by Aivars Kalvāns. --- 57b967791a552656f4c21a4af283788269d06d83 diff --cc Lib/test/test_uuid.py index 115e66c2160a,10105b00dc7c..bfa9f973d77b --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@@ -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 018bb6f51ba4,832101349034..598aea1956ab --- a/Lib/uuid.py +++ b/Lib/uuid.py @@@ -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 @@@ -346,11 -352,9 +350,9 @@@ 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."""