def _setsyslog(cls, facility=LOGFACILITY.USER): cls._initlogger() try: facility = int(facility) for fac in dir(LOGFACILITY): if '_' in fac: continue if getattr(LOGFACILITY, fac) == facility: facility = 'LOG_' + fac break else: raise MythError("Invalid syslog facility") except ValueError: if not facility.startswith('LOG_'): facility = 'LOG_' + facility.upper() if not hasattr(LOGFACILITY, facility[4:]): raise MythError("Invalid syslog facility") cls._SYSLOG = facility application = argv[0] if '/' in application: application = application.rsplit('/', 1)[1] syslog.openlog(application, syslog.LOG_NDELAY | syslog.LOG_PID, getattr(syslog, facility)) cls._logwrite = cls._logsyslog # clear other logging options: if cls._LOGFILE: if cls._LOGFILE.fileno() != 1: cls._LOGFILE.close() cls._LOGFILE = None if cls._JOURNALLOG: cls._JOURNALLOG = False
def dlrecv(self, bufsize, flags=0, deadline=None): # pull default timeout if deadline is None: deadline = self._deadline if deadline < 1000: deadline += time() buff = BytesIO() # loop until necessary data has been received while bufsize > buff.tell(): # wait for data on the socket t = time() timeout = (deadline-t) if (deadline-t>0) else 0.0 if len(select([self],[],[], timeout)[0]) == 0: # deadline reached, terminate return b'' # append response to buffer p = buff.tell() try: buff.write(self.recv(bufsize-buff.tell(), flags)) except socket.error as e: raise MythError(MythError.SOCKET, e.args) if buff.tell() == p: # no data read from a 'ready' socket, connection terminated raise MythError(MythError.SOCKET, (54, 'Connection reset by peer')) if timeout == 0: break return buff.getvalue()
def dlexpect(self, pattern, flags=0, deadline=None): """Loop recv listening for a provided regular expression.""" # pull default timeout if deadline is None: deadline = self._deadline if deadline < 1000: deadline += time() buff = BytesIO() # loop until pattern has been found while not pattern.search(buff.getvalue()): # wait for data on the socket t = time() timeout = (deadline-t) if (deadline-t>0) else 0.0 if len(select([self],[],[], timeout)[0]) == 0: # deadline reached, terminate return b'' # append response to buffer p = buff.tell() try: buff.write(self.recv(100, flags)) except socket.error as e: raise MythError(MythError.SOCKET, e.args) if buff.tell() == p: # no data read from a 'ready' socket, connection terminated raise MythError(MythError.SOCKET, (54, 'Connection reset by peer')) if timeout == 0: break return buff.getvalue()
def __call__(self, *args, **kwargs): if self.func is None: if len(args) == 1: self.func = args[0] elif 'func' in kwargs: self.func = kwargs['func'] if not callable(self.func): raise MythError('_ProgramQuery must receive a callable '+\ 'before it is functional') self.__doc__ = self.func.__doc__ self.__name__ = self.func.__name__ self.__module__ = self.func.__module__ return self elif self.inst is None: raise MythError('Call to uninitialized _ProgramQuery instance') if self.sorted: return self.sortedrun(*args, **kwargs) return self.run(*args, **kwargs)
def sendheader(self, data, flags=0): """Send data, prepending the length in the first 8 bytes.""" try: self.log(MythLog.SOCKET|MythLog.NETWORK, MythLog.DEBUG, \ 'write --> %d' % len(data), data) data = '%-8d%s' % (len(data), data) self.send(data, flags) except socket.error, e: raise MythError(MythError.SOCKET, e.args)
def _runcmd(self, cmd): p = self.Process(cmd, self.useshell, self.log) p.wait() self.returncode = p.poll() self.stderr = p.stderr.read() if self.returncode: raise MythError(MythError.SYSTEM,self.returncode,cmd,self.stderr) return p.stdout.read()
def sendheader(self, data, flags=0): """Send data, prepending the length in the first 8 bytes.""" try: self.log(MythLog.SOCKET|MythLog.NETWORK, MythLog.DEBUG, \ 'write --> %d' % len(data), py3_str(data, True)) # build the byte array: length = b'%-8d' % len(data) data = b"".join([length, data]) self.send(data, flags) except socket.error as e: raise MythError(MythError.SOCKET, e.args)
def __init__(self, path=None, setting=None, db=None, useshell=True, prefix=''): DBCache.__init__(self, db=db) self.log = MythLog(self.logmodule, db=self) self.path = None if setting is not None: # pull local setting from database host = self.gethostname() self.path = self.settings[host][setting] if self.path is None: # see if that setting is applied globally self.path = self.settings['NULL'][setting] if self.path is None: # not set globally either, use supplied default self.path = path if self.path is None: # no default supplied, just error out raise MythDBError(MythError.DB_SETTING, setting, host) if self.path is None: # setting not given, use path from argument if path is None: raise MythError('Invalid input to System()') self.path = path if prefix: self.path = os.path.join(prefix, self.path) cmd = self.path.split()[0] if self.path.startswith('/'): # test full given path if not os.access(cmd, os.F_OK): raise MythFileError('Defined executable path does not exist.') else: # search command from PATH for folder in os.environ['PATH'].split(':'): if os.access(os.path.join(folder, cmd), os.F_OK): self.path = os.path.join(folder, self.path) break else: raise MythFileError('Defined executable path does not exist.') self.returncode = 0 self.stderr = '' self.useshell = useshell
def _process(self, data): """ Accepts a list of data, processes according to specified types, and returns a dictionary """ if self._field_type != 'Pass': if len(data) != len(self._field_type): raise MythError('Incorrect raw input length to DictData()') data = list(data) for i, v in enumerate(data): if v == '': data[i] = None else: data[i] = self._trans[self._field_type[i]](v) return dict(zip(self._field_order, data))
def _setjournallog(cls): cls._initlogger() if journal: cls._JOURNALLOG = True cls._logwrite = cls._logjournallog # clear other logging options: if cls._LOGFILE: if cls._LOGFILE.fileno() != 1: cls._LOGFILE.close() cls._LOGFILE = None if cls._SYSLOG: cls._SYSLOG = None syslog.closelog() else: raise MythError("Error: Python module 'systemd.journal' not available! " + \ "Please install 'python-systemd' module.")
def __init__(self, func): # set function and update strings self.func = func self.__doc__ = self.func.__doc__ self.__name__ = self.func.__name__ self.__module__ = self.func.__module__ # set defaults self.table = None self.handler = None self.require = () self.joins = () # pull in properties self.func(self, self) # sanity check if (self.table is None) or (self.handler is None): raise MythError('Improperly configured databaseSearch class')
def __init__(self): self.log = MythLog('Python M-Search') port = 1900 addr = '239.255.255.250' self.dest = (addr, port) self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) listening = False while listening == False: try: self.sock.bind(('', port)) self.addr = (addr, port) listening = True except socket.error, e: if port < 1910: port += 1 else: raise MythError(MythError.SOCKET, e)
def _parseinput(cls): args = iter(argv) next(args) n = 0 try: while True: arg = next(args) if arg == '--quiet': cls._QUIET += 1 elif arg == '--nodblog': cls._DBLOG = False elif arg == '--enable-dblog': cls._DBLOG = True elif arg == '--loglevel': cls._setlevel(next(args)) elif arg == '--verbose': cls._setmask(next(args)) elif arg == '--logfile': cls._setfile(next(args)) n += 1 elif arg == '--logpath': cls._setpath(next(args)) n += 1 elif arg == '--syslog': cls._setsyslog(next(args)) n += 1 elif arg == '--systemd-journal': cls._setjournallog() n += 1 elif arg == '--': break except StopIteration: pass # only allow one logging method if (n > 1): raise MythError("Error: These logging options are mutually exclusive: " + \ "'logfile', 'logpath', 'syslog' or 'systemd-journal'!")
def ftopen(file, mode, forceremote=False, nooverwrite=False, db=None, \ chanid=None, starttime=None, download=False): """ ftopen(file, mode, forceremote=False, nooverwrite=False, db=None) -> FileTransfer object -> file object Method will attempt to open file locally, falling back to remote access over mythprotocol if necessary. 'forceremote' will force a FileTransfer object if possible. 'file' takes a standard MythURI: myth://<group>@<host>:<port>/<path> 'mode' takes a 'r' or 'w' 'nooverwrite' will refuse to open a file writable, if a local file is found. """ db = DBCache(db) log = MythLog('Python File Transfer', db=db) reuri = re.compile(\ 'myth://((?P<group>.*)@)?(?P<host>[\[\]a-zA-Z0-9_\-\.]*)(:[0-9]*)?/(?P<file>.*)') reip = re.compile('(?:\d{1,3}\.){3}\d{1,3}') if mode not in ('r', 'w'): raise TypeError("File I/O must be of type 'r' or 'w'") if chanid and starttime: protoopen = lambda host, file, storagegroup: \ RecordFileTransfer(host, file, storagegroup,\ mode, chanid, starttime, db) elif download: protoopen = lambda host, lfile, storagegroup: \ DownloadFileTransfer(host, lfile, storagegroup, \ mode, file, db) else: protoopen = lambda host, file, storagegroup: \ FileTransfer(host, file, storagegroup, mode, db) # process URI (myth://<group>@<host>[:<port>]/<path/to/file>) match = reuri.match(file) if match is None: raise MythError('Invalid FileTransfer input string: ' + file) host = match.group('host') filename = match.group('file') sgroup = match.group('group') if sgroup is None: sgroup = 'Default' # get full system name host = host.strip('[]') if reip.match(host) or check_ipv6(host): host = db._gethostfromaddr(host) # user forced to remote access if forceremote: if (mode == 'w') and (filename.find('/') != -1): raise MythFileError(MythError.FILE_FAILED_WRITE, file, 'attempting remote write outside base path') if nooverwrite and FileOps(host, db=db).fileExists(filename, sgroup): raise MythFileError(MythError.FILE_FAILED_WRITE, file, 'refusing to overwrite existing file') return protoopen(host, filename, sgroup) if mode == 'w': # check for pre-existing file path = FileOps(host, db=db).fileExists(filename, sgroup) sgs = list(db.getStorageGroup(groupname=sgroup)) if path is not None: if nooverwrite: raise MythFileError(MythError.FILE_FAILED_WRITE, file, 'refusing to overwrite existing file') for sg in sgs: if sg.dirname in path: if sg.local: return open(sg.dirname + filename, mode) else: return protoopen(host, filename, sgroup) # prefer local storage for new files for i, v in reversed(list(enumerate(sgs))): if not v.local: sgs.pop(i) else: st = os.statvfs(v.dirname) v.free = st[0] * st[3] if len(sgs) > 0: # choose path with most free space sg = sorted(sgs, key=lambda sg: sg.free, reverse=True)[0] # create folder if it does not exist if filename.find('/') != -1: path = sg.dirname + filename.rsplit('/', 1)[0] if not os.access(path, os.F_OK): os.makedirs(path) log(log.FILE, log.INFO, 'Opening local file (w)', sg.dirname + filename) return open(sg.dirname + filename, mode) # fallback to remote write else: if filename.find('/') != -1: raise MythFileError( MythError.FILE_FAILED_WRITE, file, 'attempting remote write outside base path') return protoopen(host, filename, sgroup) else: # search for file in local directories sg = findfile(filename, sgroup, db) if sg is not None: # file found, open local log(log.FILE, log.INFO, 'Opening local file (r)', sg.dirname + filename) return open(sg.dirname + filename, mode) else: # file not found, open remote return protoopen(host, filename, sgroup)