text: # Microsoft Azure Linux Agent
  #
  # Copyright 2018 Microsoft Corporation
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  #
  # Requires Python 2.6+ and Openssl 1.0+
  #
  
  import subprocess
  import azurelinuxagent.common.logger as logger
  from azurelinuxagent.common.future import ustr
  
  if not hasattr(subprocess, 'check_output'):
      def check_output(*popenargs, **kwargs):
          r"""Backport from subprocess module from python 2.7"""
          if 'stdout' in kwargs:
              raise ValueError('stdout argument not allowed, '
                               'it will be overridden.')
          process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
          output, unused_err = process.communicate()
          retcode = process.poll()
          if retcode:
              cmd = kwargs.get("args")
              if cmd is None:
                  cmd = popenargs[0]
              raise subprocess.CalledProcessError(retcode, cmd, output=output)
          return output
  
  
      # Exception classes used by this module.
      class CalledProcessError(Exception):
          def __init__(self, returncode, cmd, output=None):
              self.returncode = returncode
              self.cmd = cmd
              self.output = output
  
          def __str__(self):
              return ("Command '{0}' returned non-zero exit status {1}"
                      "").format(self.cmd, self.returncode)
  
  
      subprocess.check_output = check_output
      subprocess.CalledProcessError = CalledProcessError
  
  """
  Shell command util functions
  """
  
  
  def run(cmd, chk_err=True):
      """
      Calls run_get_output on 'cmd', returning only the return code.
      If chk_err=True then errors will be reported in the log.
      If chk_err=False then errors will be suppressed from the log.
      """
      retcode, out = run_get_output(cmd, chk_err)
      return retcode
  
  
  def run_get_output(cmd, chk_err=True, log_cmd=True):
      """
      Wrapper for subprocess.check_output.
      Execute 'cmd'.  Returns return code and STDOUT, trapping expected
      exceptions.
      Reports exceptions to Error if chk_err parameter is True
      """
      if log_cmd:
          logger.verbose(u"Run '{0}'", cmd)
      try:
          output = subprocess.check_output(cmd,
                                           stderr=subprocess.STDOUT,
                                           shell=True)
          output = ustr(output,
                        encoding='utf-8',
                        errors="backslashreplace")
      except Exception as e:
          if type(e) is subprocess.CalledProcessError:
              output = ustr(e.output,
                          encoding='utf-8',
                          errors="backslashreplace")
              if chk_err:
                  if log_cmd:
                      logger.error(u"Command: '{0}'", e.cmd)
                  logger.error(u"Return code: {0}", e.returncode)
                  logger.error(u"Result: {0}", output)
              return e.returncode, output
          else:
              logger.error(
                  u"'{0}' raised unexpected exception: '{1}'".format(
                      cmd, ustr(e)))
              return -1, ustr(e)
      return 0, output
  
  
  def quote(word_list):
      """
      Quote a list or tuple of strings for Unix Shell as words, using the
      byte-literal single quote.
  
      The resulting string is safe for use with ``shell=True`` in ``subprocess``,
      and in ``os.system``. ``assert shlex.split(ShellQuote(wordList)) == wordList``.
  
      See POSIX.1:2013 Vol 3, Chap 2, Sec 2.2.2:
      http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_02
      """
      if not isinstance(word_list, (tuple, list)):
          word_list = (word_list,)
  
      return " ".join(list("'{0}'".format(s.replace("'", "'\\''")) for s in word_list))
  
  # End shell command util functions
  