(root)/
glibc-2.38/
localedata/
tst-localedef-hardlinks.c
       1  /* Test --no-hard-links option to localedef.
       2     Copyright (C) 2020-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* The test is designed to run in a container and execute localedef
      20     once without --no-hard-links, verify that there are 2 hard links to
      21     LC_CTYPE, and then run again *with* --no-hard-links and verify there
      22     are no hard links and link counts remain at 1.  The expectation here
      23     is that LC_CTYPE is identical for both locales because they are same
      24     empty locale but with a different name.  We use tests-container in
      25     this test because the hard link optimziation is only carried out for
      26     the default locale installation directory, and to write to that we
      27     need write access to that directory, enabled by 'su' via
      28     tests-container framework.  */
      29  
      30  #include <stdio.h>
      31  #include <stdlib.h>
      32  #include <sys/stat.h>
      33  #include <sys/types.h>
      34  #include <sys/wait.h>
      35  
      36  #include <support/check.h>
      37  #include <support/support.h>
      38  #include <support/xunistd.h>
      39  #include <support/capture_subprocess.h>
      40  
      41  /* Each test compiles a locale to output, and has an expected link count
      42     for LC_CTYPE.  This test expects that localedef removes the existing
      43     files before installing new copies of the files, and we do not
      44     cleanup between localedef runs.  We can't cleanup between each pair
      45     of runs since localedef must see the existing locale in order to
      46     determine that space could be saved by using a hardlink.  */
      47  struct test_data
      48  {
      49    /* Arguments to localedef for this step.  */
      50    const char * argv[16];
      51    /* Expected output file generated by running localedef.  */
      52    const char *output;
      53    /* Expected st_nlink count for the output.  */
      54    int st_nlink;
      55  };
      56  
      57  /* Check for link count.  */
      58  void
      59  check_link (struct test_data step)
      60  {
      61    struct stat64 locale;
      62    char *output;
      63  
      64    output = xasprintf ("%s/%s", support_complocaledir_prefix, step.output);
      65    xstat (output, &locale);
      66    free (output);
      67    TEST_COMPARE (locale.st_nlink, step.st_nlink);
      68  }
      69  
      70  static void
      71  run_localedef (void *step)
      72  {
      73    const char *prog = xasprintf ("%s/localedef", support_bindir_prefix);
      74    struct test_data *one = (struct test_data *) step;
      75  
      76    one->argv[0] = prog;
      77    execv (prog, (char * const *) one->argv);
      78    FAIL_EXIT1 ("execv: %m");
      79  }
      80  
      81  #define TEST1DIR "test1_locale.dir"
      82  #define TEST2DIR "test2_locale.dir"
      83  
      84  /* The whole test has 4 steps described below.  Note the argv[0] NULL
      85     will be filled in at runtime by run_localedef.  */
      86  static struct test_data step[4] = {
      87    { .argv = { NULL, "--no-archive", "-i", "/test1_locale", TEST1DIR, NULL },
      88      .output = TEST1DIR "/LC_CTYPE",
      89      .st_nlink = 1 },
      90    { .argv = { NULL, "--no-archive", "-i", "/test2_locale", TEST2DIR, NULL },
      91      .output = TEST2DIR "/LC_CTYPE",
      92      .st_nlink = 2 },
      93    { .argv = { NULL, "--no-archive", "--no-hard-links", "-i", "/test1_locale",
      94  	      TEST1DIR, NULL },
      95      .output = TEST1DIR "/LC_CTYPE",
      96      .st_nlink = 1 },
      97    { .argv = { NULL, "--no-archive", "--no-hard-links", "-i", "/test2_locale",
      98  	      TEST1DIR, NULL },
      99      .output = TEST2DIR "/LC_CTYPE",
     100      .st_nlink = 1 },
     101  };
     102  
     103  static int
     104  do_test (void)
     105  {
     106    struct support_capture_subprocess result;
     107  
     108    printf ("INFO: $complocaledir is %s\n", support_complocaledir_prefix);
     109    /* Compile the first locale.  */
     110    result = support_capture_subprocess (run_localedef, (void *) &step[0]);
     111    support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
     112    check_link (step[0]);
     113  
     114    /* This time around we should have link counts of 2 for the second
     115       linked locale since categories are identical.  */
     116    result = support_capture_subprocess (run_localedef, (void *) &step[1]);
     117    support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
     118    check_link (step[1]);
     119  
     120    /* Again with --no-hard-links (link count is always one).  */
     121    result = support_capture_subprocess (run_localedef, (void *) &step[2]);
     122    support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
     123    check_link (step[2]);
     124  
     125    /* Again with --no-hard-links, and the link count must remain 1.  */
     126    result = support_capture_subprocess (run_localedef, (void *) &step[3]);
     127    support_capture_subprocess_check (&result, "execv", 1, sc_allow_stderr);
     128    check_link (step[3]);
     129  
     130    /* Tested without and with --no-hard-links and link counts were
     131       consistent.  */
     132    return EXIT_SUCCESS;
     133  }
     134  
     135  #include <support/test-driver.c>