forked from rpms/glibc
Resolves: #156477
- Support installing only those locales specified by the RPM macro %%_install_langs (#156477).
This commit is contained in:
parent
6aa6486e1b
commit
91764bd9ec
@ -8,6 +8,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -21,6 +22,7 @@ const char *alias_file = DATADIR "/locale/locale.alias";
|
|||||||
const char *locar_file = PREFIX "/lib/locale/locale-archive";
|
const char *locar_file = PREFIX "/lib/locale/locale-archive";
|
||||||
const char *tmpl_file = PREFIX "/lib/locale/locale-archive.tmpl";
|
const char *tmpl_file = PREFIX "/lib/locale/locale-archive.tmpl";
|
||||||
const char *loc_path = PREFIX "/lib/locale/";
|
const char *loc_path = PREFIX "/lib/locale/";
|
||||||
|
/* Flags set by `--verbose` option. */
|
||||||
int be_quiet = 1;
|
int be_quiet = 1;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
int max_locarchive_open_retry = 10;
|
int max_locarchive_open_retry = 10;
|
||||||
@ -122,7 +124,7 @@ open_tmpl_archive (struct locarhandle *ah)
|
|||||||
ah->mmaped = (head.sumhash_offset
|
ah->mmaped = (head.sumhash_offset
|
||||||
+ head.sumhash_size * sizeof (struct sumhashent));
|
+ head.sumhash_size * sizeof (struct sumhashent));
|
||||||
if (ah->mmaped > (unsigned long) st.st_size)
|
if (ah->mmaped > (unsigned long) st.st_size)
|
||||||
error (EXIT_FAILURE, 0, "locale archite template file truncated");
|
error (EXIT_FAILURE, 0, "locale archive template file truncated");
|
||||||
ah->mmaped = st.st_size;
|
ah->mmaped = st.st_size;
|
||||||
ah->reserved = st.st_size;
|
ah->reserved = st.st_size;
|
||||||
|
|
||||||
@ -257,7 +259,9 @@ compute_data (struct locarhandle *ah, struct nameent *name, size_t sumused,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
fill_archive (struct locarhandle *tmpl_ah,
|
fill_archive (struct locarhandle *tmpl_ah,
|
||||||
const char *fname, size_t nlist, char *list[],
|
const char *fname,
|
||||||
|
size_t install_langs_count, char *install_langs_list[],
|
||||||
|
size_t nlist, char *list[],
|
||||||
const char *primary)
|
const char *primary)
|
||||||
{
|
{
|
||||||
struct locarhandle ah;
|
struct locarhandle ah;
|
||||||
@ -288,12 +292,42 @@ fill_archive (struct locarhandle *tmpl_ah,
|
|||||||
for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
|
for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
|
||||||
if (namehashtab[cnt].locrec_offset != 0)
|
if (namehashtab[cnt].locrec_offset != 0)
|
||||||
{
|
{
|
||||||
|
char * name;
|
||||||
|
int i;
|
||||||
assert (used < head->namehash_used);
|
assert (used < head->namehash_used);
|
||||||
names[used].name = tmpl_ah->addr + namehashtab[cnt].name_offset;
|
name = tmpl_ah->addr + namehashtab[cnt].name_offset;
|
||||||
|
if (install_langs_count == 0)
|
||||||
|
{
|
||||||
|
/* Always intstall the entry. */
|
||||||
|
names[used].name = name;
|
||||||
names[used++].locrec
|
names[used++].locrec
|
||||||
= (struct locrecent *) ((char *) tmpl_ah->addr +
|
= (struct locrecent *) ((char *) tmpl_ah->addr +
|
||||||
namehashtab[cnt].locrec_offset);
|
namehashtab[cnt].locrec_offset);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Only install the entry if the user asked for it via
|
||||||
|
--install-langs. */
|
||||||
|
for (i = 0; i < install_langs_count; i++)
|
||||||
|
{
|
||||||
|
/* Add one for "_" and one for the null terminator. */
|
||||||
|
size_t len = strlen (install_langs_list[i]) + 2;
|
||||||
|
char *install_lang = (char *)xmalloc (len);
|
||||||
|
strncpy (install_lang, install_langs_list[i], len - 2);
|
||||||
|
install_lang[len - 1] = '\0';
|
||||||
|
if (strchr (install_lang, '_') == NULL)
|
||||||
|
strcat (install_lang, "_");
|
||||||
|
if (strncmp (name, install_lang, strlen (install_lang)) == 0)
|
||||||
|
{
|
||||||
|
names[used].name = name;
|
||||||
|
names[used++].locrec
|
||||||
|
= (struct locrecent *) ((char *)tmpl_ah->addr
|
||||||
|
+ namehashtab[cnt].locrec_offset);
|
||||||
|
}
|
||||||
|
free (install_lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Sort the names. */
|
/* Sort the names. */
|
||||||
qsort (names, used, sizeof (struct nameent), nameentcmp);
|
qsort (names, used, sizeof (struct nameent), nameentcmp);
|
||||||
@ -542,6 +576,62 @@ fill_archive (struct locarhandle *tmpl_ah,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usage()
|
||||||
|
{
|
||||||
|
printf ("\
|
||||||
|
Usage: build-locale-archive [OPTION]... [TEMPLATE-FILE] [ARCHIVE-FILE]\n\
|
||||||
|
Builds a locale archive from a template file.\n\
|
||||||
|
Options:\n\
|
||||||
|
-h, --help Print this usage message.\n\
|
||||||
|
-v, --verbose Verbose execution.\n\
|
||||||
|
-l, --install-langs=LIST Only include locales given in LIST into the \n\
|
||||||
|
locale archive. LIST is a colon separated list\n\
|
||||||
|
of locale prefixes, for example \"de:en:ja\".\n\
|
||||||
|
The special argument \"all\" means to install\n\
|
||||||
|
all languages and it must be present by itself.\n\
|
||||||
|
If \"all\" is present with any other language it\n\
|
||||||
|
will be treated as the name of a locale.\n\
|
||||||
|
If the --install-langs option is missing, all\n\
|
||||||
|
locales are installed. The colon separated list\n\
|
||||||
|
can contain any strings matching the beginning of\n\
|
||||||
|
locale names.\n\
|
||||||
|
If a string does not contain a \"_\", it is added.\n\
|
||||||
|
Examples:\n\
|
||||||
|
--install-langs=\"en\"\n\
|
||||||
|
installs en_US, en_US.iso88591,\n\
|
||||||
|
en_US.iso885915, en_US.utf8,\n\
|
||||||
|
en_GB ...\n\
|
||||||
|
--install-langs=\"en_US.utf8\"\n\
|
||||||
|
installs only en_US.utf8.\n\
|
||||||
|
--install-langs=\"ko\"\n\
|
||||||
|
installs ko_KR, ko_KR.euckr,\n\
|
||||||
|
ko_KR.utf8 but *not* kok_IN\n\
|
||||||
|
because \"ko\" does not contain\n\
|
||||||
|
\"_\" and it is silently added\n\
|
||||||
|
--install-langs\"ko:kok\"\n\
|
||||||
|
installs ko_KR, ko_KR.euckr,\n\
|
||||||
|
ko_KR.utf8, kok_IN, and\n\
|
||||||
|
kok_IN.utf8.\n\
|
||||||
|
--install-langs=\"POSIX\" will\n\
|
||||||
|
installs *no* locales at all\n\
|
||||||
|
because POSIX matches none of\n\
|
||||||
|
the locales. Actually, any string\n\
|
||||||
|
matching nothing will do that.\n\
|
||||||
|
POSIX and C will always be\n\
|
||||||
|
available because they are\n\
|
||||||
|
builtin.\n\
|
||||||
|
Aliases are installed as well,\n\
|
||||||
|
i.e. --install-langs=\"de\"\n\
|
||||||
|
will install not only every locale starting with\n\
|
||||||
|
\"de\" but also the aliases \"deutsch\"\n\
|
||||||
|
and and \"german\" although the latter does not\n\
|
||||||
|
start with \"de\".\n\
|
||||||
|
\n\
|
||||||
|
If the arguments TEMPLATE-FILE and ARCHIVE-FILE are not given the locations\n\
|
||||||
|
where the glibc used expects these files are used by default.\n\
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
int main (int argc, char *argv[])
|
int main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char path[4096];
|
char path[4096];
|
||||||
@ -549,21 +639,132 @@ int main (int argc, char *argv[])
|
|||||||
struct dirent64 *d;
|
struct dirent64 *d;
|
||||||
struct stat64 st;
|
struct stat64 st;
|
||||||
char *list[16384], *primary;
|
char *list[16384], *primary;
|
||||||
|
char *lang;
|
||||||
|
int install_langs_count = 0;
|
||||||
|
int i;
|
||||||
|
char *install_langs_arg, *ila_start;
|
||||||
|
char **install_langs_list;
|
||||||
unsigned int cnt = 0;
|
unsigned int cnt = 0;
|
||||||
struct locarhandle tmpl_ah;
|
struct locarhandle tmpl_ah;
|
||||||
|
char *new_locar_fname = NULL;
|
||||||
size_t loc_path_len = strlen (loc_path);
|
size_t loc_path_len = strlen (loc_path);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"verbose", no_argument, 0, 'v'},
|
||||||
|
{"install-langs", required_argument, 0, 'l'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
/* getopt_long stores the option index here. */
|
||||||
|
int option_index = 0;
|
||||||
|
|
||||||
|
c = getopt_long (argc, argv, "vhl:",
|
||||||
|
long_options, &option_index);
|
||||||
|
|
||||||
|
/* Detect the end of the options. */
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
printf ("unknown option %s", long_options[option_index].name);
|
||||||
|
if (optarg)
|
||||||
|
printf (" with arg %s", optarg);
|
||||||
|
printf ("\n");
|
||||||
|
usage ();
|
||||||
|
exit (1);
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
verbose = 1;
|
||||||
|
be_quiet = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
usage ();
|
||||||
|
exit (0);
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
install_langs_arg = ila_start = strdup (optarg);
|
||||||
|
/* If the argument to --install-lang is "all", do
|
||||||
|
not limit the list of languages to install and install
|
||||||
|
them all. We do not support installing a single locale
|
||||||
|
called "all". */
|
||||||
|
#define MAGIC_INSTALL_ALL "all"
|
||||||
|
if (install_langs_arg != NULL
|
||||||
|
&& install_langs_arg[0] != '\0'
|
||||||
|
&& !(strncmp(install_langs_arg, MAGIC_INSTALL_ALL,
|
||||||
|
strlen(MAGIC_INSTALL_ALL)) == 0
|
||||||
|
&& strlen (install_langs_arg) == 3))
|
||||||
|
{
|
||||||
|
/* Count the number of languages we will install. */
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
lang = strtok(install_langs_arg, ":;,");
|
||||||
|
if (lang == NULL)
|
||||||
|
break;
|
||||||
|
install_langs_count++;
|
||||||
|
install_langs_arg = NULL;
|
||||||
|
}
|
||||||
|
free (ila_start);
|
||||||
|
/* Copy the list. */
|
||||||
|
install_langs_list = (char **)xmalloc (sizeof(char *) * install_langs_count);
|
||||||
|
install_langs_arg = ila_start = strdup (optarg);
|
||||||
|
install_langs_count = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
lang = strtok(install_langs_arg, ":;,");
|
||||||
|
if (lang == NULL)
|
||||||
|
break;
|
||||||
|
install_langs_list[install_langs_count] = lang;
|
||||||
|
install_langs_count++;
|
||||||
|
install_langs_arg = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
/* getopt_long already printed an error message. */
|
||||||
|
usage ();
|
||||||
|
exit (0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmpl_ah.fname = NULL;
|
||||||
|
if (optind < argc)
|
||||||
|
tmpl_ah.fname = argv[optind];
|
||||||
|
if (optind + 1 < argc)
|
||||||
|
new_locar_fname = argv[optind + 1];
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
if (tmpl_ah.fname)
|
||||||
|
printf("input archive file specified on command line: %s\n",
|
||||||
|
tmpl_ah.fname);
|
||||||
|
else
|
||||||
|
printf("using default input archive file.\n");
|
||||||
|
if (new_locar_fname)
|
||||||
|
printf("output archive file specified on command line: %s\n",
|
||||||
|
new_locar_fname);
|
||||||
|
else
|
||||||
|
printf("using default output archive file.\n");
|
||||||
|
}
|
||||||
|
|
||||||
dirp = opendir (loc_path);
|
dirp = opendir (loc_path);
|
||||||
if (dirp == NULL)
|
if (dirp == NULL)
|
||||||
error (EXIT_FAILURE, errno, "cannot open directory \"%s\"", loc_path);
|
error (EXIT_FAILURE, errno, "cannot open directory \"%s\"", loc_path);
|
||||||
|
|
||||||
/* Use the template file as specified on the command line. */
|
|
||||||
tmpl_ah.fname = NULL;
|
|
||||||
if (argc > 1)
|
|
||||||
tmpl_ah.fname = argv[1];
|
|
||||||
|
|
||||||
open_tmpl_archive (&tmpl_ah);
|
open_tmpl_archive (&tmpl_ah);
|
||||||
|
|
||||||
|
if (new_locar_fname)
|
||||||
|
unlink (new_locar_fname);
|
||||||
|
else
|
||||||
unlink (locar_file);
|
unlink (locar_file);
|
||||||
primary = getenv ("LC_ALL");
|
primary = getenv ("LC_ALL");
|
||||||
if (primary == NULL)
|
if (primary == NULL)
|
||||||
@ -575,7 +776,8 @@ int main (int argc, char *argv[])
|
|||||||
&& strncmp (primary, "zh", 2) != 0)
|
&& strncmp (primary, "zh", 2) != 0)
|
||||||
{
|
{
|
||||||
char *ptr = malloc (strlen (primary) + strlen (".utf8") + 1), *p, *q;
|
char *ptr = malloc (strlen (primary) + strlen (".utf8") + 1), *p, *q;
|
||||||
|
/* This leads to invalid locales sometimes:
|
||||||
|
de_DE.iso885915@euro -> de_DE.utf8@euro */
|
||||||
if (ptr != NULL)
|
if (ptr != NULL)
|
||||||
{
|
{
|
||||||
p = ptr;
|
p = ptr;
|
||||||
@ -640,9 +842,16 @@ int main (int argc, char *argv[])
|
|||||||
closedir (dirp);
|
closedir (dirp);
|
||||||
/* Store the archive to the file specified as the second argument on the
|
/* Store the archive to the file specified as the second argument on the
|
||||||
command line or the default locale archive. */
|
command line or the default locale archive. */
|
||||||
fill_archive (&tmpl_ah, argc > 2 ? argv[2] : NULL, cnt, list, primary);
|
fill_archive (&tmpl_ah, new_locar_fname,
|
||||||
|
install_langs_count, install_langs_list,
|
||||||
|
cnt, list, primary);
|
||||||
close_archive (&tmpl_ah);
|
close_archive (&tmpl_ah);
|
||||||
truncate (tmpl_file, 0);
|
truncate (tmpl_file, 0);
|
||||||
|
if (install_langs_count > 0)
|
||||||
|
{
|
||||||
|
free (ila_start);
|
||||||
|
free (install_langs_list);
|
||||||
|
}
|
||||||
char *tz_argv[] = { "/usr/sbin/tzdata-update", NULL };
|
char *tz_argv[] = { "/usr/sbin/tzdata-update", NULL };
|
||||||
execve (tz_argv[0], (char *const *)tz_argv, (char *const *)&tz_argv[1]);
|
execve (tz_argv[0], (char *const *)tz_argv, (char *const *)&tz_argv[1]);
|
||||||
exit (0);
|
exit (0);
|
||||||
|
14
glibc.spec
14
glibc.spec
@ -1,6 +1,6 @@
|
|||||||
%define glibcsrcdir glibc-2.21-104-gbdf1ff0
|
%define glibcsrcdir glibc-2.21-104-gbdf1ff0
|
||||||
%define glibcversion 2.21.90
|
%define glibcversion 2.21.90
|
||||||
%define glibcrelease 4%{?dist}
|
%define glibcrelease 5%{?dist}
|
||||||
# Pre-release tarballs are pulled in from git using a command that is
|
# Pre-release tarballs are pulled in from git using a command that is
|
||||||
# effectively:
|
# effectively:
|
||||||
#
|
#
|
||||||
@ -1579,22 +1579,22 @@ end
|
|||||||
|
|
||||||
%postun -p /sbin/ldconfig
|
%postun -p /sbin/ldconfig
|
||||||
|
|
||||||
%triggerin common -p <lua> -- glibc
|
%triggerin common -e -p <lua> -- glibc
|
||||||
if posix.stat("%{_prefix}/lib/locale/locale-archive.tmpl", "size") > 0 then
|
if posix.stat("%{_prefix}/lib/locale/locale-archive.tmpl", "size") > 0 then
|
||||||
pid = posix.fork()
|
pid = posix.fork()
|
||||||
if pid == 0 then
|
if pid == 0 then
|
||||||
posix.exec("%{_prefix}/sbin/build-locale-archive")
|
posix.exec("%{_prefix}/sbin/build-locale-archive", "--install-langs", "%%{_install_langs}")
|
||||||
elseif pid > 0 then
|
elseif pid > 0 then
|
||||||
posix.wait(pid)
|
posix.wait(pid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
%post common -p <lua>
|
%post common -e -p <lua>
|
||||||
if posix.access("/etc/ld.so.cache") then
|
if posix.access("/etc/ld.so.cache") then
|
||||||
if posix.stat("%{_prefix}/lib/locale/locale-archive.tmpl", "size") > 0 then
|
if posix.stat("%{_prefix}/lib/locale/locale-archive.tmpl", "size") > 0 then
|
||||||
pid = posix.fork()
|
pid = posix.fork()
|
||||||
if pid == 0 then
|
if pid == 0 then
|
||||||
posix.exec("%{_prefix}/sbin/build-locale-archive")
|
posix.exec("%{_prefix}/sbin/build-locale-archive", "--install-langs", "%%{_install_langs}")
|
||||||
elseif pid > 0 then
|
elseif pid > 0 then
|
||||||
posix.wait(pid)
|
posix.wait(pid)
|
||||||
end
|
end
|
||||||
@ -1751,6 +1751,10 @@ rm -f *.filelist*
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Mar 3 2015 Mike Fabian <mfabian@redhat.com> - 2.21.90-5
|
||||||
|
- Support installing only those locales specified by the RPM macro
|
||||||
|
%%_install_langs (#156477).
|
||||||
|
|
||||||
* Mon Feb 23 2015 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.21.90-4
|
* Mon Feb 23 2015 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.21.90-4
|
||||||
- Auto-sync with upstream master.
|
- Auto-sync with upstream master.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user