Ejemplo n.º 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
Ejemplo n.º 2
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
Ejemplo n.º 3
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