diff --git a/SOURCES/glibc-rh1020637.patch b/SOURCES/glibc-rh1020637.patch new file mode 100644 index 0000000..54df97d --- /dev/null +++ b/SOURCES/glibc-rh1020637.patch @@ -0,0 +1,128 @@ +commit acd98a8ed1460497e788c701eb92616f1df9b446 +Author: Andreas Krebbel +Date: Fri Nov 29 09:57:04 2013 +0100 + + [BZ #16214] S/390: Fix TLS GOT pointer setup. + +diff --git a/sysdeps/s390/Versions b/sysdeps/s390/Versions +index e18617c..baf9842 100644 +--- a/sysdeps/s390/Versions ++++ b/sysdeps/s390/Versions +@@ -3,4 +3,8 @@ ld { + # runtime interface to TLS + __tls_get_offset; + } ++ GLIBC_PRIVATE { ++ # Exported by ld used by libc. ++ __tls_get_addr_internal; ++ } + } +diff --git a/sysdeps/s390/dl-tls.h b/sysdeps/s390/dl-tls.h +index 68a5af4..52192a2 100644 +--- a/sysdeps/s390/dl-tls.h ++++ b/sysdeps/s390/dl-tls.h +@@ -26,11 +26,26 @@ typedef struct + + + #ifdef SHARED +-/* This is the prototype for the GNU version. */ +-extern void *__tls_get_addr (tls_index *ti) attribute_hidden; ++ + extern unsigned long __tls_get_offset (unsigned long got_offset); + + # ifdef IS_IN_rtld ++ ++# include ++ ++extern void *__tls_get_addr (tls_index *ti) attribute_hidden; ++/* Make a temporary alias of __tls_get_addr to remove the hidden ++ attribute. Then export __tls_get_addr as __tls_get_addr_internal ++ for use from libc. We do not want to export __tls_get_addr, but we ++ do need to use it from libc when looking up the address of a TLS ++ variable. We don't use __tls_get_offset because it requires r12 to ++ be setup and that might not always be true. Either way it's more ++ optimal to use __tls_get_addr directly (that's what ++ __tls_get_offset does anyways). */ ++strong_alias (__tls_get_addr, __tls_get_addr_internal_tmp); ++versioned_symbol (ld, __tls_get_addr_internal_tmp, ++ __tls_get_addr_internal, GLIBC_PRIVATE); ++ + /* The special thing about the s390 TLS ABI is that we do not have the + standard __tls_get_addr function but the __tls_get_offset function + which differs in two important aspects: +@@ -63,15 +78,21 @@ __tls_get_offset:\n\ + 1: .long __tls_get_addr - 0b\n\ + "); + # endif +-# endif ++# else /* IS_IN_rtld */ ++extern void *__tls_get_addr_internal (tls_index *ti); ++# endif /* !IS_IN_rtld */ + + # define GET_ADDR_OFFSET \ + (ti->ti_offset - (unsigned long) __builtin_thread_pointer ()) + +-# define __TLS_GET_ADDR(__ti) \ +- ({ extern char _GLOBAL_OFFSET_TABLE_[] attribute_hidden; \ +- (void *) __tls_get_offset ((char *) (__ti) - _GLOBAL_OFFSET_TABLE_) \ +- + (unsigned long) __builtin_thread_pointer (); }) ++/* Use the privately exported __tls_get_addr_internal instead of ++ __tls_get_offset in order to avoid the __tls_get_offset special ++ linkage requiring the GOT pointer to be set up in r12. The ++ compiler will take care of setting up r12 only if itself issued the ++ __tls_get_offset call. */ ++# define __TLS_GET_ADDR(__ti) \ ++ ({ (void *) __tls_get_addr_internal ((char *) (__ti)) \ ++ + (unsigned long) __builtin_thread_pointer (); }) + + #endif + +diff --git a/sysdeps/s390/s390-32/tls-macros.h b/sysdeps/s390/s390-32/tls-macros.h +index 8a0ad58..a592d81 100644 +--- a/sysdeps/s390/s390-32/tls-macros.h ++++ b/sysdeps/s390/s390-32/tls-macros.h +@@ -8,12 +8,15 @@ + + #ifdef PIC + # define TLS_IE(x) \ +- ({ unsigned long __offset; \ ++ ({ unsigned long __offset, __got; \ + asm ("bras %0,1f\n" \ +- "0:\t.long " #x "@gotntpoff\n" \ +- "1:\tl %0,0(%0)\n\t" \ +- "l %0,0(%0,%%r12):tls_load:" #x \ +- : "=&a" (__offset) : : "cc" ); \ ++ "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ ++ ".long " #x "@gotntpoff\n" \ ++ "1:\tl %1,0(%0)\n\t" \ ++ "la %1,0(%1,%0)\n\t" \ ++ "l %0,4(%0)\n\t" \ ++ "l %0,0(%0,%1):tls_load:" #x "\n" \ ++ : "=&a" (__offset), "=&a" (__got) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + #else + # define TLS_IE(x) \ +diff --git a/sysdeps/s390/s390-64/tls-macros.h b/sysdeps/s390/s390-64/tls-macros.h +index be8aa6c..3c59436 100644 +--- a/sysdeps/s390/s390-64/tls-macros.h ++++ b/sysdeps/s390/s390-64/tls-macros.h +@@ -8,12 +8,13 @@ + + #ifdef PIC + # define TLS_IE(x) \ +- ({ unsigned long __offset; \ +- asm ("bras %0,1f\n" \ +- "0:\t.quad " #x "@gotntpoff\n" \ +- "1:\tlg %0,0(%0)\n\t" \ +- "lg %0,0(%0,%%r12):tls_load:" #x \ +- : "=&a" (__offset) : : "cc" ); \ ++ ({ unsigned long __offset, __got; \ ++ asm ("bras %0,0f\n\t" \ ++ ".quad " #x "@gotntpoff\n" \ ++ "0:\tlarl %1,_GLOBAL_OFFSET_TABLE_\n\t" \ ++ "lg %0,0(%0)\n\t" \ ++ "lg %0,0(%0,%1):tls_load:" #x "\n" \ ++ : "=&a" (__offset), "=&a" (__got) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + #else + # define TLS_IE(x) \ diff --git a/SOURCES/glibc-rh1025612.patch b/SOURCES/glibc-rh1025612.patch new file mode 100644 index 0000000..bec4acd --- /dev/null +++ b/SOURCES/glibc-rh1025612.patch @@ -0,0 +1,50 @@ +commit 7cbcdb3699584db8913ca90f705d6337633ee10f +Author: Siddhesh Poyarekar +Date: Fri Oct 25 10:22:12 2013 +0530 + + Fix stack overflow due to large AF_INET6 requests + + Resolves #16072 (CVE-2013-4458). + + This patch fixes another stack overflow in getaddrinfo when it is + called with AF_INET6. The AF_UNSPEC case was fixed as CVE-2013-1914, + but the AF_INET6 case went undetected back then. + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index e6ce4cf..8ff74b4 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -197,7 +197,22 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + &rc, &herrno, NULL, &localcanon)); \ + if (rc != ERANGE || herrno != NETDB_INTERNAL) \ + break; \ +- tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ ++ if (!malloc_tmpbuf && __libc_use_alloca (alloca_used + 2 * tmpbuflen)) \ ++ tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen, 2 * tmpbuflen, \ ++ alloca_used); \ ++ else \ ++ { \ ++ char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL, \ ++ 2 * tmpbuflen); \ ++ if (newp == NULL) \ ++ { \ ++ result = -EAI_MEMORY; \ ++ goto free_and_return; \ ++ } \ ++ tmpbuf = newp; \ ++ malloc_tmpbuf = true; \ ++ tmpbuflen = 2 * tmpbuflen; \ ++ } \ + } \ + if (status == NSS_STATUS_SUCCESS && rc == 0) \ + h = &th; \ +@@ -209,7 +224,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + { \ + __set_h_errno (herrno); \ + _res.options |= old_res_options & RES_USE_INET6; \ +- return -EAI_SYSTEM; \ ++ result = -EAI_SYSTEM; \ ++ goto free_and_return; \ + } \ + if (herrno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ diff --git a/SOURCES/glibc-rh1028652.patch b/SOURCES/glibc-rh1028652.patch new file mode 100644 index 0000000..4c642a9 --- /dev/null +++ b/SOURCES/glibc-rh1028652.patch @@ -0,0 +1,64 @@ +# +# Upstream power patch to increase MINSIGSTKSZ and SIGSTKSZ to +# account for the kernel signal frame size increase. +# +diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/sigstack.h b/sysdeps/unix/sysv/linux/powerpc/bits/sigstack.h +new file mode 100644 +index 0000000..33be9e8 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/powerpc/bits/sigstack.h +@@ -0,0 +1,54 @@ ++/* sigstack, sigaltstack definitions. ++ Copyright (C) 1998-2013 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 ++ . */ ++ ++#ifndef _SIGNAL_H ++# error "Never include this file directly. Use instead" ++#endif ++ ++ ++/* Structure describing a signal stack (obsolete). */ ++struct sigstack ++ { ++ void *ss_sp; /* Signal stack pointer. */ ++ int ss_onstack; /* Nonzero if executing on this stack. */ ++ }; ++ ++ ++/* Possible values for `ss_flags.'. */ ++enum ++{ ++ SS_ONSTACK = 1, ++#define SS_ONSTACK SS_ONSTACK ++ SS_DISABLE ++#define SS_DISABLE SS_DISABLE ++}; ++ ++/* Minimum stack size for a signal handler. */ ++#define MINSIGSTKSZ 4096 ++ ++/* System default stack size. */ ++#define SIGSTKSZ 16384 ++ ++ ++/* Alternate, preferred interface. */ ++typedef struct sigaltstack ++ { ++ void *ss_sp; ++ int ss_flags; ++ size_t ss_size; ++ } stack_t; diff --git a/SOURCES/glibc-rh1032435.patch b/SOURCES/glibc-rh1032435.patch new file mode 100644 index 0000000..dad4891 --- /dev/null +++ b/SOURCES/glibc-rh1032435.patch @@ -0,0 +1,117 @@ +commit 977f4b31b7ca4a4e498c397f3fd70510694bbd86 +Author: Siddhesh Poyarekar +Date: Wed Oct 30 16:13:37 2013 +0530 + + Fix reads for sizes larger than INT_MAX in AF_INET lookup + + Currently for AF_INET lookups from the hosts file, buffer sizes larger + than INT_MAX silently overflow and may result in access beyond bounds + of a buffer. This happens when the number of results in an AF_INET + lookup in /etc/hosts are very large. + + There are two aspects to the problem. One problem is that the size + computed from the buffer size is stored into an int, which results in + overflow for large sizes. Additionally, even if this size was + expanded, the function used to read content into the buffer (fgets) + accepts only int sizes. As a result, the fix is to have a function + wrap around fgets that calls it multiple times with int sizes if + necessary. + +diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c +index 082d1ea..b62208c 100644 +--- a/nss/nss_files/files-XXX.c ++++ b/nss/nss_files/files-XXX.c +@@ -179,8 +179,51 @@ CONCAT(_nss_files_end,ENTNAME) (void) + return NSS_STATUS_SUCCESS; + } + +-/* Parsing the database file into `struct STRUCTURE' data structures. */ + ++typedef enum ++{ ++ gcr_ok = 0, ++ gcr_error = -1, ++ gcr_overflow = -2 ++} get_contents_ret; ++ ++/* Hack around the fact that fgets only accepts int sizes. */ ++static get_contents_ret ++get_contents (char *linebuf, size_t len, FILE *stream) ++{ ++ size_t remaining_len = len; ++ char *curbuf = linebuf; ++ ++ do ++ { ++ int curlen = ((remaining_len > (size_t) INT_MAX) ? INT_MAX ++ : remaining_len); ++ char *p = fgets_unlocked (curbuf, curlen, stream); ++ ++ ((unsigned char *) curbuf)[curlen - 1] = 0xff; ++ ++ /* EOF or read error. */ ++ if (p == NULL) ++ return gcr_error; ++ ++ /* Done reading in the line. */ ++ if (((unsigned char *) curbuf)[curlen - 1] == 0xff) ++ return gcr_ok; ++ ++ /* Drop the terminating '\0'. */ ++ remaining_len -= curlen - 1; ++ curbuf += curlen - 1; ++ } ++ /* fgets copies one less than the input length. Our last iteration is of ++ REMAINING_LEN and once that is done, REMAINING_LEN is decremented by ++ REMAINING_LEN - 1, leaving the result as 1. */ ++ while (remaining_len > 1); ++ ++ /* This means that the current buffer was not large enough. */ ++ return gcr_overflow; ++} ++ ++/* Parsing the database file into `struct STRUCTURE' data structures. */ + static enum nss_status + internal_getent (struct STRUCTURE *result, + char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO +@@ -188,7 +231,7 @@ internal_getent (struct STRUCTURE *result, + { + char *p; + struct parser_data *data = (void *) buffer; +- int linebuflen = buffer + buflen - data->linebuffer; ++ size_t linebuflen = buffer + buflen - data->linebuffer; + int parse_result; + + if (buflen < sizeof *data + 2) +@@ -200,17 +243,16 @@ internal_getent (struct STRUCTURE *result, + + do + { +- /* Terminate the line so that we can test for overflow. */ +- ((unsigned char *) data->linebuffer)[linebuflen - 1] = '\xff'; ++ get_contents_ret r = get_contents (data->linebuffer, linebuflen, stream); + +- p = fgets_unlocked (data->linebuffer, linebuflen, stream); +- if (p == NULL) ++ if (r == gcr_error) + { + /* End of file or read error. */ + H_ERRNO_SET (HOST_NOT_FOUND); + return NSS_STATUS_NOTFOUND; + } +- else if (((unsigned char *) data->linebuffer)[linebuflen - 1] != 0xff) ++ ++ if (r == gcr_overflow) + { + /* The line is too long. Give the user the opportunity to + enlarge the buffer. */ +@@ -219,7 +261,8 @@ internal_getent (struct STRUCTURE *result, + return NSS_STATUS_TRYAGAIN; + } + +- /* Skip leading blanks. */ ++ /* Everything OK. Now skip leading blanks. */ ++ p = data->linebuffer; + while (isspace (*p)) + ++p; + } diff --git a/SOURCES/glibc-rh1039496.patch b/SOURCES/glibc-rh1039496.patch new file mode 100644 index 0000000..f4dae4d --- /dev/null +++ b/SOURCES/glibc-rh1039496.patch @@ -0,0 +1,102 @@ +diff -urN a/libio/tst-widetext.input b/libio/tst-widetext.input +--- a/libio/tst-widetext.input 2012-12-24 22:02:13.000000000 -0500 ++++ b/libio/tst-widetext.input 2013-12-11 09:48:30.760084849 -0500 +@@ -126,7 +126,7 @@ + ઀◌ઁ◌ંઃ઄અઆઇઈઉઊઋઌઍ઎એઐઑ઒ઓઔકખગઘઙચછજઝઞટઠડઢણતથદધન઩પફબભમયર઱લળ઴વશષસહ઺઻◌઼ઽાિ + ી◌ુ◌ૂ◌ૃ◌ૄ◌ૅ૆◌ે◌ૈૉ૊ોૌ◌્૎૏ૐ૑૒૓૔૕૖૗૘૙૚૛૜૝૞૟ૠૡૢૣ૤૥૦૧૨૩૪૫૬૭૮૯૰૱૲૳૴૵૶૷૸ૹૺૻૼ૽૾૿ + +-Oriya (U+0B00-U+0B7F): ++Odia (U+0B00-U+0B7F): + + ଀◌ଁଂଃ଄ଅଆଇଈଉଊଋଌ଍଎ଏଐ଑଒ଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନ଩ପଫବଭମଯର଱ଲଳ଴ଵଶଷସହ଺଻◌଼ଽା◌ି + ୀ◌ୁ◌ୂ◌ୃୄ୅୆େୈ୉୊ୋୌ◌୍୎୏୐୑୒୓୔୕◌ୖୗ୘୙୚୛ଡ଼ଢ଼୞ୟୠୡୢୣ୤୥୦୧୨୩୪୫୬୭୮୯୰ୱ୲୳୴୵୶୷୸୹୺୻୼୽୾୿ +diff -urN a/locale/iso-639.def b/locale/iso-639.def +--- a/locale/iso-639.def 2012-12-24 22:02:13.000000000 -0500 ++++ b/locale/iso-639.def 2013-12-11 09:58:58.414959856 -0500 +@@ -181,7 +181,7 @@ + DEFINE_LANGUAGE_CODE ("Greek, Modern (1453-)", el, ell, gre) + DEFINE_LANGUAGE_CODE ("Guarani", gn, grn, grn) + DEFINE_LANGUAGE_CODE ("Gujarati", gu, guj, guj) +-DEFINE_LANGUAGE_CODE3 ("Gwich�in", gwi, gwi) ++DEFINE_LANGUAGE_CODE3 ("Gwich´in", gwi, gwi) + DEFINE_LANGUAGE_CODE3 ("Haida", hai, hai) + DEFINE_LANGUAGE_CODE ("Haitian; Haitian Creole", ht, hat, hat) + DEFINE_LANGUAGE_CODE ("Hausa", ha, hau, hau) +@@ -337,7 +337,7 @@ + DEFINE_LANGUAGE_CODE3 ("North American Indian", nai, nai) + DEFINE_LANGUAGE_CODE ("Northern Sami", se, sme, sme) + DEFINE_LANGUAGE_CODE3 ("Northern Sotho; Pedi; Sepedi", nso, nso) +-DEFINE_LANGUAGE_CODE ("Norwegian Bokm�l", nb, nob, nob) ++DEFINE_LANGUAGE_CODE ("Norwegian Bokmål", nb, nob, nob) + DEFINE_LANGUAGE_CODE ("Norwegian Nynorsk", nn, nno, nno) + DEFINE_LANGUAGE_CODE ("Norwegian", no, nor, nor) + DEFINE_LANGUAGE_CODE3 ("Nubian languages", nub, nub) +@@ -345,9 +345,9 @@ + DEFINE_LANGUAGE_CODE3 ("Nyankole", nyn, nyn) + DEFINE_LANGUAGE_CODE3 ("Nyoro", nyo, nyo) + DEFINE_LANGUAGE_CODE3 ("Nzima", nzi, nzi) +-DEFINE_LANGUAGE_CODE ("Occitan (post 1500); Proven�al", oc, oci, oci) ++DEFINE_LANGUAGE_CODE ("Occitan (post 1500); Provençal", oc, oci, oci) + DEFINE_LANGUAGE_CODE ("Ojibwa", oj, oji, oji) +-DEFINE_LANGUAGE_CODE ("Oriya", or, ori, ori) ++DEFINE_LANGUAGE_CODE ("Odia", or, ori, ori) + DEFINE_LANGUAGE_CODE ("Oromo", om, orm, orm) + DEFINE_LANGUAGE_CODE3 ("Osage", osa, osa) + DEFINE_LANGUAGE_CODE ("Ossetian; Ossetic", os, oss, oss) +@@ -368,7 +368,7 @@ + DEFINE_LANGUAGE_CODE ("Polish", pl, pol, pol) + DEFINE_LANGUAGE_CODE ("Portuguese", pt, por, por) + DEFINE_LANGUAGE_CODE3 ("Prakrit languages", pra, pra) +-DEFINE_LANGUAGE_CODE3 ("Proven�al, Old (to 1500)", pro, pro) ++DEFINE_LANGUAGE_CODE3 ("Provençal, Old (to 1500)", pro, pro) + DEFINE_LANGUAGE_CODE ("Pushto", ps, pus, pus) + DEFINE_LANGUAGE_CODE ("Quechua", qu, que, que) + DEFINE_LANGUAGE_CODE ("Raeto-Romance", rm, roh, roh) +@@ -476,7 +476,7 @@ + DEFINE_LANGUAGE_CODE3 ("Vai", vai, vai) + DEFINE_LANGUAGE_CODE ("Venda", ve, ven, ven) + DEFINE_LANGUAGE_CODE ("Vietnamese", vi, vie, vie) +-DEFINE_LANGUAGE_CODE ("Volap�k", vo, vol, vol) ++DEFINE_LANGUAGE_CODE ("Volapük", vo, vol, vol) + DEFINE_LANGUAGE_CODE3 ("Votic", vot, vot) + DEFINE_LANGUAGE_CODE3 ("Wakashan languages", wak, wak) + DEFINE_LANGUAGE_CODE3 ("Walser", wae, wae) +diff -urN a/localedata/locales/or_IN b/localedata/locales/or_IN +--- a/localedata/locales/or_IN 2012-12-24 22:02:13.000000000 -0500 ++++ b/localedata/locales/or_IN 2013-12-11 09:52:26.932931534 -0500 +@@ -1,19 +1,19 @@ + comment_char % + escape_char / + +-% Oriya locale for India. ++% Odia locale for India. + % Contributed by Masahide Washizawa + + %%%%%%%%%%%%% + LC_IDENTIFICATION +-title "Oriya language locale for India" ++title "Odia language locale for India" + source "IBM AP Linux Technology Center, Yamato Software Laboratory" + address "1623-14, Shimotsuruma, Yamato-shi, Kanagawa-ken, 242-8502, Japan" + contact "" + email "bug-glibc@gnu.org" + tel "" + fax "" +-language "Oriya" ++language "Odia" + territory "India" + revision "1.0" + date "2006-05-25" +@@ -35,10 +35,10 @@ + LC_CTYPE + copy "i18n" + +-% Oriya uses the alternate digits U+0B66..U+0B6F ++% Odia uses the alternate digits U+0B66..U+0B6F + outdigit .. + +-% This is used in the scanf family of functions to read Oriya numbers ++% This is used in the scanf family of functions to read Odia numbers + % using "%Id" and such. + map to_inpunct; / + (,); / diff --git a/SOURCES/glibc-rh1039970.patch b/SOURCES/glibc-rh1039970.patch new file mode 100644 index 0000000..7286804 --- /dev/null +++ b/SOURCES/glibc-rh1039970.patch @@ -0,0 +1,129 @@ +diff -pruN glibc-2.18-488-gd674f0e/nscd/netgroupcache.c glibc-2.18-488-gd674f0e.patched/nscd/netgroupcache.c +--- glibc-2.18-488-gd674f0e/nscd/netgroupcache.c 2013-12-03 20:41:12.000000000 -0500 ++++ glibc-2.18-488-gd674f0e.patched/nscd/netgroupcache.c 2013-12-19 08:36:52.253000000 -0500 +@@ -65,6 +65,55 @@ struct dataset + char strdata[0]; + }; + ++/* Sends a notfound message and prepares a notfound dataset to write to the ++ cache. Returns true if there was enough memory to allocate the dataset and ++ returns the dataset in DATASETP, total bytes to write in TOTALP and the ++ timeout in TIMEOUTP. KEY_COPY is set to point to the copy of the key in the ++ dataset. */ ++static bool ++do_notfound (struct database_dyn *db, int fd, request_header *req, ++ const char *key, struct dataset **datasetp, ssize_t *totalp, ++ time_t *timeoutp, char **key_copy) ++{ ++ struct dataset *dataset; ++ ssize_t total; ++ time_t timeout; ++ bool cacheable = false; ++ ++ total = sizeof (notfound); ++ timeout = time (NULL) + db->negtimeout; ++ ++ if (fd != -1) ++ TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL)); ++ ++ dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1); ++ /* If we cannot permanently store the result, so be it. */ ++ if (dataset != NULL) ++ { ++ dataset->head.allocsize = sizeof (struct dataset) + req->key_len; ++ dataset->head.recsize = total; ++ dataset->head.notfound = true; ++ dataset->head.nreloads = 0; ++ dataset->head.usable = true; ++ ++ /* Compute the timeout time. */ ++ timeout = dataset->head.timeout = time (NULL) + db->negtimeout; ++ dataset->head.ttl = db->negtimeout; ++ ++ /* This is the reply. */ ++ memcpy (&dataset->resp, ¬found, total); ++ ++ /* Copy the key data. */ ++ memcpy (dataset->strdata, key, req->key_len); ++ *key_copy = dataset->strdata; ++ ++ cacheable = true; ++ } ++ *timeoutp = timeout; ++ *totalp = total; ++ *datasetp = dataset; ++ return cacheable; ++} + + static time_t + addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, +@@ -84,6 +133,7 @@ addgetnetgrentX (struct database_dyn *db + struct dataset *dataset; + bool cacheable = false; + ssize_t total; ++ bool found = false; + + char *key_copy = NULL; + struct __netgrent data; +@@ -103,35 +153,8 @@ addgetnetgrentX (struct database_dyn *db + && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database)) + { + /* No such service. */ +- total = sizeof (notfound); +- timeout = time (NULL) + db->negtimeout; +- +- if (fd != -1) +- TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL)); +- +- dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1); +- /* If we cannot permanently store the result, so be it. */ +- if (dataset != NULL) +- { +- dataset->head.allocsize = sizeof (struct dataset) + req->key_len; +- dataset->head.recsize = total; +- dataset->head.notfound = true; +- dataset->head.nreloads = 0; +- dataset->head.usable = true; +- +- /* Compute the timeout time. */ +- timeout = dataset->head.timeout = time (NULL) + db->negtimeout; +- dataset->head.ttl = db->negtimeout; +- +- /* This is the reply. */ +- memcpy (&dataset->resp, ¬found, total); +- +- /* Copy the key data. */ +- memcpy (dataset->strdata, key, req->key_len); +- +- cacheable = true; +- } +- ++ cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout, ++ &key_copy); + goto writeout; + } + +@@ -167,6 +190,7 @@ addgetnetgrentX (struct database_dyn *db + + if (status == NSS_STATUS_SUCCESS) + { ++ found = true; + union + { + enum nss_status (*f) (struct __netgrent *, char *, size_t, +@@ -325,6 +349,15 @@ addgetnetgrentX (struct database_dyn *db + } + } + ++ /* No results. Return a failure and write out a notfound record in the ++ cache. */ ++ if (!found) ++ { ++ cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout, ++ &key_copy); ++ goto writeout; ++ } ++ + total = buffilled; + + /* Fill in the dataset. */ diff --git a/SOURCES/glibc-rh1046199.patch b/SOURCES/glibc-rh1046199.patch new file mode 100644 index 0000000..46d9c01 --- /dev/null +++ b/SOURCES/glibc-rh1046199.patch @@ -0,0 +1,17 @@ +diff -pruN glibc-2.18-488-gd674f0e/nscd/netgroupcache.c glibc-2.18-488-gd674f0e.patched/nscd/netgroupcache.c +--- glibc-2.18-488-gd674f0e/nscd/netgroupcache.c 2013-12-20 04:38:40.432000000 -0500 ++++ glibc-2.18-488-gd674f0e.patched/nscd/netgroupcache.c 2013-12-20 04:37:29.945000000 -0500 +@@ -204,9 +204,10 @@ addgetnetgrentX (struct database_dyn *db + int e; + status = getfct.f (&data, buffer + buffilled, + buflen - buffilled, &e); +- if (status == NSS_STATUS_RETURN) +- /* This was the last one for this group. Look +- at next group if available. */ ++ if (status == NSS_STATUS_RETURN ++ || status == NSS_STATUS_NOTFOUND) ++ /* This was either the last one for this group or the ++ group was empty. Look at next group if available. */ + break; + if (status == NSS_STATUS_SUCCESS) + { diff --git a/SOURCES/glibc-rh1047983.patch b/SOURCES/glibc-rh1047983.patch new file mode 100644 index 0000000..695da21 --- /dev/null +++ b/SOURCES/glibc-rh1047983.patch @@ -0,0 +1,555 @@ +commit 5a4c6d53f50b264d60cf6453576ca2810c7890b7 +Author: Siddhesh Poyarekar +Date: Thu Nov 28 17:18:12 2013 +0530 + + Get canonical name in getaddrinfo from hosts file for AF_INET (fixes 16077) + + AF_INET lookup in hosts file uses _nss_files_gethostbyname2_r, which + is not capable of returning a canonical name if it has found one. + This change adds _nss_files_gethostbyname3_r, which wraps around + _nss_files_gethostbyname2_r and then returns result.h_name as the + canonical name. + +diff --git a/nss/Versions b/nss/Versions +index d13d570..f8ababc 100644 +--- a/nss/Versions ++++ b/nss/Versions +@@ -40,6 +40,7 @@ libnss_files { + _nss_files_endhostent; + _nss_files_gethostbyaddr_r; + _nss_files_gethostbyname2_r; ++ _nss_files_gethostbyname3_r; + _nss_files_gethostbyname4_r; + _nss_files_gethostbyname_r; + _nss_files_gethostent_r; +diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c +index 6db2535..957c9aa 100644 +--- a/nss/nss_files/files-hosts.c ++++ b/nss/nss_files/files-hosts.c +@@ -97,262 +97,12 @@ LINE_PARSER + STRING_FIELD (result->h_name, isspace, 1); + }) + +- +- +-#define HOST_DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \ +-enum nss_status \ +-_nss_files_get##name##_r (proto, \ +- struct STRUCTURE *result, char *buffer, \ +- size_t buflen, int *errnop H_ERRNO_PROTO) \ +-{ \ +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); \ +- buffer += pad; \ +- buflen = buflen > pad ? buflen - pad : 0; \ +- \ +- __libc_lock_lock (lock); \ +- \ +- /* Reset file pointer to beginning or open file. */ \ +- enum nss_status status = internal_setent (keep_stream); \ +- \ +- if (status == NSS_STATUS_SUCCESS) \ +- { \ +- /* Tell getent function that we have repositioned the file pointer. */ \ +- last_use = getby; \ +- \ +- while ((status = internal_getent (result, buffer, buflen, errnop \ +- H_ERRNO_ARG EXTRA_ARGS_VALUE)) \ +- == NSS_STATUS_SUCCESS) \ +- { break_if_match } \ +- \ +- if (status == NSS_STATUS_SUCCESS \ +- && _res_hconf.flags & HCONF_FLAG_MULTI) \ +- { \ +- /* We have to get all host entries from the file. */ \ +- size_t tmp_buflen = MIN (buflen, 4096); \ +- char tmp_buffer_stack[tmp_buflen] \ +- __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));\ +- char *tmp_buffer = tmp_buffer_stack; \ +- struct hostent tmp_result_buf; \ +- int naddrs = 1; \ +- int naliases = 0; \ +- char *bufferend; \ +- bool tmp_buffer_malloced = false; \ +- \ +- while (result->h_aliases[naliases] != NULL) \ +- ++naliases; \ +- \ +- bufferend = (char *) &result->h_aliases[naliases + 1]; \ +- \ +- again: \ +- while ((status = internal_getent (&tmp_result_buf, tmp_buffer, \ +- tmp_buflen, errnop H_ERRNO_ARG \ +- EXTRA_ARGS_VALUE)) \ +- == NSS_STATUS_SUCCESS) \ +- { \ +- int matches = 1; \ +- struct hostent *old_result = result; \ +- result = &tmp_result_buf; \ +- /* The following piece is a bit clumsy but we want to use the \ +- `break_if_match' value. The optimizer should do its \ +- job. */ \ +- do \ +- { \ +- break_if_match \ +- result = old_result; \ +- } \ +- while ((matches = 0)); \ +- \ +- if (matches) \ +- { \ +- /* We could be very clever and try to recycle a few bytes \ +- in the buffer instead of generating new arrays. But \ +- we are not doing this here since it's more work than \ +- it's worth. Simply let the user provide a bit bigger \ +- buffer. */ \ +- char **new_h_addr_list; \ +- char **new_h_aliases; \ +- int newaliases = 0; \ +- size_t newstrlen = 0; \ +- int cnt; \ +- \ +- /* Count the new aliases and the length of the strings. */ \ +- while (tmp_result_buf.h_aliases[newaliases] != NULL) \ +- { \ +- char *cp = tmp_result_buf.h_aliases[newaliases]; \ +- ++newaliases; \ +- newstrlen += strlen (cp) + 1; \ +- } \ +- /* If the real name is different add it also to the \ +- aliases. This means that there is a duplication \ +- in the alias list but this is really the user's \ +- problem. */ \ +- if (strcmp (old_result->h_name, \ +- tmp_result_buf.h_name) != 0) \ +- { \ +- ++newaliases; \ +- newstrlen += strlen (tmp_result_buf.h_name) + 1; \ +- } \ +- \ +- /* Make sure bufferend is aligned. */ \ +- assert ((bufferend - (char *) 0) % sizeof (char *) == 0); \ +- \ +- /* Now we can check whether the buffer is large enough. \ +- 16 is the maximal size of the IP address. */ \ +- if (bufferend + 16 + (naddrs + 2) * sizeof (char *) \ +- + roundup (newstrlen, sizeof (char *)) \ +- + (naliases + newaliases + 1) * sizeof (char *) \ +- >= buffer + buflen) \ +- { \ +- *errnop = ERANGE; \ +- *herrnop = NETDB_INTERNAL; \ +- status = NSS_STATUS_TRYAGAIN; \ +- goto out; \ +- } \ +- \ +- new_h_addr_list = \ +- (char **) (bufferend \ +- + roundup (newstrlen, sizeof (char *)) \ +- + 16); \ +- new_h_aliases = \ +- (char **) ((char *) new_h_addr_list \ +- + (naddrs + 2) * sizeof (char *)); \ +- \ +- /* Copy the old data in the new arrays. */ \ +- for (cnt = 0; cnt < naddrs; ++cnt) \ +- new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; \ +- \ +- for (cnt = 0; cnt < naliases; ++cnt) \ +- new_h_aliases[cnt] = old_result->h_aliases[cnt]; \ +- \ +- /* Store the new strings. */ \ +- cnt = 0; \ +- while (tmp_result_buf.h_aliases[cnt] != NULL) \ +- { \ +- new_h_aliases[naliases++] = bufferend; \ +- bufferend = (__stpcpy (bufferend, \ +- tmp_result_buf.h_aliases[cnt]) \ +- + 1); \ +- ++cnt; \ +- } \ +- \ +- if (cnt < newaliases) \ +- { \ +- new_h_aliases[naliases++] = bufferend; \ +- bufferend = __stpcpy (bufferend, \ +- tmp_result_buf.h_name) + 1; \ +- } \ +- \ +- /* Final NULL pointer. */ \ +- new_h_aliases[naliases] = NULL; \ +- \ +- /* Round up the buffer end address. */ \ +- bufferend += (sizeof (char *) \ +- - ((bufferend - (char *) 0) \ +- % sizeof (char *))) % sizeof (char *); \ +- \ +- /* Now the new address. */ \ +- new_h_addr_list[naddrs++] = \ +- memcpy (bufferend, tmp_result_buf.h_addr, \ +- tmp_result_buf.h_length); \ +- \ +- /* Also here a final NULL pointer. */ \ +- new_h_addr_list[naddrs] = NULL; \ +- \ +- /* Store the new array pointers. */ \ +- old_result->h_aliases = new_h_aliases; \ +- old_result->h_addr_list = new_h_addr_list; \ +- \ +- /* Compute the new buffer end. */ \ +- bufferend = (char *) &new_h_aliases[naliases + 1]; \ +- assert (bufferend <= buffer + buflen); \ +- \ +- result = old_result; \ +- } \ +- } \ +- \ +- if (status == NSS_STATUS_TRYAGAIN) \ +- { \ +- size_t newsize = 2 * tmp_buflen; \ +- if (tmp_buffer_malloced) \ +- { \ +- char *newp = realloc (tmp_buffer, newsize); \ +- if (newp != NULL) \ +- { \ +- assert ((((uintptr_t) newp) \ +- & (__alignof__ (struct hostent_data) - 1)) \ +- == 0); \ +- tmp_buffer = newp; \ +- tmp_buflen = newsize; \ +- goto again; \ +- } \ +- } \ +- else if (!__libc_use_alloca (buflen + newsize)) \ +- { \ +- tmp_buffer = malloc (newsize); \ +- if (tmp_buffer != NULL) \ +- { \ +- assert ((((uintptr_t) tmp_buffer) \ +- & (__alignof__ (struct hostent_data) - 1)) \ +- == 0); \ +- tmp_buffer_malloced = true; \ +- tmp_buflen = newsize; \ +- goto again; \ +- } \ +- } \ +- else \ +- { \ +- tmp_buffer \ +- = extend_alloca (tmp_buffer, tmp_buflen, \ +- newsize \ +- + __alignof__ (struct hostent_data)); \ +- tmp_buffer = (char *) (((uintptr_t) tmp_buffer \ +- + __alignof__ (struct hostent_data) \ +- - 1) \ +- & ~(__alignof__ (struct hostent_data)\ +- - 1)); \ +- goto again; \ +- } \ +- } \ +- else \ +- status = NSS_STATUS_SUCCESS; \ +- out: \ +- if (tmp_buffer_malloced) \ +- free (tmp_buffer); \ +- } \ +- \ +- \ +- if (! keep_stream) \ +- internal_endent (); \ +- } \ +- \ +- __libc_lock_unlock (lock); \ +- \ +- return status; \ +-} +- +- + #define EXTRA_ARGS_VALUE \ + , ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET), \ + ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0) + #include "files-XXX.c" +-HOST_DB_LOOKUP (hostbyname, ,, +- { +- LOOKUP_NAME_CASE (h_name, h_aliases) +- }, const char *name) + #undef EXTRA_ARGS_VALUE + +- +-/* XXX Is using _res to determine whether we want to convert IPv4 addresses +- to IPv6 addresses really the right thing to do? */ +-#define EXTRA_ARGS_VALUE \ +- , af, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0) +-HOST_DB_LOOKUP (hostbyname2, ,, +- { +- LOOKUP_NAME_CASE (h_name, h_aliases) +- }, const char *name, int af) +-#undef EXTRA_ARGS_VALUE +- +- + /* We only need to consider IPv4 mapped addresses if the input to the + gethostbyaddr() function is an IPv6 address. */ + #define EXTRA_ARGS_VALUE \ +@@ -365,6 +115,263 @@ DB_LOOKUP (hostbyaddr, ,,, + }, const void *addr, socklen_t len, int af) + #undef EXTRA_ARGS_VALUE + ++enum nss_status ++_nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result, ++ char *buffer, size_t buflen, int *errnop, ++ int *herrnop, int32_t *ttlp, char **canonp) ++{ ++ uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); ++ buffer += pad; ++ buflen = buflen > pad ? buflen - pad : 0; ++ ++ __libc_lock_lock (lock); ++ ++ /* Reset file pointer to beginning or open file. */ ++ enum nss_status status = internal_setent (keep_stream); ++ ++ if (status == NSS_STATUS_SUCCESS) ++ { ++ /* XXX Is using _res to determine whether we want to convert IPv4 ++ addresses to IPv6 addresses really the right thing to do? */ ++ int flags = ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0); ++ ++ /* Tell getent function that we have repositioned the file pointer. */ ++ last_use = getby; ++ ++ while ((status = internal_getent (result, buffer, buflen, errnop, ++ herrnop, af, flags)) ++ == NSS_STATUS_SUCCESS) ++ { ++ LOOKUP_NAME_CASE (h_name, h_aliases) ++ } ++ ++ if (status == NSS_STATUS_SUCCESS ++ && _res_hconf.flags & HCONF_FLAG_MULTI) ++ { ++ /* We have to get all host entries from the file. */ ++ size_t tmp_buflen = MIN (buflen, 4096); ++ char tmp_buffer_stack[tmp_buflen] ++ __attribute__ ((__aligned__ (__alignof__ (struct hostent_data)))); ++ char *tmp_buffer = tmp_buffer_stack; ++ struct hostent tmp_result_buf; ++ int naddrs = 1; ++ int naliases = 0; ++ char *bufferend; ++ bool tmp_buffer_malloced = false; ++ ++ while (result->h_aliases[naliases] != NULL) ++ ++naliases; ++ ++ bufferend = (char *) &result->h_aliases[naliases + 1]; ++ ++ again: ++ while ((status = internal_getent (&tmp_result_buf, tmp_buffer, ++ tmp_buflen, errnop, herrnop, af, ++ flags)) ++ == NSS_STATUS_SUCCESS) ++ { ++ int matches = 1; ++ struct hostent *old_result = result; ++ result = &tmp_result_buf; ++ /* The following piece is a bit clumsy but we want to use the ++ `LOOKUP_NAME_CASE' value. The optimizer should do its ++ job. */ ++ do ++ { ++ LOOKUP_NAME_CASE (h_name, h_aliases) ++ result = old_result; ++ } ++ while ((matches = 0)); ++ ++ if (matches) ++ { ++ /* We could be very clever and try to recycle a few bytes ++ in the buffer instead of generating new arrays. But ++ we are not doing this here since it's more work than ++ it's worth. Simply let the user provide a bit bigger ++ buffer. */ ++ char **new_h_addr_list; ++ char **new_h_aliases; ++ int newaliases = 0; ++ size_t newstrlen = 0; ++ int cnt; ++ ++ /* Count the new aliases and the length of the strings. */ ++ while (tmp_result_buf.h_aliases[newaliases] != NULL) ++ { ++ char *cp = tmp_result_buf.h_aliases[newaliases]; ++ ++newaliases; ++ newstrlen += strlen (cp) + 1; ++ } ++ /* If the real name is different add it also to the ++ aliases. This means that there is a duplication ++ in the alias list but this is really the user's ++ problem. */ ++ if (strcmp (old_result->h_name, ++ tmp_result_buf.h_name) != 0) ++ { ++ ++newaliases; ++ newstrlen += strlen (tmp_result_buf.h_name) + 1; ++ } ++ ++ /* Make sure bufferend is aligned. */ ++ assert ((bufferend - (char *) 0) % sizeof (char *) == 0); ++ ++ /* Now we can check whether the buffer is large enough. ++ 16 is the maximal size of the IP address. */ ++ if (bufferend + 16 + (naddrs + 2) * sizeof (char *) ++ + roundup (newstrlen, sizeof (char *)) ++ + (naliases + newaliases + 1) * sizeof (char *) ++ >= buffer + buflen) ++ { ++ *errnop = ERANGE; ++ *herrnop = NETDB_INTERNAL; ++ status = NSS_STATUS_TRYAGAIN; ++ goto out; ++ } ++ ++ new_h_addr_list = ++ (char **) (bufferend ++ + roundup (newstrlen, sizeof (char *)) ++ + 16); ++ new_h_aliases = ++ (char **) ((char *) new_h_addr_list ++ + (naddrs + 2) * sizeof (char *)); ++ ++ /* Copy the old data in the new arrays. */ ++ for (cnt = 0; cnt < naddrs; ++cnt) ++ new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; ++ ++ for (cnt = 0; cnt < naliases; ++cnt) ++ new_h_aliases[cnt] = old_result->h_aliases[cnt]; ++ ++ /* Store the new strings. */ ++ cnt = 0; ++ while (tmp_result_buf.h_aliases[cnt] != NULL) ++ { ++ new_h_aliases[naliases++] = bufferend; ++ bufferend = (__stpcpy (bufferend, ++ tmp_result_buf.h_aliases[cnt]) ++ + 1); ++ ++cnt; ++ } ++ ++ if (cnt < newaliases) ++ { ++ new_h_aliases[naliases++] = bufferend; ++ bufferend = __stpcpy (bufferend, ++ tmp_result_buf.h_name) + 1; ++ } ++ ++ /* Final NULL pointer. */ ++ new_h_aliases[naliases] = NULL; ++ ++ /* Round up the buffer end address. */ ++ bufferend += (sizeof (char *) ++ - ((bufferend - (char *) 0) ++ % sizeof (char *))) % sizeof (char *); ++ ++ /* Now the new address. */ ++ new_h_addr_list[naddrs++] = ++ memcpy (bufferend, tmp_result_buf.h_addr, ++ tmp_result_buf.h_length); ++ ++ /* Also here a final NULL pointer. */ ++ new_h_addr_list[naddrs] = NULL; ++ ++ /* Store the new array pointers. */ ++ old_result->h_aliases = new_h_aliases; ++ old_result->h_addr_list = new_h_addr_list; ++ ++ /* Compute the new buffer end. */ ++ bufferend = (char *) &new_h_aliases[naliases + 1]; ++ assert (bufferend <= buffer + buflen); ++ ++ result = old_result; ++ } ++ } ++ ++ if (status == NSS_STATUS_TRYAGAIN) ++ { ++ size_t newsize = 2 * tmp_buflen; ++ if (tmp_buffer_malloced) ++ { ++ char *newp = realloc (tmp_buffer, newsize); ++ if (newp != NULL) ++ { ++ assert ((((uintptr_t) newp) ++ & (__alignof__ (struct hostent_data) - 1)) ++ == 0); ++ tmp_buffer = newp; ++ tmp_buflen = newsize; ++ goto again; ++ } ++ } ++ else if (!__libc_use_alloca (buflen + newsize)) ++ { ++ tmp_buffer = malloc (newsize); ++ if (tmp_buffer != NULL) ++ { ++ assert ((((uintptr_t) tmp_buffer) ++ & (__alignof__ (struct hostent_data) - 1)) ++ == 0); ++ tmp_buffer_malloced = true; ++ tmp_buflen = newsize; ++ goto again; ++ } ++ } ++ else ++ { ++ tmp_buffer ++ = extend_alloca (tmp_buffer, tmp_buflen, ++ newsize ++ + __alignof__ (struct hostent_data)); ++ tmp_buffer = (char *) (((uintptr_t) tmp_buffer ++ + __alignof__ (struct hostent_data) ++ - 1) ++ & ~(__alignof__ (struct hostent_data) ++ - 1)); ++ goto again; ++ } ++ } ++ else ++ status = NSS_STATUS_SUCCESS; ++ out: ++ if (tmp_buffer_malloced) ++ free (tmp_buffer); ++ } ++ ++ if (! keep_stream) ++ internal_endent (); ++ } ++ ++ if (canonp && status == NSS_STATUS_SUCCESS) ++ *canonp = result->h_name; ++ ++ __libc_lock_unlock (lock); ++ ++ return status; ++} ++ ++enum nss_status ++_nss_files_gethostbyname_r (const char *name, struct hostent *result, ++ char *buffer, size_t buflen, int *errnop, ++ int *herrnop) ++{ ++ int af = ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET); ++ ++ return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen, ++ errnop, herrnop, NULL, NULL); ++} ++ ++enum nss_status ++_nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result, ++ char *buffer, size_t buflen, int *errnop, ++ int *herrnop) ++{ ++ return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen, ++ errnop, herrnop, NULL, NULL); ++} + + enum nss_status + _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, diff --git a/SOURCES/glibc-rh1048036.patch b/SOURCES/glibc-rh1048036.patch new file mode 100644 index 0000000..02eddbe --- /dev/null +++ b/SOURCES/glibc-rh1048036.patch @@ -0,0 +1,29 @@ +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 87d3cdc..877fc1f 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -715,7 +715,7 @@ _IO_wfile_seekoff (fp, offset, dir, mode) + - fp->_wide_data->_IO_write_base) / clen; + else + { +- enum __codecvt_result status; ++ enum __codecvt_result status = __codecvt_ok; + delta = (fp->_wide_data->_IO_write_ptr + - fp->_wide_data->_IO_write_base); + const wchar_t *write_base = fp->_wide_data->_IO_write_base; +@@ -728,9 +728,12 @@ _IO_wfile_seekoff (fp, offset, dir, mode) + flush buffers for every ftell. */ + do + { +- /* Ugh, no point trying to avoid the flush. Just do it +- and go back to how it was with the read mode. */ +- if (delta > 0 && new_write_ptr == fp->_IO_buf_end) ++ /* There is not enough space in the buffer to do the entire ++ conversion, so there is no point trying to avoid the ++ buffer flush. Just do it and go back to how it was with ++ the read mode. */ ++ if (status == __codecvt_partial ++ || (delta > 0 && new_write_ptr == fp->_IO_buf_end)) + { + if (_IO_switch_to_wget_mode (fp)) + return WEOF; diff --git a/SOURCES/glibc-rh1048123.patch b/SOURCES/glibc-rh1048123.patch new file mode 100644 index 0000000..018661e --- /dev/null +++ b/SOURCES/glibc-rh1048123.patch @@ -0,0 +1,515 @@ +commit 0582f6b3d6fab2128ee43a06250571922ee7c1e3 +Author: Andreas Schwab +Date: Sun Dec 23 09:45:07 2012 +0100 + + nscd: don't fork twice + +commit 532a60357ef4c5852cc1bf836cfd9d6f093ef204 +Author: Siddhesh Poyarekar +Date: Mon Mar 3 22:51:39 2014 +0530 + + nscd: Improved support for tracking startup failure in nscd service (BZ #16639) + + Currently, the nscd parent process parses commandline options and + configuration, forks on startup and immediately exits with a success. + If the child process encounters some error after this, it goes + undetected and any services started up after it may have to repeatedly + check to make sure that the nscd service did actually start up and is + serving requests. + + To make this process more reliable, I have added a pipe between the + parent and child process, through which the child process sends a + notification to the parent informing it of its status. The parent + waits for this status and once it receives it, exits with the + corresponding exit code. So if the child service sends a success + status (0), the parent exits with a success status. Similarly for + error conditions, the child sends the non-zero status code, which the + parent passes on as the exit code. + + This, along with setting the nscd service type to forking in its + systemd configuration file, allows systemd to be certain that the nscd + service is ready and is accepting connections. + + +diff --git a/nscd/connections.c b/nscd/connections.c +index f463f45..180ae77 100644 +--- a/nscd/connections.c ++++ b/nscd/connections.c +@@ -649,8 +649,8 @@ cannot create read-only descriptor for \"%s\"; no mmap"), + close (fd); + } + else if (errno == EACCES) +- error (EXIT_FAILURE, 0, _("cannot access '%s'"), +- dbs[cnt].db_filename); ++ do_exit (EXIT_FAILURE, 0, _("cannot access '%s'"), ++ dbs[cnt].db_filename); + } + + if (dbs[cnt].head == NULL) +@@ -699,8 +699,7 @@ cannot create read-only descriptor for \"%s\"; no mmap"), + { + dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"), + dbnames[cnt], dbs[cnt].db_filename); +- // XXX Correct way to terminate? +- exit (1); ++ do_exit (1, 0, NULL); + } + + if (dbs[cnt].persistent) +@@ -867,7 +866,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), + if (sock < 0) + { + dbg_log (_("cannot open socket: %s"), strerror (errno)); +- exit (errno == EACCES ? 4 : 1); ++ do_exit (errno == EACCES ? 4 : 1, 0, NULL); + } + /* Bind a name to the socket. */ + struct sockaddr_un sock_addr; +@@ -876,7 +875,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), + if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0) + { + dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno)); +- exit (errno == EACCES ? 4 : 1); ++ do_exit (errno == EACCES ? 4 : 1, 0, NULL); + } + + #ifndef __ASSUME_SOCK_CLOEXEC +@@ -888,7 +887,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), + { + dbg_log (_("cannot change socket to nonblocking mode: %s"), + strerror (errno)); +- exit (1); ++ do_exit (1, 0, NULL); + } + + /* The descriptor needs to be closed on exec. */ +@@ -896,7 +895,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), + { + dbg_log (_("cannot set socket to close on exec: %s"), + strerror (errno)); +- exit (1); ++ do_exit (1, 0, NULL); + } + } + #endif +@@ -909,7 +908,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), + { + dbg_log (_("cannot enable socket to accept connections: %s"), + strerror (errno)); +- exit (1); ++ do_exit (1, 0, NULL); + } + + #ifdef HAVE_NETLINK +@@ -953,7 +952,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), + dbg_log (_("\ + cannot change socket to nonblocking mode: %s"), + strerror (errno)); +- exit (1); ++ do_exit (1, 0, NULL); + } + + /* The descriptor needs to be closed on exec. */ +@@ -962,7 +961,7 @@ cannot change socket to nonblocking mode: %s"), + { + dbg_log (_("cannot set socket to close on exec: %s"), + strerror (errno)); +- exit (1); ++ do_exit (1, 0, NULL); + } + } + # endif +@@ -2392,7 +2391,7 @@ start_threads (void) + if (pthread_cond_init (&dbs[i].prune_cond, &condattr) != 0) + { + dbg_log (_("could not initialize conditional variable")); +- exit (1); ++ do_exit (1, 0, NULL); + } + + pthread_t th; +@@ -2400,7 +2399,7 @@ start_threads (void) + && pthread_create (&th, &attr, nscd_run_prune, (void *) i) != 0) + { + dbg_log (_("could not start clean-up thread; terminating")); +- exit (1); ++ do_exit (1, 0, NULL); + } + } + +@@ -2414,13 +2413,17 @@ start_threads (void) + if (i == 0) + { + dbg_log (_("could not start any worker thread; terminating")); +- exit (1); ++ do_exit (1, 0, NULL); + } + + break; + } + } + ++ /* Now it is safe to let the parent know that we're doing fine and it can ++ exit. */ ++ notify_parent (0); ++ + /* Determine how much room for descriptors we should initially + allocate. This might need to change later if we cap the number + with MAXCONN. */ +@@ -2465,8 +2468,8 @@ begin_drop_privileges (void) + if (pwd == NULL) + { + dbg_log (_("Failed to run nscd as user '%s'"), server_user); +- error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"), +- server_user); ++ do_exit (EXIT_FAILURE, 0, ++ _("Failed to run nscd as user '%s'"), server_user); + } + + server_uid = pwd->pw_uid; +@@ -2483,7 +2486,8 @@ begin_drop_privileges (void) + { + /* This really must never happen. */ + dbg_log (_("Failed to run nscd as user '%s'"), server_user); +- error (EXIT_FAILURE, errno, _("initial getgrouplist failed")); ++ do_exit (EXIT_FAILURE, errno, ++ _("initial getgrouplist failed")); + } + + server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t)); +@@ -2492,7 +2496,7 @@ begin_drop_privileges (void) + == -1) + { + dbg_log (_("Failed to run nscd as user '%s'"), server_user); +- error (EXIT_FAILURE, errno, _("getgrouplist failed")); ++ do_exit (EXIT_FAILURE, errno, _("getgrouplist failed")); + } + } + +@@ -2510,7 +2514,7 @@ finish_drop_privileges (void) + if (setgroups (server_ngroups, server_groups) == -1) + { + dbg_log (_("Failed to run nscd as user '%s'"), server_user); +- error (EXIT_FAILURE, errno, _("setgroups failed")); ++ do_exit (EXIT_FAILURE, errno, _("setgroups failed")); + } + + int res; +@@ -2521,8 +2525,7 @@ finish_drop_privileges (void) + if (res == -1) + { + dbg_log (_("Failed to run nscd as user '%s'"), server_user); +- perror ("setgid"); +- exit (4); ++ do_exit (4, errno, "setgid"); + } + + if (paranoia) +@@ -2532,8 +2535,7 @@ finish_drop_privileges (void) + if (res == -1) + { + dbg_log (_("Failed to run nscd as user '%s'"), server_user); +- perror ("setuid"); +- exit (4); ++ do_exit (4, errno, "setuid"); + } + + #if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP +diff --git a/nscd/nscd.c b/nscd/nscd.c +index 63d9d83..5680378 100644 +--- a/nscd/nscd.c ++++ b/nscd/nscd.c +@@ -39,6 +39,8 @@ + #include + #include + #include ++#include ++#include + + #include "dbg_log.h" + #include "nscd.h" +@@ -101,6 +103,7 @@ gid_t old_gid; + + static int check_pid (const char *file); + static int write_pid (const char *file); ++static int monitor_child (int fd); + + /* Name and version of program. */ + static void print_version (FILE *stream, struct argp_state *state); +@@ -142,6 +145,7 @@ static struct argp argp = + + /* True if only statistics are requested. */ + static bool get_stats; ++static int parent_fd = -1; + + int + main (int argc, char **argv) +@@ -196,11 +200,27 @@ main (int argc, char **argv) + /* Behave like a daemon. */ + if (run_mode == RUN_DAEMONIZE) + { ++ int fd[2]; ++ ++ if (pipe (fd) != 0) ++ error (EXIT_FAILURE, errno, ++ _("cannot create a pipe to talk to the child")); ++ + pid = fork (); + if (pid == -1) + error (EXIT_FAILURE, errno, _("cannot fork")); + if (pid != 0) +- exit (0); ++ { ++ /* The parent only reads from the child. */ ++ close (fd[1]); ++ exit (monitor_child (fd[0])); ++ } ++ else ++ { ++ /* The child only writes to the parent. */ ++ close (fd[0]); ++ parent_fd = fd[1]; ++ } + } + + int nullfd = open (_PATH_DEVNULL, O_RDWR); +@@ -242,7 +262,8 @@ main (int argc, char **argv) + char *endp; + long int fdn = strtol (dirent->d_name, &endp, 10); + +- if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd) ++ if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd ++ && fdn != parent_fd) + close ((int) fdn); + } + +@@ -250,22 +271,14 @@ main (int argc, char **argv) + } + else + for (i = min_close_fd; i < getdtablesize (); i++) +- close (i); ++ if (i != parent_fd) ++ close (i); + +- if (run_mode == RUN_DAEMONIZE) +- { +- pid = fork (); +- if (pid == -1) +- error (EXIT_FAILURE, errno, _("cannot fork")); +- if (pid != 0) +- exit (0); +- } +- + setsid (); + + if (chdir ("/") != 0) +- error (EXIT_FAILURE, errno, +- _("cannot change current working directory to \"/\"")); ++ do_exit (EXIT_FAILURE, errno, ++ _("cannot change current working directory to \"/\"")); + + openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON); + +@@ -592,3 +614,79 @@ write_pid (const char *file) + + return result; + } ++ ++static int ++monitor_child (int fd) ++{ ++ int child_ret = 0; ++ int ret = read (fd, &child_ret, sizeof (child_ret)); ++ ++ /* The child terminated with an error, either via exit or some other abnormal ++ method, like a segfault. */ ++ if (ret <= 0 || child_ret != 0) ++ { ++ int err = wait (&child_ret); ++ ++ if (err < 0) ++ { ++ fprintf (stderr, _("wait failed")); ++ return 1; ++ } ++ ++ fprintf (stderr, _("child exited with status %d"), ++ WEXITSTATUS (child_ret)); ++ if (WIFSIGNALED (child_ret)) ++ fprintf (stderr, _(", terminated by signal %d.\n"), ++ WTERMSIG (child_ret)); ++ else ++ fprintf (stderr, ".\n"); ++ } ++ ++ /* We have the child status, so exit with that code. */ ++ close (fd); ++ ++ return child_ret; ++} ++ ++void ++do_exit (int child_ret, int errnum, const char *format, ...) ++{ ++ if (parent_fd != -1) ++ { ++ int ret = write (parent_fd, &child_ret, sizeof (child_ret)); ++ assert (ret == sizeof (child_ret)); ++ close (parent_fd); ++ } ++ ++ if (format != NULL) ++ { ++ /* Emulate error() since we don't have a va_list variant for it. */ ++ va_list argp; ++ ++ fflush (stdout); ++ ++ fprintf (stderr, "%s: ", program_invocation_name); ++ ++ va_start (argp, format); ++ vfprintf (stderr, format, argp); ++ va_end (argp); ++ ++ fprintf (stderr, ": %s\n", strerror (errnum)); ++ fflush (stderr); ++ } ++ ++ /* Finally, exit. */ ++ exit (child_ret); ++} ++ ++void ++notify_parent (int child_ret) ++{ ++ if (parent_fd == -1) ++ return; ++ ++ int ret = write (parent_fd, &child_ret, sizeof (child_ret)); ++ assert (ret == sizeof (child_ret)); ++ close (parent_fd); ++ parent_fd = -1; ++} +diff --git a/nscd/nscd.h b/nscd/nscd.h +index 972f462..529b3f5 100644 +--- a/nscd/nscd.h ++++ b/nscd/nscd.h +@@ -205,6 +205,8 @@ extern gid_t old_gid; + /* nscd.c */ + extern void termination_handler (int signum) __attribute__ ((__noreturn__)); + extern int nscd_open_socket (void); ++void notify_parent (int child_ret); ++void do_exit (int child_ret, int errnum, const char *format, ...); + + /* connections.c */ + extern void nscd_init (void); +diff --git a/nscd/selinux.c b/nscd/selinux.c +index e477254..46b0ea9 100644 +--- a/nscd/selinux.c ++++ b/nscd/selinux.c +@@ -179,7 +179,7 @@ preserve_capabilities (void) + if (prctl (PR_SET_KEEPCAPS, 1) == -1) + { + dbg_log (_("Failed to set keep-capabilities")); +- error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); ++ do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); + /* NOTREACHED */ + } + +@@ -194,7 +194,7 @@ preserve_capabilities (void) + cap_free (tmp_caps); + + dbg_log (_("Failed to initialize drop of capabilities")); +- error (EXIT_FAILURE, 0, _("cap_init failed")); ++ do_exit (EXIT_FAILURE, 0, _("cap_init failed")); + } + + /* There is no reason why these should not work. */ +@@ -216,7 +216,7 @@ preserve_capabilities (void) + { + cap_free (new_caps); + dbg_log (_("Failed to drop capabilities")); +- error (EXIT_FAILURE, 0, _("cap_set_proc failed")); ++ do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed")); + } + + return new_caps; +@@ -233,7 +233,7 @@ install_real_capabilities (cap_t new_caps) + { + cap_free (new_caps); + dbg_log (_("Failed to drop capabilities")); +- error (EXIT_FAILURE, 0, _("cap_set_proc failed")); ++ do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed")); + /* NOTREACHED */ + } + +@@ -242,7 +242,7 @@ install_real_capabilities (cap_t new_caps) + if (prctl (PR_SET_KEEPCAPS, 0) == -1) + { + dbg_log (_("Failed to unset keep-capabilities")); +- error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); ++ do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); + /* NOTREACHED */ + } + } +@@ -258,7 +258,7 @@ nscd_selinux_enabled (int *selinux_enabled) + if (*selinux_enabled < 0) + { + dbg_log (_("Failed to determine if kernel supports SELinux")); +- exit (EXIT_FAILURE); ++ do_exit (EXIT_FAILURE, 0, NULL); + } + } + +@@ -272,7 +272,7 @@ avc_create_thread (void (*run) (void)) + rc = + pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL); + if (rc != 0) +- error (EXIT_FAILURE, rc, _("Failed to start AVC thread")); ++ do_exit (EXIT_FAILURE, rc, _("Failed to start AVC thread")); + + return &avc_notify_thread; + } +@@ -294,7 +294,7 @@ avc_alloc_lock (void) + + avc_mutex = malloc (sizeof (pthread_mutex_t)); + if (avc_mutex == NULL) +- error (EXIT_FAILURE, errno, _("Failed to create AVC lock")); ++ do_exit (EXIT_FAILURE, errno, _("Failed to create AVC lock")); + pthread_mutex_init (avc_mutex, NULL); + + return avc_mutex; +@@ -334,7 +334,7 @@ nscd_avc_init (void) + avc_entry_ref_init (&aeref); + + if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0) +- error (EXIT_FAILURE, errno, _("Failed to start AVC")); ++ do_exit (EXIT_FAILURE, errno, _("Failed to start AVC")); + else + dbg_log (_("Access Vector Cache (AVC) started")); + #ifdef HAVE_LIBAUDIT +--- a/releng/nscd.service 2012-11-06 03:03:19.000000000 +0530 ++++ b/releng/nscd.service 2014-02-28 16:59:51.096630222 +0530 +@@ -1,10 +1,13 @@ ++# systemd service file for nscd ++ + [Unit] + Description=Name Service Cache Daemon + After=syslog.target + + [Service] ++Type=forking + EnvironmentFile=-/etc/sysconfig/nscd +-ExecStart=/usr/sbin/nscd --foreground $NSCD_OPTIONS ++ExecStart=/usr/sbin/nscd $NSCD_OPTIONS + ExecStop=/usr/sbin/nscd --shutdown + ExecReload=/usr/sbin/nscd -i passwd + ExecReload=/usr/sbin/nscd -i group +@@ -12,6 +14,7 @@ + ExecReload=/usr/sbin/nscd -i services + ExecReload=/usr/sbin/nscd -i netgroup + Restart=always ++PIDFile=/run/nscd/nscd.pid + + [Install] + WantedBy=multi-user.target diff --git a/SOURCES/glibc-rh1063681.patch b/SOURCES/glibc-rh1063681.patch new file mode 100644 index 0000000..429a0a3 --- /dev/null +++ b/SOURCES/glibc-rh1063681.patch @@ -0,0 +1,948 @@ +diff --git a/libio/Makefile b/libio/Makefile +index 22dbcae..488ee51 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -60,7 +60,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ + tst-wmemstream1 tst-wmemstream2 \ + bug-memstream1 bug-wmemstream1 \ + tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ +- tst-fwrite-error ++ tst-fwrite-error tst-ftell-active-handler + ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on + # shared localedata objects. +diff --git a/libio/fileops.c b/libio/fileops.c +index a3499be..2e7bc8d 100644 +--- a/libio/fileops.c ++++ b/libio/fileops.c +@@ -929,6 +929,93 @@ _IO_file_sync_mmap (_IO_FILE *fp) + return 0; + } + ++/* Get the current file offset using a system call. This is the safest method ++ to get the current file offset, since we are sure that we get the current ++ state of the file. Before the stream handle is activated (by using fread, ++ fwrite, etc.), an application may alter the state of the file descriptor ++ underlying it by calling read/write/lseek on it. Using a cached offset at ++ this point will result in returning the incorrect value. Same is the case ++ when one switches from reading in a+ mode to writing, where the buffer has ++ not been flushed - the cached offset would reflect the reading position ++ while the actual write position would be at the end of the file. ++ ++ do_ftell and do_ftell_wide may resort to using the cached offset in some ++ special cases instead of calling get_file_offset, but those cases should be ++ thoroughly described. */ ++_IO_off64_t ++get_file_offset (_IO_FILE *fp) ++{ ++ if ((fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING) ++ { ++ struct stat64 st; ++ bool ret = (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)); ++ if (ret) ++ return st.st_size; ++ else ++ return EOF; ++ } ++ else ++ return _IO_SYSSEEK (fp, 0, _IO_seek_cur); ++} ++ ++ ++/* ftell{,o} implementation. Don't modify any state of the file pointer while ++ we try to get the current state of the stream. */ ++static _IO_off64_t ++do_ftell (_IO_FILE *fp) ++{ ++ _IO_off64_t result = 0; ++ bool use_cached_offset = false; ++ ++ /* No point looking at unflushed data if we haven't allocated buffers ++ yet. */ ++ if (fp->_IO_buf_base != NULL) ++ { ++ bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base ++ || _IO_in_put_mode (fp)); ++ ++ /* Adjust for unflushed data. */ ++ if (!was_writing) ++ result -= fp->_IO_read_end - fp->_IO_read_ptr; ++ else ++ result += fp->_IO_write_ptr - fp->_IO_read_end; ++ ++ /* It is safe to use the cached offset when available if there is ++ unbuffered data (indicating that the file handle is active) and the ++ handle is not for a file open in a+ mode. The latter condition is ++ because there could be a scenario where there is a switch from read ++ mode to write mode using an fseek to an arbitrary position. In this ++ case, there would be unbuffered data due to be appended to the end of ++ the file, but the offset may not necessarily be the end of the ++ file. It is fine to use the cached offset when the a+ stream is in ++ read mode though, since the offset is maintained correctly in that ++ case. Note that this is not a comprehensive set of cases when the ++ offset is reliable. The offset may be reliable even in some cases ++ where there is no unflushed input and the handle is active, but it's ++ just that we don't have a way to identify that condition reliably. */ ++ use_cached_offset = (result != 0 && fp->_offset != _IO_pos_BAD ++ && ((fp->_flags & (_IO_IS_APPENDING | _IO_NO_READS)) ++ == (_IO_IS_APPENDING | _IO_NO_READS) ++ && was_writing)); ++ } ++ ++ if (use_cached_offset) ++ result += fp->_offset; ++ else ++ result += get_file_offset (fp); ++ ++ if (result == EOF) ++ return result; ++ ++ if (result < 0) ++ { ++ __set_errno (EINVAL); ++ return EOF; ++ } ++ ++ return result; ++} ++ + + _IO_off64_t + _IO_new_file_seekoff (fp, offset, dir, mode) +@@ -940,6 +1027,13 @@ _IO_new_file_seekoff (fp, offset, dir, mode) + _IO_off64_t result; + _IO_off64_t delta, new_offset; + long count; ++ ++ /* Short-circuit into a separate function. We don't want to mix any ++ functionality and we don't want to touch anything inside the FILE ++ object. */ ++ if (mode == 0) ++ return do_ftell (fp); ++ + /* POSIX.1 8.2.3.7 says that after a call the fflush() the file + offset of the underlying file must be exact. */ + int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end +@@ -948,9 +1042,6 @@ _IO_new_file_seekoff (fp, offset, dir, mode) + bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base + || _IO_in_put_mode (fp)); + +- if (mode == 0) +- dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ +- + /* Flush unwritten characters. + (This may do an unneeded write if we seek within the buffer. + But to be able to switch to reading, we would need to set +@@ -958,7 +1049,7 @@ _IO_new_file_seekoff (fp, offset, dir, mode) + which assumes file_ptr() is eGptr. Anyway, since we probably + end up flushing when we close(), it doesn't make much difference.) + FIXME: simulate mem-mapped files. */ +- else if (was_writing && _IO_switch_to_get_mode (fp)) ++ if (was_writing && _IO_switch_to_get_mode (fp)) + return EOF; + + if (fp->_IO_buf_base == NULL) +@@ -978,30 +1069,10 @@ _IO_new_file_seekoff (fp, offset, dir, mode) + { + case _IO_seek_cur: + /* Adjust for read-ahead (bytes is buffer). */ +- if (mode != 0 || !was_writing) +- offset -= fp->_IO_read_end - fp->_IO_read_ptr; +- else +- { +- /* _IO_read_end coincides with fp._offset, so the actual file position +- is fp._offset - (_IO_read_end - new_write_ptr). This is fine +- even if fp._offset is not set, since fp->_IO_read_end is then at +- _IO_buf_base and this adjustment is for unbuffered output. */ +- offset -= fp->_IO_read_end - fp->_IO_write_ptr; +- } ++ offset -= fp->_IO_read_end - fp->_IO_read_ptr; + + if (fp->_offset == _IO_pos_BAD) +- { +- if (mode != 0) +- goto dumb; +- else +- { +- result = _IO_SYSSEEK (fp, 0, dir); +- if (result == EOF) +- return result; +- +- fp->_offset = result; +- } +- } ++ goto dumb; + /* Make offset absolute, assuming current pointer is file_ptr(). */ + offset += fp->_offset; + if (offset < 0) +@@ -1028,10 +1099,6 @@ _IO_new_file_seekoff (fp, offset, dir, mode) + } + /* At this point, dir==_IO_seek_set. */ + +- /* If we are only interested in the current position we've found it now. */ +- if (mode == 0) +- return offset; +- + /* If destination is within current buffer, optimize: */ + if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL + && !_IO_in_backup (fp)) +diff --git a/libio/iofdopen.c b/libio/iofdopen.c +index 066ff19..3f266f7 100644 +--- a/libio/iofdopen.c ++++ b/libio/iofdopen.c +@@ -141,9 +141,6 @@ _IO_new_fdopen (fd, mode) + #ifdef _IO_MTSAFE_IO + new_f->fp.file._lock = &new_f->lock; + #endif +- /* Set up initially to use the `maybe_mmap' jump tables rather than using +- __fopen_maybe_mmap to do it, because we need them in place before we +- call _IO_file_attach or else it will allocate a buffer immediately. */ + _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, + #ifdef _G_HAVE_MMAP + (use_mmap && (read_write & _IO_NO_WRITES)) +@@ -159,13 +156,12 @@ _IO_new_fdopen (fd, mode) + #if !_IO_UNIFIED_JUMPTABLES + new_f->fp.vtable = NULL; + #endif +- if (_IO_file_attach ((_IO_FILE *) &new_f->fp, fd) == NULL) +- { +- _IO_setb (&new_f->fp.file, NULL, NULL, 0); +- _IO_un_link (&new_f->fp); +- free (new_f); +- return NULL; +- } ++ /* We only need to record the fd because _IO_file_init will have unset the ++ offset. It is important to unset the cached offset because the real ++ offset in the file could change between now and when the handle is ++ activated and we would then mislead ftell into believing that we have a ++ valid offset. */ ++ new_f->fp.file._fileno = fd; + new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE; + + _IO_mask_flags (&new_f->fp.file, read_write, +diff --git a/libio/iofwide.c b/libio/iofwide.c +index 5cff632..64187e4 100644 +--- a/libio/iofwide.c ++++ b/libio/iofwide.c +@@ -199,12 +199,6 @@ _IO_fwide (fp, mode) + + /* From now on use the wide character callback functions. */ + ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable; +- +- /* One last twist: we get the current stream position. The wide +- char streams have much more problems with not knowing the +- current position and so we should disable the optimization +- which allows the functions without knowing the position. */ +- fp->_offset = _IO_SYSSEEK (fp, 0, _IO_seek_cur); + } + + /* Set the mode now. */ +diff --git a/libio/libioP.h b/libio/libioP.h +index 4ca723c..8a7b85b 100644 +--- a/libio/libioP.h ++++ b/libio/libioP.h +@@ -397,6 +397,7 @@ extern void _IO_wdoallocbuf (_IO_FILE *) __THROW; + libc_hidden_proto (_IO_wdoallocbuf) + extern void _IO_unsave_wmarkers (_IO_FILE *) __THROW; + extern unsigned _IO_adjust_wcolumn (unsigned, const wchar_t *, int) __THROW; ++extern _IO_off64_t get_file_offset (_IO_FILE *fp); + + /* Marker-related function. */ + +diff --git a/libio/tst-ftell-active-handler.c b/libio/tst-ftell-active-handler.c +new file mode 100644 +index 0000000..175e904 +--- /dev/null ++++ b/libio/tst-ftell-active-handler.c +@@ -0,0 +1,384 @@ ++/* Verify that ftell returns the correct value at various points before and ++ after the handler on which it is called becomes active. ++ Copyright (C) 2014 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int do_test (void); ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" ++ ++#define get_handles_fdopen(filename, fd, fp, fd_mode, mode) \ ++({ \ ++ int ret = 0; \ ++ (fd) = open ((filename), (fd_mode), 0); \ ++ if ((fd) == -1) \ ++ { \ ++ printf ("open failed: %m\n"); \ ++ ret = 1; \ ++ } \ ++ else \ ++ { \ ++ (fp) = fdopen ((fd), (mode)); \ ++ if ((fp) == NULL) \ ++ { \ ++ printf ("fdopen failed: %m\n"); \ ++ close (fd); \ ++ ret = 1; \ ++ } \ ++ } \ ++ ret; \ ++}) ++ ++#define get_handles_fopen(filename, fd, fp, mode) \ ++({ \ ++ int ret = 0; \ ++ (fp) = fopen ((filename), (mode)); \ ++ if ((fp) == NULL) \ ++ { \ ++ printf ("fopen failed: %m\n"); \ ++ ret = 1; \ ++ } \ ++ else \ ++ { \ ++ (fd) = fileno (fp); \ ++ if ((fd) == -1) \ ++ { \ ++ printf ("fileno failed: %m\n"); \ ++ ret = 1; \ ++ } \ ++ } \ ++ ret; \ ++}) ++ ++/* data points to either char_data or wide_data, depending on whether we're ++ testing regular file mode or wide mode respectively. Similarly, ++ fputs_func points to either fputs or fputws. data_len keeps track of the ++ length of the current data and file_len maintains the current file ++ length. */ ++static const void *data; ++static const char *char_data = "abcdef"; ++static const wchar_t *wide_data = L"abcdef"; ++static size_t data_len; ++static size_t file_len; ++ ++typedef int (*fputs_func_t) (const void *data, FILE *fp); ++fputs_func_t fputs_func; ++ ++/* Test that the value of ftell is not cached when the stream handle is not ++ active. */ ++static int ++do_ftell_test (const char *filename) ++{ ++ int ret = 0; ++ struct test ++ { ++ const char *mode; ++ int fd_mode; ++ size_t old_off; ++ size_t new_off; ++ } test_modes[] = { ++ /* In w, w+ and r+ modes, the file position should be at the ++ beginning of the file. After the write, the offset should be ++ updated to data_len. */ ++ {"w", O_WRONLY, 0, data_len}, ++ {"w+", O_RDWR, 0, data_len}, ++ {"r+", O_RDWR, 0, data_len}, ++ /* For 'a' and 'a+' modes, the initial file position should be the ++ current end of file. After the write, the offset has data_len ++ added to the old value. */ ++ {"a", O_WRONLY, data_len, 2 * data_len}, ++ {"a+", O_RDWR, 2 * data_len, 3 * data_len}, ++ }; ++ for (int j = 0; j < 2; j++) ++ { ++ for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) ++ { ++ FILE *fp; ++ int fd; ++ printf ("\tftell: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen", ++ test_modes[i].mode); ++ ++ if (j == 0) ++ ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, ++ test_modes[i].mode); ++ else ++ ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); ++ ++ if (ret != 0) ++ return ret; ++ ++ long off = ftell (fp); ++ if (off != test_modes[i].old_off) ++ { ++ printf ("Incorrect old offset. Expected %zu but got %ld, ", ++ test_modes[i].old_off, off); ++ ret |= 1; ++ } ++ else ++ printf ("old offset = %ld, ", off); ++ ++ /* The effect of this write on the offset should be seen in the ftell ++ call that follows it. */ ++ int ret = write (fd, data, data_len); ++ off = ftell (fp); ++ ++ if (off != test_modes[i].new_off) ++ { ++ printf ("Incorrect new offset. Expected %zu but got %ld\n", ++ test_modes[i].old_off, off); ++ ret |= 1; ++ } ++ else ++ printf ("new offset = %ld\n", off); ++ ++ fclose (fp); ++ } ++ } ++ ++ return ret; ++} ++ ++/* This test opens the file for writing, moves the file offset of the ++ underlying file, writes out data and then checks if ftell trips on it. */ ++static int ++do_write_test (const char *filename) ++{ ++ FILE *fp = NULL; ++ int fd; ++ int ret = 0; ++ struct test ++ { ++ const char *mode; ++ int fd_mode; ++ } test_modes[] = { ++ {"w", O_WRONLY}, ++ {"w+", O_RDWR}, ++ {"r+", O_RDWR} ++ }; ++ ++ for (int j = 0; j < 2; j++) ++ { ++ for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) ++ { ++ printf ("\twrite: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen", ++ test_modes[i].mode); ++ ++ if (j == 0) ++ ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); ++ else ++ ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, ++ test_modes[i].mode); ++ ++ if (ret != 0) ++ return ret; ++ ++ /* Move offset to just before the end of the file. */ ++ off_t ret = lseek (fd, file_len - 1, SEEK_SET); ++ if (ret == -1) ++ { ++ printf ("lseek failed: %m\n"); ++ ret |= 1; ++ } ++ ++ /* Write some data. */ ++ size_t written = fputs_func (data, fp); ++ ++ if (written == EOF) ++ { ++ printf ("fputs[1] failed to write data\n"); ++ ret |= 1; ++ } ++ ++ /* Verify that the offset points to the end of the file. The length ++ of the file would be the original length + the length of data ++ written to it - the amount by which we moved the offset using ++ lseek. */ ++ long offset = ftell (fp); ++ file_len = file_len - 1 + data_len; ++ ++ if (offset != file_len) ++ { ++ printf ("Incorrect offset. Expected %zu, but got %ld\n", ++ file_len, offset); ++ ++ ret |= 1; ++ } ++ ++ printf ("offset = %ld\n", offset); ++ fclose (fp); ++ } ++ } ++ ++ return ret; ++} ++ ++/* This test opens a file in append mode, writes some data, and then verifies ++ that ftell does not trip over it. */ ++static int ++do_append_test (const char *filename) ++{ ++ FILE *fp = NULL; ++ int ret = 0; ++ int fd; ++ ++ struct test ++ { ++ const char *mode; ++ int fd_mode; ++ } test_modes[] = { ++ {"a", O_WRONLY}, ++ {"a+", O_RDWR} ++ }; ++ ++ for (int j = 0; j < 2; j++) ++ { ++ for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) ++ { ++ printf ("\tappend: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen", ++ test_modes[i].mode); ++ ++ if (j == 0) ++ ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); ++ else ++ ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, ++ test_modes[i].mode); ++ ++ if (ret != 0) ++ return ret; ++ ++ /* Write some data. */ ++ size_t written = fputs_func (data, fp); ++ ++ if (written == EOF) ++ { ++ printf ("fputs[1] failed to write all data\n"); ++ ret |= 1; ++ } ++ ++ /* Verify that the offset points to the end of the file. The file ++ len is maintained by adding data_len each time to reflect the data ++ written to it. */ ++ long offset = ftell (fp); ++ file_len += data_len; ++ ++ if (offset != file_len) ++ { ++ printf ("Incorrect offset. Expected %zu, but got %ld\n", ++ file_len, offset); ++ ++ ret |= 1; ++ } ++ ++ printf ("offset = %ld\n", offset); ++ fclose (fp); ++ } ++ } ++ ++ return ret; ++} ++ ++static int ++do_one_test (const char *filename) ++{ ++ int ret = 0; ++ ++ ret |= do_ftell_test (filename); ++ ret |= do_write_test (filename); ++ ret |= do_append_test (filename); ++ ++ return ret; ++} ++ ++/* Run a set of tests for ftell for regular files and wide mode files. */ ++static int ++do_test (void) ++{ ++ int ret = 0; ++ FILE *fp = NULL; ++ char *filename; ++ size_t written; ++ int fd = create_temp_file ("tst-active-handler-tmp.", &filename); ++ ++ if (fd == -1) ++ { ++ printf ("create_temp_file: %m\n"); ++ return 1; ++ } ++ ++ fp = fdopen (fd, "w"); ++ if (fp == NULL) ++ { ++ printf ("fdopen[0]: %m\n"); ++ close (fd); ++ return 1; ++ } ++ ++ data = char_data; ++ data_len = strlen (char_data); ++ file_len = strlen (char_data); ++ written = fputs (data, fp); ++ ++ if (written == EOF) ++ { ++ printf ("fputs[1] failed to write data\n"); ++ ret = 1; ++ } ++ ++ fclose (fp); ++ if (ret) ++ return ret; ++ ++ /* Tests for regular files. */ ++ puts ("Regular mode:"); ++ fputs_func = (fputs_func_t) fputs; ++ data = char_data; ++ data_len = strlen (char_data); ++ ret |= do_one_test (filename); ++ ++ /* Truncate the file before repeating the tests in wide mode. */ ++ fp = fopen (filename, "w"); ++ if (fp == NULL) ++ { ++ printf ("fopen failed %m\n"); ++ return 1; ++ } ++ fclose (fp); ++ ++ /* Tests for wide files. */ ++ puts ("Wide mode:"); ++ if (setlocale (LC_ALL, "en_US.UTF-8") == NULL) ++ { ++ printf ("Cannot set en_US.UTF-8 locale.\n"); ++ return 1; ++ } ++ fputs_func = (fputs_func_t) fputws; ++ data = wide_data; ++ data_len = wcslen (wide_data); ++ ret |= do_one_test (filename); ++ ++ return ret; ++} +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 9cebe77..8b2e108 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -596,29 +596,25 @@ done: + return 0; + } + +-_IO_off64_t +-_IO_wfile_seekoff (fp, offset, dir, mode) +- _IO_FILE *fp; +- _IO_off64_t offset; +- int dir; +- int mode; ++/* ftell{,o} implementation for wide mode. Don't modify any state of the file ++ pointer while we try to get the current state of the stream. */ ++static _IO_off64_t ++do_ftell_wide (_IO_FILE *fp) + { +- _IO_off64_t result; +- _IO_off64_t delta, new_offset; +- long int count; +- /* POSIX.1 8.2.3.7 says that after a call the fflush() the file +- offset of the underlying file must be exact. */ +- int must_be_exact = ((fp->_wide_data->_IO_read_base +- == fp->_wide_data->_IO_read_end) +- && (fp->_wide_data->_IO_write_base +- == fp->_wide_data->_IO_write_ptr)); ++ _IO_off64_t result, offset = 0; ++ bool use_cached_offset = false; + +- bool was_writing = ((fp->_wide_data->_IO_write_ptr +- > fp->_wide_data->_IO_write_base) +- || _IO_in_put_mode (fp)); +- +- if (mode == 0) ++ /* No point looking for offsets in the buffer if it hasn't even been ++ allocated. */ ++ if (fp->_wide_data->_IO_buf_base != NULL) + { ++ const wchar_t *wide_read_base; ++ const wchar_t *wide_read_ptr; ++ const wchar_t *wide_read_end; ++ bool was_writing = ((fp->_wide_data->_IO_write_ptr ++ > fp->_wide_data->_IO_write_base) ++ || _IO_in_put_mode (fp)); ++ + /* XXX For wide stream with backup store it is not very + reasonable to determine the offset. The pushed-back + character might require a state change and we need not be +@@ -633,14 +629,142 @@ _IO_wfile_seekoff (fp, offset, dir, mode) + return -1; + } + +- /* There is no more data in the backup buffer. We can +- switch back. */ +- _IO_switch_to_main_wget_area (fp); ++ /* Nothing in the backup store, so note the backed up pointers ++ without changing the state. */ ++ wide_read_base = fp->_wide_data->_IO_save_base; ++ wide_read_ptr = wide_read_base; ++ wide_read_end = fp->_wide_data->_IO_save_end; ++ } ++ else ++ { ++ wide_read_base = fp->_wide_data->_IO_read_base; ++ wide_read_ptr = fp->_wide_data->_IO_read_ptr; ++ wide_read_end = fp->_wide_data->_IO_read_end; ++ } ++ ++ struct _IO_codecvt *cv = fp->_codecvt; ++ int clen = (*cv->__codecvt_do_encoding) (cv); ++ ++ if (!was_writing) ++ { ++ if (clen > 0) ++ { ++ offset -= (wide_read_end - wide_read_ptr) * clen; ++ offset -= fp->_IO_read_end - fp->_IO_read_ptr; ++ } ++ else ++ { ++ int nread; ++ ++ size_t delta = wide_read_ptr - wide_read_base; ++ __mbstate_t state = fp->_wide_data->_IO_last_state; ++ nread = (*cv->__codecvt_do_length) (cv, &state, ++ fp->_IO_read_base, ++ fp->_IO_read_end, delta); ++ offset -= fp->_IO_read_end - fp->_IO_read_base - nread; ++ } ++ } ++ else ++ { ++ if (clen > 0) ++ offset += (fp->_wide_data->_IO_write_ptr ++ - fp->_wide_data->_IO_write_base) * clen; ++ else ++ { ++ size_t delta = (fp->_wide_data->_IO_write_ptr ++ - fp->_wide_data->_IO_write_base); ++ ++ /* Allocate enough space for the conversion. */ ++ size_t outsize = delta * sizeof (wchar_t); ++ char *out = malloc (outsize); ++ char *outstop = out; ++ const wchar_t *in = fp->_wide_data->_IO_write_base; ++ ++ enum __codecvt_result status; ++ ++ __mbstate_t state = fp->_wide_data->_IO_last_state; ++ status = (*cv->__codecvt_do_out) (cv, &state, ++ in, in + delta, &in, ++ out, out + outsize, &outstop); ++ ++ /* We don't check for __codecvt_partial because it can be ++ returned on one of two conditions: either the output ++ buffer is full or the input sequence is incomplete. We ++ take care to allocate enough buffer and our input ++ sequences must be complete since they are accepted as ++ wchar_t; if not, then that is an error. */ ++ if (__glibc_unlikely (status != __codecvt_ok)) ++ return WEOF; ++ ++ offset += outstop - out; ++ } ++ ++ /* _IO_read_end coincides with fp._offset, so the actual file ++ position is fp._offset - (_IO_read_end - new_write_ptr). */ ++ offset -= fp->_IO_read_end - fp->_IO_write_ptr; + } + +- dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ ++ /* It is safe to use the cached offset when available if there is ++ unbuffered data (indicating that the file handle is active) and ++ the handle is not for a file open in a+ mode. The latter ++ condition is because there could be a scenario where there is a ++ switch from read mode to write mode using an fseek to an arbitrary ++ position. In this case, there would be unbuffered data due to be ++ appended to the end of the file, but the offset may not ++ necessarily be the end of the file. It is fine to use the cached ++ offset when the a+ stream is in read mode though, since the offset ++ is maintained correctly in that case. Note that this is not a ++ comprehensive set of cases when the offset is reliable. The ++ offset may be reliable even in some cases where there is no ++ unflushed input and the handle is active, but it's just that we ++ don't have a way to identify that condition reliably. */ ++ use_cached_offset = (offset != 0 && fp->_offset != _IO_pos_BAD ++ && ((fp->_flags & (_IO_IS_APPENDING | _IO_NO_READS)) ++ == (_IO_IS_APPENDING | _IO_NO_READS) ++ && was_writing)); + } + ++ if (use_cached_offset) ++ result = fp->_offset; ++ else ++ result = get_file_offset (fp); ++ ++ if (result == EOF) ++ return result; ++ ++ result += offset; ++ ++ return result; ++} ++ ++_IO_off64_t ++_IO_wfile_seekoff (fp, offset, dir, mode) ++ _IO_FILE *fp; ++ _IO_off64_t offset; ++ int dir; ++ int mode; ++{ ++ _IO_off64_t result; ++ _IO_off64_t delta, new_offset; ++ long int count; ++ ++ /* Short-circuit into a separate function. We don't want to mix any ++ functionality and we don't want to touch anything inside the FILE ++ object. */ ++ if (mode == 0) ++ return do_ftell_wide (fp); ++ ++ /* POSIX.1 8.2.3.7 says that after a call the fflush() the file ++ offset of the underlying file must be exact. */ ++ int must_be_exact = ((fp->_wide_data->_IO_read_base ++ == fp->_wide_data->_IO_read_end) ++ && (fp->_wide_data->_IO_write_base ++ == fp->_wide_data->_IO_write_ptr)); ++ ++ bool was_writing = ((fp->_wide_data->_IO_write_ptr ++ > fp->_wide_data->_IO_write_base) ++ || _IO_in_put_mode (fp)); ++ + /* Flush unwritten characters. + (This may do an unneeded write if we seek within the buffer. + But to be able to switch to reading, we would need to set +@@ -648,7 +772,7 @@ _IO_wfile_seekoff (fp, offset, dir, mode) + which assumes file_ptr() is eGptr. Anyway, since we probably + end up flushing when we close(), it doesn't make much difference.) + FIXME: simulate mem-mapped files. */ +- else if (was_writing && _IO_switch_to_wget_mode (fp)) ++ if (was_writing && _IO_switch_to_wget_mode (fp)) + return WEOF; + + if (fp->_wide_data->_IO_buf_base == NULL) +@@ -693,7 +817,6 @@ _IO_wfile_seekoff (fp, offset, dir, mode) + { + int nread; + +- flushed: + delta = (fp->_wide_data->_IO_read_ptr + - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; +@@ -706,80 +829,9 @@ _IO_wfile_seekoff (fp, offset, dir, mode) + offset -= fp->_IO_read_end - fp->_IO_read_base - nread; + } + } +- else +- { +- char *new_write_ptr = fp->_IO_write_ptr; +- +- if (clen > 0) +- offset += (fp->_wide_data->_IO_write_ptr +- - fp->_wide_data->_IO_write_base) / clen; +- else +- { +- enum __codecvt_result status = __codecvt_ok; +- delta = (fp->_wide_data->_IO_write_ptr +- - fp->_wide_data->_IO_write_base); +- const wchar_t *write_base = fp->_wide_data->_IO_write_base; +- +- /* FIXME: This actually ends up in two iterations of conversion, +- one here and the next when the buffer actually gets flushed. +- It may be possible to optimize this in future so that +- wdo_write identifies already converted content and does not +- redo it. In any case, this is much better than having to +- flush buffers for every ftell. */ +- do +- { +- /* There is not enough space in the buffer to do the entire +- conversion, so there is no point trying to avoid the +- buffer flush. Just do it and go back to how it was with +- the read mode. */ +- if (status == __codecvt_partial +- || (delta > 0 && new_write_ptr == fp->_IO_buf_end)) +- { +- if (_IO_switch_to_wget_mode (fp)) +- return WEOF; +- goto flushed; +- } +- +- const wchar_t *new_wbase = fp->_wide_data->_IO_write_base; +- fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; +- status = (*cv->__codecvt_do_out) (cv, +- &fp->_wide_data->_IO_state, +- write_base, +- write_base + delta, +- &new_wbase, +- new_write_ptr, +- fp->_IO_buf_end, +- &new_write_ptr); +- +- delta -= new_wbase - write_base; +- +- /* If there was an error, then return WEOF. +- TODO: set buffer state. */ +- if (__builtin_expect (status == __codecvt_error, 0)) +- return WEOF; +- } +- while (delta > 0); +- } +- +- /* _IO_read_end coincides with fp._offset, so the actual file position +- is fp._offset - (_IO_read_end - new_write_ptr). This is fine +- even if fp._offset is not set, since fp->_IO_read_end is then at +- _IO_buf_base and this adjustment is for unbuffered output. */ +- offset -= fp->_IO_read_end - new_write_ptr; +- } + + if (fp->_offset == _IO_pos_BAD) +- { +- if (mode != 0) +- goto dumb; +- else +- { +- result = _IO_SYSSEEK (fp, 0, dir); +- if (result == EOF) +- return result; +- fp->_offset = result; +- } +- } ++ goto dumb; + + /* Make offset absolute, assuming current pointer is file_ptr(). */ + offset += fp->_offset; +@@ -802,10 +854,6 @@ _IO_wfile_seekoff (fp, offset, dir, mode) + } + /* At this point, dir==_IO_seek_set. */ + +- /* If we are only interested in the current position we've found it now. */ +- if (mode == 0) +- return offset; +- + /* If destination is within current buffer, optimize: */ + if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL + && !_IO_in_backup (fp)) diff --git a/SOURCES/glibc-rh1064945.patch b/SOURCES/glibc-rh1064945.patch new file mode 100644 index 0000000..119a8fc --- /dev/null +++ b/SOURCES/glibc-rh1064945.patch @@ -0,0 +1,78 @@ +commit 736c304a1ab4cee36a2f3343f1698bc0abae4608 +Author: Adhemerval Zanella +Date: Thu Jan 16 06:53:18 2014 -0600 + + PowerPC: Fix ftime gettimeofday internal call returning bogus data + + This patches fixes BZ#16430 by setting a different symbol for internal + GLIBC calls that points to ifunc resolvers. For PPC32, if the symbol + is defined as hidden (which is the case for gettimeofday and time) the + compiler will create local branches (symbol@local) and linker will not + create PLT calls (required for IFUNC). This will leads to internal symbol + calling the IFUNC resolver instead of the resolved symbol. + For PPC64 this behavior does not occur because a call to a function in + another translation unit might use a different toc pointer thus requiring + a PLT call. + +diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c +index 29a5e08..2085b68 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c ++++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c +@@ -44,8 +44,24 @@ asm (".type __gettimeofday, %gnu_indirect_function"); + /* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't + let us do it in C because it doesn't know we're defining __gettimeofday + here in this file. */ +-asm (".globl __GI___gettimeofday\n" +- "__GI___gettimeofday = __gettimeofday"); ++asm (".globl __GI___gettimeofday"); ++ ++/* __GI___gettimeofday is defined as hidden and for ppc32 it enables the ++ compiler make a local call (symbol@local) for internal GLIBC usage. It ++ means the PLT won't be used and the ifunc resolver will be called directly. ++ For ppc64 a call to a function in another translation unit might use a ++ different toc pointer thus disallowing direct branchess and making internal ++ ifuncs calls safe. */ ++#ifdef __powerpc64__ ++asm ("__GI___gettimeofday = __gettimeofday"); ++#else ++int ++__gettimeofday_vsyscall (struct timeval *tv, struct timezone *tz) ++{ ++ return INLINE_VSYSCALL (gettimeofday, 2, tv, tz); ++} ++asm ("__GI___gettimeofday = __gettimeofday_vsyscall"); ++#endif + + #else + +diff --git a/sysdeps/unix/sysv/linux/powerpc/time.c b/sysdeps/unix/sysv/linux/powerpc/time.c +index 089d0b6..023bc02 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/time.c ++++ b/sysdeps/unix/sysv/linux/powerpc/time.c +@@ -54,8 +54,24 @@ asm (".type time, %gnu_indirect_function"); + /* This is doing "libc_hidden_def (time)" but the compiler won't + * let us do it in C because it doesn't know we're defining time + * here in this file. */ +-asm (".globl __GI_time\n" +- "__GI_time = time"); ++asm (".globl __GI_time"); ++ ++/* __GI_time is defined as hidden and for ppc32 it enables the ++ compiler make a local call (symbol@local) for internal GLIBC usage. It ++ means the PLT won't be used and the ifunc resolver will be called directly. ++ For ppc64 a call to a function in another translation unit might use a ++ different toc pointer thus disallowing direct branchess and making internal ++ ifuncs calls safe. */ ++#ifdef __powerpc64__ ++asm ("__GI_time = time"); ++#else ++time_t ++__time_vsyscall (time_t *t) ++{ ++ return INLINE_VSYSCALL (time, 1, t); ++} ++asm ("__GI_time = __time_vsyscall"); ++#endif + + #else + diff --git a/SOURCES/glibc-rh1070806.patch b/SOURCES/glibc-rh1070806.patch new file mode 100644 index 0000000..6b3d501 --- /dev/null +++ b/SOURCES/glibc-rh1070806.patch @@ -0,0 +1,107 @@ +diff -urN glibc-2.17-c758a686/config.make.in glibc-2.17-c758a686.mod/config.make.in +--- glibc-2.17-c758a686/config.make.in 2014-02-27 10:33:11.466763885 -0500 ++++ glibc-2.17-c758a686.mod/config.make.in 2014-02-27 10:36:44.481320149 -0500 +@@ -62,6 +62,7 @@ + have-as-vis3 = @libc_cv_sparc_as_vis3@ + gnu89-inline-CFLAGS = @gnu89_inline@ + have-ssp = @libc_cv_ssp@ ++have-ssp-strong = @libc_cv_ssp_strong@ + have-selinux = @have_selinux@ + have-libaudit = @have_libaudit@ + have-libcap = @have_libcap@ +diff -urN glibc-2.17-c758a686/configure glibc-2.17-c758a686.mod/configure +--- glibc-2.17-c758a686/configure 2014-02-27 10:33:11.561763687 -0500 ++++ glibc-2.17-c758a686.mod/configure 2014-02-27 10:32:28.885852593 -0500 +@@ -610,6 +610,7 @@ + libc_cv_cc_submachine + exceptions + gnu89_inline ++libc_cv_ssp_strong + libc_cv_ssp + fno_unit_at_a_time + libc_cv_output_format +@@ -6758,6 +6759,27 @@ + $as_echo "$libc_cv_ssp" >&6; } + + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector-strong" >&5 ++$as_echo_n "checking for -fstack-protector-strong... " >&6; } ++if ${libc_cv_ssp_strong+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -fstack-protector-strong -xc /dev/null -S -o /dev/null' ++ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; }; then : ++ libc_cv_ssp_strong=yes ++else ++ libc_cv_ssp_strong=no ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ssp_strong" >&5 ++$as_echo "$libc_cv_ssp_strong" >&6; } ++ ++ + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fgnu89-inline" >&5 + $as_echo_n "checking for -fgnu89-inline... " >&6; } + if ${libc_cv_gnu89_inline+:} false; then : +diff -urN glibc-2.17-c758a686/configure.in glibc-2.17-c758a686.mod/configure.in +--- glibc-2.17-c758a686/configure.in 2014-02-27 10:33:11.469763878 -0500 ++++ glibc-2.17-c758a686.mod/configure.in 2014-02-27 10:32:09.171893663 -0500 +@@ -1682,6 +1682,13 @@ + ]) + AC_SUBST(libc_cv_ssp) + ++AC_CACHE_CHECK(for -fstack-protector-strong, libc_cv_ssp_strong, [dnl ++LIBC_TRY_CC_OPTION([$CFLAGS $CPPFLAGS -Werror -fstack-protector-strong], ++ [libc_cv_ssp_strong=yes], ++ [libc_cv_ssp_strong=no]) ++]) ++AC_SUBST(libc_cv_ssp_strong) ++ + AC_CACHE_CHECK(for -fgnu89-inline, libc_cv_gnu89_inline, [dnl + cat > conftest.c < +Date: Wed Mar 19 00:42:30 2014 +0530 + + Fix offset computation for append+ mode on switching from read (BZ #16724) + + The offset computation in write mode uses the fact that _IO_read_end + is kept in sync with the external file offset. This however is not + true when O_APPEND is in effect since switching to write mode ought to + send the external file offset to the end of file without making the + necessary adjustment to _IO_read_end. + + Hence in append mode, offset computation when writing should only + consider the effect of unflushed writes, i.e. from _IO_write_base to + _IO_write_ptr. + +diff --git a/libio/Makefile b/libio/Makefile +index 69c25c0..4bedfad 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -60,7 +60,8 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ + tst-wmemstream1 tst-wmemstream2 \ + bug-memstream1 bug-wmemstream1 \ + tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ +- tst-fwrite-error tst-ftell-active-handler ++ tst-fwrite-error tst-ftell-active-handler \ ++ tst-ftell-append + ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on + # shared localedata objects. +diff --git a/libio/fileops.c b/libio/fileops.c +index cf68dbf..204cfea 100644 +--- a/libio/fileops.c ++++ b/libio/fileops.c +@@ -91,7 +91,9 @@ extern struct __gconv_trans_data __libio_translit attribute_hidden; + + The position in the buffer that corresponds to the position + in external file system is normally _IO_read_end, except in putback +- mode, when it is _IO_save_end. ++ mode, when it is _IO_save_end and also when the file is in append mode, ++ since switching from read to write mode automatically sends the position in ++ the external file system to the end of file. + If the field _fb._offset is >= 0, it gives the offset in + the file as a whole corresponding to eGptr(). (?) + +@@ -966,6 +968,14 @@ do_ftell (_IO_FILE *fp) + /* Adjust for unflushed data. */ + if (!was_writing) + offset -= fp->_IO_read_end - fp->_IO_read_ptr; ++ /* We don't trust _IO_read_end to represent the current file offset when ++ writing in append mode because the value would have to be shifted to ++ the end of the file during a flush. Use the write base instead, along ++ with the new offset we got above when we did a seek to the end of the ++ file. */ ++ else if (append_mode) ++ offset += fp->_IO_write_ptr - fp->_IO_write_base; ++ /* For all other modes, _IO_read_end represents the file offset. */ + else + offset += fp->_IO_write_ptr - fp->_IO_read_end; + } +diff --git a/libio/tst-ftell-append.c b/libio/tst-ftell-append.c +new file mode 100644 +index 0000000..604dc03 +--- /dev/null ++++ b/libio/tst-ftell-append.c +@@ -0,0 +1,169 @@ ++/* Verify that ftell returns the correct value after a read and a write on a ++ file opened in a+ mode. ++ Copyright (C) 2014 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* data points to either char_data or wide_data, depending on whether we're ++ testing regular file mode or wide mode respectively. Similarly, ++ fputs_func points to either fputs or fputws. data_len keeps track of the ++ length of the current data and file_len maintains the current file ++ length. */ ++#define BUF_LEN 4 ++static void *buf; ++static char char_buf[BUF_LEN]; ++static wchar_t wide_buf[BUF_LEN]; ++static const void *data; ++static const char *char_data = "abcdefghijklmnopqrstuvwxyz"; ++static const wchar_t *wide_data = L"abcdefghijklmnopqrstuvwxyz"; ++static size_t data_len; ++static size_t file_len; ++ ++typedef int (*fputs_func_t) (const void *data, FILE *fp); ++fputs_func_t fputs_func; ++ ++typedef void *(*fgets_func_t) (void *s, int size, FILE *stream); ++fgets_func_t fgets_func; ++ ++static int do_test (void); ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" ++ ++static FILE * ++init_file (const char *filename) ++{ ++ FILE *fp = fopen (filename, "w"); ++ if (fp == NULL) ++ { ++ printf ("fopen: %m\n"); ++ return NULL; ++ } ++ ++ int written = fputs_func (data, fp); ++ ++ if (written == EOF) ++ { ++ printf ("fputs failed to write data\n"); ++ fclose (fp); ++ return NULL; ++ } ++ ++ file_len = data_len; ++ ++ fclose (fp); ++ ++ fp = fopen (filename, "a+"); ++ if (fp == NULL) ++ { ++ printf ("fopen(a+): %m\n"); ++ return NULL; ++ } ++ ++ return fp; ++} ++ ++static int ++do_one_test (const char *filename) ++{ ++ FILE *fp = init_file (filename); ++ ++ if (fp == NULL) ++ return 1; ++ ++ void *ret = fgets_func (buf, BUF_LEN, fp); ++ ++ if (ret == NULL) ++ { ++ printf ("read failed: %m\n"); ++ fclose (fp); ++ return 1; ++ } ++ ++ int written = fputs_func (data, fp); ++ ++ if (written == EOF) ++ { ++ printf ("fputs failed to write data\n"); ++ fclose (fp); ++ return 1; ++ } ++ ++ file_len += data_len; ++ ++ long off = ftell (fp); ++ ++ if (off != file_len) ++ { ++ printf ("Incorrect offset %ld, expected %zu\n", off, file_len); ++ fclose (fp); ++ return 1; ++ } ++ else ++ printf ("Correct offset %ld after write.\n", off); ++ ++ return 0; ++} ++ ++/* Run the tests for regular files and wide mode files. */ ++static int ++do_test (void) ++{ ++ int ret = 0; ++ char *filename; ++ int fd = create_temp_file ("tst-ftell-append-tmp.", &filename); ++ ++ if (fd == -1) ++ { ++ printf ("create_temp_file: %m\n"); ++ return 1; ++ } ++ ++ close (fd); ++ ++ /* Tests for regular files. */ ++ puts ("Regular mode:"); ++ fputs_func = (fputs_func_t) fputs; ++ fgets_func = (fgets_func_t) fgets; ++ data = char_data; ++ buf = char_buf; ++ data_len = strlen (char_data); ++ ret |= do_one_test (filename); ++ ++ /* Tests for wide files. */ ++ puts ("Wide mode:"); ++ if (setlocale (LC_ALL, "en_US.UTF-8") == NULL) ++ { ++ printf ("Cannot set en_US.UTF-8 locale.\n"); ++ return 1; ++ } ++ fputs_func = (fputs_func_t) fputws; ++ fgets_func = (fgets_func_t) fgetws; ++ data = wide_data; ++ buf = wide_buf; ++ data_len = wcslen (wide_data); ++ ret |= do_one_test (filename); ++ ++ return ret; ++} +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 3199861..f123add 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -713,9 +713,16 @@ do_ftell_wide (_IO_FILE *fp) + offset += outstop - out; + } + +- /* _IO_read_end coincides with fp._offset, so the actual file +- position is fp._offset - (_IO_read_end - new_write_ptr). */ +- offset -= fp->_IO_read_end - fp->_IO_write_ptr; ++ /* We don't trust _IO_read_end to represent the current file offset ++ when writing in append mode because the value would have to be ++ shifted to the end of the file during a flush. Use the write base ++ instead, along with the new offset we got above when we did a seek ++ to the end of the file. */ ++ if (append_mode) ++ offset += fp->_IO_write_ptr - fp->_IO_write_base; ++ /* For all other modes, _IO_read_end represents the file offset. */ ++ else ++ offset += fp->_IO_write_ptr - fp->_IO_read_end; + } + } + diff --git a/SOURCES/glibc-rh1074410.patch b/SOURCES/glibc-rh1074410.patch new file mode 100644 index 0000000..f1303ea --- /dev/null +++ b/SOURCES/glibc-rh1074410.patch @@ -0,0 +1,656 @@ +commit ae42bbc55a9e05976269026ddabcfb917f6e922f +Author: Siddhesh Poyarekar +Date: Mon Mar 17 18:42:53 2014 +0530 + + Change offset in fdopen only if setting O_APPEND + + fdopen should only be allowed to change the offset in the file it + attaches to if it is setting O_APPEND. If O_APPEND is already set, it + should not change the state of the handle. + +commit ea33158c96c53a64402a772186956c1f5cb556ae +Author: Siddhesh Poyarekar +Date: Tue Mar 11 17:04:49 2014 +0530 + + Fix offset caching for streams and use it for ftell (BZ #16680) + + The ftell implementation was made conservative to ensure that + incorrectly cached offsets never affect it. However, this causes + problems for append mode when a file stream is rewound. Additionally, + the 'clever' trick of using stat to get position for append mode files + caused more problems than it solved and broke old behavior. I have + described the various problems that it caused and then finally the + solution. + + For a and a+ mode files, rewinding the stream should result in ftell + returning 0 as the offset, but the stat() trick caused it to + (incorrectly) always return the end of file. Now I couldn't find + anything in POSIX that specifies the stream position after rewind() + for a file opened in 'a' mode, but for 'a+' mode it should be set to + 0. For 'a' mode too, it probably makes sense to keep it set to 0 in + the interest of retaining old behavior. + + The initial file position for append mode files is implementation + defined, so the implementation could either retain the current file + position or move the position to the end of file. The earlier ftell + implementation would move the offset to end of file for append-only + mode, but retain the old offset for a+ mode. It would also cache the + offset (this detail is important). My patch broke this and would set + the initial position to end of file for both append modes, thus + breaking old behavior. I was ignorant enough to write an incorrect + test case for it too. + + The Change: + + I have now brought back the behavior of seeking to end of file for + append-only streams, but with a slight difference. I don't cache the + offset though, since we would want ftell to query the current file + position through lseek while the stream is not active. Since the + offset is moved to the end of file, we can rely on the file position + reported by lseek and we don't need to resort to the stat() nonsense. + + Finally, the cache is always reliable, except when there are unflished + writes in an append mode stream (i.e. both a and a+). In the latter + case, it is safe to just do an lseek to SEEK_END. The value can be + safely cached too, since the file handle is already active at this + point. Incidentally, this is the only state change we affect in the + file handle (apart from taking locks of course). + + I have also updated the test case to correct my impression of the + initial file position for a+ streams to the initial behavior. I have + verified that this does not break any existing tests in the testsuite + and also passes with the new tests. + +commit b1dbb426e164ad1236c2c76268e03fec5c7a7bbe +Author: Siddhesh Poyarekar +Date: Mon Mar 10 16:20:01 2014 +0530 + + Fix up return codes for tests in tst-ftell-active-handler + + The test functions used a variable ret to store failure codes for + individual tests, but the variable was incorrectly used to record + other failure codes too, resulting in overwriting of the tests status. + This is now fixed by making sure that the ret variable is used only + for recording test failures. + + * libio/tst-ftell-active-handler.c (do_ftell_test): Don't mix + up test status with function return status. + (do_write_test): Likewise. + (do_append_test): Likewise. +diff --git a/libio/fileops.c b/libio/fileops.c +index 2e7bc8d..cf68dbf 100644 +--- a/libio/fileops.c ++++ b/libio/fileops.c +@@ -232,13 +232,18 @@ _IO_file_open (fp, filename, posix_mode, prot, read_write, is32not64) + return NULL; + fp->_fileno = fdesc; + _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); +- if ((read_write & _IO_IS_APPENDING) && (read_write & _IO_NO_READS)) +- if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT) +- == _IO_pos_BAD && errno != ESPIPE) +- { +- close_not_cancel (fdesc); +- return NULL; +- } ++ /* For append mode, send the file offset to the end of the file. Don't ++ update the offset cache though, since the file handle is not active. */ ++ if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS)) ++ == (_IO_IS_APPENDING | _IO_NO_READS)) ++ { ++ _IO_off64_t new_pos = _IO_SYSSEEK (fp, 0, _IO_seek_end); ++ if (new_pos == _IO_pos_BAD && errno != ESPIPE) ++ { ++ close_not_cancel (fdesc); ++ return NULL; ++ } ++ } + _IO_link_in ((struct _IO_FILE_plus *) fp); + return fp; + } +@@ -929,43 +934,13 @@ _IO_file_sync_mmap (_IO_FILE *fp) + return 0; + } + +-/* Get the current file offset using a system call. This is the safest method +- to get the current file offset, since we are sure that we get the current +- state of the file. Before the stream handle is activated (by using fread, +- fwrite, etc.), an application may alter the state of the file descriptor +- underlying it by calling read/write/lseek on it. Using a cached offset at +- this point will result in returning the incorrect value. Same is the case +- when one switches from reading in a+ mode to writing, where the buffer has +- not been flushed - the cached offset would reflect the reading position +- while the actual write position would be at the end of the file. +- +- do_ftell and do_ftell_wide may resort to using the cached offset in some +- special cases instead of calling get_file_offset, but those cases should be +- thoroughly described. */ +-_IO_off64_t +-get_file_offset (_IO_FILE *fp) +-{ +- if ((fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING) +- { +- struct stat64 st; +- bool ret = (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)); +- if (ret) +- return st.st_size; +- else +- return EOF; +- } +- else +- return _IO_SYSSEEK (fp, 0, _IO_seek_cur); +-} +- +- +-/* ftell{,o} implementation. Don't modify any state of the file pointer while +- we try to get the current state of the stream. */ ++/* ftell{,o} implementation. The only time we modify the state of the stream ++ is when we have unflushed writes. In that case we seek to the end and ++ record that offset in the stream object. */ + static _IO_off64_t + do_ftell (_IO_FILE *fp) + { +- _IO_off64_t result = 0; +- bool use_cached_offset = false; ++ _IO_off64_t result, offset = 0; + + /* No point looking at unflushed data if we haven't allocated buffers + yet. */ +@@ -974,39 +949,37 @@ do_ftell (_IO_FILE *fp) + bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base + || _IO_in_put_mode (fp)); + ++ bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING; ++ ++ /* When we have unflushed writes in append mode, seek to the end of the ++ file and record that offset. This is the only time we change the file ++ stream state and it is safe since the file handle is active. */ ++ if (was_writing && append_mode) ++ { ++ result = _IO_SYSSEEK (fp, 0, _IO_seek_end); ++ if (result == _IO_pos_BAD) ++ return EOF; ++ else ++ fp->_offset = result; ++ } ++ + /* Adjust for unflushed data. */ + if (!was_writing) +- result -= fp->_IO_read_end - fp->_IO_read_ptr; ++ offset -= fp->_IO_read_end - fp->_IO_read_ptr; + else +- result += fp->_IO_write_ptr - fp->_IO_read_end; +- +- /* It is safe to use the cached offset when available if there is +- unbuffered data (indicating that the file handle is active) and the +- handle is not for a file open in a+ mode. The latter condition is +- because there could be a scenario where there is a switch from read +- mode to write mode using an fseek to an arbitrary position. In this +- case, there would be unbuffered data due to be appended to the end of +- the file, but the offset may not necessarily be the end of the +- file. It is fine to use the cached offset when the a+ stream is in +- read mode though, since the offset is maintained correctly in that +- case. Note that this is not a comprehensive set of cases when the +- offset is reliable. The offset may be reliable even in some cases +- where there is no unflushed input and the handle is active, but it's +- just that we don't have a way to identify that condition reliably. */ +- use_cached_offset = (result != 0 && fp->_offset != _IO_pos_BAD +- && ((fp->_flags & (_IO_IS_APPENDING | _IO_NO_READS)) +- == (_IO_IS_APPENDING | _IO_NO_READS) +- && was_writing)); ++ offset += fp->_IO_write_ptr - fp->_IO_read_end; + } + +- if (use_cached_offset) +- result += fp->_offset; ++ if (fp->_offset != _IO_pos_BAD) ++ result = fp->_offset; + else +- result += get_file_offset (fp); ++ result = _IO_SYSSEEK (fp, 0, _IO_seek_cur); + + if (result == EOF) + return result; + ++ result += offset; ++ + if (result < 0) + { + __set_errno (EINVAL); +@@ -1016,7 +989,6 @@ do_ftell (_IO_FILE *fp) + return result; + } + +- + _IO_off64_t + _IO_new_file_seekoff (fp, offset, dir, mode) + _IO_FILE *fp; +diff --git a/libio/iofdopen.c b/libio/iofdopen.c +index 3f266f7..b36d21d 100644 +--- a/libio/iofdopen.c ++++ b/libio/iofdopen.c +@@ -59,6 +59,11 @@ _IO_new_fdopen (fd, mode) + int i; + int use_mmap = 0; + ++ /* Decide whether we modify the offset of the file we attach to and seek to ++ the end of file. We only do this if the mode is 'a' and if the file ++ descriptor did not have O_APPEND in its flags already. */ ++ bool do_seek = false; ++ + switch (*mode) + { + case 'r': +@@ -128,6 +133,7 @@ _IO_new_fdopen (fd, mode) + */ + if ((posix_mode & O_APPEND) && !(fd_flags & O_APPEND)) + { ++ do_seek = true; + #ifdef F_SETFL + if (_IO_fcntl (fd, F_SETFL, fd_flags | O_APPEND) == -1) + #endif +@@ -167,6 +173,16 @@ _IO_new_fdopen (fd, mode) + _IO_mask_flags (&new_f->fp.file, read_write, + _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); + ++ /* For append mode, set the file offset to the end of the file if we added ++ O_APPEND to the file descriptor flags. Don't update the offset cache ++ though, since the file handle is not active. */ ++ if (do_seek && ((read_write & (_IO_IS_APPENDING | _IO_NO_READS)) ++ == (_IO_IS_APPENDING | _IO_NO_READS))) ++ { ++ _IO_off64_t new_pos = _IO_SYSSEEK (&new_f->fp.file, 0, _IO_seek_end); ++ if (new_pos == _IO_pos_BAD && errno != ESPIPE) ++ return NULL; ++ } + return &new_f->fp.file; + } + libc_hidden_ver (_IO_new_fdopen, _IO_fdopen) +diff --git a/libio/tst-ftell-active-handler.c b/libio/tst-ftell-active-handler.c +index 54bfe63..e9dc7b3 100644 +--- a/libio/tst-ftell-active-handler.c ++++ b/libio/tst-ftell-active-handler.c +@@ -88,6 +88,107 @@ static size_t file_len; + typedef int (*fputs_func_t) (const void *data, FILE *fp); + fputs_func_t fputs_func; + ++/* Test that ftell output after a rewind is correct. */ ++static int ++do_rewind_test (const char *filename) ++{ ++ int ret = 0; ++ struct test ++ { ++ const char *mode; ++ int fd_mode; ++ size_t old_off; ++ size_t new_off; ++ } test_modes[] = { ++ {"w", O_WRONLY, 0, data_len}, ++ {"w+", O_RDWR, 0, data_len}, ++ {"r+", O_RDWR, 0, data_len}, ++ /* The new offsets for 'a' and 'a+' modes have to factor in the ++ previous writes since they always append to the end of the ++ file. */ ++ {"a", O_WRONLY, 0, 3 * data_len}, ++ {"a+", O_RDWR, 0, 4 * data_len}, ++ }; ++ ++ /* Empty the file before the test so that our offsets are simple to ++ calculate. */ ++ FILE *fp = fopen (filename, "w"); ++ if (fp == NULL) ++ { ++ printf ("Failed to open file for emptying\n"); ++ return 1; ++ } ++ fclose (fp); ++ ++ for (int j = 0; j < 2; j++) ++ { ++ for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) ++ { ++ FILE *fp; ++ int fd; ++ int fileret; ++ ++ printf ("\trewind: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen", ++ test_modes[i].mode); ++ ++ if (j == 0) ++ fileret = get_handles_fdopen (filename, fd, fp, ++ test_modes[i].fd_mode, ++ test_modes[i].mode); ++ else ++ fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); ++ ++ if (fileret != 0) ++ return fileret; ++ ++ /* Write some content to the file, rewind and ensure that the ftell ++ output after the rewind is 0. POSIX does not specify what the ++ behavior is when a file is rewound in 'a' mode, so we retain ++ current behavior, which is to keep the 0 offset. */ ++ size_t written = fputs_func (data, fp); ++ ++ if (written == EOF) ++ { ++ printf ("fputs[1] failed to write data\n"); ++ ret |= 1; ++ } ++ ++ rewind (fp); ++ long offset = ftell (fp); ++ ++ if (offset != test_modes[i].old_off) ++ { ++ printf ("Incorrect old offset. Expected %zu, but got %ld, ", ++ test_modes[i].old_off, offset); ++ ret |= 1; ++ } ++ else ++ printf ("old offset = %ld, ", offset); ++ ++ written = fputs_func (data, fp); ++ ++ if (written == EOF) ++ { ++ printf ("fputs[1] failed to write data\n"); ++ ret |= 1; ++ } ++ ++ /* After this write, the offset in append modes should factor in the ++ implicit lseek to the end of file. */ ++ offset = ftell (fp); ++ if (offset != test_modes[i].new_off) ++ { ++ printf ("Incorrect new offset. Expected %zu, but got %ld\n", ++ test_modes[i].new_off, offset); ++ ret |= 1; ++ } ++ else ++ printf ("new offset = %ld\n", offset); ++ } ++ } ++ return ret; ++} ++ + /* Test that the value of ftell is not cached when the stream handle is not + active. */ + static int +@@ -107,11 +208,13 @@ do_ftell_test (const char *filename) + {"w", O_WRONLY, 0, data_len}, + {"w+", O_RDWR, 0, data_len}, + {"r+", O_RDWR, 0, data_len}, +- /* For 'a' and 'a+' modes, the initial file position should be the ++ /* For the 'a' mode, the initial file position should be the + current end of file. After the write, the offset has data_len +- added to the old value. */ ++ added to the old value. For a+ mode however, the initial file ++ position is the file position of the underlying file descriptor, ++ since it is initially assumed to be in read mode. */ + {"a", O_WRONLY, data_len, 2 * data_len}, +- {"a+", O_RDWR, 2 * data_len, 3 * data_len}, ++ {"a+", O_RDWR, 0, 3 * data_len}, + }; + for (int j = 0; j < 2; j++) + { +@@ -119,17 +222,20 @@ do_ftell_test (const char *filename) + { + FILE *fp; + int fd; ++ int fileret; ++ + printf ("\tftell: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen", + test_modes[i].mode); + + if (j == 0) +- ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, +- test_modes[i].mode); ++ fileret = get_handles_fdopen (filename, fd, fp, ++ test_modes[i].fd_mode, ++ test_modes[i].mode); + else +- ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); ++ fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); + +- if (ret != 0) +- return ret; ++ if (fileret != 0) ++ return fileret; + + long off = ftell (fp); + if (off != test_modes[i].old_off) +@@ -143,13 +249,18 @@ do_ftell_test (const char *filename) + + /* The effect of this write on the offset should be seen in the ftell + call that follows it. */ +- int ret = write (fd, data, data_len); ++ int write_ret = write (fd, data, data_len); ++ if (write_ret != data_len) ++ { ++ printf ("write failed (%m)\n"); ++ ret |= 1; ++ } + off = ftell (fp); + + if (off != test_modes[i].new_off) + { + printf ("Incorrect new offset. Expected %zu but got %ld\n", +- test_modes[i].old_off, off); ++ test_modes[i].new_off, off); + ret |= 1; + } + else +@@ -184,21 +295,23 @@ do_write_test (const char *filename) + { + for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) + { ++ int fileret; + printf ("\twrite: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen", + test_modes[i].mode); + + if (j == 0) +- ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); ++ fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); + else +- ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, +- test_modes[i].mode); ++ fileret = get_handles_fdopen (filename, fd, fp, ++ test_modes[i].fd_mode, ++ test_modes[i].mode); + +- if (ret != 0) +- return ret; ++ if (fileret != 0) ++ return fileret; + + /* Move offset to just before the end of the file. */ +- off_t ret = lseek (fd, file_len - 1, SEEK_SET); +- if (ret == -1) ++ off_t seek_ret = lseek (fd, file_len - 1, SEEK_SET); ++ if (seek_ret == -1) + { + printf ("lseek failed: %m\n"); + ret |= 1; +@@ -258,17 +371,20 @@ do_append_test (const char *filename) + { + for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) + { ++ int fileret; ++ + printf ("\tappend: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen", + test_modes[i].mode); + + if (j == 0) +- ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); ++ fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); + else +- ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, +- test_modes[i].mode); ++ fileret = get_handles_fdopen (filename, fd, fp, ++ test_modes[i].fd_mode, ++ test_modes[i].mode); + +- if (ret != 0) +- return ret; ++ if (fileret != 0) ++ return fileret; + + /* Write some data. */ + size_t written = fputs_func (data, fp); +@@ -298,6 +414,61 @@ do_append_test (const char *filename) + } + } + ++ /* For fdopen in 'a' mode, the file descriptor should not change if the file ++ is already open with the O_APPEND flag set. */ ++ fd = open (filename, O_WRONLY | O_APPEND, 0); ++ if (fd == -1) ++ { ++ printf ("open(O_APPEND) failed: %m\n"); ++ return 1; ++ } ++ ++ off_t seek_ret = lseek (fd, file_len - 1, SEEK_SET); ++ if (seek_ret == -1) ++ { ++ printf ("lseek[O_APPEND][0] failed: %m\n"); ++ ret |= 1; ++ } ++ ++ fp = fdopen (fd, "a"); ++ if (fp == NULL) ++ { ++ printf ("fdopen(O_APPEND) failed: %m\n"); ++ close (fd); ++ return 1; ++ } ++ ++ off_t new_seek_ret = lseek (fd, 0, SEEK_CUR); ++ if (seek_ret == -1) ++ { ++ printf ("lseek[O_APPEND][1] failed: %m\n"); ++ ret |= 1; ++ } ++ ++ printf ("\tappend: fdopen (file, \"a\"): O_APPEND: "); ++ ++ if (seek_ret != new_seek_ret) ++ { ++ printf ("incorrectly modified file offset to %ld, should be %ld", ++ new_seek_ret, seek_ret); ++ ret |= 1; ++ } ++ else ++ printf ("retained current file offset %ld", seek_ret); ++ ++ new_seek_ret = ftello (fp); ++ ++ if (seek_ret != new_seek_ret) ++ { ++ printf (", ftello reported incorrect offset %ld, should be %ld\n", ++ new_seek_ret, seek_ret); ++ ret |= 1; ++ } ++ else ++ printf (", ftello reported correct offset %ld\n", seek_ret); ++ ++ fclose (fp); ++ + return ret; + } + +@@ -309,6 +480,7 @@ do_one_test (const char *filename) + ret |= do_ftell_test (filename); + ret |= do_write_test (filename); + ret |= do_append_test (filename); ++ ret |= do_rewind_test (filename); + + return ret; + } +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 8b2e108..3199861 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -597,12 +597,12 @@ done: + } + + /* ftell{,o} implementation for wide mode. Don't modify any state of the file +- pointer while we try to get the current state of the stream. */ ++ pointer while we try to get the current state of the stream except in one ++ case, which is when we have unflushed writes in append mode. */ + static _IO_off64_t + do_ftell_wide (_IO_FILE *fp) + { + _IO_off64_t result, offset = 0; +- bool use_cached_offset = false; + + /* No point looking for offsets in the buffer if it hasn't even been + allocated. */ +@@ -615,6 +615,20 @@ do_ftell_wide (_IO_FILE *fp) + > fp->_wide_data->_IO_write_base) + || _IO_in_put_mode (fp)); + ++ bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING; ++ ++ /* When we have unflushed writes in append mode, seek to the end of the ++ file and record that offset. This is the only time we change the file ++ stream state and it is safe since the file handle is active. */ ++ if (was_writing && append_mode) ++ { ++ result = _IO_SYSSEEK (fp, 0, _IO_seek_end); ++ if (result == _IO_pos_BAD) ++ return EOF; ++ else ++ fp->_offset = result; ++ } ++ + /* XXX For wide stream with backup store it is not very + reasonable to determine the offset. The pushed-back + character might require a state change and we need not be +@@ -703,37 +717,24 @@ do_ftell_wide (_IO_FILE *fp) + position is fp._offset - (_IO_read_end - new_write_ptr). */ + offset -= fp->_IO_read_end - fp->_IO_write_ptr; + } +- +- /* It is safe to use the cached offset when available if there is +- unbuffered data (indicating that the file handle is active) and +- the handle is not for a file open in a+ mode. The latter +- condition is because there could be a scenario where there is a +- switch from read mode to write mode using an fseek to an arbitrary +- position. In this case, there would be unbuffered data due to be +- appended to the end of the file, but the offset may not +- necessarily be the end of the file. It is fine to use the cached +- offset when the a+ stream is in read mode though, since the offset +- is maintained correctly in that case. Note that this is not a +- comprehensive set of cases when the offset is reliable. The +- offset may be reliable even in some cases where there is no +- unflushed input and the handle is active, but it's just that we +- don't have a way to identify that condition reliably. */ +- use_cached_offset = (offset != 0 && fp->_offset != _IO_pos_BAD +- && ((fp->_flags & (_IO_IS_APPENDING | _IO_NO_READS)) +- == (_IO_IS_APPENDING | _IO_NO_READS) +- && was_writing)); + } + +- if (use_cached_offset) ++ if (fp->_offset != _IO_pos_BAD) + result = fp->_offset; + else +- result = get_file_offset (fp); ++ result = _IO_SYSSEEK (fp, 0, _IO_seek_cur); + + if (result == EOF) + return result; + + result += offset; + ++ if (result < 0) ++ { ++ __set_errno (EINVAL); ++ return EOF; ++ } ++ + return result; + } + diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index 1b6976c..ea79353 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.17-c758a686 %define glibcversion 2.17 -%define glibcrelease 36%{?dist} +%define glibcrelease 55%{?dist} ############################################################################## # If run_glibc_tests is zero then tests are not run for the build. # You must always set run_glibc_tests to one for production builds. @@ -24,14 +24,7 @@ %define xenpackage 0 %endif ############################################################################## -# In RHEL7 for 32-bit POWER the following runtimes are provided: -# - POWER7 (-mcpu=power6 -mtune=power7) -# - POWER8 (-mcpu=power6 -mtune=power8) -# -# We temporarily deploy a POWER6 runtime tuned for POWER7 as our official -# POWER7 runtime because of bug 1019549 which has yet to be fixed. -# -# In RHEL7 for 64-bit POWER the following runtimes are provided: +# In RHEL7 for 32-bit and 64-bit POWER the following runtimes are provided: # - POWER7 (-mcpu=power7 -mtune=power7) # - POWER8 (-mcpu=power7 -mtune=power8) # @@ -41,7 +34,7 @@ # # The POWER5 and POWER6 runtimes are now deprecated and no longer provided # or supported. This means that RHEL7 will only run on POWER7 or newer -# hardware (or POWER6 for 32-bit POWER until bug 1019549 is fixed). +# hardware. # %ifarch ppc %{power64} %define buildpower6 0 @@ -78,7 +71,7 @@ # If the architecture has SDT probe point support then we build glibc with # --enable-systemtap and include all SDT probe points in the library. It is # the eventual goal that all supported arches should be on this list. -%define systemtaparches %{ix86} x86_64 +%define systemtaparches %{ix86} x86_64 ppc ppc64 s390 s390x ############################################################################## # Add -s for a less verbose build output. %define silentrules PARALLELMFLAGS= @@ -128,9 +121,11 @@ Source1: %{glibcsrcdir}-releng.tar.gz # the changes from one bucket to another won't necessarily result in needing # to twiddle the patch because of dependencies on prior patches and the like. +############################################################################## # -# Patches that are highly unlikely to ever be accepted upstream. +# Patches that are unlikely to go upstream or not yet analyzed. # +############################################################################## # Configuration twiddle, not sure there's a good case to get upstream to # change this. @@ -196,16 +191,15 @@ Patch0043: %{name}-rh990388-4.patch Patch0044: %{name}-rh731833-rtkaio.patch Patch0045: %{name}-rh731833-rtkaio-2.patch -# Patch to update translation for stale file handle error -Patch0046: %{name}-rh981332.patch - -# Patch to update the manual to say SunRPC AUTH_DES will prevent FIPS 140-2 -# compliance. -Patch0047: %{name}-rh971589.patch +# Add -fstack-protector-strong support. +Patch0048: %{name}-rh1070806.patch +############################################################################## # # Patches from upstream # +############################################################################## + Patch1000: %{name}-rh905877.patch Patch1001: %{name}-rh958652.patch Patch1002: %{name}-rh977870.patch @@ -258,56 +252,109 @@ Patch1036: %{name}-rh884008.patch Patch1037: %{name}-rh1008298.patch # Add support for rtlddir distinct from slibdir. Patch1038: %{name}-rh950093.patch +Patch1039: %{name}-rh1025612.patch +Patch1040: %{name}-rh1032435.patch +Patch1041: %{name}-rh1020637.patch +# Power value increase for MINSIGSTKSZ and SIGSTKSZ. +Patch1042: %{name}-rh1028652.patch -# Patches submitted, but not yet approved upstream. -# Each should be associated with a BZ. -# Obviously we're not there right now, but that's the goal -# -# http://sourceware.org/ml/libc-alpha/2012-12/msg00103.html -Patch2007: %{name}-rh697421.patch +# Upstream BZ 15601 +Patch1043: %{name}-rh1039496.patch -Patch2011: %{name}-rh757881.patch +Patch1044: %{name}-rh1047983.patch -Patch2013: %{name}-rh741105.patch +Patch1045: %{name}-rh1064945.patch -# Upstream BZ 9954 -Patch2021: %{name}-rh739743.patch +# Patch to update the manual to say SunRPC AUTH_DES will prevent FIPS 140-2 +# compliance. +Patch1046: %{name}-rh971589.patch +# Patch to update translation for stale file handle error. +# Only libc.pot part is sent upstream, the only valid part +# since upstream translations are done by the TP. +Patch1047: %{name}-rh981332.patch -# Upstream BZ 14247 -Patch2023: %{name}-rh827510.patch +# Upstream BZ 9954 +Patch1048: %{name}-rh739743.patch # Upstream BZ 13028 -Patch2026: %{name}-rh841787.patch +Patch1049: %{name}-rh841787.patch -# Upstream BZ 14185 -Patch2027: %{name}-rh819430.patch +# Systemtap malloc probes +Patch1050: %{name}-rh742038.patch # Upstream BZ 15006 -Patch2028: %{name}-rh905184.patch +Patch1051: %{name}-rh905184.patch # Upstream BZ 14256 -Patch2039: %{name}-rh966259.patch +Patch1052: %{name}-rh966259.patch -Patch2040: %{name}-rh979363.patch +# Upstream BZ 15362 +Patch1053: %{name}-rh979363.patch # Upstream BZ 14547 -Patch2041: %{name}-rh989862.patch -Patch2042: %{name}-rh989862-2.patch -Patch2043: %{name}-rh989862-3.patch -Patch2044: %{name}-rh989861.patch - -#Systemtap malloc probes -Patch2045: %{name}-rh742038.patch +Patch1054: %{name}-rh989862.patch +Patch1055: %{name}-rh989862-2.patch +Patch1056: %{name}-rh989862-3.patch +Patch1057: %{name}-rh989861.patch # Upstream s390/s390x bug fixes -Patch2046: glibc-rh804768-bugfix.patch +Patch1058: %{name}-rh804768-bugfix.patch # Upstream BZ 15754 -Patch2047: %{name}-rh990481-CVE-2013-4788.patch +Patch1059: %{name}-rh990481-CVE-2013-4788.patch + +# Upstream BZ 16366 +Patch1060: %{name}-rh1039970.patch + +# Upstream BZ 16365 +Patch1061: %{name}-rh1046199.patch + +# Upstream BZ 16532 +Patch1062: %{name}-rh1063681.patch + +# Upstream BZ 16680 +Patch1063: %{name}-rh1074410.patch + + +############################################################################## +# +# Patches submitted, but not yet approved upstream. +# +############################################################################## +# +# Each should be associated with a BZ. +# Obviously we're not there right now, but that's the goal +# + +# http://sourceware.org/ml/libc-alpha/2012-12/msg00103.html +# Not upstream as of 2014-02-27 +Patch2007: %{name}-rh697421.patch + +# Not upstream as of 2014-02-27 +Patch2011: %{name}-rh757881.patch + +# Not upstream as of 2014-02-27 +Patch2013: %{name}-rh741105.patch + +# Upstream BZ 14247 +# Not upstream as of 2014-02-27. +Patch2023: %{name}-rh827510.patch + +# Upstream BZ 14185 +# Not upstream as of 2014-02-27. +Patch2027: %{name}-rh819430.patch # Fix nscd to use permission names not constants. +# Not upstream as of 2014-02-27. Patch2048: %{name}-rh1025934.patch +# Upstream BZ 16398. +Patch2051: %{name}-rh1048036.patch +Patch2052: %{name}-rh1048123.patch + +# Upstream BZ 16680 +Patch2053: %{name}-rh1074410-2.patch + ############################################################################## # End of glibc patches. ############################################################################## @@ -611,11 +658,11 @@ package or when debugging this package. %patch0017 -p1 %patch0019 -p1 %patch0020 -p1 -%patch2021 -p1 +%patch1048 -p1 %patch2023 -p1 %patch0024 -p1 %patch0025 -p1 -%patch2026 -p1 +%patch1049 -p1 %patch2027 -p1 %patch0028 -p1 %patch0029 -p1 @@ -624,13 +671,13 @@ package or when debugging this package. %patch0032 -p1 %patch0033 -p1 %patch0034 -p1 -%patch2028 -p1 +%patch1051 -p1 %patch0035 -p1 %patch0036 -p1 %patch0037 -p1 %patch1000 -p1 %patch0038 -p1 -%patch2039 -p1 +%patch1052 -p1 %patch1001 -p1 %patch1002 -p1 %patch1003 -p1 @@ -640,18 +687,18 @@ package or when debugging this package. %patch1007 -p1 %patch1008 -p1 %patch1009 -p1 -%patch2040 -p1 +%patch1053 -p1 %patch1010 -p1 %patch0039 -p1 -%patch2041 -p1 -%patch2042 -p1 -%patch2043 -p1 -%patch2044 -p1 +%patch1054 -p1 +%patch1055 -p1 +%patch1056 -p1 +%patch1057 -p1 %patch0040 -p1 %patch0041 -p1 %patch0042 -p1 %patch0043 -p1 -%patch2045 -p0 +%patch1050 -p0 %patch1011 -p1 %patch1012 -p1 %patch1013 -p1 @@ -677,16 +724,31 @@ package or when debugging this package. %patch1033 -p1 %patch0044 -p1 %patch0045 -p1 -%patch0046 -p1 +%patch1047 -p1 %patch1034 -p1 -%patch2046 -p1 +%patch1058 -p1 %patch1035 -p1 -%patch2047 -p1 +%patch1059 -p1 %patch1036 -p1 -%patch0047 -p1 +%patch1046 -p1 %patch1037 -p1 %patch1038 -p1 %patch2048 -p1 +%patch1039 -p1 +%patch1040 -p1 +%patch1041 -p1 +%patch1042 -p1 +%patch1043 -p1 +%patch1060 -p1 +%patch1061 -p1 +%patch2051 -p1 +%patch1044 -p1 +%patch1045 -p1 +%patch2052 -p1 +%patch0048 -p1 +%patch1062 -p1 +%patch1063 -p1 +%patch2053 -p1 ############################################################################## # %%prep - Additional prep required... @@ -771,8 +833,8 @@ GXX="g++ -m64" %endif %ifarch ppc BuildFlags="" -GCC="gcc -mcpu=power6 -mtune=power7" -GXX="g++ -mcpu=power6 -mtune=power7" +GCC="gcc -mcpu=power7 -mtune=power7" +GXX="g++ -mcpu=power7 -mtune=power7" %endif %ifarch %{power64} BuildFlags="" @@ -830,7 +892,7 @@ configure_CFLAGS="$build_CFLAGS -fno-asynchronous-unwind-tables" %ifarch %{systemtaparches} --enable-systemtap \ %endif -%ifarch %{power64} +%ifarch ppc %{power64} --with-cpu=power7 \ %endif --disable-profile --enable-nss-crypt || @@ -882,16 +944,9 @@ build power6 %if %{buildpower8} ( -%ifarch %{power64} AddOns="$AddOns --with-cpu=power7" GCC="$GCC -mcpu=power7 -mtune=power8" GXX="$GXX -mcpu=power7 -mtune=power8" -%endif -%ifarch ppc -# See bug 1019549. We must use POWER6 until we fix POWER7 failures. - GCC="$GCC -mcpu=power6 -mtune=power8" - GXX="$GXX -mcpu=power6 -mtune=power8" -%endif build power8 ) %endif @@ -1749,6 +1804,70 @@ rm -f *.filelist* %endif %changelog +* Wed Mar 19 2014 Siddhesh Poyarekar - 2.17-55 +- Fix up test case for previous ftell bug (#1074410). + +* Tue Mar 18 2014 Siddhesh Poyarekar - 2.17-54 +- Fix offset computation for a+ mode on switching from read (#1074410). + +* Mon Mar 17 2014 Siddhesh Poyarekar - 2.17-53 +- Fix offset caching for streams and use it for ftell (#1074410). +- Change offset in fdopen only if setting O_APPEND (#1074410). +- Fix up return codes for tests in tst-ftell-active-handler (#1074410). + +* Tue Mar 4 2014 Siddhesh Poyarekar - 2.17-52 +- Fix ftell behavior when the stream handle is not active (#1063681). + +* Mon Mar 3 2014 Carlos O'Donell - 2.17-51 +- Build parts of the library with -fstack-protector-strong (#1070806). + +* Fri Feb 28 2014 Siddhesh Poyarekar - 2.17-50 +- Better support for detecting nscd startup failures (#1048123). + +* Wed Feb 26 2014 Siddhesh Poyarekar - 2.17-49 +- Fix ftime gettimeofday internal call returning bogus data (#1064945). + +* Fri Jan 24 2014 Daniel Mach - 2.17-48 +- Mass rebuild 2014-01-24 + +* Mon Jan 13 2014 Patsy Franklin - 2.17-47 +- Rebuild without ppc64p7 package (#1051065). + +* Thu Jan 9 2014 Siddhesh Poyarekar - 2.17-46 +- Enable systemtap probes on S/390 and Power (#1049206). + +* Mon Jan 6 2014 Siddhesh Poyarekar - 2.17-45 +- Revert to flushing buffer for ftell if output buffer does not have sufficient + space for conversion (#1048036). +- Use first name entry for address in /etc/hosts as the canonical name in + getaddrinfo (#1047983). + +* Fri Dec 27 2013 Daniel Mach - 2.17-44 +- Mass rebuild 2013-12-27 + +* Fri Dec 27 2013 Siddhesh Poyarekar - 2.17-43 +- Fix infinite loop on empty netgroups (#1046199). + +* Tue Dec 24 2013 Siddhesh Poyarekar - 2.17-42 +- Return failure for negative lookups from nscd in netgroup cache (#1039970). + +* Fri Dec 20 2013 Carlos O'Donell - 2.17-41 +- Use POWER7 instructions for 32-bit POWER7 and POWER8 runtimes + (#1028661). + +* Thu Dec 12 2013 Patsy Franklin - 2.17-40 +- Change Oriya to Odia. Convert iso-639.def to utf-8. (#1039496) + +* Thu Dec 12 2013 Carlos O'Donell - 2.17-39 +- Increase the value of SIGSTKSZ and MINSIGSTKSZ for Power (#1028652). + +* Fri Nov 29 2013 Siddhesh Poyarekar - 2.17-38 +- S/390: Fix TLS GOT pointer setup (#1020637). + +* Thu Nov 28 2013 Siddhesh Poyarekar - 2.17-37 +- Fix stack overflow due to large AF_INET6 requests (CVE-2013-4458, #1025612). +- Fix reads for sizes larger than INT_MAX in AF_INET lookup (#1032435). + * Fri Nov 8 2013 Carlos O'Donell - 2.17-36 - Enhance NSCD's SELinux support to use dynamic permission names (#1025934).