diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | fedora/build-locale-archive.c | 509 | ||||
-rw-r--r-- | fedora/glibc.spec.in | 35 | ||||
-rw-r--r-- | locale/programs/locarchive.c | 4 |
4 files changed, 519 insertions, 33 deletions
@@ -1,3 +1,7 @@ +2007-04-16 Jakub Jelinek <jakub@redhat.com> + + * locale/programs/locarchive.c (add_alias, insert_name): Remove static. + 2007-03-23 Jakub Jelinek <jakub@redhat.com> * scripts/check-local-headers.sh: Filter out sys/capability.h. diff --git a/fedora/build-locale-archive.c b/fedora/build-locale-archive.c index a35171736e..ef0ac91ba7 100644 --- a/fedora/build-locale-archive.c +++ b/fedora/build-locale-archive.c @@ -1,23 +1,39 @@ #define _GNU_SOURCE -#include <stdlib.h> -#include <unistd.h> +#include <assert.h> #include <dirent.h> #include <errno.h> -#include <string.h> +#include <fcntl.h> +#include <locale.h> +#include <stdarg.h> #include <stdbool.h> -#include <sys/stat.h> #include <stdio.h> -#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> #include "../locale/hashval.h" +#define __LC_LAST 13 +#include "../locale/locarchive.h" +#include "../crypt/md5.h" const char *alias_file = DATADIR "/locale/locale.alias"; const char *locar_file = PREFIX "/lib/locale/locale-archive"; +const char *tmpl_file = PREFIX "/lib/locale/locale-archive.tmpl"; const char *loc_path = PREFIX "/lib/locale/"; int be_quiet = 1; int verbose = 0; int max_locarchive_open_retry = 10; const char *output_prefix; +static const char *locnames[] = + { +#define DEFINE_CATEGORY(category, category_name, items, a) \ + [category] = category_name, +#include "../locale/categories.def" +#undef DEFINE_CATEGORY + }; + static int is_prime (unsigned long candidate) { @@ -51,6 +67,7 @@ next_prime (unsigned long seed) void * xmalloc (size_t size) { + (void) size; exit (255); } @@ -72,7 +89,446 @@ error (int status, int errnum, const char *message, ...) exit (errnum == EROFS ? 0 : status); } -extern int add_locales_to_archive (size_t nlist, char *list[], bool replace); +static void +open_tmpl_archive (struct locarhandle *ah) +{ + struct stat64 st; + int fd; + struct locarhead head; + const char *archivefname = tmpl_file; + + /* Open the archive. We must have exclusive write access. */ + fd = open64 (archivefname, O_RDONLY); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot open locale archive template file \"%s\"", + archivefname); + + if (fstat64 (fd, &st) < 0) + error (EXIT_FAILURE, errno, "cannot stat locale archive template file \"%s\"", + archivefname); + + /* Read the header. */ + if (TEMP_FAILURE_RETRY (read (fd, &head, sizeof (head))) != sizeof (head)) + error (EXIT_FAILURE, errno, "cannot read archive header"); + + ah->fd = fd; + ah->len = (head.sumhash_offset + + head.sumhash_size * sizeof (struct sumhashent)); + if (ah->len > st.st_size) + error (EXIT_FAILURE, 0, "locale archite template file truncated"); + ah->len = st.st_size; + + /* Now we know how large the administrative information part is. + Map all of it. */ + ah->addr = mmap64 (NULL, ah->len, PROT_READ, MAP_SHARED, fd, 0); + if (ah->addr == MAP_FAILED) + error (EXIT_FAILURE, errno, "cannot map archive header"); +} + +/* Open the locale archive. */ +extern void open_archive (struct locarhandle *ah, bool readonly); + +/* Close the locale archive. */ +extern void close_archive (struct locarhandle *ah); + +/* Add given locale data to the archive. */ +extern int add_locale_to_archive (struct locarhandle *ah, const char *name, + locale_data_t data, bool replace); + +extern void add_alias (struct locarhandle *ah, const char *alias, + bool replace, const char *oldname, + uint32_t *locrec_offset_p); + +extern struct namehashent * +insert_name (struct locarhandle *ah, + const char *name, size_t name_len, bool replace); + +struct nameent +{ + char *name; + struct locrecent *locrec; +}; + +struct dataent +{ + const unsigned char *sum; + uint32_t file_offset; +}; + +static int +nameentcmp (const void *a, const void *b) +{ + struct locrecent *la = ((const struct nameent *) a)->locrec; + struct locrecent *lb = ((const struct nameent *) b)->locrec; + uint32_t start_a = -1, end_a = 0; + uint32_t start_b = -1, end_b = 0; + int cnt; + + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + if (la->record[cnt].offset < start_a) + start_a = la->record[cnt].offset; + if (la->record[cnt].offset + la->record[cnt].len > end_a) + end_a = la->record[cnt].offset + la->record[cnt].len; + } + assert (start_a != (uint32_t)-1); + assert (end_a != 0); + + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + if (lb->record[cnt].offset < start_b) + start_b = lb->record[cnt].offset; + if (lb->record[cnt].offset + lb->record[cnt].len > end_b) + end_b = lb->record[cnt].offset + lb->record[cnt].len; + } + assert (start_b != (uint32_t)-1); + assert (end_b != 0); + + if (start_a != start_b) + return (int)start_a - (int)start_b; + return (int)end_a - (int)end_b; +} + +static int +dataentcmp (const void *a, const void *b) +{ + if (((const struct dataent *) a)->file_offset + < ((const struct dataent *) b)->file_offset) + return -1; + + if (((const struct dataent *) a)->file_offset + > ((const struct dataent *) b)->file_offset) + return 1; + + return 0; +} + +static int +sumsearchfn (const void *key, const void *ent) +{ + uint32_t keyn = *(uint32_t *)key; + uint32_t entn = ((struct dataent *)ent)->file_offset; + + if (keyn < entn) + return -1; + if (keyn > entn) + return 1; + return 0; +} + +static void +compute_data (struct locarhandle *ah, struct nameent *name, size_t sumused, + struct dataent *files, locale_data_t data) +{ + int cnt; + struct locrecent *locrec = name->locrec; + struct dataent *file; + data[LC_ALL].addr = ((char *) ah->addr) + locrec->record[LC_ALL].offset; + data[LC_ALL].size = locrec->record[LC_ALL].len; + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + data[cnt].addr = ((char *) ah->addr) + locrec->record[cnt].offset; + data[cnt].size = locrec->record[cnt].len; + if (data[cnt].addr >= data[LC_ALL].addr + && data[cnt].addr + data[cnt].size + <= data[LC_ALL].addr + data[LC_ALL].size) + __md5_buffer (data[cnt].addr, data[cnt].size, data[cnt].sum); + else + { + file = bsearch (&locrec->record[cnt].offset, files, sumused, + sizeof (*files), sumsearchfn); + if (file == NULL) + error (EXIT_FAILURE, 0, "inconsistent template file"); + memcpy (data[cnt].sum, file->sum, sizeof (data[cnt].sum)); + } + } +} + +static int +fill_archive (struct locarhandle *tmpl_ah, size_t nlist, char *list[], + const char *primary) +{ + struct locarhandle ah; + struct locarhead *head; + int result = 0; + struct nameent *names; + struct namehashent *namehashtab; + size_t cnt, used; + struct dataent *files; + struct sumhashent *sumhashtab; + size_t sumused; + struct locrecent *primary_locrec = NULL; + struct nameent *primary_nameent = NULL; + + head = tmpl_ah->addr; + names = (struct nameent *) malloc (head->namehash_used + * sizeof (struct nameent)); + files = (struct dataent *) malloc (head->sumhash_used + * sizeof (struct dataent)); + if (names == NULL || files == NULL) + error (EXIT_FAILURE, errno, "could not allocate tables"); + + namehashtab = (struct namehashent *) ((char *) tmpl_ah->addr + + head->namehash_offset); + sumhashtab = (struct sumhashent *) ((char *) tmpl_ah->addr + + head->sumhash_offset); + + for (cnt = used = 0; cnt < head->namehash_size; ++cnt) + if (namehashtab[cnt].locrec_offset != 0) + { + assert (used < head->namehash_used); + names[used].name = tmpl_ah->addr + namehashtab[cnt].name_offset; + names[used++].locrec + = (struct locrecent *) ((char *) tmpl_ah->addr + + namehashtab[cnt].locrec_offset); + } + + /* Sort the names. */ + qsort (names, used, sizeof (struct nameent), nameentcmp); + + for (cnt = sumused = 0; cnt < head->sumhash_size; ++cnt) + if (sumhashtab[cnt].file_offset != 0) + { + assert (sumused < head->sumhash_used); + files[sumused].sum = (const unsigned char *) sumhashtab[cnt].sum; + files[sumused++].file_offset = sumhashtab[cnt].file_offset; + } + + /* Sort by file locations. */ + qsort (files, sumused, sizeof (struct dataent), dataentcmp); + + /* Open the archive. This call never returns if we cannot + successfully open the archive. */ + open_archive (&ah, false); + + if (primary != NULL) + { + for (cnt = 0; cnt < used; ++cnt) + if (strcmp (names[cnt].name, primary) == 0) + break; + if (cnt < used) + { + locale_data_t data; + + compute_data (tmpl_ah, &names[cnt], sumused, files, data); + result |= add_locale_to_archive (&ah, primary, data, 0); + primary_locrec = names[cnt].locrec; + primary_nameent = &names[cnt]; + } + } + + for (cnt = 0; cnt < used; ++cnt) + if (&names[cnt] == primary_nameent) + continue; + else if ((cnt > 0 && names[cnt - 1].locrec == names[cnt].locrec) + || names[cnt].locrec == primary_locrec) + { + const char *oldname; + struct namehashent *namehashent; + uint32_t locrec_offset; + + if (names[cnt].locrec == primary_locrec) + oldname = primary; + else + oldname = names[cnt - 1].name; + namehashent = insert_name (&ah, oldname, strlen (oldname), true); + assert (namehashent->name_offset != 0); + assert (namehashent->locrec_offset != 0); + locrec_offset = namehashent->locrec_offset; + add_alias (&ah, names[cnt].name, 0, oldname, &locrec_offset); + } + else + { + locale_data_t data; + + compute_data (tmpl_ah, &names[cnt], sumused, files, data); + result |= add_locale_to_archive (&ah, names[cnt].name, data, 0); + } + + while (nlist-- > 0) + { + const char *fname = *list++; + size_t fnamelen = strlen (fname); + struct stat64 st; + DIR *dirp; + struct dirent64 *d; + int seen; + locale_data_t data; + int cnt; + + /* First see whether this really is a directory and whether it + contains all the require locale category files. */ + if (stat64 (fname, &st) < 0) + { + error (0, 0, "stat of \"%s\" failed: %s: ignored", fname, + strerror (errno)); + continue; + } + if (!S_ISDIR (st.st_mode)) + { + error (0, 0, "\"%s\" is no directory; ignored", fname); + continue; + } + + dirp = opendir (fname); + if (dirp == NULL) + { + error (0, 0, "cannot open directory \"%s\": %s: ignored", + fname, strerror (errno)); + continue; + } + + seen = 0; + while ((d = readdir64 (dirp)) != NULL) + { + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + if (strcmp (d->d_name, locnames[cnt]) == 0) + { + unsigned char d_type; + + /* We have an object of the required name. If it's + a directory we have to look at a file with the + prefix "SYS_". Otherwise we have found what we + are looking for. */ +#ifdef _DIRENT_HAVE_D_TYPE + d_type = d->d_type; + + if (d_type != DT_REG) +#endif + { + char fullname[fnamelen + 2 * strlen (d->d_name) + 7]; + +#ifdef _DIRENT_HAVE_D_TYPE + if (d_type == DT_UNKNOWN) +#endif + { + strcpy (stpcpy (stpcpy (fullname, fname), "/"), + d->d_name); + + if (stat64 (fullname, &st) == -1) + /* We cannot stat the file, ignore it. */ + break; + + d_type = IFTODT (st.st_mode); + } + + if (d_type == DT_DIR) + { + /* We have to do more tests. The file is a + directory and it therefore must contain a + regular file with the same name except a + "SYS_" prefix. */ + char *t = stpcpy (stpcpy (fullname, fname), "/"); + strcpy (stpcpy (stpcpy (t, d->d_name), "/SYS_"), + d->d_name); + + if (stat64 (fullname, &st) == -1) + /* There is no SYS_* file or we cannot + access it. */ + break; + + d_type = IFTODT (st.st_mode); + } + } + + /* If we found a regular file (eventually after + following a symlink) we are successful. */ + if (d_type == DT_REG) + ++seen; + break; + } + } + + closedir (dirp); + + if (seen != __LC_LAST - 1) + { + /* We don't have all locale category files. Ignore the name. */ + error (0, 0, "incomplete set of locale files in \"%s\"", + fname); + continue; + } + + /* Add the files to the archive. To do this we first compute + sizes and the MD5 sums of all the files. */ + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + { + char fullname[fnamelen + 2 * strlen (locnames[cnt]) + 7]; + int fd; + + strcpy (stpcpy (stpcpy (fullname, fname), "/"), locnames[cnt]); + fd = open64 (fullname, O_RDONLY); + if (fd == -1 || fstat64 (fd, &st) == -1) + { + /* Cannot read the file. */ + if (fd != -1) + close (fd); + break; + } + + if (S_ISDIR (st.st_mode)) + { + char *t; + close (fd); + t = stpcpy (stpcpy (fullname, fname), "/"); + strcpy (stpcpy (stpcpy (t, locnames[cnt]), "/SYS_"), + locnames[cnt]); + + fd = open64 (fullname, O_RDONLY); + if (fd == -1 || fstat64 (fd, &st) == -1 + || !S_ISREG (st.st_mode)) + { + if (fd != -1) + close (fd); + break; + } + } + + /* Map the file. */ + data[cnt].addr = mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED, + fd, 0); + if (data[cnt].addr == MAP_FAILED) + { + /* Cannot map it. */ + close (fd); + break; + } + + data[cnt].size = st.st_size; + __md5_buffer (data[cnt].addr, st.st_size, data[cnt].sum); + + /* We don't need the file descriptor anymore. */ + close (fd); + } + + if (cnt != __LC_LAST) + { + while (cnt-- > 0) + if (cnt != LC_ALL) + munmap (data[cnt].addr, data[cnt].size); + + error (0, 0, "cannot read all files in \"%s\": ignored", fname); + + continue; + } + + result |= add_locale_to_archive (&ah, basename (fname), data, 0); + + for (cnt = 0; cnt < __LC_LAST; ++cnt) + if (cnt != LC_ALL) + munmap (data[cnt].addr, data[cnt].size); + } + + /* We are done. */ + close_archive (&ah); + + return result; +} int main () { @@ -82,12 +538,16 @@ int main () struct stat64 st; char *list[16384], *primary; unsigned int cnt = 0; + struct locarhandle tmpl_ah; + size_t loc_path_len = strlen (loc_path); - unlink (locar_file); dirp = opendir (loc_path); if (dirp == NULL) error (EXIT_FAILURE, errno, "cannot open directory \"%s\"", loc_path); + open_tmpl_archive (&tmpl_ah); + + unlink (locar_file); primary = getenv ("LC_ALL"); if (primary == NULL) primary = getenv ("LANG"); @@ -113,30 +573,25 @@ int main () primary = ptr; } else - primary = "....."; - } - strcpy (stpcpy (path, loc_path), primary); - if (stat64 (path, &st) >= 0 && S_ISDIR (st.st_mode)) - { - list[cnt] = strdup (path); - if (list[cnt] == NULL) - error (0, errno, "cannot add file to list \"%s\"", path); - else - cnt++; + primary = NULL; } - if (cnt == 0) - primary = NULL; } + memcpy (path, loc_path, loc_path_len); + while ((d = readdir64 (dirp)) != NULL) { if (strcmp (d->d_name, ".") == 0 || strcmp (d->d_name, "..") == 0) continue; - if (primary && strcmp (d->d_name, primary) == 0) - continue; + size_t d_name_len = strlen (d->d_name); + if (loc_path_len + d_name_len + 1 > sizeof (path)) + { + error (0, 0, "too long filename \"%s\"", d->d_name); + continue; + } - strcpy (stpcpy (path, loc_path), d->d_name); + memcpy (path + loc_path_len, d->d_name, d_name_len + 1); if (stat64 (path, &st) < 0) { error (0, errno, "cannot stat \"%s\"", path); @@ -152,10 +607,18 @@ int main () error (0, errno, "cannot add file to list \"%s\"", path); continue; } + if (primary != NULL && cnt > 0 && strcmp (primary, d->d_name) == 0) + { + char *p = list[0]; + list[0] = list[cnt]; + list[cnt] = p; + } cnt++; } closedir (dirp); - add_locales_to_archive (cnt, list, 0); + fill_archive (&tmpl_ah, cnt, list, primary); + close_archive (&tmpl_ah); + unlink (tmpl_file); char *argv[] = { "/usr/sbin/tzdata-update", NULL }; execve (argv[0], (char *const *)argv, (char *const *)&argv[1]); exit (0); diff --git a/fedora/glibc.spec.in b/fedora/glibc.spec.in index 779c17e370..a8b70f8a0b 100644 --- a/fedora/glibc.spec.in +++ b/fedora/glibc.spec.in @@ -1,4 +1,4 @@ -%define glibcrelease 20 +%define glibcrelease 21 %define auxarches i586 i686 athlon sparcv9 alphaev6 %define xenarches i686 athlon %ifarch %{xenarches} @@ -969,11 +969,6 @@ popd cd .. %endif -# compatibility hack: this locale has vanished from glibc, but some other -# programs are still using it. Normally we would handle it in the %pre -# section but with glibc that is simply not an option -mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/locale/ru_RU/LC_MESSAGES - # Remove the files we don't want to distribute rm -f $RPM_BUILD_ROOT%{_prefix}/%{_lib}/libNoVersion* rm -f $RPM_BUILD_ROOT/%{_lib}/libNoVersion* @@ -1051,7 +1046,19 @@ rm -f $RPM_BUILD_ROOT%{_prefix}/include/rpcsvc/rquota.[hx] # Hardlink identical locale files together %ifnarch %{auxarches} gcc -O2 -o build-%{nptl_target_cpu}-linuxnptl/hardlink fedora/hardlink.c -build-%{nptl_target_cpu}-linuxnptl/hardlink -vc $RPM_BUILD_ROOT%{_prefix}/lib/locale +rm ${RPM_BUILD_ROOT}${_prefix}/lib/locale/locale-archive || : +olddir=`pwd` +pushd ${RPM_BUILD_ROOT}${_prefix}/lib/locale +# Intentionally we do not pass --alias-file=, aliases will be added +# by build-locale-archive. +$olddir/build-%{nptl_target_cpu}-linuxnptl/elf/ld.so \ + --library-path $olddir/build-%{nptl_target_cpu}-linuxnptl/ \ + $olddir/build-%{nptl_target_cpu}-linuxnptl/locale/localedef \ + --prefix ${RPM_BUILD_ROOT} --add-to-archive \ + *_* +rm -rf *_* +popd +#build-%{nptl_target_cpu}-linuxnptl/hardlink -vc $RPM_BUILD_ROOT%{_prefix}/lib/locale %endif rm -f ${RPM_BUILD_ROOT}/%{_lib}/libnss1-* @@ -1125,7 +1132,7 @@ grep -v '%{_prefix}/%{_lib}/lib.*\.a' < rpm.filelist.full | grep -v 'nscd' > rpm.filelist grep '%{_prefix}/bin' < rpm.filelist >> common.filelist -grep '%{_prefix}/lib/locale' < rpm.filelist >> common.filelist +grep '%{_prefix}/lib/locale' < rpm.filelist | grep -v /locale-archive.tmpl >> common.filelist grep '%{_prefix}/libexec/pt_chown' < rpm.filelist >> common.filelist grep '%{_prefix}/sbin/[^gi]' < rpm.filelist >> common.filelist grep '%{_prefix}/share' < rpm.filelist \ @@ -1495,6 +1502,7 @@ rm -f *.filelist* %ifnarch %{auxarches} %files -f common.filelist common %defattr(-,root,root) +%attr(0644,root,root) %config(missingok) %{_prefix}/lib/locale/locale-archive.tmpl %attr(0644,root,root) %verify(not md5 size mtime mode) %ghost %config(missingok,noreplace) %{_prefix}/lib/locale/locale-archive %dir %attr(755,root,root) /etc/default %verify(not md5 size mtime) %config(noreplace) /etc/default/nss @@ -1549,10 +1557,21 @@ rm -f *.filelist* %endif %changelog +* Mon Apr 16 2007 Jakub Jelinek <jakub@redhat.com> 2.5.90-21 +- don't include individual locale files in glibc-common, + rather include prepared locale-archive template and let + build-locale-archive create locale-archive from the template + and any user supplied /usr/lib/locale/*_* directories, + then unlink the locale-archive template - this should save + > 80MB of glibc-common occupied disk space + * Sat Mar 31 2007 Jakub Jelinek <jakub@redhat.com> 2.5.90-20 - assorted NIS+ speedups (#223467) - fix HAVE_LIBCAP configure detection (#178934) - remove %{_prefix}/sbin/rpcinfo from glibc-common (#228894) +- nexttoward*/nextafter* fixes (BZ#3306) +- feholdexcept/feupdateenv fixes (BZ#3427) +- speed up fnmatch with two or more * in the pattern * Sat Mar 17 2007 Jakub Jelinek <jakub@redhat.com> 2.5.90-19 - fix power6 libm compat symbols on ppc32 (#232633) diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c index 5c0d5f18ce..201700dcb0 100644 --- a/locale/programs/locarchive.c +++ b/locale/programs/locarchive.c @@ -521,7 +521,7 @@ close_archive (struct locarhandle *ah) #include "../../intl/explodename.c" #include "../../intl/l10nflist.c" -static struct namehashent * +struct namehashent * insert_name (struct locarhandle *ah, const char *name, size_t name_len, bool replace) { @@ -579,7 +579,7 @@ insert_name (struct locarhandle *ah, return &namehashtab[idx]; } -static void +void add_alias (struct locarhandle *ah, const char *alias, bool replace, const char *oldname, uint32_t *locrec_offset_p) { |