This file is command.def, from which is created command.c.
It implements the builtin "command" in Bash.

Copyright (C) 1987-2023 Free Software Foundation, Inc.

This file is part of GNU Bash, the Bourne Again SHell.

Bash 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, either version 3 of the License, or
(at your option) any later version.

Bash 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 Bash.  If not, see <http://www.gnu.org/licenses/>.

$PRODUCES command.c

$BUILTIN command
$FUNCTION command_builtin
$SHORT_DOC command [-pVv] command [arg ...]
Execute a simple command or display information about commands.

Runs COMMAND with ARGS suppressing  shell function lookup, or display
information about the specified COMMANDs.  Can be used to invoke commands
on disk when a function with the same name exists.

Options:
  -p    use a default value for PATH that is guaranteed to find all of
        the standard utilities
  -v    print a single word indicating the command or filename that
        invokes COMMAND
  -V    print a more verbose description of each COMMAND

Exit Status:
Returns exit status of COMMAND, or failure if COMMAND is not found.
$END

#include <config.h>

#if defined (HAVE_UNISTD_H)
#  ifdef _MINIX
#    include <sys/types.h>
#  endif
#  include <unistd.h>
#endif

#include "../bashansi.h"

#include "../shell.h"
#include "../execute_cmd.h"
#include "../flags.h"
#include "../parser.h"
#include "bashgetopt.h"
#include "common.h"

#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR
extern size_t confstr (int, char *, size_t);
#endif

/* Run the commands mentioned in LIST without paying attention to shell
   functions. */
int
command_builtin (WORD_LIST *list)
{
  int result, verbose, use_standard_path, opt;
  COMMAND *command;

  verbose = use_standard_path = 0;
  reset_internal_getopt ();
  while ((opt = internal_getopt (list, "pvV")) != -1)
    {
      switch (opt)
	{
	case 'p':
	  use_standard_path = CDESC_STDPATH;
	  break;
	case 'V':
	  verbose = CDESC_SHORTDESC|CDESC_ABSPATH;	/* look in common.h for constants */
	  break;
	case 'v':
	  verbose = CDESC_REUSABLE;	/* ditto */
	  break;
	CASE_HELPOPT;
	default:
	  builtin_usage ();
	  return (EX_USAGE);
	}
    }
  list = loptend;

  if (list == 0)
    return (EXECUTION_SUCCESS);

#if defined (RESTRICTED_SHELL)
  if (use_standard_path && restricted)
    {
      sh_restricted ("-p");
      return (EXECUTION_FAILURE);
    }
#endif

  if (verbose)
    {
      int found, any_found;

      for (any_found = 0; list; list = list->next)
	{
	  found = describe_command (list->word->word, verbose|use_standard_path);

	  if (found == 0 && verbose != CDESC_REUSABLE)
	    sh_notfound (list->word->word);

	  any_found += found;
	}

      return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
    }

  begin_unwind_frame ("command_builtin");

#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN | (use_standard_path ? CMD_STDPATH : 0))

  /* This code isn't executed any more; look at execute_cmd.c:execute_simple_command()
     where command is treated as a pseudo-reserved prefix so we can optimize
     away forks where possible. */

  /* We don't want this to be reparsed (consider command echo 'foo &'), so
     just make a simple_command structure and call execute_command with it. */
  command = make_bare_simple_command (line_number);
  command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
  command->value.Simple->redirects = (REDIRECT *)NULL;
  command->flags |= COMMAND_BUILTIN_FLAGS;
  command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;

  add_unwind_protect (uw_dispose_command, command);
  result = execute_command (command);
  dispose_command (command);

  discard_unwind_frame ("command_builtin");
  return (result);
}
