diff --git a/localedata/Makefile b/localedata/Makefile index e89bacc1aa..ccfcb0049f 100644 --- a/localedata/Makefile +++ b/localedata/Makefile @@ -167,6 +167,8 @@ tests-special += $(objpfx)mtrace-tst-leaks.out endif endif endif +tests-container = \ + tst-localedef-hardlinks # Files to install. ifeq ($(INSTALL_UNCOMPRESSED),yes) diff --git a/localedata/tst-localedef-hardlinks.c b/localedata/tst-localedef-hardlinks.c new file mode 100644 index 0000000000..e8fda167be --- /dev/null +++ b/localedata/tst-localedef-hardlinks.c @@ -0,0 +1,135 @@ +/* Test --no-hard-links option to localedef. + Copyright (C) 2020 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 + . */ + +/* 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +/* 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); + xstat (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 diff --git a/localedata/tst-localedef-hardlinks.root/postclean.req b/localedata/tst-localedef-hardlinks.root/postclean.req new file mode 100644 index 0000000000..48f3c4bd4e --- /dev/null +++ b/localedata/tst-localedef-hardlinks.root/postclean.req @@ -0,0 +1,2 @@ +# We do not want test locales to remain installed for future tests so +# we request that the testroot be cleaned after the test is complete. diff --git a/localedata/tst-localedef-hardlinks.root/test1_locale b/localedata/tst-localedef-hardlinks.root/test1_locale new file mode 100644 index 0000000000..79f4c3aec4 --- /dev/null +++ b/localedata/tst-localedef-hardlinks.root/test1_locale @@ -0,0 +1,3 @@ +comment_char % +escape_char / +% Empty test locale. Must be identical to the other test locale. diff --git a/localedata/tst-localedef-hardlinks.root/test2_locale b/localedata/tst-localedef-hardlinks.root/test2_locale new file mode 100644 index 0000000000..79f4c3aec4 --- /dev/null +++ b/localedata/tst-localedef-hardlinks.root/test2_locale @@ -0,0 +1,3 @@ +comment_char % +escape_char / +% Empty test locale. Must be identical to the other test locale. diff --git a/localedata/tst-localedef-hardlinks.root/tst-localedef-hardlinks.script b/localedata/tst-localedef-hardlinks.root/tst-localedef-hardlinks.script new file mode 100644 index 0000000000..f0eccec251 --- /dev/null +++ b/localedata/tst-localedef-hardlinks.root/tst-localedef-hardlinks.script @@ -0,0 +1,9 @@ +# Need root to write to $complocaledir when running localedef. +su + +# The container install ensures we have uncompressed charmaps so we don't +# need gzip, and we don't need to copy in the uncompressed charmap from +# the source tree. + +# The container install ensures we have the compiled locale dirctory +# present for localedef to write to by default.