Example #1
0
    def _Visit(self, node):
        """
    """
        #log('VISIT %s', node.__class__.__name__)

        # NOTE: The tags are not unique!!!  We would need this:
        # if isinstance(node, ast.command) and node.tag == command_e.Simple:
        # But it's easier to check the __class__ attribute.

        cls = node.__class__
        if cls is command.Simple:
            #log('SimpleCommand %s', node.words)
            #log('--')
            #node.PrettyPrint()

            # Things to consider:
            # - source and .
            # - DONE builtins: get a list from builtin.py
            # - DONE functions: have to enter function definitions into a dictionary
            # - Commands that call others: sudo, su, find, xargs, etc.
            # - builtins that call others: exec, command
            #   - except not command -v!

            if not node.words:
                return

            w = node.words[0]
            ok, argv0, _ = word_.StaticEval(w)
            if not ok:
                log("Couldn't statically evaluate %r", w)
                return

            if (builtin.ResolveSpecial(argv0) == builtin_e.NONE
                    and builtin.ResolveAssign(argv0) == builtin_e.NONE
                    and builtin.Resolve(argv0) == builtin_e.NONE):
                self.progs_used[argv0] = True

            # NOTE: If argv1 is $0, then we do NOT print a warning!
            if argv0 == 'sudo':
                if len(node.words) < 2:
                    return
                w1 = node.words[1]
                ok, argv1, _ = word_.StaticEval(w1)
                if not ok:
                    log("Couldn't statically evaluate %r", w)
                    return

                # Should we mark them behind 'sudo'?  e.g. "sudo apt install"?
                self.progs_used[argv1] = True

        elif cls is command.ShFunction:
            self.funcs_defined[node.name] = True
Example #2
0
  def RunSimpleCommand(self, argv, fork_external, span_id, funcs=True):
    """
    Args:
      fork_external: for subshell ( ls / ) or ( command ls / )
    """
    # This happens when you write "$@" but have no arguments.
    if not argv:
      if self.exec_opts.strict_argv:
        e_die("Command evaluated to an empty argv array",
              span_id=span_id)
      else:
        return 0  # status 0, or skip it?

    arg0 = argv[0]

    builtin_id = builtin.ResolveSpecial(arg0)
    if builtin_id != builtin_e.NONE:
      try:
        status = self._RunBuiltin(builtin_id, argv, fork_external, span_id)
      except args.UsageError as e:
        ui.usage('osh %r usage error: %s', arg0, e)
        status = 2  # consistent error code for usage error
      return status

    # Builtins like 'true' can be redefined as functions.
    if funcs:
      func_node = self.funcs.get(arg0)
      if func_node is not None:
        # NOTE: Functions could call 'exit 42' directly, etc.
        status = self._RunFunc(func_node, argv[1:])
        return status

    builtin_id = builtin.Resolve(arg0)

    if builtin_id != builtin_e.NONE:
      try:
        status = self._RunBuiltin(builtin_id, argv, fork_external, span_id)
      except args.UsageError as e:
        ui.usage('osh %r usage error: %s', arg0, e)
        status = 2  # consistent error code for usage error
      return status

    environ = self.mem.GetExported()  # Include temporary variables

    if fork_external:
      thunk = process.ExternalThunk(self.ext_prog, argv, environ)
      p = process.Process(thunk)
      status = p.Run(self.waiter)
      return status

    self.ext_prog.Exec(argv, environ)  # NEVER RETURNS
Example #3
0
  def RunSimpleCommand(self, arg_vec, fork_external, funcs=True):
    """Public interface to run a simple command (excluding assignment)

    Args:
      fork_external: for subshell ( ls / ) or ( command ls / )
    """
    argv = arg_vec.strs
    if arg_vec.spids:
      span_id = arg_vec.spids[0]
    else:
      span_id = const.NO_INTEGER

    # This happens when you write "$@" but have no arguments.
    if not argv:
      if self.exec_opts.strict_argv:
        e_die("Command evaluated to an empty argv array",
              span_id=span_id)
      else:
        return 0  # status 0, or skip it?

    arg0 = argv[0]

    builtin_id = builtin.ResolveAssign(arg0)
    if builtin_id != builtin_e.NONE:
      # command readonly is disallowed, for technical reasons.  Could relax it
      # later.
      self.errfmt.Print("Can't run assignment builtin recursively",
                        span_id=span_id)
      return 1

    builtin_id = builtin.ResolveSpecial(arg0)
    if builtin_id != builtin_e.NONE:
      status = self._RunBuiltin(builtin_id, arg_vec, fork_external)
      # TODO: Enable this and fix spec test failures.
      # Also update _SPECIAL_BUILTINS in osh/builtin.py.
      #if status != 0:
      #  e_die('special builtin failed', status=status)
      return status

    # Builtins like 'true' can be redefined as functions.
    if funcs:
      func_node = self.funcs.get(arg0)
      if func_node is not None:
        # NOTE: Functions could call 'exit 42' directly, etc.
        status = self._RunFunc(func_node, argv[1:])
        return status

    builtin_id = builtin.Resolve(arg0)

    if builtin_id != builtin_e.NONE:
      return self._RunBuiltin(builtin_id, arg_vec, fork_external)

    environ = self.mem.GetExported()  # Include temporary variables

    # Resolve argv[0] BEFORE forking.
    argv0_path = self.search_path.CachedLookup(argv[0])
    if argv0_path is None:
      self.errfmt.Print('%r not found', argv[0], span_id=span_id)
      return 127

    if fork_external:
      thunk = process.ExternalThunk(self.ext_prog, argv0_path, arg_vec, environ)
      p = process.Process(thunk, self.job_state)
      status = p.Run(self.waiter)
      return status

    self.ext_prog.Exec(argv0_path, arg_vec, environ)  # NEVER RETURNS
Example #4
0
  def _RunBuiltin(self, builtin_id, argv, fork_external, span_id):
    argv = argv[1:]  # Builtins don't need to know their own name.

    #
    # TODO: Convert everything to this new style
    #

    builtin_func = self.builtins.get(builtin_id)
    if builtin_func is not None:
      status = builtin_func(argv)

    elif builtin_id == builtin_e.EXEC:
      status = self._Exec(argv)  # may never return
      # But if it returns, then we want to permanently apply the redirects
      # associated with it.
      self.fd_state.MakePermanent()

    elif builtin_id == builtin_e.READ:
      status = builtin.Read(argv, self.splitter, self.mem)

    elif builtin_id == builtin_e.ECHO:
      status = builtin.Echo(argv)

    elif builtin_id == builtin_e.PRINTF:
      status = builtin.Printf(argv, self.mem)

    elif builtin_id == builtin_e.SHIFT:
      status = builtin.Shift(argv, self.mem)

    elif builtin_id == builtin_e.CD:
      status = builtin.Cd(argv, self.mem, self.dir_stack)

    elif builtin_id == builtin_e.SET:
      status = builtin.Set(argv, self.exec_opts, self.mem)

    elif builtin_id == builtin_e.SHOPT:
      status = builtin.Shopt(argv, self.exec_opts)

    elif builtin_id == builtin_e.UNSET:
      status = builtin.Unset(argv, self.mem, self.funcs)

    elif builtin_id == builtin_e.EXPORT:
      status = builtin.Export(argv, self.mem)

    elif builtin_id == builtin_e.WAIT:
      status = builtin.Wait(argv, self.waiter, self.job_state, self.mem)

    elif builtin_id == builtin_e.JOBS:
      status = builtin.Jobs(argv, self.job_state)

    elif builtin_id == builtin_e.PUSHD:
      status = builtin.Pushd(argv, self.mem, self.dir_stack)

    elif builtin_id == builtin_e.POPD:
      status = builtin.Popd(argv, self.mem, self.dir_stack)

    elif builtin_id == builtin_e.DIRS:
      status = builtin.Dirs(argv, self.mem.GetVar('HOME'), self.dir_stack)

    elif builtin_id == builtin_e.PWD:
      status = builtin.Pwd(argv, self.mem)

    elif builtin_id in (builtin_e.SOURCE, builtin_e.DOT):
      status = self._Source(argv)

    elif builtin_id == builtin_e.TRAP:
      status = builtin.Trap(argv, self.traps, self.nodes_to_run, self)

    elif builtin_id == builtin_e.UMASK:
      status = builtin.Umask(argv)

    elif builtin_id == builtin_e.EVAL:
      status = self._Eval(argv, span_id)

    elif builtin_id == builtin_e.COLON:  # special builtin like 'true'
      status = 0

    elif builtin_id == builtin_e.TRUE:
      status = 0

    elif builtin_id == builtin_e.FALSE:
      status = 1

    elif builtin_id == builtin_e.TEST:
      status = builtin_bracket.Test(argv, False)

    elif builtin_id == builtin_e.BRACKET:
      status = builtin_bracket.Test(argv, True)  # need_right_bracket

    elif builtin_id == builtin_e.GETOPTS:
      status = builtin.GetOpts(argv, self.mem)

    elif builtin_id == builtin_e.COMMAND:
      # TODO: Pull Command up to the top level?
      b = builtin.Command(self, self.funcs, self.mem)
      status = b(argv, fork_external, span_id)

    elif builtin_id == builtin_e.TYPE:
      path = self.mem.GetVar('PATH')
      status = builtin.Type(argv, self.funcs, path)

    elif builtin_id == builtin_e.HELP:
      loader = pyutil.GetResourceLoader()
      status = builtin.Help(argv, loader)

    elif builtin_id in (builtin_e.DECLARE, builtin_e.TYPESET):
      # These are synonyms
      status = builtin.DeclareTypeset(argv, self.mem, self.funcs)

    elif builtin_id == builtin_e.ALIAS:
      status = builtin.Alias(argv, self.aliases)

    elif builtin_id == builtin_e.UNALIAS:
      status = builtin.UnAlias(argv, self.aliases)

    elif builtin_id == builtin_e.REPR:
      status = builtin.Repr(argv, self.mem)

    elif builtin_id == builtin_e.BUILTIN:  # NOTE: uses early return style
      if not argv:
        return 0  # this could be an error in strict mode?

      # Run regular builtin or special builtin
      to_run = builtin.Resolve(argv[0])
      if to_run == builtin_e.NONE:
        to_run = builtin.ResolveSpecial(argv[0])
      if to_run == builtin_e.NONE:
        util.error("builtin: %s: not a shell builtin", argv[0])
        return 1

      return self._RunBuiltin(to_run, argv, fork_external, span_id)

    else:
      raise AssertionError('Unhandled builtin: %s' % builtin_id)

    assert isinstance(status, int)
    return status
Example #5
0
  def _RunBuiltinAndRaise(self, builtin_id, arg_vec, fork_external):
    """
    Raises:
      args.UsageError
    """
    # Shift one arg.  Builtins don't need to know their own name.
    argv = arg_vec.strs[1:]

    # Most builtins dispatch with a dictionary
    builtin_func = self.builtins.get(builtin_id)
    if builtin_func is not None:
      status = builtin_func(arg_vec)

    # Some builtins "belong" to the executor.

    elif builtin_id == builtin_e.EXEC:
      status = self._Exec(arg_vec)  # may never return
      # But if it returns, then we want to permanently apply the redirects
      # associated with it.
      self.fd_state.MakePermanent()

    elif builtin_id == builtin_e.EVAL:
      status = self._Eval(arg_vec)

    elif builtin_id in (builtin_e.SOURCE, builtin_e.DOT):
      status = self._Source(arg_vec)

    elif builtin_id == builtin_e.COMMAND:
      # TODO: How do we handle fork_external?  It doesn't fit the common
      # signature.  We also don't handle 'command local', etc.
      b = builtin.Command(self, self.funcs, self.aliases, self.search_path)
      status = b(arg_vec, fork_external)

    elif builtin_id == builtin_e.BUILTIN:  # NOTE: uses early return style
      if not argv:
        return 0  # this could be an error in strict mode?

      name = arg_vec.strs[1]

      # Run regular builtin or special builtin
      to_run = builtin.Resolve(name)
      if to_run == builtin_e.NONE:
        to_run = builtin.ResolveSpecial(name)
      if to_run == builtin_e.NONE:
        span_id = arg_vec.spids[1]
        if builtin.ResolveAssign(name) != builtin_e.NONE:
          # NOTE: There's a similar restriction for 'command'
          self.errfmt.Print("Can't run assignment builtin recursively",
                            span_id=span_id)
        else:
          self.errfmt.Print("%r isn't a shell builtin", span_id=span_id)
        return 1

      arg_vec2 = arg_vector(arg_vec.strs[1:], arg_vec.spids[1:])
      status = self._RunBuiltinAndRaise(to_run, arg_vec2, fork_external)

    else:
      raise AssertionError('Unhandled builtin: %s' % builtin_id)

    assert isinstance(status, int)
    return status