Skip to content

Instantly share code, notes, and snippets.

@devopsec
Created August 24, 2018 06:42
Show Gist options
  • Save devopsec/bb8978d3795a96a83ce44ed024ce6a1c to your computer and use it in GitHub Desktop.
Save devopsec/bb8978d3795a96a83ce44ed024ce6a1c to your computer and use it in GitHub Desktop.
Freeswitch xml debugger
#!/usr/bin/env python3
#
#################### fs_startdbg ################################
# #
# Summary: #
# trace freeswitch startup errors to corresponging xml file #
# freeswitch should not be running & should be expected to fail #
# #
# Author: Tyler Moore #
# License: MIT #
# Date: 24-Aug-2018 #
# #
# Notes: #
# make sure these requirements are installed #
# sudo apt-get install -y libxml2 libxml2-utils python3 #
# #
#################################################################
import re, os, glob, subprocess, time
from shutil import which
# defaults
error_list = []
error_str_list = []
error_file_list = []
line_num_list = []
xml_file_list = []
freeswitch_config_dir = "/etc/freeswitch"
main_config_file = os.path.join(freeswitch_config_dir, "freeswitch.xml")
freeswitch_log_dir = "/var/log/freeswitch"
compiled_xml_file = os.path.join(freeswitch_log_dir, "freeswitch.xml.fsxml")
def find_lines(l, f):
""" return line nums of 1st occurence of each str | None """
nums = []
i = 0
for line in f:
i += 1
for j in range(len(l)-1, -1, -1):
if l[j] in line:
nums.append(i)
l.pop(j)
return nums
if __name__ == '__main__':
# find our binaries
freeswitch = which('freeswitch')
xmllint = which('xmllint')
# startup freeswitch expecting it to fail
p = subprocess.Popen([freeswitch], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(2)
try:
p.kill()
except OSError:
pass
# allow xmllint parser to give us hints
p = subprocess.Popen([xmllint, compiled_xml_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
error_str_full = p.communicate()[0]
# get xml file list
with open(main_config_file, 'r') as fsconfig:
regex = r'<X-PRE-PROCESS cmd="include" data="(.*)"'
res = re.findall(regex, fsconfig.read(), flags=re.MULTILINE)
xml_file_list = [os.path.join(freeswitch_config_dir, r.strip()) for r in res if re.search('\w', r)]
# get error string list
regex = r"freeswitch\.xml\.fsxml.+?error : (.+?)(?:\n|\\n)(.+?)(?:\n|\\n)"
error_list,error_str_list = zip(*re.findall(regex, error_str_full, flags=re.MULTILINE))
# trace um back
for path in xml_file_list:
for p in glob.glob(path):
with open(p, 'r') as f:
line_nums = find_lines(list(error_str_list), f)
line_num_list.extend(line_nums)
error_file_list.extend([f.name] * len(line_nums))
# print out cause w/ filepath and linenum
for filepath,linenum,error,cause in zip(error_file_list,line_num_list,error_list,error_str_list):
print('XML PARSER ERROR')
print('{:10s}{}'.format('FILE:',filepath))
print('{:10s}{}'.format('LINE:',linenum))
print('{:10s}{}'.format('ERROR:',error))
print('{:10s}{}'.format('CAUSE:',cause.strip()))
print('', flush=True)
exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment