# -*- coding: utf-8 -*- # # Copyright (c) 2014 Virtual Cable S.L. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * Neither the name of Virtual Cable S.L. nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' @author: Adolfo Gómez, dkmaster at dkmon dot com ''' import socket import platform import fcntl import os import locale import ctypes # @UnusedImport import ctypes.util import subprocess import struct import array import six import json from opengnsys import utils ip_a_s = None ## make sure /usr/local/bin is in PATH ## we need that to run /usr/local/bin/ip, which uses 'env' and pulls from PATH anyway def check_path(): path = os.getenv ('PATH', '') usr_local_bin = '/usr/local/bin' if usr_local_bin not in path.split (os.pathsep): os.environ['PATH'] = usr_local_bin + os.pathsep + path def _getMacAddr(ifname): ''' Returns the mac address of an interface Mac is returned as unicode utf-8 encoded ''' for interface in ip_a_s: if interface.get ('ifname') != ifname: continue return interface.get ('address') return None def _getIpAddr(ifname): ''' Returns the first IP address of an interface IPv4 is preferred over IPv6 IP is returned as unicode utf-8 encoded ''' ## loop and return the first IPv4 address found for interface in ip_a_s: if interface.get ('ifname') != ifname: continue for addr_info in interface.get ('addr_info', []): ip_address = addr_info.get ('local') try: ip_address.index ('.') return ip_address except: pass ## if nothing found, loop again and return the first IP found, which will be an IPv6 for interface in ip_a_s: if interface.get ('ifname') != ifname: continue for addr_info in interface.get ('addr_info', []): return addr_info.get ('local') return None def _getInterfaces(): ''' Returns a list of interfaces names ''' global ip_a_s check_path() result = subprocess.run (['/usr/local/bin/ip', '-json', 'address', 'show'], capture_output=True, text=True) if result.returncode != 0: raise Exception (f'Command "ip" failed with exit code {result.returncode}') ip_a_s = json.loads (result.stdout) return [i.get('ifname') for i in ip_a_s] def _getIpAndMac(ifname): ip, mac = _getIpAddr(ifname), _getMacAddr(ifname) return (ip, mac) def getNetworkInfo(): ''' Obtains a list of network interfaces @return: A "generator" of elements, that are dict-as-object, with this elements: name: Name of the interface mac: mac of the interface ip: ip of the interface ''' for ifname in _getInterfaces(): ip, mac = _getIpAndMac(ifname) if mac != None and ip != None: # Skips local interfaces yield utils.Bunch(name=ifname, mac=mac, ip=ip) def getMacosVersion(): return 'macOS {}'.format(platform.mac_ver()[0]) def reboot(flags=0): ''' Simple reboot command ''' # Workaround for dummy thread if six.PY3 is False: import threading threading._DummyThread._Thread__stop = lambda x: 42 # Exec reboot command subprocess.call('/sbin/shutdown -r now', shell=True) def poweroff(flags=0): ''' Simple poweroff command ''' # Workaround for dummy thread if six.PY3 is False: import threading threading._DummyThread._Thread__stop = lambda x: 42 # Exec shutdown command subprocess.call('/sbin/shutdown -h now', shell=True) def logoff(): ''' Simple logout using AppleScript ''' # Workaround for dummy thread if six.PY3 is False: import threading threading._DummyThread._Thread__stop = lambda x: 42 # Exec logout using AppleScript subprocess.call('/usr/bin/osascript -e \'tell app "System Events" to «event aevtrlgo»\'', shell=True) def getCurrentUser(): ''' Returns current logged in user ''' return os.environ['USER'] def getSessionLanguage(): ''' Returns the user's session language ''' lang = locale.getdefaultlocale()[0] if lang is None: return 'C' else: return lang def get_session_type(): """ Minimal implementation of this required function :return: string """ return 'unknown' def showPopup(title, message): ''' Displays a message box on user's session (during 1 min). ''' # Show a dialog using AppleSctipt return subprocess.call('/usr/bin/osascript -e \'display notification "{}" with title "{}"\''.format(message, title), shell=True) def get_etc_path(): """ :return: Returns etc directory path. """ return os.sep + 'etc' def build_popen_args(script): return ['/bin/sh', '-c', script]