|
Packit Service |
4b33e2 |
# Copyright 2012,2018 Red Hat Inc.
|
|
Packit Service |
4b33e2 |
# Author: Kushal Das <kdas@redhat.com>
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
4b33e2 |
# it under the terms of the GNU General Public License as published by
|
|
Packit Service |
4b33e2 |
# the Free Software Foundation; either version 2 of the License, or
|
|
Packit Service |
4b33e2 |
# (at your option) any later version. See
|
|
Packit Service |
4b33e2 |
# http://www.gnu.org/copyleft/gpl.html for the full text of the
|
|
Packit Service |
4b33e2 |
# license.
|
|
Packit Service |
4b33e2 |
#
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Helper functions for ksc.
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
import os
|
|
Packit Service |
4b33e2 |
import re
|
|
Packit Service |
4b33e2 |
import sys
|
|
Packit Service |
4b33e2 |
import time
|
|
Packit Service |
4b33e2 |
import getpass
|
|
Packit Service |
4b33e2 |
import subprocess
|
|
Packit Service |
4b33e2 |
import locale
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
from bugzilla import Bugzilla, BugzillaError
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# whitelist directory
|
|
Packit Service |
4b33e2 |
WHPATH = '/lib/modules'
|
|
Packit Service |
4b33e2 |
# Module.symvers directory
|
|
Packit Service |
4b33e2 |
SRCPATH = '/usr/src/kernels'
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def query_user(query, max_tries=10, is_valid=lambda x: len(x) > 0):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Queries user for a value.
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
:arg query: query string
|
|
Packit Service |
4b33e2 |
:arg max_tries: maximal number of times user will be prompted to give a
|
|
Packit Service |
4b33e2 |
valid reply (avoid cycling)
|
|
Packit Service |
4b33e2 |
:arg is_valid: lambda function that determines if and when user supplied
|
|
Packit Service |
4b33e2 |
input is valid
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
:return response if valid
|
|
Packit Service |
4b33e2 |
:return "" if received max_tries invalid reponses
|
|
Packit Service |
4b33e2 |
:return "" if we couldn't read data from stdin
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
tries_left = max_tries
|
|
Packit Service |
4b33e2 |
response = ""
|
|
Packit Service |
4b33e2 |
while not is_valid(response):
|
|
Packit Service |
4b33e2 |
if tries_left < max_tries:
|
|
Packit Service |
4b33e2 |
if response == "":
|
|
Packit Service |
4b33e2 |
print("Empty response received. Please try again.")
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
print("Option `%s' is invalid. Please try again." % response)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if tries_left == 0:
|
|
Packit Service |
4b33e2 |
print("Reached maximum number of invalid responses.")
|
|
Packit Service |
4b33e2 |
return ""
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
tries_left = tries_left - 1
|
|
Packit Service |
4b33e2 |
response = input(query)
|
|
Packit Service |
4b33e2 |
except EOFError:
|
|
Packit Service |
4b33e2 |
print("Reached early EOF.")
|
|
Packit Service |
4b33e2 |
return ""
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return response
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def query_user_bool(query):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Queries user for a Y/N value
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
:arg query: query string
|
|
Packit Service |
4b33e2 |
:return response if valid
|
|
Packit Service |
4b33e2 |
:return "" if received max_tries invalid reponses
|
|
Packit Service |
4b33e2 |
:return "" if we couldn't read data from stdin
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
check_fx = lambda x: x.lower() in ['y', 'n']
|
|
Packit Service |
4b33e2 |
return query_user(query, is_valid=check_fx)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def get_release_name():
|
|
Packit Service |
4b33e2 |
if not os.path.isfile('/etc/redhat-release'):
|
|
Packit Service |
4b33e2 |
print('This tool needs to run on Red Hat Enterprise Linux')
|
|
Packit Service |
4b33e2 |
return None
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
with open('/etc/redhat-release', 'r') as fptr:
|
|
Packit Service |
4b33e2 |
release = fptr.read().split(' ')
|
|
Packit Service |
4b33e2 |
if len(release) <= 6:
|
|
Packit Service |
4b33e2 |
print('This tool needs to run on Red Hat Enterprise Linux')
|
|
Packit Service |
4b33e2 |
return None
|
|
Packit Service |
4b33e2 |
for rel in release:
|
|
Packit Service |
4b33e2 |
if re.match("\d.\d+",rel):
|
|
Packit Service |
4b33e2 |
return rel
|
|
Packit Service |
4b33e2 |
print('This tool needs to run on Red Hat Enterprise Linux')
|
|
Packit Service |
4b33e2 |
return None
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def read_list(arch, kabipath, verbose=False):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Reads a whitelist file and returns the symbols
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
result = []
|
|
Packit Service |
4b33e2 |
fpath = os.path.join(WHPATH, kabipath, "kabi_whitelist_%s" % arch)
|
|
Packit Service |
4b33e2 |
if not os.path.isfile(fpath): # pragma: no cover
|
|
Packit Service |
4b33e2 |
print("File not found:", fpath)
|
|
Packit Service |
4b33e2 |
return [], False
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
if verbose: # pragma: no cover
|
|
Packit Service |
4b33e2 |
print("Reading %s" % fpath)
|
|
Packit Service |
4b33e2 |
fptr = open(fpath)
|
|
Packit Service |
4b33e2 |
for line in fptr.readlines():
|
|
Packit Service |
4b33e2 |
if line.startswith("["):
|
|
Packit Service |
4b33e2 |
continue
|
|
Packit Service |
4b33e2 |
result.append(line.strip("\n\t"))
|
|
Packit Service |
4b33e2 |
fptr.close()
|
|
Packit Service |
4b33e2 |
except IOError as err: # pragma: no cover
|
|
Packit Service |
4b33e2 |
print(err)
|
|
Packit Service |
4b33e2 |
print("whitelist missing")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return result, True
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def read_total_list(symvers=None):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Reads total symbol list and returns the list
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
if not symvers:
|
|
Packit Service |
4b33e2 |
release = os.uname()[2]
|
|
Packit Service |
4b33e2 |
symvers = os.path.join(SRCPATH, release, "Module.symvers")
|
|
Packit Service |
4b33e2 |
if not os.path.isfile(symvers): # pragma: no cover
|
|
Packit Service |
4b33e2 |
print("File not found:", symvers)
|
|
Packit Service |
4b33e2 |
print("Do you have current kernel-devel package installed?")
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|
|
Packit Service |
4b33e2 |
result = []
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
with open(symvers, "r") as fptr:
|
|
Packit Service |
4b33e2 |
for line in fptr.readlines():
|
|
Packit Service |
4b33e2 |
if line.startswith("["):
|
|
Packit Service |
4b33e2 |
continue # pragma: no cover
|
|
Packit Service |
4b33e2 |
result.append(line.split()[1])
|
|
Packit Service |
4b33e2 |
except IOError as err: # pragma: no cover
|
|
Packit Service |
4b33e2 |
print(err)
|
|
Packit Service |
4b33e2 |
print("Missing all symbol list")
|
|
Packit Service |
4b33e2 |
return result
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def run(command):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
runs the given command
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
ret = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE,
|
|
Packit Service |
4b33e2 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
Packit Service |
4b33e2 |
close_fds=True)
|
|
Packit Service |
4b33e2 |
out, err = ret.communicate()
|
|
Packit Service |
4b33e2 |
if err:
|
|
Packit Service |
4b33e2 |
errs = err.decode(locale.getpreferredencoding()).split(':', 1)
|
|
Packit Service |
4b33e2 |
raise IOError(errs[1].strip() if len(errs) > 1 else err)
|
|
Packit Service |
4b33e2 |
return out.decode(locale.getpreferredencoding())
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def getconfig(path='/etc/ksc.conf', mock=False):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Returns the bugzilla config
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
result = {}
|
|
Packit Service |
4b33e2 |
result['partner'] = ''
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not os.path.isfile(path):
|
|
Packit Service |
4b33e2 |
path = '/etc/ksc.conf'
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
fptr = open(path)
|
|
Packit Service |
4b33e2 |
lines = fptr.readlines()
|
|
Packit Service |
4b33e2 |
fptr.close()
|
|
Packit Service |
4b33e2 |
for line in lines:
|
|
Packit Service |
4b33e2 |
if line.startswith("user="):
|
|
Packit Service |
4b33e2 |
result["user"] = line[5:-1]
|
|
Packit Service |
4b33e2 |
elif line.startswith("partner="):
|
|
Packit Service |
4b33e2 |
result["partner"] = line[8:-1]
|
|
Packit Service |
4b33e2 |
elif line.startswith("server="):
|
|
Packit Service |
4b33e2 |
result["server"] = line[7:-1]
|
|
Packit Service |
4b33e2 |
elif line.startswith("partnergroup="):
|
|
Packit Service |
4b33e2 |
result["group"] = line[13:-1]
|
|
Packit Service |
4b33e2 |
elif line.startswith("api_key="):
|
|
Packit Service |
4b33e2 |
result["api_key"] = line[8:-1]
|
|
Packit Service |
4b33e2 |
if 'user' not in result and 'api_key' not in result:
|
|
Packit Service |
4b33e2 |
print("Either user name or api_key must be specified in configuration.")
|
|
Packit Service |
4b33e2 |
return False
|
|
Packit Service |
4b33e2 |
if ('server' not in result or
|
|
Packit Service |
4b33e2 |
not result['server'].endswith('xmlrpc.cgi')):
|
|
Packit Service |
4b33e2 |
print("Servername is not valid in configuration.")
|
|
Packit Service |
4b33e2 |
return False
|
|
Packit Service |
4b33e2 |
if not mock: # pragma: no cover
|
|
Packit Service |
4b33e2 |
if not result['partner'] or result['partner'] == 'partner-name':
|
|
Packit Service |
4b33e2 |
result["partner"] = input("Partner name: ")
|
|
Packit Service |
4b33e2 |
if not result['group'] or result['group'] == 'partner-group':
|
|
Packit Service |
4b33e2 |
result['group'] = input("Partner group: ")
|
|
Packit Service |
4b33e2 |
if "api_key" not in result or not result['api_key'] or result['api_key'] == 'api_key':
|
|
Packit Service |
4b33e2 |
print('Current Bugzilla user: %s' % result['user'])
|
|
Packit Service |
4b33e2 |
result['password'] = getpass.getpass('Please enter password: ')
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
print('Using API Key for authentication')
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
result['password'] = 'mockpassword'
|
|
Packit Service |
4b33e2 |
if not result['user']:
|
|
Packit Service |
4b33e2 |
print("Error: missing values in configuration file.")
|
|
Packit Service |
4b33e2 |
print("Bug not submitted")
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|
|
Packit Service |
4b33e2 |
except Exception as err:
|
|
Packit Service |
4b33e2 |
print("Error reading %s" % path)
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|
|
Packit Service |
4b33e2 |
return result
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def createbug(filename, arch, mock=False, path='/etc/ksc.conf',
|
|
Packit Service |
4b33e2 |
releasename='7.0', module=None):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Opens a bug in the Bugzilla
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if releasename.startswith('6.'):
|
|
Packit Service |
4b33e2 |
bughash = {'product': 'Red Hat Enterprise Linux 6'}
|
|
Packit Service |
4b33e2 |
elif releasename.startswith('7.'):
|
|
Packit Service |
4b33e2 |
bughash = {'product': 'Red Hat Enterprise Linux 7'}
|
|
Packit Service |
4b33e2 |
elif releasename.startswith('8.'):
|
|
Packit Service |
4b33e2 |
bughash = {'product': 'Red Hat Enterprise Linux 8'}
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
print("Invalid releasename: Bug not created")
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
bughash["component"] = 'kernel'
|
|
Packit Service |
4b33e2 |
bughash["sub_component"] = 'kabi-whitelists'
|
|
Packit Service |
4b33e2 |
bughash["summary"] = "kABI Symbol Usage"
|
|
Packit Service |
4b33e2 |
bughash["version"] = releasename
|
|
Packit Service |
4b33e2 |
bughash["platform"] = arch
|
|
Packit Service |
4b33e2 |
bughash["severity"] = "medium"
|
|
Packit Service |
4b33e2 |
bughash["priority"] = "medium"
|
|
Packit Service |
4b33e2 |
bughash["description"] = "Creating the bug to attach the symbol " + \
|
|
Packit Service |
4b33e2 |
"usage details."
|
|
Packit Service |
4b33e2 |
bughash["qa_contact"] = "kernel-qe@redhat.com"
|
|
Packit Service |
4b33e2 |
groups = []
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if module:
|
|
Packit Service |
4b33e2 |
bughash["summary"] += " ({})".format(str(module))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# We change the path if only it is mock
|
|
Packit Service |
4b33e2 |
if mock:
|
|
Packit Service |
4b33e2 |
print("Using local config file data/ksc.conf")
|
|
Packit Service |
4b33e2 |
path = './data/ksc.conf'
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
conf = getconfig(path, mock=mock)
|
|
Packit Service |
4b33e2 |
except Exception as err:
|
|
Packit Service |
4b33e2 |
print("Problem in parsing the configuration.")
|
|
Packit Service |
4b33e2 |
print(err)
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not conf:
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
if 'group' in conf:
|
|
Packit Service |
4b33e2 |
if conf['group'] != 'partner-group':
|
|
Packit Service |
4b33e2 |
groups.append(conf['group'])
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
groups = list(filter(lambda x: len(x) > 0, groups))
|
|
Packit Service |
4b33e2 |
if not groups:
|
|
Packit Service |
4b33e2 |
print("Error: Please specify a non-empty partner-group config " +\
|
|
Packit Service |
4b33e2 |
"option in your ksc.conf config file or in the prompt above. " +\
|
|
Packit Service |
4b33e2 |
"Bug was not filed!")
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
bughash["groups"] = groups
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if 'api_key' in conf and conf['api_key'] != 'api_key':
|
|
Packit Service |
4b33e2 |
bughash["Bugzilla_api_key"] = conf["api_key"]
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
bughash["Bugzilla_login"] = conf["user"]
|
|
Packit Service |
4b33e2 |
bughash["Bugzilla_password"] = conf["password"]
|
|
Packit Service |
4b33e2 |
bughash["cf_partner"] = [conf["partner"], ]
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
bugid = 0
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
if 'api_key' in conf and conf['api_key'] != 'api_key':
|
|
Packit Service |
4b33e2 |
bz = Bugzilla(
|
|
Packit Service |
4b33e2 |
url=conf['server'],
|
|
Packit Service |
4b33e2 |
api_key=conf["api_key"]
|
|
Packit Service |
4b33e2 |
)
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
bz = Bugzilla(
|
|
Packit Service |
4b33e2 |
url=conf['server'],
|
|
Packit Service |
4b33e2 |
user=conf["user"],
|
|
Packit Service |
4b33e2 |
password=conf["password"]
|
|
Packit Service |
4b33e2 |
)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not mock: # pragma: no cover
|
|
Packit Service |
4b33e2 |
print("Creating a new bug")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
ret = bz.build_createbug(
|
|
Packit Service |
4b33e2 |
product=bughash['product'],
|
|
Packit Service |
4b33e2 |
component=bughash['component'],
|
|
Packit Service |
4b33e2 |
sub_component=bughash['sub_component'],
|
|
Packit Service |
4b33e2 |
summary=bughash['summary'],
|
|
Packit Service |
4b33e2 |
version=bughash['version'],
|
|
Packit Service |
4b33e2 |
platform=bughash['platform'],
|
|
Packit Service |
4b33e2 |
qa_contact=bughash['qa_contact'],
|
|
Packit Service |
4b33e2 |
severity=bughash['severity'],
|
|
Packit Service |
4b33e2 |
priority=bughash['priority'],
|
|
Packit Service |
4b33e2 |
description=bughash['description'],
|
|
Packit Service |
4b33e2 |
groups=bughash['groups']
|
|
Packit Service |
4b33e2 |
)
|
|
Packit Service |
4b33e2 |
ret['cf_partner'] = bughash['cf_partner']
|
|
Packit Service |
4b33e2 |
bug = bz.createbug(ret)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
bugid = bug.id
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not mock: # pragma: no cover
|
|
Packit Service |
4b33e2 |
print("Bug URL %s/show_bug.cgi?id=%s" % \
|
|
Packit Service |
4b33e2 |
(conf['server'][:-11], bugid))
|
|
Packit Service |
4b33e2 |
print("Attaching the report")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
dhash = {}
|
|
Packit Service |
4b33e2 |
dhash["filename"] = "ksc-result.txt"
|
|
Packit Service |
4b33e2 |
dhash["contenttype"] = "text/plain"
|
|
Packit Service |
4b33e2 |
desc = "kABI symbol usage."
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
for _ in range(3):
|
|
Packit Service |
4b33e2 |
with open(filename, "r") as fptr:
|
|
Packit Service |
4b33e2 |
attachment_id = bz.attachfile(bugid, fptr, desc, **dhash)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not mock: # pragma: no cover
|
|
Packit Service |
4b33e2 |
if not attachment_id:
|
|
Packit Service |
4b33e2 |
time.sleep(1)
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
print("Attached successfully as %s on bug %s" % (attachment_id, bugid))
|
|
Packit Service |
4b33e2 |
break
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
print("Failed to attach symbol usage result")
|
|
Packit Service |
4b33e2 |
sys.exit()
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
except Exception as err: # pragma: no cover
|
|
Packit Service |
4b33e2 |
print("Could not create bug. %s" % err)
|
|
Packit Service |
4b33e2 |
if not mock:
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|
|
Packit Service |
4b33e2 |
except BugzillaError as err:
|
|
Packit Service |
4b33e2 |
print("Bug not submitted. %s" % err)
|
|
Packit Service |
4b33e2 |
if not mock:
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return bugid
|