This file is indexed.

/usr/lib/python2.7/dist-packages/mysql/utilities/command/proc.py is in mysql-utilities 1.6.1-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#
# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#

"""
This file contains grep processing.
"""

import re
import sys

import mysql.connector

from mysql.utilities.exception import EmptyResultError, FormatError
from mysql.utilities.common.format import print_list
from mysql.utilities.common.ip_parser import parse_connection
from mysql.utilities.common.options import obj2sql
from mysql.utilities.common.server import set_ssl_opts_in_connection_info


KILL_QUERY, KILL_CONNECTION, PRINT_PROCESS = range(3)

ID = "ID"
USER = "USER"
HOST = "HOST"
DB = "DB"
COMMAND = "COMMAND"
TIME = "TIME"
STATE = "STATE"
INFO = "INFO"


#
# TODO : Can _spec and similar methods be shared for grep.py?
#
def _spec(info):
    """Create a server specification string from an info structure.
    """
    result = "{user}:*@{host}:{port}".format(**info)
    if "unix_socket" in info:
        result += ":" + info["unix_socket"]
    return result

_SELECT_PROC_FRM = """
SELECT
  Id, User, Host, Db, Command, Time, State, Info
FROM
  INFORMATION_SCHEMA.PROCESSLIST{condition}"""


def _make_select(matches, use_regexp, conditions):
    """Generate a SELECT statement for matching the processes.
    """
    oper = 'REGEXP' if use_regexp else 'LIKE'
    for field, pattern in matches:
        conditions.append("    {0} {1} {2}"
                          "".format(field, oper, obj2sql(pattern)))
    if len(conditions) > 0:
        condition = "\nWHERE\n" + "\n  AND\n".join(conditions)
    else:
        condition = ""
    return _SELECT_PROC_FRM.format(condition=condition)

# Map to map single-letter suffixes number of seconds
_SECS = {'s': 1, 'm': 60, 'h': 3600, 'd': 24 * 3600, 'w': 7 * 24 * 3600}

_INCORRECT_FORMAT_MSG = "'{0}' does not have correct format"


def _make_age_cond(age):
    """Make age condition

    Accept an age description return a timedelta representing the age.  We
    allow the forms: hh:mm:ss, mm:ss, 4h3m, with suffixes d (days), w (weeks),
    h (hours), m (minutes), and s(seconds)

    age[in]            Age (time)

    Returns string - time delta
    """
    mobj = re.match(r"([+-])?(?:(?:(\d?\d):)?(\d?\d):)?(\d?\d)\Z", age)
    if mobj:
        sign, hrs, mins, secs = mobj.groups()
        if not hrs:
            hrs = 0
        if not mins:
            mins = 0
        seconds = int(secs) + 60 * (int(mins) + 60 * int(hrs))
        oper = "<=" if sign and sign == "-" else ">="
        return '    {0} {1} {2}'.format(TIME, oper, seconds)
    mobj = re.match(r"([+-])?(\d+[dwhms])+", age)
    if mobj:
        sign = None
        if mobj.group(1):
            sign = age[0]
            age = age[1:]
        seconds = 0
        periods = [x for x in re.split(r"(\d+[dwhms])", age)]
        if len(''.join(x[0::2])) > 0:  # pylint: disable=W0631
            raise FormatError(_INCORRECT_FORMAT_MSG.format(age))
        for period in periods[1::2]:
            seconds += int(period[0:-1]) * _SECS[period[-1:]]
        oper = "<=" if sign and sign == "-" else ">="
        return '    {0} {1} {2}'.format(TIME, oper, seconds)
    raise FormatError(_INCORRECT_FORMAT_MSG.format(age))

_KILL_BODY = """
DECLARE kill_done INT;
DECLARE kill_cursor CURSOR FOR
  {select}
OPEN kill_cursor;
BEGIN
   DECLARE id BIGINT;
   DECLARE EXIT HANDLER FOR NOT FOUND SET kill_done = 1;
   kill_loop: LOOP
      FETCH kill_cursor INTO id;
      KILL {kill} id;
   END LOOP kill_loop;
END;
CLOSE kill_cursor;"""

_KILL_PROCEDURE = """
CREATE PROCEDURE {name} ()
BEGIN{body}
END"""


class ProcessGrep(object):
    """Grep processing
    """

    def __init__(self, matches, actions=None, use_regexp=False, age=None):
        """Constructor

        matches[in]    matches identified
        actions[in]    actions to perform
        use_regexp[in] if True, use regexp for compare
                       default = False
        age[in]        age in time, if provided
                       default = None
        """
        if actions is None:
            actions = []
        conds = [_make_age_cond(age)] if age else []
        self.__select = _make_select(matches, use_regexp, conds).strip()
        self.__actions = actions

    def sql(self, only_body=False):
        """Generate a SQL command for KILL

        This method generates the KILL <id> SQL command for killing processes.
        It can also generate SQL to kill procedures by recreating them without
        a body (if only_body = True).

        only_body[in]  if True, limit to body of object
                       default = False

        Returns string - SQL statement
        """
        params = {
            'select': "\n      ".join(self.__select.split("\n")),
            'kill': 'CONNECTION' if KILL_CONNECTION in self.__actions
            else 'QUERY',
        }
        if KILL_CONNECTION in self.__actions or KILL_QUERY in self.__actions:
            sql = _KILL_BODY.format(**params)
            if not only_body:
                sql = _KILL_PROCEDURE.format(
                    name="kill_processes",
                    body="\n   ".join(sql.split("\n"))
                )
            return sql
        else:
            return self.__select

    def execute(self, connections, **kwrds):
        """Execute the search for processes, queries, or connections

        This method searches for processes, queriers, or connections to
        either kill or display the matches for one or more servers.

        connections[in]    list of connection parameters
        kwrds[in]          dictionary of options
          output           file stream to display information
                           default = sys.stdout
          connector        connector to use
                           default = mysql.connector
          format           format for display
                           default = GRID
        """

        output = kwrds.get('output', sys.stdout)
        connector = kwrds.get('connector', mysql.connector)
        fmt = kwrds.get('format', "grid")
        charset = kwrds.get('charset', None)
        ssl_opts = kwrds.get('ssl_opts', {})

        headers = ("Connection", "Id", "User", "Host", "Db",
                   "Command", "Time", "State", "Info")
        entries = []
        # Build SQL statement
        for info in connections:
            conn = parse_connection(info)
            if not conn:
                msg = "'%s' is not a valid connection specifier" % (info,)
                raise FormatError(msg)
            if charset:
                conn['charset'] = charset
            info = conn

            if connector == mysql.connector:
                set_ssl_opts_in_connection_info(ssl_opts, info)

            connection = connector.connect(**info)

            if not charset:
                # If no charset provided, get it from the
                # "character_set_client" server variable.
                cursor = connection.cursor()
                cursor.execute("SHOW VARIABLES LIKE 'character_set_client'")
                res = cursor.fetchall()
                connection.set_charset_collation(charset=str(res[0][1]))
                cursor.close()

            cursor = connection.cursor()
            cursor.execute(self.__select)
            print_rows = []
            cols = ["Id", "User", "Host", "db", "Command", "Time",
                    "State", "Info"]
            for row in cursor:
                if (KILL_QUERY in self.__actions) or \
                   (KILL_CONNECTION in self.__actions):
                    print_rows.append(row)
                    cursor.execute("KILL {0}".format(row[0]))
                if PRINT_PROCESS in self.__actions:
                    entries.append(tuple([_spec(info)] + list(row)))
            if print_rows:
                print "# The following KILL commands were executed:"
                print_list(output, fmt, cols, print_rows)

        # If output is None, nothing is printed
        if len(entries) > 0 and output:
            entries.sort(key=lambda fifth: fifth[5])
            print_list(output, fmt, headers, entries)
        elif PRINT_PROCESS in self.__actions:
            raise EmptyResultError("No matches found")