(root)/
coreutils-9.4/
src/
coreutils.c
       1  /* Copyright (C) 2014-2023 Free Software Foundation, Inc.
       2  
       3     This program is free software: you can redistribute it and/or modify
       4     it under the terms of the GNU General Public License as published by
       5     the Free Software Foundation, either version 3 of the License, or
       6     (at your option) any later version.
       7  
       8     This program is distributed in the hope that it will be useful,
       9     but WITHOUT ANY WARRANTY; without even the implied warranty of
      10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      11     GNU General Public License for more details.
      12  
      13     You should have received a copy of the GNU General Public License
      14     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      15  
      16  /* coreutils.c aggregates the functionality of every other tool into a single
      17     binary multiplexed by the value of argv[0]. This is enabled by passing
      18     --enable-single-binary to configure.
      19  
      20     Written by Alex Deymo <deymo@chromium.org>.  */
      21  
      22  #include <config.h>
      23  #include <getopt.h>
      24  #include <stdio.h>
      25  #if HAVE_PRCTL
      26  # include <sys/prctl.h>
      27  #endif
      28  
      29  #include "system.h"
      30  #include "quote.h"
      31  
      32  #ifdef SINGLE_BINARY
      33  /* Declare the main function on each one of the selected tools.  This name
      34     needs to match the one passed as CFLAGS on single-binary.mk (generated
      35     by gen-single-binary.sh). */
      36  # define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
      37    int single_binary_main_##main_name (int, char **);
      38  # include "coreutils.h"
      39  # undef SINGLE_BINARY_PROGRAM
      40  #endif
      41  
      42  /* The official name of this program (e.g., no 'g' prefix).  */
      43  #define PROGRAM_NAME "coreutils"
      44  
      45  #define AUTHORS \
      46    proper_name ("Alex Deymo")
      47  
      48  static struct option const long_options[] =
      49  {
      50    {GETOPT_HELP_OPTION_DECL},
      51    {GETOPT_VERSION_OPTION_DECL},
      52    {nullptr, 0, nullptr, 0}
      53  };
      54  
      55  
      56  void
      57  usage (int status)
      58  {
      59    if (status != EXIT_SUCCESS)
      60      emit_try_help ();
      61    else
      62      {
      63        printf (_("\
      64  Usage: %s --coreutils-prog=PROGRAM_NAME [PARAMETERS]... \n"),
      65                program_name);
      66        fputs (_("\
      67  Execute the PROGRAM_NAME built-in program with the given PARAMETERS.\n\
      68  \n"), stdout);
      69        fputs (HELP_OPTION_DESCRIPTION, stdout);
      70        fputs (VERSION_OPTION_DESCRIPTION, stdout);
      71  
      72  #ifdef SINGLE_BINARY
      73  /* XXX: Ideally we'd like to present "install" here, not "ginstall".  */
      74        char const *prog_name_list =
      75  # define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) " " prog_name_str
      76  # include "coreutils.h"
      77  # undef SINGLE_BINARY_PROGRAM
      78        ;
      79        printf ("\n\
      80  Built-in programs:\n\
      81  %s\n", prog_name_list);
      82  #endif
      83  
      84        printf (_("\
      85  \n\
      86  Use: '%s --coreutils-prog=PROGRAM_NAME --help' for individual program help.\n"),
      87                program_name);
      88        emit_ancillary_info (PROGRAM_NAME);
      89      }
      90    exit (status);
      91  }
      92  
      93  static void
      94  launch_program (char const *prog_name, int prog_argc, char **prog_argv)
      95  {
      96    int (*prog_main) (int, char **) = nullptr;
      97  
      98    /* Ensure that at least one parameter was passed.  */
      99    if (!prog_argc || !prog_argv || !prog_argv[0] || !prog_name)
     100      return;
     101  
     102  #ifdef SINGLE_BINARY
     103    if (false);
     104    /* Look up the right main program.  */
     105  # define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
     106    else if (STREQ (prog_name_str, prog_name)) \
     107      prog_main = single_binary_main_##main_name;
     108  # include "coreutils.h"
     109  # undef SINGLE_BINARY_PROGRAM
     110  #endif
     111  
     112    if (! prog_main)
     113      return;
     114  
     115  #if HAVE_PRCTL && defined PR_SET_NAME
     116    /* Not being able to set the program name is not a fatal error.  */
     117    prctl (PR_SET_NAME, prog_argv[0]);
     118  #endif
     119  #if HAVE_PRCTL && defined PR_SET_MM_ARG_START
     120    /* Shift the beginning of the command line to prog_argv[0] (if set) so
     121       /proc/$pid/cmdline reflects a more specific value.  Note one needs
     122       CAP_SYS_RESOURCE or root privileges for this to succeed.  */
     123    prctl (PR_SET_MM, PR_SET_MM_ARG_START, prog_argv[0], 0, 0);
     124  #endif
     125  
     126    exit (prog_main (prog_argc, prog_argv));
     127  }
     128  
     129  int
     130  main (int argc, char **argv)
     131  {
     132    char *prog_name = last_component (argv[0]);
     133    int optc;
     134  
     135    /* Map external name to internal name.  */
     136    char ginstall[] = "ginstall";
     137    if (STREQ (prog_name, "install"))
     138      prog_name = ginstall;
     139  
     140    /* If this program is called directly as "coreutils" or if the value of
     141       argv[0] is an unknown tool (which "coreutils" is), we proceed and parse
     142       the options.  */
     143    launch_program (prog_name, argc, argv);
     144  
     145    /* No known program was selected via argv[0].  Try parsing the first
     146       argument as --coreutils-prog=PROGRAM to determine the program.  The
     147       invocation for this case should be:
     148         path/to/coreutils --coreutils-prog=someprog someprog ...
     149       The third argument is what the program will see as argv[0].  */
     150  
     151    if (argc >= 2)
     152      {
     153        size_t nskip = 0;
     154        char *arg_name = nullptr;
     155  
     156        /* If calling coreutils directly, the "script" name isn't passed.
     157           Distinguish the two cases with a -shebang suffix.  */
     158        if (STRPREFIX (argv[1], "--coreutils-prog="))
     159          {
     160            nskip = 1;
     161            arg_name = prog_name = argv[1] + strlen ("--coreutils-prog=");
     162          }
     163        else if (STRPREFIX (argv[1], "--coreutils-prog-shebang="))
     164          {
     165            nskip = 2;
     166            prog_name = argv[1] + strlen ("--coreutils-prog-shebang=");
     167            if (argc >= 3)
     168              arg_name = last_component (argv[2]);
     169            else
     170              arg_name = prog_name;
     171          }
     172  
     173        if (nskip)
     174          {
     175            argv[nskip] = arg_name; /* XXX: Discards any specified path.  */
     176            launch_program (prog_name, argc - nskip, argv + nskip);
     177            error (EXIT_FAILURE, 0, _("unknown program %s"),
     178                   quote (prog_name));
     179          }
     180      }
     181  
     182    /* No known program was selected.  From here on, we behave like any other
     183       coreutils program.  */
     184    initialize_main (&argc, &argv);
     185    set_program_name (argv[0]);
     186    setlocale (LC_ALL, "");
     187    bindtextdomain (PACKAGE, LOCALEDIR);
     188    textdomain (PACKAGE);
     189    atexit (close_stdout);
     190  
     191    if ((optc = getopt_long (argc, argv, "", long_options, nullptr)) != -1)
     192      switch (optc)
     193        {
     194        case_GETOPT_HELP_CHAR;
     195  
     196        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     197        }
     198  
     199    /* Only print the error message when no options have been passed
     200       to coreutils.  */
     201    if (optind == 1 && prog_name && !STREQ (prog_name, "coreutils"))
     202      error (0, 0, _("unknown program %s"),
     203             quote (prog_name));
     204  
     205    usage (EXIT_FAILURE);
     206  }