/* Test --no-hard-links option to localedef.
   Copyright (C) 2020-2026 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <https://www.gnu.org/licenses/>.  */

/* The test is designed to run in a container and execute localedef
   once without --no-hard-links, verify that there are 2 hard links to
   LC_CTYPE, and then run again *with* --no-hard-links and verify there
   are no hard links and link counts remain at 1.  The expectation here
   is that LC_CTYPE is identical for both locales because they are same
   empty locale but with a different name.  We use tests-container in
   this test because the hard link optimziation is only carried out for
   the default locale installation directory, and to write to that we
   need write access to that directory, enabled by 'su' via
   tests-container framework.  */

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <support/check.h>
#include <support/support.h>
#include <support/xunistd.h>
#include <support/capture_subprocess.h>

/* Each test compiles a locale to output, and has an expected link count
   for LC_CTYPE.  This test expects that localedef removes the existing
   files before installing new copies of the files, and we do not
   cleanup between localedef runs.  We can't cleanup between each pair
   of runs since localedef must see the existing locale in order to
   determine that space could be saved by using a hardlink.  */
struct test_data
{
  /* Arguments to localedef for this step.  */
  const char * argv[16];
  /* Expected output file generated by running localedef.  */
  const char *output;
  /* Expected st_nlink count for the output.  */
  int st_nlink;
};

/* Check for link count.  */
void
check_link (struct test_data step)
{
  struct stat64 locale;
  char *output;

  output = xasprintf ("%s/%s", support_complocaledir_prefix, step.output);
  xstat64 (output, &locale);
  free (output);
  TEST_COMPARE (locale.st_nlink, step.st_nlink);
}

static void
run_localedef (void *step)
{
  const char *prog = xasprintf ("%s/localedef", support_bindir_prefix);
  struct test_data *one = (struct test_data *) step;

  one->argv[0] = prog;
  execv (prog, (char * const *) one->argv);
  FAIL_EXIT1 ("execv: %m");
}

#define TEST1DIR "test1_locale.dir"
#define TEST2DIR "test2_locale.dir"

/* The whole test has 4 steps described below.  Note the argv[0] NULL
   will be filled in at runtime by run_localedef.  */
static struct test_data step[4] = {
  { .argv = { NULL, "--no-archive", "-i", "/test1_locale", TEST1DIR, NULL },
    .output = TEST1DIR "/LC_CTYPE",
    .st_nlink = 1 },
  { .argv = { NULL, "--no-archive", "-i", "/test2_locale", TEST2DIR, NULL },
    .output = TEST2DIR "/LC_CTYPE",
    .st_nlink = 2 },
  { .argv = { NULL, "--no-archive", "--no-hard-links", "-i", "/test1_locale",
	      TEST1DIR, NULL },
    .output = TEST1DIR "/LC_CTYPE",
    .st_nlink = 1 },
  { .argv = { NULL, "--no-archive", "--no-hard-links", "-i", "/test2_locale",
	      TEST1DIR, NULL },
    .output = TEST2DIR "/LC_CTYPE",
    .st_nlink = 1 },
};

static int
do_test (void)
{
  struct support_capture_subprocess result;

  printf ("INFO: $complocaledir is %s\n", support_complocaledir_prefix);
  /* Compile the first locale.  */
  result = support_capture_subprocess (run_localedef, (void *) &step[0]);
  support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
  check_link (step[0]);

  /* This time around we should have link counts of 2 for the second
     linked locale since categories are identical.  */
  result = support_capture_subprocess (run_localedef, (void *) &step[1]);
  support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
  check_link (step[1]);

  /* Again with --no-hard-links (link count is always one).  */
  result = support_capture_subprocess (run_localedef, (void *) &step[2]);
  support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
  check_link (step[2]);

  /* Again with --no-hard-links, and the link count must remain 1.  */
  result = support_capture_subprocess (run_localedef, (void *) &step[3]);
  support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
  check_link (step[3]);

  /* Tested without and with --no-hard-links and link counts were
     consistent.  */
  return EXIT_SUCCESS;
}

#include <support/test-driver.c>
