boot/config.txt
etc/alternatives
etc/collectd.custom
+etc/default/grub
etc/ipsec.conf
etc/ipsec.secrets
etc/ipsec.user.conf
--- /dev/null
+boot/config.txt
+etc/alternatives
+etc/collectd.custom
+etc/ipsec.conf
+etc/ipsec.secrets
+etc/ipsec.user.conf
+etc/ipsec.user.secrets
+etc/localtime
+etc/shadow
+etc/snort/snort.conf
+etc/ssh/ssh_config
+etc/ssh/sshd_config
+etc/ssl/openssl.cnf
+etc/sudoers
+etc/sysconfig/firewall.local
+etc/sysconfig/rc.local
+etc/udev/rules.d/30-persistent-network.rules
+srv/web/ipfire/html/proxy.pac
+var/ipfire/dma
+var/ipfire/time
+var/ipfire/ovpn
+var/lib/alternatives
+var/log/cache
+var/state/dhcp/dhcpd.leases
+var/updatecache
--- /dev/null
+../../../../common/armv5tel/glibc
\ No newline at end of file
--- /dev/null
+etc/system-release
+etc/issue
--- /dev/null
+../../../../common/i586/glibc
\ No newline at end of file
--- /dev/null
+../../../../common/x86_64/glibc
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+############################################################################
+# #
+# This file is part of the IPFire Firewall. #
+# #
+# IPFire is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# IPFire 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 General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with IPFire; if not, write to the Free Software #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+# #
+# Copyright (C) 2016 IPFire-Team <info@ipfire.org>. #
+# #
+############################################################################
+#
+. /opt/pakfire/lib/functions.sh
+/usr/local/bin/backupctrl exclude >/dev/null 2>&1
+
+# Remove old core updates from pakfire cache to save space...
+core=98
+for (( i=1; i<=$core; i++ ))
+do
+ rm -f /var/cache/pakfire/core-upgrade-*-$i.ipfire
+done
+
+# Stop services
+
+# Extract files
+extract_files
+
+# Bugfixes for core96 updater bugs...
+if [ -e /boot/grub/grub.conf ]; then
+ # legacy grub config on xen or citrix conflicts with grub2 config
+ rm /boot/grub/grub.cfg
+fi
+
+if [ -e /boot/grub/grub.cfg ]; then
+ # test if serial console is enabled
+ grep "^7:2345" /etc/inittab > /dev/null
+ if [ "${?}" == "0" ]; then
+ # Fix grub config for serial console
+ sed -i /etc/default/grub \
+ -e "s|\"panic=10\"|\"panic=10 console=ttyS0,115200n8\"|g"
+ sed -i /etc/default/grub \
+ -e "s|^GRUB_TERMINAL=.*||g"
+ sed -i /etc/default/grub \
+ -e "s|^GRUB_SERIAL_COMMAND=.*||g"
+ echo "GRUB_TERMINAL=\"serial\"" >> /etc/default/grub
+ echo "GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=115200\"" >> /etc/default/grub
+ fi
+fi
+
+
+# Update Language cache
+# /usr/local/bin/update-lang-cache
+
+# restart init after glibc update
+telinit u
+
+# Start services
+
+# This update need a reboot...
+touch /var/run/need_reboot
+
+# Finish
+/etc/init.d/fireinfo start
+sendprofile
+# Update grub config to display new core version
+if [ -e /boot/grub/grub.cfg ]; then
+ grub-mkconfig -o /boot/grub/grub.cfg
+fi
+sync
+
+# Don't report the exitcode last command
+exit 0
###############################################################################
# #
# IPFire.org - A linux based firewall #
-# Copyright (C) 2007-2011 IPFire Team <info@ipfire.org> #
+# Copyright (C) 2007-2016 IPFire Team <info@ipfire.org> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-getlogin-r.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-localedata.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-recvmmsg.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh580498.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh582738.patch
+
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh587360.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh582738.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh593396.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh593686.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh601686.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh607010.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh607461.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615090.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615701.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh621959.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh623187.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh625893.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh607010.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh630801.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh631011.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh641128.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh642584.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh643822.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh645672.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh580498.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615090.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh623187.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh646954.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh647448.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615701.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh652661.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh656014.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh656530.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh657572.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh656014.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh661982.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh667974.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh601686.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh676076.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh676591.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh667974.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh625893.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh681054.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688720.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688980.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh689471.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh692177.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh692838.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh694386.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695595.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695963.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh696472.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh697421.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh699724.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh700507.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh703480.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh703481.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh705465.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh711927.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh703481.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh694386.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh676591.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh711987.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh712248.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695595.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695963.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh713134.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh714823.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh718057.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh726517.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh730379.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688980.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh712248.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh731042.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh730379.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh700507.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh699724.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh736346.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh737778.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh738665.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh738763.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh739184.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh711927.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688720.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh726517.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh752122.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh739971.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506-2.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh749188.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh750531.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh751750.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh752122.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh757888.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh766513.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767146.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh750531.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh749188.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767746.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh696472.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh771342.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh657572.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693-2.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh782585.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh784402.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh697421.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh785984.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767146.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh766513.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789209.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh788959.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh788959-2.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789189.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789209.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789238.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789238-2.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh794817.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh794817-2.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh795498.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh797094-1.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh797094-2.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh804686.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789238-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh795498.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh794817-2.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh804689.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh806404.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809602.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh808337.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh788959-2.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh808545.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809602.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809726.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh833717.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh823909.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh826149.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh827362.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh830127.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh841787.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809726.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh806404.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh832516.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh830127.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh832694.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh833717.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837695.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837918.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh841787.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh843673.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh846342.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh847932.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh848082.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837918.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh849203.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh849651.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh827362.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837695.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh804686.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh848082.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh846342.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh852445.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh861167.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh863453.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh864322.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh929388.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970992.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh989558.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh989558-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh919562.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh886968.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905575.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905874.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh916986.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh928318.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh947882.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh952422.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966775.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh834386.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh834386-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh862094.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh851470.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh868808.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh552960.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh663641.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh663641-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh848748.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh952422.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh663641-3.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh916986.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970776.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966778.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh863384.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh629823.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh629823-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh947882.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905874.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh929302.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh928318.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905575.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh988931.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970090.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh995972.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1008310.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1019916.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1022022.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027101.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027261.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1043557.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1039988.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh995972.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh981942.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1032628.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027101.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1025933.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh845218.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1044628.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1085273.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1074342.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1085289.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1082379.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1074353.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1019916.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1028285.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1099025.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1087833.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027261.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905941.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1054846.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1111460.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-1.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-2.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1139571.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1099025-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133810-1.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133810-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1138769.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1171296.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1172044.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1154563.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1170121.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1183533.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1207995.patch
- cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1209375.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1125307.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1176907.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1183534.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1159167.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1023306.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1085312.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1091915.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh859965.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1124204.patch
+ifneq "$(MACHINE_TYPE)" "arm"
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh978098.patch
+endif
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1144019.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1053178.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1144132.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1116050.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1116050-1.patch
+ifneq "$(MACHINE_TYPE)" "arm"
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh867679.patch
+endif
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1088301.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1195453-avx512.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1066724.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1209376.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1207236.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1217186.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812-2.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812-3.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812-4.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256890.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256891.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1291270.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1296031.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1296031-0.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1299319-0.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1299319-1.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-resolv-stack_chk_fail.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-remove-ctors-dtors-output-sections.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-test-installation.pl-nss_test1.patch
+
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-test-installation.pl-libgcc_s.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-2.12-accept-make-versions-4.0-and-greater.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-mq_open.patch
NAME="IPFire" # Software name
SNAME="ipfire" # Short name
VERSION="2.17" # Version number
-CORE="98" # Core Level (Filename)
-PAKFIRE_CORE="97" # Core Level (PAKFIRE)
+CORE="99" # Core Level (Filename)
+PAKFIRE_CORE="98" # Core Level (PAKFIRE)
GIT_BRANCH=`git rev-parse --abbrev-ref HEAD` # Git Branch
SLOGAN="www.ipfire.org" # Software slogan
CONFIG_ROOT=/var/ipfire # Configuration rootdir
-From 6e236b92765cdafb46d19e4907471699accc8269 Mon Sep 17 00:00:00 2001
-From: Siddhesh Poyarekar <siddhesh@redhat.com>
-Date: Thu, 26 Apr 2012 09:18:48 +0530
-Subject: [PATCH] move libgcc_s soname definition to shlib-versions
-
-diff --git a/nptl/sysdeps/pthread/unwind-forcedunwind.c b/nptl/sysdeps/pthread/unwind-forcedunwind.c
-index adce6e7..60dfbe6 100644
---- a/nptl/sysdeps/pthread/unwind-forcedunwind.c
-+++ b/nptl/sysdeps/pthread/unwind-forcedunwind.c
-@@ -21,7 +21,7 @@
+diff -Naur glibc-2.12-2-gc4ccff1.org/nptl/sysdeps/pthread/unwind-forcedunwind.c glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/unwind-forcedunwind.c
+index db56428..495f4b7 100644
+--- glibc-2.12-2-gc4ccff1.org/nptl/sysdeps/pthread/unwind-forcedunwind.c
++++ glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/unwind-forcedunwind.c
+@@ -22,7 +22,7 @@
#include <unwind.h>
#include <pthreadP.h>
#include <sysdep.h>
static void *libgcc_s_handle;
static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
-diff --git a/scripts/test-installation.pl b/scripts/test-installation.pl
-index c4f3d6d..1b22086 100755
---- a/scripts/test-installation.pl
-+++ b/scripts/test-installation.pl
-
-@@ -105,9 +105,10 @@ while (<SOVERSIONS>) {
+diff -Naur glibc-2.12-2-gc4ccff1.org/scripts/test-installation.pl glibc-2.12-2-gc4ccff1/scripts/test-installation.pl
+index 25a919b..3f409ab 100755
+--- glibc-2.12-2-gc4ccff1.org/scripts/test-installation.pl
++++ glibc-2.12-2-gc4ccff1/scripts/test-installation.pl
+@@ -106,9 +106,10 @@ while (<SOVERSIONS>) {
# - libnss1_* from glibc-compat add-on
# - libthread_db since it contains unresolved references
# - it's just a test NSS module
$link_libs .= " -l$name";
$versions{$name} = $version;
}
-diff --git a/shlib-versions b/shlib-versions
-index c530a44..840e08f 100644
---- a/shlib-versions
-+++ b/shlib-versions
-@@ -124,3 +124,7 @@ sparc64.*-.*-.* libBrokenLocale=1 GLIBC_2.2
+diff -Naur glibc-2.12-2-gc4ccff1.org/shlib-versions glibc-2.12-2-gc4ccff1/shlib-versions
+index d3e8407..ac98e49 100644
+--- glibc-2.12-2-gc4ccff1.org/shlib-versions
++++ glibc-2.12-2-gc4ccff1/shlib-versions
+@@ -138,3 +138,7 @@ sparc64.*-.*-.* libBrokenLocale=1 GLIBC_2.2
# The asynchronous name lookup library.
.*-.*-.* libanl=1
+# This defines the libgcc soname version this glibc is to load for
+# asynchronous cancellation to work correctly.
+.*-.*-.* libgcc_s=1
-diff --git a/sysdeps/generic/framestate.c b/sysdeps/generic/framestate.c
-index 3638bbe..3bad5b5 100644
---- a/sysdeps/generic/framestate.c
-+++ b/sysdeps/generic/framestate.c
+diff -Naur glibc-2.12-2-gc4ccff1.org/sysdeps/generic/framestate.c glibc-2.12-2-gc4ccff1/sysdeps/generic/framestate.c
+index 80375bb..edc3539 100644
+--- glibc-2.12-2-gc4ccff1.org/sysdeps/generic/framestate.c
++++ glibc-2.12-2-gc4ccff1/sysdeps/generic/framestate.c
@@ -1,5 +1,5 @@
/* __frame_state_for unwinder helper function wrapper.
- Copyright (C) 2001, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
-@@ -23,7 +23,7 @@
+@@ -24,7 +24,7 @@
#define __frame_state_for fallback_frame_state_for
#include <unwind-dw2.c>
#undef __frame_state_for
typedef struct frame_state * (*framesf)(void *pc, struct frame_state *);
struct frame_state *__frame_state_for (void *pc,
-diff --git a/sysdeps/generic/libgcc_s.h b/sysdeps/generic/libgcc_s.h
+diff -Naur glibc-2.12-2-gc4ccff1.org/sysdeps/generic/libgcc_s.h glibc-2.12-2-gc4ccff1.org/sysdeps/generic/libgcc_s.h
deleted file mode 100644
index e74a103..0000000
---- a/sysdeps/generic/libgcc_s.h
+--- glibc-2.12-2-gc4ccff1.org/sysdeps/generic/libgcc_s.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Name of libgcc_s library provided by gcc. */
-#define LIBGCC_S_SO "libgcc_s.so.1"
-diff --git a/sysdeps/gnu/unwind-resume.c b/sysdeps/gnu/unwind-resume.c
-index 1d3e33f..6afaebd 100644
---- a/sysdeps/gnu/unwind-resume.c
-+++ b/sysdeps/gnu/unwind-resume.c
+diff -Naur glibc-2.12-2-gc4ccff1.org/sysdeps/gnu/unwind-resume.c glibc-2.12-2-gc4ccff1/sysdeps/gnu/unwind-resume.c
+index f8ff0c4..dab4370 100644
+--- glibc-2.12-2-gc4ccff1.org/sysdeps/gnu/unwind-resume.c
++++ glibc-2.12-2-gc4ccff1/sysdeps/gnu/unwind-resume.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>.
-@@ -19,7 +19,7 @@
- #include <dlfcn.h>
- #include <stdio.h>
+@@ -22,7 +22,7 @@
#include <unwind.h>
+ #include <pthreadP.h>
+ #include <sysdep.h>
-#include <libgcc_s.h>
+#include <gnu/lib-names.h>
+ static void *libgcc_s_handle;
static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
- static _Unwind_Reason_Code (*libgcc_s_personality)
---
-1.7.3.4
-
--- /dev/null
+diff -pruN glibc-2.17-c758a686/nptl/Makefile glibc-2.17-c758a686.new/nptl/Makefile
+--- glibc-2.17-c758a686/nptl/Makefile 2013-07-31 11:51:24.882747234 +0530
++++ glibc-2.17-c758a686.new/nptl/Makefile 2013-07-31 11:58:55.964731526 +0530
+@@ -276,10 +276,7 @@ gen-as-const-headers = pthread-errnos.sy
+ LDFLAGS-tst-cond24 = -lrt
+ LDFLAGS-tst-cond25 = -lrt
+
+-# The size is 1MB + 4KB. The extra 4KB has been added to prevent allocatestack
+-# from resizing the input size to avoid the 64K aliasing conflict on Intel
+-# processors.
+-DEFAULT_STACKSIZE=1052672
++DEFAULT_STACKSIZE=1048576
+ CFLAGS-tst-default-attr.c = -DDEFAULT_STACKSIZE=$(DEFAULT_STACKSIZE)
+ tst-default-attr-ENV = GLIBC_PTHREAD_STACKSIZE=$(DEFAULT_STACKSIZE)
+
+diff -pruN glibc-2.17-c758a686/nptl/tst-default-attr.c glibc-2.17-c758a686.new/nptl/tst-default-attr.c
+--- glibc-2.17-c758a686/nptl/tst-default-attr.c 2013-07-31 11:51:24.885747234 +0530
++++ glibc-2.17-c758a686.new/nptl/tst-default-attr.c 2013-07-31 12:18:10.016691337 +0530
+@@ -38,6 +38,7 @@
+
+ /* DEFAULT_STACKSIZE macro is defined in the Makefile. */
+ static size_t stacksize = DEFAULT_STACKSIZE;
++long int pagesize;
+
+ static int
+ verify_stacksize_result (pthread_attr_t *attr)
+@@ -46,12 +47,20 @@ verify_stacksize_result (pthread_attr_t
+
+ RETURN_IF_FAIL (pthread_attr_getstacksize, attr, &stack);
+
+- if (stacksize != stack)
++ /* pthread_create perturbs the stack size by a page if it aligns to 64K to
++ avoid the 64K aliasing conflict. We cannot simply add 4K to the size in
++ the Makefile because it breaks the test on powerpc since the page size
++ there is 64K, resulting in a resize in __pthread_initialize_minimal.
++ Hence, our check is to ensure that the stack size is not more than a page
++ more than the requested size. */
++ if (stack < stacksize || stack > stacksize + pagesize)
+ {
+ printf ("failed to set default stacksize (%zu, %zu)\n", stacksize, stack);
+ return 1;
+ }
+
++ printf ("Requested %zu and got %zu\n", stacksize, stack);
++
+ return 0;
+ }
+
+@@ -101,6 +110,15 @@ run_threads (void)
+ static int
+ do_test (void)
+ {
++ pthread_attr_t attr;
++
++ pagesize = sysconf (_SC_PAGESIZE);
++ if (pagesize < 0)
++ {
++ printf ("sysconf failed: %s\n", strerror (errno));
++ return 1;
++ }
++
+ RETURN_IF_FAIL (run_threads);
+ return 0;
+ }
--- /dev/null
+commit 0699f766b10c86912b75f35bef697106b70c1cf6
+Author: Carlos O'Donell <carlos@redhat.com>
+Date: Thu Apr 10 18:31:53 2014 -0400
+
+ nscd: Make SELinux checks dynamic.
+
+ The SELinux team has indicated to me that glibc's SELinux checks
+ in nscd are not being carried out as they would expect the API
+ to be used today. They would like to move away from static header
+ defines for class and permissions and instead use dynamic checks
+ at runtime that provide an answer which is dependent on the runtime
+ status of SELinux i.e. more dynamic.
+
+ The following patch is a minimal change that moves us forward in
+ this direction.
+
+ It does the following:
+
+ * Stop checking for SELinux headers that define NSCD__SHMEMHOST.
+ Check only for the presence or absence of the library.
+
+ * Don't encode the specific SELinux permission constants into a
+ table at build time, and instead use the symbolic name for the
+ permission as expected.
+
+ * Lookup the "What do we do if we don't know this permission?"
+ policy and use that if we find SELinux's policy is older than
+ the glibc policy e.g. we make a request for a permission that
+ SELinux doesn't know about.
+
+ * Lastly, translate the class and permission and then make
+ the permission check. This is done every time we lookup
+ a permission, and this is the expected way to use the API.
+ SELinux will optimize this for us, and we expect the network
+ latencies to hide these extra library calls.
+
+ Tested on x86, x86-64, and via Fedora Rawhide since November 2013.
+
+ See:
+ https://sourceware.org/ml/libc-alpha/2014-04/msg00179.html
+
+diff --git a/configure b/configure
+index abefcdb..8b0b222 100755
+--- a/configure
++++ b/configure
+@@ -7774,64 +7774,10 @@ else
+ have_selinux=no
+ fi
+
+- # See if we have the SELinux header with the NSCD permissions in it.
+- if test x$have_selinux = xyes ; then
+- { $as_echo "$as_me:$LINENO: checking for NSCD Flask permissions in selinux/av_permissions.h" >&5
+-$as_echo_n "checking for NSCD Flask permissions in selinux/av_permissions.h... " >&6; }
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
+-/* end confdefs.h. */
+-#include <selinux/av_permissions.h>
+-int
+-main ()
+-{
+-#ifdef NSCD__SHMEMHOST
+- return 0;
+- #else
+- #error NSCD__SHMEMHOST not defined
+- #endif
+- ;
+- return 0;
+-}
+-_ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+-$as_echo "$ac_try_echo") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } && {
+- test -z "$ac_c_werror_flag" ||
+- test ! -s conftest.err
+- } && test -s conftest.$ac_objext; then
+- have_selinux=yes
+-else
+- $as_echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+- have_selinux=no
+-fi
+-
+-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+- { $as_echo "$as_me:$LINENO: result: $have_selinux" >&5
+-$as_echo "$have_selinux" >&6; }
+- fi
+-
+ if test x$with_selinux = xyes ; then
+ if test x$have_selinux = xno ; then
+- { { $as_echo "$as_me:$LINENO: error: SELinux explicitly required, but sufficiently recent SELinux library not found" >&5
+-$as_echo "$as_me: error: SELinux explicitly required, but sufficiently recent SELinux library not found" >&2;}
++ { { $as_echo "$as_me:$LINENO: error: SELinux explicitly required, but SELinux library not found" >&5
++$as_echo "$as_me: error: SELinux explicitly required, but SELinux library not found" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+diff --git a/configure.in b/configure.in
+index 6291872..97a9591 100644
+--- a/configure.in
++++ b/configure.in
+@@ -1945,22 +1945,9 @@ else
+ # See if we have the SELinux library
+ AC_CHECK_LIB(selinux, is_selinux_enabled,
+ have_selinux=yes, have_selinux=no)
+- # See if we have the SELinux header with the NSCD permissions in it.
+- if test x$have_selinux = xyes ; then
+- AC_MSG_CHECKING([for NSCD Flask permissions in selinux/av_permissions.h])
+- AC_TRY_COMPILE([#include <selinux/av_permissions.h>],
+- [#ifdef NSCD__SHMEMHOST
+- return 0;
+- #else
+- #error NSCD__SHMEMHOST not defined
+- #endif],
+- have_selinux=yes, have_selinux=no)
+- AC_MSG_RESULT($have_selinux)
+- fi
+-
+ if test x$with_selinux = xyes ; then
+ if test x$have_selinux = xno ; then
+- AC_MSG_ERROR([SELinux explicitly required, but sufficiently recent SELinux library not found])
++ AC_MSG_ERROR([SELinux explicitly required, but SELinux library not found])
+ fi
+ fi
+ fi
+diff --git a/nscd/selinux.c b/nscd/selinux.c
+index 46b0ea9..9a8a5a8 100644
+--- a/nscd/selinux.c
++++ b/nscd/selinux.c
+@@ -28,7 +28,6 @@
+ #include <syslog.h>
+ #include <unistd.h>
+ #include <sys/prctl.h>
+-#include <selinux/av_permissions.h>
+ #include <selinux/avc.h>
+ #include <selinux/flask.h>
+ #include <selinux/selinux.h>
+@@ -44,35 +43,31 @@
+ /* Global variable to tell if the kernel has SELinux support. */
+ int selinux_enabled;
+
+-/* Define mappings of access vector permissions to request types. */
+-static const access_vector_t perms[LASTREQ] =
++/* Define mappings of request type to AVC permission name. */
++static const char *perms[LASTREQ] =
+ {
+- [GETPWBYNAME] = NSCD__GETPWD,
+- [GETPWBYUID] = NSCD__GETPWD,
+- [GETGRBYNAME] = NSCD__GETGRP,
+- [GETGRBYGID] = NSCD__GETGRP,
+- [GETHOSTBYNAME] = NSCD__GETHOST,
+- [GETHOSTBYNAMEv6] = NSCD__GETHOST,
+- [GETHOSTBYADDR] = NSCD__GETHOST,
+- [GETHOSTBYADDRv6] = NSCD__GETHOST,
+- [GETSTAT] = NSCD__GETSTAT,
+- [SHUTDOWN] = NSCD__ADMIN,
+- [INVALIDATE] = NSCD__ADMIN,
+- [GETFDPW] = NSCD__SHMEMPWD,
+- [GETFDGR] = NSCD__SHMEMGRP,
+- [GETFDHST] = NSCD__SHMEMHOST,
+- [GETAI] = NSCD__GETHOST,
+- [INITGROUPS] = NSCD__GETGRP,
+-#ifdef NSCD__GETSERV
+- [GETSERVBYNAME] = NSCD__GETSERV,
+- [GETSERVBYPORT] = NSCD__GETSERV,
+- [GETFDSERV] = NSCD__SHMEMSERV,
+-#endif
+-#ifdef NSCD__GETNETGRP
+- [GETNETGRENT] = NSCD__GETNETGRP,
+- [INNETGR] = NSCD__GETNETGRP,
+- [GETFDNETGR] = NSCD__SHMEMNETGRP,
+-#endif
++ [GETPWBYNAME] = "getpwd",
++ [GETPWBYUID] = "getpwd",
++ [GETGRBYNAME] = "getgrp",
++ [GETGRBYGID] = "getgrp",
++ [GETHOSTBYNAME] = "gethost",
++ [GETHOSTBYNAMEv6] = "gethost",
++ [GETHOSTBYADDR] = "gethost",
++ [GETHOSTBYADDRv6] = "gethost",
++ [SHUTDOWN] = "admin",
++ [GETSTAT] = "getstat",
++ [INVALIDATE] = "admin",
++ [GETFDPW] = "shmempwd",
++ [GETFDGR] = "shmemgrp",
++ [GETFDHST] = "shmemhost",
++ [GETAI] = "gethost",
++ [INITGROUPS] = "getgrp",
++ [GETSERVBYNAME] = "getserv",
++ [GETSERVBYPORT] = "getserv",
++ [GETFDSERV] = "shmemserv",
++ [GETNETGRENT] = "getnetgrp",
++ [INNETGR] = "getnetgrp",
++ [GETFDNETGR] = "shmemnetgrp",
+ };
+
+ /* Store an entry ref to speed AVC decisions. */
+@@ -344,7 +339,16 @@ nscd_avc_init (void)
+
+
+ /* Check the permission from the caller (via getpeercon) to nscd.
+- Returns 0 if access is allowed, 1 if denied, and -1 on error. */
++ Returns 0 if access is allowed, 1 if denied, and -1 on error.
++
++ The SELinux policy, enablement, and permission bits are all dynamic and the
++ caching done by glibc is not entirely correct. This nscd support should be
++ rewritten to use selinux_check_permission. A rewrite is risky though and
++ requires some refactoring. Currently we use symbolic mappings instead of
++ compile time constants (which SELinux upstream says are going away), and we
++ use security_deny_unknown to determine what to do if selinux-policy* doesn't
++ have a definition for the the permission or object class we are looking
++ up. */
+ int
+ nscd_request_avc_has_perm (int fd, request_type req)
+ {
+@@ -354,6 +358,33 @@ nscd_request_avc_has_perm (int fd, request_type req)
+ security_id_t ssid = NULL;
+ security_id_t tsid = NULL;
+ int rc = -1;
++ security_class_t sc_nscd;
++ access_vector_t perm;
++ int avc_deny_unknown;
++
++ /* Check if SELinux denys or allows unknown object classes
++ and permissions. It is 0 if they are allowed, 1 if they
++ are not allowed and -1 on error. */
++ if ((avc_deny_unknown = security_deny_unknown ()) == -1)
++ dbg_log (_("Error querying policy for undefined object classes "
++ "or permissions."));
++
++ /* Get the security class for nscd. If this fails we will likely be
++ unable to do anything unless avc_deny_unknown is 0. */
++ sc_nscd = string_to_security_class ("nscd");
++ if (perm == 0 && avc_deny_unknown == 1)
++ dbg_log (_("Error getting security class for nscd."));
++
++ /* Convert permission to AVC bits. */
++ perm = string_to_av_perm (sc_nscd, perms[req]);
++ if (perm == 0 && avc_deny_unknown == 1)
++ dbg_log (_("Error translating permission name "
++ "\"%s\" to access vector bit."), perms[req]);
++
++ /* If the nscd security class was not found or perms were not
++ found and AVC does not deny unknown values then allow it. */
++ if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0)
++ return 0;
+
+ if (getpeercon (fd, &scon) < 0)
+ {
+@@ -372,15 +403,13 @@ nscd_request_avc_has_perm (int fd, request_type req)
+ goto out;
+ }
+
+-#ifndef NSCD__GETSERV
+- if (perms[req] == 0)
+- {
+- dbg_log (_("compile-time support for database policy missing"));
+- goto out;
+- }
+-#endif
+-
+- rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0;
++ /* The SELinux API for avc_has_perm conflates access denied and error into
++ the return code -1, while nscd_request_avs_has_perm has distinct error
++ (-1) and denied (1) return codes. We map the avc_has_perm access denied or
++ error into an access denied at the nscd interface level (we do accurately
++ report error for the getpeercon, getcon, and avc_context_to_sid interfaces
++ used above). */
++ rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0;
+
+ out:
+ if (scon)
--- /dev/null
+From a5675717e35a02a3eba7e13701c6f9c0d7222e13 Mon Sep 17 00:00:00 2001
+From: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date: Fri, 7 Jun 2013 14:50:23 -0500
+Subject: [PATCH 2/2] PowerPC: gettimeofday optimization by using IFUNC
+
+Backport of ef26eece6331a1f6d959818e37c438cc7ce68e53 from master.
+---
+ sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h | 10 ++++
+ sysdeps/unix/sysv/linux/powerpc/gettimeofday.c | 49 +++++++++++++++-------
+ 2 files changed, 44 insertions(+), 15 deletions(-)
+
+commit 76a9b9986141b1a7d9fd290c349d27fcee780c7a
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date: Thu Nov 7 05:34:22 2013 -0600
+
+ PowerPC: Fix vDSO missing ODP entries
+
+ This patch fixes the vDSO symbol used directed in IFUNC resolver where
+ they do not have an associated ODP entry leading to undefined behavior
+ in some cases. It adds an artificial OPD static entry to such cases
+ and set its TOC to non 0 to avoid triggering lazy resolutions.
+
+commit d98720e07f67fbeec00f9e1347840404240d3c48
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date: Mon Jan 20 12:29:51 2014 -0600
+
+ PowerPC: Fix gettimeofday ifunc selection
+
+ The IFUNC selector for gettimeofday runs before _libc_vdso_platform_setup where
+ __vdso_gettimeofday is set. The selector then sets __gettimeofday (the internal
+ version used within GLIBC) to use the system call version instead of the vDSO one.
+ This patch changes the check if vDSO is available to get its value directly
+ instead of rely on __vdso_gettimeofday.
+
+ This patch changes it by getting the vDSO value directly.
+
+ It fixes BZ#16431.
+
+diff -pruN a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h 2014-05-20 14:46:51.026871920 +0530
++++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h 2014-05-20 14:44:39.294877321 +0530
+@@ -33,6 +33,36 @@ extern void *__vdso_get_tbfreq;
+
+ extern void *__vdso_getcpu;
+
++#if defined(__PPC64__) || defined(__powerpc64__)
++/* The correct solution is for _dl_vdso_vsym to return the address of the OPD
++ for the kernel VDSO function. That address would then be stored in the
++ __vdso_* variables and returned as the result of the IFUNC resolver function.
++ Yet, the kernel does not contain any OPD entries for the VDSO functions
++ (incomplete implementation). However, PLT relocations for IFUNCs still expect
++ the address of an OPD to be returned from the IFUNC resolver function (since
++ PLT entries on PPC64 are just copies of OPDs). The solution for now is to
++ create an artificial static OPD for each VDSO function returned by a resolver
++ function. The TOC value is set to a non-zero value to avoid triggering lazy
++ symbol resolution via .glink0/.plt0 for a zero TOC (requires thread-safe PLT
++ sequences) when the dynamic linker isn't prepared for it e.g. RTLD_NOW. None
++ of the kernel VDSO routines use the TOC or AUX values so any non-zero value
++ will work. Note that function pointer comparisons will not use this artificial
++ static OPD since those are resolved via ADDR64 relocations and will point at
++ the non-IFUNC default OPD for the symbol. Lastly, because the IFUNC relocations
++ are processed immediately at startup the resolver functions and this code need
++ not be thread-safe, but if the caller writes to a PLT slot it must do so in a
++ thread-safe manner with all the required barriers. */
++#define VDSO_IFUNC_RET(value) \
++ ({ \
++ static Elf64_FuncDesc vdso_opd = { .fd_toc = ~0x0 }; \
++ vdso_opd.fd_func = (Elf64_Addr)value; \
++ &vdso_opd; \
++ })
++
++#else
++#define VDSO_IFUNC_RET(value) ((void *) (value))
++#endif
++
+ #endif
+
+ #endif /* _LIBC_VDSO_H */
+diff -pruN a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c 2010-05-04 16:57:23.000000000 +0530
++++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c 2014-05-20 14:44:39.298877321 +0530
+@@ -16,27 +16,51 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <sysdep.h>
+-#include <bp-checks.h>
+-#include <stddef.h>
+ #include <sys/time.h>
+-#include <time.h>
+-#include <hp-timing.h>
+
+-#undef __gettimeofday
+-#include <bits/libc-vdso.h>
++#ifdef SHARED
+
+-/* Get the current time of day and timezone information,
+- putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
+- Returns 0 on success, -1 on errors. */
+-
+-int
+-__gettimeofday (tv, tz)
+- struct timeval *tv;
+- struct timezone *tz;
++# include <dl-vdso.h>
++# include <bits/libc-vdso.h>
++# include <dl-machine.h>
++
++void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday");
++
++static int
++__gettimeofday_syscall (struct timeval *tv, struct timezone *tz)
++{
++ return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
++}
++
++void *
++gettimeofday_ifunc (void)
++{
++ PREPARE_VERSION (linux2615, "LINUX_2.6.15", 123718565);
++
++ /* If the vDSO is not available we fall back syscall. */
++ void *vdso_gettimeofday = _dl_vdso_vsym ("__kernel_gettimeofday", &linux2615);
++ return (vdso_gettimeofday ? VDSO_IFUNC_RET (vdso_gettimeofday)
++ : (void*)__gettimeofday_syscall);
++}
++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");
++
++#else
++
++# include <sysdep.h>
++# include <errno.h>
++
++int
++__gettimeofday (struct timeval *tv, struct timezone *tz)
+ {
+- return INLINE_VSYSCALL (gettimeofday, 2, CHECK_1 (tv), CHECK_1 (tz));
++ return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
+ }
+
++#endif
+ INTDEF (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
--- /dev/null
+commit 9a3c6a6ff602c88d7155139a7d7d0000b7b7e946
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Thu Jan 2 10:05:27 2014 +0530
+
+ Fix return code from getent netgroup when the netgroup is not found (bz #16366)
+
+ nscd incorrectly returns a success even when the netgroup in question
+ is not found and adds a positive result in the cache. this patch
+ fixes this behaviour by adding a negative lookup entry to cache and
+ returning an error when the netgroup is not found.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 50936ee..9fc1664 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -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, int fd, request_header *req,
+ 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, int fd, request_header *req,
+ && __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, int fd, request_header *req,
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
++ found = true;
+ union
+ {
+ enum nss_status (*f) (struct __netgrent *, char *, size_t,
+@@ -326,6 +350,15 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ }
+ }
+
++ /* 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. */
--- /dev/null
+commit af37a8a3496327a6e5617a2c76f17aa1e8db835e
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Mon Jan 27 11:32:44 2014 +0530
+
+ Avoid undefined behaviour in netgroupcache
+
+ Using a buffer after it has been reallocated is undefined behaviour,
+ so get offsets of the triplets in the old buffer before reallocating
+ it.
+
+commit 5d41dadf31bc8a2f9c34c40d52a442d3794e405c
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Fri Jan 24 13:51:15 2014 +0530
+
+ Adjust pointers to triplets in netgroup query data (BZ #16474)
+
+ The _nss_*_getnetgrent_r query populates the netgroup results in the
+ allocated buffer and then sets the result triplet to point to strings
+ in the buffer. This is a problem when the buffer is reallocated since
+ the pointers to the triplet strings are no longer valid. The pointers
+ need to be adjusted so that they now point to strings in the
+ reallocated buffer.
+
+commit 980cb5180e1b71224a57ca52b995c959b7148c09
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Thu Jan 16 10:20:22 2014 +0530
+
+ Don't use alloca in addgetnetgrentX (BZ #16453)
+
+ addgetnetgrentX has a buffer which is grown as per the needs of the
+ requested size either by using alloca or by falling back to malloc if
+ the size is larger than 1K. There are two problems with the alloca
+ bits: firstly, it doesn't really extend the buffer since it does not
+ use the return value of the extend_alloca macro, which is the location
+ of the reallocated buffer. Due to this the buffer does not actually
+ extend itself and hence a subsequent write may overwrite stuff on the
+ stack.
+
+ The second problem is more subtle - the buffer growth on the stack is
+ discontinuous due to block scope local variables. Combine that with
+ the fact that unlike realloc, extend_alloca does not copy over old
+ content and you have a situation where the buffer just has garbage in
+ the space where it should have had data.
+
+ This could have been fixed by adding code to copy over old data
+ whenever we call extend_alloca, but it seems unnecessarily
+ complicated. This code is not exactly a performance hotspot (it's
+ called when there is a cache miss, so factors like network lookup or
+ file reads will dominate over memory allocation/reallocation), so this
+ premature optimization is unnecessary.
+
+ Thanks Brad Hubbard <bhubbard@redhat.com> for his help with debugging
+ the problem.
+
+diff -pruN glibc-2.12-2-gc4ccff1/nscd/netgroupcache.c glibc-2.12-2-gc4ccff1.patched/nscd/netgroupcache.c
+--- glibc-2.12-2-gc4ccff1/nscd/netgroupcache.c 2014-04-09 12:13:58.618582111 +0530
++++ glibc-2.12-2-gc4ccff1.patched/nscd/netgroupcache.c 2014-04-09 12:07:21.486598665 +0530
+@@ -93,7 +93,6 @@ addgetnetgrentX (struct database_dyn *db
+ size_t buffilled = sizeof (*dataset);
+ char *buffer = NULL;
+ size_t nentries = 0;
+- bool use_malloc = false;
+ size_t group_len = strlen (key) + 1;
+ union
+ {
+@@ -138,7 +137,7 @@ addgetnetgrentX (struct database_dyn *db
+ }
+
+ memset (&data, '\0', sizeof (data));
+- buffer = alloca (buflen);
++ buffer = xmalloc (buflen);
+ first_needed.elem.next = &first_needed.elem;
+ memcpy (first_needed.elem.name, key, group_len);
+ data.needed_groups = &first_needed.elem;
+@@ -218,21 +217,24 @@ addgetnetgrentX (struct database_dyn *db
+
+ if (buflen - req->key_len - bufused < needed)
+ {
+- size_t newsize = MAX (2 * buflen,
+- buflen + 2 * needed);
+- if (use_malloc || newsize > 1024 * 1024)
+- {
+- buflen = newsize;
+- char *newbuf = xrealloc (use_malloc
+- ? buffer
+- : NULL,
+- buflen);
+-
+- buffer = newbuf;
+- use_malloc = true;
+- }
+- else
+- extend_alloca (buffer, buflen, newsize);
++ buflen += MAX (buflen, 2 * needed);
++ /* Save offset in the old buffer. We don't
++ bother with the NULL check here since
++ we'll do that later anyway. */
++ size_t nhostdiff = nhost - buffer;
++ size_t nuserdiff = nuser - buffer;
++ size_t ndomaindiff = ndomain - buffer;
++
++ char *newbuf = xrealloc (buffer, buflen);
++ /* Fix up the triplet pointers into the new
++ buffer. */
++ nhost = (nhost ? newbuf + nhostdiff
++ : NULL);
++ nuser = (nuser ? newbuf + nuserdiff
++ : NULL);
++ ndomain = (ndomain ? newbuf + ndomaindiff
++ : NULL);
++ buffer = newbuf;
+ }
+
+ nhost = memcpy (buffer + bufused,
+@@ -299,18 +301,8 @@ addgetnetgrentX (struct database_dyn *db
+ }
+ else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
+ {
+- size_t newsize = 2 * buflen;
+- if (use_malloc || newsize > 1024 * 1024)
+- {
+- buflen = newsize;
+- char *newbuf = xrealloc (use_malloc
+- ? buffer : NULL, buflen);
+-
+- buffer = newbuf;
+- use_malloc = true;
+- }
+- else
+- extend_alloca (buffer, buflen, newsize);
++ buflen *= 2;
++ buffer = xrealloc (buffer, buflen);
+ }
+ }
+
+@@ -446,8 +438,7 @@ addgetnetgrentX (struct database_dyn *db
+ }
+
+ out:
+- if (use_malloc)
+- free (buffer);
++ free (buffer);
+
+ *resultp = dataset;
+
--- /dev/null
+#
+# Based on the commit:
+#
+# commit 6c82a2f8d7c8e21e39237225c819f182ae438db3
+# Author: Carlos O'Donell <carlos@redhat.com>
+# Date: Fri Sep 6 01:02:30 2013 -0400
+#
+# Coordinate IPv6 definitions for Linux and glibc
+#
+# This change synchronizes the glibc headers with the Linux kernel
+# headers and arranges to coordinate the definition of structures
+# already defined the Linux kernel UAPI headers.
+#
+# It is now safe to include glibc's netinet/in.h or Linux's linux/in6.h
+# in any order in a userspace application and you will get the same
+# ABI. The ABI is guaranteed by UAPI and glibc.
+#
+# 2013-09-05 Carlos O'Donell <carlos@redhat.com>
+# Cong Wang <amwang@redhat.com>
+#
+# * sysdeps/unix/sysv/linux/bits/in.h
+# [_UAPI_LINUX_IN6_H]: Define __USE_KERNEL_IPV6_DEFS.
+# * inet/netinet/in.h: Move in_addr definition and bits/in.h inclusion
+# before __USE_KERNEL_IPV6_DEFS uses.
+# * inet/netinet/in.h [!__USE_KERNEL_IPV6_DEFS]: Define IPPROTO_MH, and
+# IPPROTO_BEETPH.
+# [__USE_KERNEL_IPV6_DEFS]: Don't define any of IPPROTO_*, in6_addr,
+# sockaddr_in6, or ipv6_mreq.
+#
+diff -urN glibc-2.12-2-gc4ccff1/inet/netinet/in.h glibc-2.12-2-gc4ccff1.mod/inet/netinet/in.h
+--- glibc-2.12-2-gc4ccff1/inet/netinet/in.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/inet/netinet/in.h 2015-02-18 13:06:56.436802873 -0500
+@@ -28,13 +28,21 @@
+
+ __BEGIN_DECLS
+
++/* Internet address. */
++typedef uint32_t in_addr_t;
++struct in_addr
++ {
++ in_addr_t s_addr;
++ };
++
++/* Get system-specific definitions. */
++#include <bits/in.h>
++
+ /* Standard well-defined IP protocols. */
+ enum
+ {
+ IPPROTO_IP = 0, /* Dummy protocol for TCP. */
+ #define IPPROTO_IP IPPROTO_IP
+- IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */
+-#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS
+ IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
+ #define IPPROTO_ICMP IPPROTO_ICMP
+ IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */
+@@ -57,10 +65,6 @@
+ #define IPPROTO_DCCP IPPROTO_DCCP
+ IPPROTO_IPV6 = 41, /* IPv6 header. */
+ #define IPPROTO_IPV6 IPPROTO_IPV6
+- IPPROTO_ROUTING = 43, /* IPv6 routing header. */
+-#define IPPROTO_ROUTING IPPROTO_ROUTING
+- IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */
+-#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT
+ IPPROTO_RSVP = 46, /* Reservation Protocol. */
+ #define IPPROTO_RSVP IPPROTO_RSVP
+ IPPROTO_GRE = 47, /* General Routing Encapsulation. */
+@@ -69,14 +73,10 @@
+ #define IPPROTO_ESP IPPROTO_ESP
+ IPPROTO_AH = 51, /* authentication header. */
+ #define IPPROTO_AH IPPROTO_AH
+- IPPROTO_ICMPV6 = 58, /* ICMPv6. */
+-#define IPPROTO_ICMPV6 IPPROTO_ICMPV6
+- IPPROTO_NONE = 59, /* IPv6 no next header. */
+-#define IPPROTO_NONE IPPROTO_NONE
+- IPPROTO_DSTOPTS = 60, /* IPv6 destination options. */
+-#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS
+ IPPROTO_MTP = 92, /* Multicast Transport Protocol. */
+ #define IPPROTO_MTP IPPROTO_MTP
++ IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET. */
++#define IPPROTO_BEETPH IPPROTO_BEETPH
+ IPPROTO_ENCAP = 98, /* Encapsulation Header. */
+ #define IPPROTO_ENCAP IPPROTO_ENCAP
+ IPPROTO_PIM = 103, /* Protocol Independent Multicast. */
+@@ -92,6 +92,28 @@
+ IPPROTO_MAX
+ };
+
++/* If __USER_KERNEL_IPV6_DEFS is defined then the user has included the kernel
++ network headers first and we should use those ABI-identical definitions
++ instead of our own. */
++#ifndef __USE_KERNEL_IPV6_DEFS
++enum
++ {
++ IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */
++#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS
++ IPPROTO_ROUTING = 43, /* IPv6 routing header. */
++#define IPPROTO_ROUTING IPPROTO_ROUTING
++ IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */
++#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT
++ IPPROTO_ICMPV6 = 58, /* ICMPv6. */
++#define IPPROTO_ICMPV6 IPPROTO_ICMPV6
++ IPPROTO_NONE = 59, /* IPv6 no next header. */
++#define IPPROTO_NONE IPPROTO_NONE
++ IPPROTO_DSTOPTS = 60, /* IPv6 destination options. */
++#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS
++ IPPROTO_MH = 135, /* IPv6 mobility header. */
++#define IPPROTO_MH IPPROTO_MH
++ };
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+
+ /* Type to represent a port. */
+ typedef uint16_t in_port_t;
+@@ -136,15 +158,6 @@
+ IPPORT_USERRESERVED = 5000
+ };
+
+-
+-/* Internet address. */
+-typedef uint32_t in_addr_t;
+-struct in_addr
+- {
+- in_addr_t s_addr;
+- };
+-
+-
+ /* Definitions of the bits in an Internet address integer.
+
+ On subnets, host and network parts are found according to
+@@ -193,7 +206,7 @@
+ #define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002) /* 224.0.0.2 */
+ #define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff) /* 224.0.0.255 */
+
+-
++#ifndef __USE_KERNEL_IPV6_DEFS
+ /* IPv6 address */
+ struct in6_addr
+ {
+@@ -211,6 +224,7 @@
+ # define s6_addr32 __in6_u.__u6_addr32
+ #endif
+ };
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+
+ extern const struct in6_addr in6addr_any; /* :: */
+ extern const struct in6_addr in6addr_loopback; /* ::1 */
+@@ -235,6 +249,7 @@
+ sizeof (struct in_addr)];
+ };
+
++#ifndef __USE_KERNEL_IPV6_DEFS
+ /* Ditto, for IPv6. */
+ struct sockaddr_in6
+ {
+@@ -244,7 +259,7 @@
+ struct in6_addr sin6_addr; /* IPv6 address */
+ uint32_t sin6_scope_id; /* IPv6 scope-id */
+ };
+-
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+
+ #if defined __USE_MISC || defined __USE_GNU
+ /* IPv4 multicast request. */
+@@ -270,7 +285,7 @@
+ };
+ #endif
+
+-
++#ifndef __USE_KERNEL_IPV6_DEFS
+ /* Likewise, for IPv6. */
+ struct ipv6_mreq
+ {
+@@ -280,7 +295,7 @@
+ /* local interface */
+ unsigned int ipv6mr_interface;
+ };
+-
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+
+ #if defined __USE_MISC || defined __USE_GNU
+ /* Multicast group request. */
+@@ -351,10 +366,6 @@
+ * sizeof (struct sockaddr_storage)))
+ #endif
+
+-
+-/* Get system-specific definitions. */
+-#include <bits/in.h>
+-
+ /* Functions to convert between host and network byte order.
+
+ Please note that these functions normally take `unsigned long int' or
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/bits/in.h glibc-2.12-2-gc4ccff1.mod/sysdeps/unix/sysv/linux/bits/in.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/bits/in.h 2015-02-18 13:04:15.547734092 -0500
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/unix/sysv/linux/bits/in.h 2015-02-18 13:06:56.436802873 -0500
+@@ -22,6 +22,18 @@
+ # error "Never use <bits/in.h> directly; include <netinet/in.h> instead."
+ #endif
+
++/* If the application has already included linux/in6.h from a linux-based
++ kernel then we will not define the IPv6 IPPROTO_* defines, in6_addr (nor the
++ defines), sockaddr_in6, or ipv6_mreq. The ABI used by the linux-kernel and
++ glibc match exactly. Neither the linux kernel nor glibc should break this
++ ABI without coordination. */
++#ifdef _UAPI_LINUX_IN6_H
++/* This is not quite the same API since the kernel always defines s6_addr16 and
++ s6_addr32. This is not a violation of POSIX since POSIX says "at least the
++ following member" and that holds true. */
++# define __USE_KERNEL_IPV6_DEFS
++#endif
++
+ /* Options for use with `getsockopt' and `setsockopt' at the IP level.
+ The first word in the comment at the right is the data type used;
+ "bool" means a boolean value stored in an `int'. */
--- /dev/null
+commit fbd6b5a4052316f7eb03c4617eebfaafc59dcc06
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Thu Mar 27 07:15:22 2014 +0530
+
+ Fix nscd lookup for innetgr when netgroup has wildcards (BZ #16758)
+
+ nscd works correctly when the request in innetgr is a wildcard,
+ i.e. when one or more of host, user or domain parameters is NULL.
+ However, it does not work when the the triplet in the netgroup
+ definition has a wildcard. This is easy to reproduce for a triplet
+ defined as follows:
+
+ foonet (,foo,)
+
+ Here, an innetgr call that looks like this:
+
+ innetgr ("foonet", "foohost", "foo", NULL);
+
+ should succeed and so should:
+
+ innetgr ("foonet", NULL, "foo", "foodomain");
+
+ It does succeed with nscd disabled, but not with nscd enabled. This
+ fix adds this additional check for all three parts of the triplet so
+ that it gives the correct result.
+
+ [BZ #16758]
+ * nscd/netgroupcache.c (addinnetgrX): Succeed if triplet has
+ blank values.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 5ba1e1f..5d15aa4 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -560,15 +560,19 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
+ {
+ bool success = true;
+
+- if (host != NULL)
++ /* For the host, user and domain in each triplet, we assume success
++ if the value is blank because that is how the wildcard entry to
++ match anything is stored in the netgroup cache. */
++ if (host != NULL && *triplets != '\0')
+ success = strcmp (host, triplets) == 0;
+ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
+
+- if (success && user != NULL)
++ if (success && user != NULL && *triplets != '\0')
+ success = strcmp (user, triplets) == 0;
+ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
+
+- if (success && (domain == NULL || strcmp (domain, triplets) == 0))
++ if (success && (domain == NULL || *triplets == '\0'
++ || strcmp (domain, triplets) == 0))
+ {
+ dataset->resp.result = 1;
+ break;
--- /dev/null
+diff --git a/malloc/Makefile b/malloc/Makefile
+index e7ec1ab..5330a3b 100644
+--- a/malloc/Makefile
++++ b/malloc/Makefile
+@@ -27,7 +27,8 @@ all:
+ dist-headers := malloc.h
+ headers := $(dist-headers) obstack.h mcheck.h
+ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
+- tst-mallocstate tst-mcheck tst-mallocfork tst-trim1
++ tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
++ tst-malloc-backtrace
+ test-srcs = tst-mtrace
+
+ distribute = thread-m.h mtrace.pl mcheck-init.c stackinfo.h memusage.h \
+@@ -49,6 +50,9 @@ extra-libs-others = $(extra-libs)
+ libmemusage-routines = memusage
+ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
+
++$(objpfx)tst-malloc-backtrace: $(common-objpfx)nptl/libpthread.so \
++ $(common-objpfx)nptl/libpthread_nonshared.a
++
+ # These should be removed by `make clean'.
+ extra-objs = mcheck-init.o libmcheck.a
+
+diff --git a/malloc/arena.c b/malloc/arena.c
+index 18bea2b..5180516 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -123,7 +123,7 @@ int __malloc_initialized = -1;
+
+ #ifdef PER_THREAD
+ #define arena_lock(ptr, size) do { \
+- if(ptr) \
++ if(ptr && !arena_is_corrupt (ptr)) \
+ (void)mutex_lock(&ptr->mutex); \
+ else \
+ ptr = arena_get2(ptr, (size), false); \
+@@ -1011,7 +1011,21 @@ reused_arena (bool retrying)
+ if (retrying && result == &main_arena)
+ result = result->next;
+
+- /* No arena available. Wait for the next in line. */
++ /* Make sure that the arena we get is not corrupted. */
++ mstate begin = result;
++ while (arena_is_corrupt (result))
++ {
++ result = result->next;
++ if (result == begin)
++ break;
++ }
++
++ /* We could not find any arena that was either not corrupted or not the one
++ we wanted to avoid. */
++ if (result == begin)
++ return NULL;
++
++ /* No arena available without contention. Wait for the next in line. */
+ (void)mutex_lock(&result->mutex);
+
+ out:
+diff --git a/malloc/hooks.c b/malloc/hooks.c
+index cc83d21..38d2542 100644
+--- a/malloc/hooks.c
++++ b/malloc/hooks.c
+@@ -220,7 +220,8 @@ top_check()
+ return 0;
+
+ mutex_unlock(&main_arena);
+- malloc_printerr (check_action, "malloc: top chunk is corrupt", t);
++ malloc_printerr (check_action, "malloc: top chunk is corrupt", t,
++ &main_arena);
+ mutex_lock(&main_arena);
+
+ /* Try to set up a new top chunk. */
+@@ -283,7 +284,7 @@ free_check(mem, caller) Void_t* mem; const Void_t *caller;
+ if(!p) {
+ (void)mutex_unlock(&main_arena.mutex);
+
+- malloc_printerr(check_action, "free(): invalid pointer", mem);
++ malloc_printerr(check_action, "free(): invalid pointer", mem, &main_arena);
+ return;
+ }
+ #if HAVE_MMAP
+@@ -329,7 +330,8 @@ realloc_check(oldmem, bytes, caller)
+ const mchunkptr oldp = mem2chunk_check(oldmem, &magic_p);
+ (void)mutex_unlock(&main_arena.mutex);
+ if(!oldp) {
+- malloc_printerr(check_action, "realloc(): invalid pointer", oldmem);
++ malloc_printerr(check_action, "realloc(): invalid pointer", oldmem,
++ &main_arena);
+ return malloc_check(bytes, NULL);
+ }
+ const INTERNAL_SIZE_T oldsize = chunksize(oldp);
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 597c7b0..20ac534 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1633,7 +1633,7 @@ static size_t mUSABLe(Void_t*);
+ static void mSTATs(void);
+ static int mALLOPt(int, int);
+ static struct mallinfo mALLINFo(mstate);
+-static void malloc_printerr(int action, const char *str, void *ptr);
++static void malloc_printerr(int action, const char *str, void *ptr, mstate av);
+
+ static Void_t* internal_function mem2mem_check(Void_t *p, size_t sz);
+ static int internal_function top_check(void);
+@@ -2114,7 +2114,8 @@ typedef struct malloc_chunk* mbinptr;
+ BK = P->bk; \
+ if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) { \
+ mutex_unlock(&(AV)->mutex); \
+- malloc_printerr (check_action, "corrupted double-linked list", P); \
++ malloc_printerr (check_action, "corrupted double-linked list", P, \
++ AV); \
+ mutex_lock(&(AV)->mutex); \
+ } else { \
+ FD->bk = BK; \
+@@ -2344,6 +2345,15 @@ typedef struct malloc_chunk* mfastbinptr;
+ #define set_noncontiguous(M) ((M)->flags |= NONCONTIGUOUS_BIT)
+ #define set_contiguous(M) ((M)->flags &= ~NONCONTIGUOUS_BIT)
+
++/* ARENA_CORRUPTION_BIT is set if a memory corruption was detected on the
++ arena. Such an arena is no longer used to allocate chunks. Chunks
++ allocated in that arena before detecting corruption are not freed. */
++
++#define ARENA_CORRUPTION_BIT (4U)
++
++#define arena_is_corrupt(A) (((A)->flags & ARENA_CORRUPTION_BIT))
++#define set_arena_corrupt(A) ((A)->flags |= ARENA_CORRUPTION_BIT)
++
+ /*
+ Set value of max_fast.
+ Use impossibly small value if 0.
+@@ -3002,8 +3012,9 @@ static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+ rather than expanding top.
+ */
+
+- if ((unsigned long)(nb) >= (unsigned long)(mp_.mmap_threshold) &&
+- (mp_.n_mmaps < mp_.n_mmaps_max)) {
++ if (av == NULL
++ || ((unsigned long)(nb) >= (unsigned long)(mp_.mmap_threshold) &&
++ (mp_.n_mmaps < mp_.n_mmaps_max))) {
+
+ char* mm; /* return value from mmap call*/
+
+@@ -3079,6 +3090,10 @@ static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+ }
+ #endif
+
++ /* There are no usable arenas and mmap also failed. */
++ if (av == NULL)
++ return 0;
++
+ /* Record incoming configuration of top */
+
+ old_top = av->top;
+@@ -3260,7 +3275,7 @@ static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+ else if (contiguous(av) && old_size && brk < old_end) {
+ /* Oops! Someone else killed our space.. Can't touch anything. */
+ mutex_unlock(&av->mutex);
+- malloc_printerr (3, "break adjusted to free malloc space", brk);
++ malloc_printerr (3, "break adjusted to free malloc space", brk, av);
+ mutex_lock(&av->mutex);
+ }
+
+@@ -3542,7 +3557,7 @@ munmap_chunk(p) mchunkptr p;
+ if (__builtin_expect (((block | total_size) & (mp_.pagesize - 1)) != 0, 0))
+ {
+ malloc_printerr (check_action, "munmap_chunk(): invalid pointer",
+- chunk2mem (p));
++ chunk2mem (p), NULL);
+ return;
+ }
+
+@@ -3625,65 +3640,31 @@ public_mALLOc(size_t bytes)
+ if (__builtin_expect (hook != NULL, 0))
+ return (*hook)(bytes, RETURN_ADDRESS (0));
+
+- arena_lookup(ar_ptr);
+-#if 0
+- // XXX We need double-word CAS and fastbins must be extended to also
+- // XXX hold a generation counter for each entry.
+- if (ar_ptr) {
+- INTERNAL_SIZE_T nb; /* normalized request size */
+- checked_request2size(bytes, nb);
+- if (nb <= get_max_fast ()) {
+- long int idx = fastbin_index(nb);
+- mfastbinptr* fb = &fastbin (ar_ptr, idx);
+- mchunkptr pp = *fb;
+- mchunkptr v;
+- do
+- {
+- v = pp;
+- if (v == NULL)
+- break;
+- }
+- while ((pp = catomic_compare_and_exchange_val_acq (fb, v->fd, v)) != v);
+- if (v != 0) {
+- if (__builtin_expect (fastbin_index (chunksize (v)) != idx, 0))
+- malloc_printerr (check_action, "malloc(): memory corruption (fast)",
+- chunk2mem (v));
+- check_remalloced_chunk(ar_ptr, v, nb);
+- void *p = chunk2mem(v);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
+- return p;
+- }
+- }
+- }
+-#endif
++ arena_get(ar_ptr, bytes);
+
+- arena_lock(ar_ptr, bytes);
+- if(!ar_ptr)
+- return 0;
+ victim = _int_malloc(ar_ptr, bytes);
+- if(!victim) {
++ if(!victim && ar_ptr != NULL) {
+ /* Maybe the failure is due to running out of mmapped areas. */
+ if(ar_ptr != &main_arena) {
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = &main_arena;
+ (void)mutex_lock(&ar_ptr->mutex);
+ victim = _int_malloc(ar_ptr, bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+ } else {
+ #if USE_ARENAS
+ /* ... or sbrk() has failed and there is still a chance to mmap() */
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes, true);
+- if(ar_ptr) {
++ if(ar_ptr)
+ victim = _int_malloc(ar_ptr, bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+- }
+ #endif
+ }
+- } else
++ }
++
++ if (ar_ptr != NULL)
+ (void)mutex_unlock(&ar_ptr->mutex);
++
+ assert(!victim || chunk_is_mmapped(mem2chunk(victim)) ||
+ ar_ptr == arena_for_chunk(mem2chunk(victim)));
+ return victim;
+@@ -3773,6 +3754,11 @@ public_rEALLOc(Void_t* oldmem, size_t bytes)
+ /* its size */
+ const INTERNAL_SIZE_T oldsize = chunksize(oldp);
+
++ if (chunk_is_mmapped (oldp))
++ ar_ptr = NULL;
++ else
++ ar_ptr = arena_for_chunk (oldp);
++
+ /* Little security check which won't hurt performance: the
+ allocator never wrapps around at the end of the address space.
+ Therefore we can exclude some size values which might appear
+@@ -3780,7 +3766,8 @@ public_rEALLOc(Void_t* oldmem, size_t bytes)
+ if (__builtin_expect ((uintptr_t) oldp > (uintptr_t) -oldsize, 0)
+ || __builtin_expect (misaligned_chunk (oldp), 0))
+ {
+- malloc_printerr (check_action, "realloc(): invalid pointer", oldmem);
++ malloc_printerr (check_action, "realloc(): invalid pointer", oldmem,
++ ar_ptr);
+ return NULL;
+ }
+
+@@ -3806,7 +3793,6 @@ public_rEALLOc(Void_t* oldmem, size_t bytes)
+ }
+ #endif
+
+- ar_ptr = arena_for_chunk(oldp);
+ #if THREAD_STATS
+ if(!mutex_trylock(&ar_ptr->mutex))
+ ++(ar_ptr->stat_lock_direct);
+@@ -3887,31 +3873,29 @@ public_mEMALIGn(size_t alignment, size_t bytes)
+ }
+
+ arena_get(ar_ptr, bytes + alignment + MINSIZE);
+- if(!ar_ptr)
+- return 0;
+ p = _int_memalign(ar_ptr, alignment, bytes);
+- if(!p) {
++ if(!p && ar_ptr != NULL) {
+ /* Maybe the failure is due to running out of mmapped areas. */
+ if(ar_ptr != &main_arena) {
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = &main_arena;
+ (void)mutex_lock(&ar_ptr->mutex);
+ p = _int_memalign(ar_ptr, alignment, bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+ } else {
+ #if USE_ARENAS
+ /* ... or sbrk() has failed and there is still a chance to mmap() */
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes, true);
+- if(ar_ptr) {
++ if(ar_ptr)
+ p = _int_memalign(ar_ptr, alignment, bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+- }
+ #endif
+ }
+- } else
++ }
++
++ if (ar_ptr != NULL)
+ (void)mutex_unlock(&ar_ptr->mutex);
++
+ assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
+ ar_ptr == arena_for_chunk(mem2chunk(p)));
+ return p;
+@@ -3945,31 +3929,29 @@ public_vALLOc(size_t bytes)
+ return (*hook)(pagesz, bytes, RETURN_ADDRESS (0));
+
+ arena_get(ar_ptr, bytes + pagesz + MINSIZE);
+- if(!ar_ptr)
+- return 0;
+ p = _int_valloc(ar_ptr, bytes);
+- if(!p) {
++ if(!p && ar_ptr != NULL) {
+ /* Maybe the failure is due to running out of mmapped areas. */
+ if(ar_ptr != &main_arena) {
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = &main_arena;
+ (void)mutex_lock(&ar_ptr->mutex);
+ p = _int_memalign(ar_ptr, pagesz, bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+ } else {
+ #if USE_ARENAS
+ /* ... or sbrk() has failed and there is still a chance to mmap() */
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes, true);
+- if(ar_ptr) {
++ if(ar_ptr)
+ p = _int_memalign(ar_ptr, pagesz, bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+- }
+ #endif
+ }
+- } else
++ }
++
++ if (ar_ptr != NULL)
+ (void)mutex_unlock(&ar_ptr->mutex);
++
+ assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
+ ar_ptr == arena_for_chunk(mem2chunk(p)));
+
+@@ -4004,28 +3986,28 @@ public_pVALLOc(size_t bytes)
+
+ arena_get(ar_ptr, bytes + 2*pagesz + MINSIZE);
+ p = _int_pvalloc(ar_ptr, bytes);
+- if(!p) {
++ if(!p && ar_ptr != NULL) {
+ /* Maybe the failure is due to running out of mmapped areas. */
+ if(ar_ptr != &main_arena) {
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = &main_arena;
+ (void)mutex_lock(&ar_ptr->mutex);
+ p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+ } else {
+ #if USE_ARENAS
+ /* ... or sbrk() has failed and there is still a chance to mmap() */
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes + 2*pagesz + MINSIZE, true);
+- if(ar_ptr) {
++ if(ar_ptr)
+ p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
+- (void)mutex_unlock(&ar_ptr->mutex);
+- }
+ #endif
+ }
+- } else
++ }
++
++ if (ar_ptr != NULL)
+ (void)mutex_unlock(&ar_ptr->mutex);
++
+ assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
+ ar_ptr == arena_for_chunk(mem2chunk(p)));
+
+@@ -4072,55 +4054,65 @@ public_cALLOc(size_t n, size_t elem_size)
+ sz = bytes;
+
+ arena_get(av, sz);
+- if(!av)
+- return 0;
+
+- /* Check if we hand out the top chunk, in which case there may be no
+- need to clear. */
++ if (av)
++ {
++ /* Check if we hand out the top chunk, in which case there may be no
++ need to clear. */
+ #if MORECORE_CLEARS
+- oldtop = top(av);
+- oldtopsize = chunksize(top(av));
++ oldtop = top(av);
++ oldtopsize = chunksize(top(av));
+ #if MORECORE_CLEARS < 2
+- /* Only newly allocated memory is guaranteed to be cleared. */
+- if (av == &main_arena &&
+- oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *)oldtop)
+- oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *)oldtop);
++ /* Only newly allocated memory is guaranteed to be cleared. */
++ if (av == &main_arena &&
++ oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *)oldtop)
++ oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *)oldtop);
+ #endif
+- if (av != &main_arena)
++ if (av != &main_arena)
++ {
++ heap_info *heap = heap_for_ptr (oldtop);
++ if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
++ oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
++ }
++#endif
++ }
++ else
+ {
+- heap_info *heap = heap_for_ptr (oldtop);
+- if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
+- oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
++ /* No usable arenas. */
++ oldtop = 0;
++ oldtopsize = 0;
+ }
+-#endif
+ mem = _int_malloc(av, sz);
+
+-
+ assert(!mem || chunk_is_mmapped(mem2chunk(mem)) ||
+ av == arena_for_chunk(mem2chunk(mem)));
+
+- if (mem == 0) {
++ if (mem == 0 && av != NULL) {
+ /* Maybe the failure is due to running out of mmapped areas. */
+ if(av != &main_arena) {
+ (void)mutex_unlock(&av->mutex);
+ (void)mutex_lock(&main_arena.mutex);
+ mem = _int_malloc(&main_arena, sz);
+- (void)mutex_unlock(&main_arena.mutex);
+ } else {
+ #if USE_ARENAS
+ /* ... or sbrk() has failed and there is still a chance to mmap() */
+ mstate prev = av->next ? av : 0;
+ (void)mutex_unlock(&av->mutex);
+ av = arena_get2(prev, sz, true);
+- if(av) {
++ if(av)
+ mem = _int_malloc(av, sz);
+- (void)mutex_unlock(&av->mutex);
+- }
+ #endif
+ }
+ if (mem == 0) return 0;
+- } else
++ }
++
++ if (av != NULL)
+ (void)mutex_unlock(&av->mutex);
++
++ /* Allocation failed even after a retry. */
++ if (mem == 0)
++ return 0;
++
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+@@ -4175,6 +4167,8 @@ public_cALLOc(size_t n, size_t elem_size)
+ }
+
+ #ifndef _LIBC
++/* XXX These functions are not patched to detect arena corruption because they
++ are not built in glibc. */
+
+ Void_t**
+ public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks)
+@@ -4309,6 +4303,16 @@ _int_malloc(mstate av, size_t bytes)
+
+ checked_request2size(bytes, nb);
+
++ /* There are no usable arenas. Fall back to sysmalloc to get a chunk from
++ mmap. */
++ if (__glibc_unlikely (av == NULL))
++ {
++ void *p = sYSMALLOc (nb, av);
++ if (p != NULL)
++ alloc_perturb (p, bytes);
++ return p;
++ }
++
+ /*
+ If the size qualifies as a fastbin, first check corresponding bin.
+ This code is safe to execute even if av is not yet initialized, so we
+@@ -4337,7 +4341,7 @@ _int_malloc(mstate av, size_t bytes)
+ errstr = "malloc(): memory corruption (fast)";
+ errout:
+ mutex_unlock(&av->mutex);
+- malloc_printerr (check_action, errstr, chunk2mem (victim));
++ malloc_printerr (check_action, errstr, chunk2mem (victim), av);
+ mutex_lock(&av->mutex);
+ return NULL;
+ }
+@@ -4429,7 +4433,7 @@ _int_malloc(mstate av, size_t bytes)
+ {
+ void *p = chunk2mem(victim);
+ mutex_unlock(&av->mutex);
+- malloc_printerr (check_action, "malloc(): memory corruption", p);
++ malloc_printerr (check_action, "malloc(): memory corruption", p, av);
+ mutex_lock(&av->mutex);
+ }
+ size = chunksize(victim);
+@@ -4829,7 +4833,7 @@ _int_free(mstate av, mchunkptr p)
+ if (have_lock || locked)
+ (void)mutex_unlock(&av->mutex);
+ #endif
+- malloc_printerr (check_action, errstr, chunk2mem(p));
++ malloc_printerr (check_action, errstr, chunk2mem(p), av);
+ #ifdef ATOMIC_FASTBINS
+ if (have_lock)
+ mutex_lock(&av->mutex);
+@@ -5281,7 +5285,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
+ errstr = "realloc(): invalid old size";
+ errout:
+ mutex_unlock(&av->mutex);
+- malloc_printerr (check_action, errstr, chunk2mem(oldp));
++ malloc_printerr (check_action, errstr, chunk2mem(oldp), av);
+ mutex_lock(&av->mutex);
+ return NULL;
+ }
+@@ -5881,6 +5885,10 @@ static int mTRIm(mstate av, size_t pad)
+ static int mTRIm(av, pad) mstate av; size_t pad;
+ #endif
+ {
++ /* Don't touch corrupt arenas. */
++ if (arena_is_corrupt (av))
++ return 0;
++
+ /* Ensure initialization/consolidation */
+ malloc_consolidate (av);
+
+@@ -6320,8 +6328,14 @@ int mALLOPt(param_number, value) int param_number; int value;
+ extern char **__libc_argv attribute_hidden;
+
+ static void
+-malloc_printerr(int action, const char *str, void *ptr)
++malloc_printerr(int action, const char *str, void *ptr, mstate ar_ptr)
+ {
++ /* Avoid using this arena in future. We do not attempt to synchronize this
++ with anything else because we minimally want to ensure that __libc_message
++ gets its resources safely without stumbling on the current corruption. */
++ if (ar_ptr)
++ set_arena_corrupt (ar_ptr);
++
+ if ((action & 5) == 5)
+ __libc_message (action & 2, "%s\n", str);
+ else if (action & 1)
+diff --git a/malloc/tst-malloc-backtrace.c b/malloc/tst-malloc-backtrace.c
+new file mode 100644
+index 0000000..796a42f
+--- /dev/null
++++ b/malloc/tst-malloc-backtrace.c
+@@ -0,0 +1,50 @@
++/* Verify that backtrace does not deadlock on itself on memory corruption.
++ Copyright (C) 2015 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
++ <http://www.gnu.org/licenses/>. */
++
++
++#include <stdlib.h>
++
++#define SIZE 4096
++
++/* Wrap free with a function to prevent gcc from optimizing it out. */
++static void
++__attribute__((noinline))
++call_free (void *ptr)
++{
++ free (ptr);
++ *(size_t *)(ptr - sizeof (size_t)) = 1;
++}
++
++int
++do_test (void)
++{
++ void *ptr1 = malloc (SIZE);
++ void *ptr2 = malloc (SIZE);
++
++ call_free ((void *) ptr1);
++ ptr1 = malloc (SIZE);
++
++ /* Not reached. The return statement is to put ptr2 into use so that gcc
++ doesn't optimize out that malloc call. */
++ return (ptr1 == ptr2);
++}
++
++#define TEST_FUNCTION do_test ()
++#define EXPECTED_SIGNAL SIGABRT
++
++#include "../test-skeleton.c"
--- /dev/null
+commit c44496df2f090a56d3bf75df930592dac6bba46f
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Wed Mar 12 17:27:22 2014 +0530
+
+ Provide correct buffer length to netgroup queries in nscd (BZ #16695)
+
+ The buffer to query netgroup entries is allocated sufficient space for
+ the netgroup entries and the key to be appended at the end, but it
+ sends in an incorrect available length to the NSS netgroup query
+ functions, resulting in overflow of the buffer in some special cases.
+ The fix here is to factor in the key length when sending the available
+ buffer and buffer length to the query functions.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 426d3c5..5ba1e1f 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -202,7 +202,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ {
+ int e;
+ status = getfct.f (&data, buffer + buffilled,
+- buflen - buffilled, &e);
++ buflen - buffilled - req->key_len, &e);
+ if (status == NSS_STATUS_RETURN
+ || status == NSS_STATUS_NOTFOUND)
+ /* This was either the last one for this group or the
--- /dev/null
+commit bc8f194c8c29e46e8ee4034f06e46988dfff38f7
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Wed Apr 30 12:00:39 2014 +0530
+
+ Initialize all of datahead structure in nscd (BZ #16791)
+
+ The datahead structure has an unused padding field that remains
+ uninitialized. Valgrind prints out a warning for it on querying a
+ netgroups entry. This is harmless, but is a potential data leak since
+ it would result in writing out an uninitialized byte to the cache
+ file. Besides, this happens only when there is a cache miss, so we're
+ not adding computation to any fast path.
+
+commit 1cdeb2372ddecac0dfe0c132a033e9590ffa07d2
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Wed Apr 30 11:57:09 2014 +0530
+
+ Consolidate code to initialize nscd dataset header
+
+ This patch consolidates the code to initialize the header of a dataset
+ into a single set of functions (one for positive and another for
+ negative datasets) primarily to reduce repetition of code. The
+ secondary reason is to simplify Patch 2/2 which fixes the problem of
+ an uninitialized byte in the header by initializing an unused field in
+ the structure and hence preventing a possible data leak into the cache
+ file.
+
+diff --git a/nscd/aicache.c b/nscd/aicache.c
+index 98d40a1..d7966bd 100644
+--- a/nscd/aicache.c
++++ b/nscd/aicache.c
+@@ -383,17 +383,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
+ cp = family;
+ }
+
+- /* Fill in the rest of the dataset. */
+- dataset->head.allocsize = total + req->key_len;
+- dataset->head.recsize = total - offsetof (struct dataset, resp);
+- dataset->head.notfound = false;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+-
+- /* Compute the timeout time. */
+- dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
+- timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
++ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++ total - offsetof (struct dataset, resp),
++ he == NULL ? 0 : dh->nreloads + 1,
++ ttl == INT32_MAX ? db->postimeout : ttl);
+
++ /* Fill in the rest of the dataset. */
+ dataset->resp.version = NSCD_VERSION;
+ dataset->resp.found = 1;
+ dataset->resp.naddrs = naddrs;
+@@ -528,15 +523,9 @@ next_nip:
+ else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ + req->key_len), 1)) != 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;
++ timeout = datahead_init_neg (&dataset->head,
++ sizeof (struct dataset) + req->key_len,
++ total, db->negtimeout);
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, ¬found, total);
+diff --git a/nscd/grpcache.c b/nscd/grpcache.c
+index b5a33eb..df59fa7 100644
+--- a/nscd/grpcache.c
++++ b/nscd/grpcache.c
+@@ -128,14 +128,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
+ }
+ else if ((dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1)) != 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 = t + db->negtimeout;
++ timeout = datahead_init_neg (&dataset->head,
++ (sizeof (struct dataset)
++ + req->key_len), total,
++ db->negtimeout);
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, ¬found, total);
+@@ -232,14 +228,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
+ dataset_temporary = true;
+ }
+
+- dataset->head.allocsize = total + n;
+- dataset->head.recsize = total - offsetof (struct dataset, resp);
+- dataset->head.notfound = false;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+-
+- /* Compute the timeout time. */
+- timeout = dataset->head.timeout = t + db->postimeout;
++ timeout = datahead_init_pos (&dataset->head, total + n,
++ total - offsetof (struct dataset, resp),
++ he == NULL ? 0 : dh->nreloads + 1,
++ db->postimeout);
+
+ dataset->resp.version = NSCD_VERSION;
+ dataset->resp.found = 1;
+diff --git a/nscd/hstcache.c b/nscd/hstcache.c
+index a79b67a..d4f1ad2 100644
+--- a/nscd/hstcache.c
++++ b/nscd/hstcache.c
+@@ -152,15 +152,11 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
+ else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ + req->key_len), 1)) != 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. */
+- dataset->head.ttl = ttl == INT32_MAX ? db->negtimeout : ttl;
+- timeout = dataset->head.timeout = t + dataset->head.ttl;
++ timeout = datahead_init_neg (&dataset->head,
++ (sizeof (struct dataset)
++ + req->key_len), total,
++ (ttl == INT32_MAX
++ ? db->negtimeout : ttl));
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, resp, total);
+@@ -257,15 +253,10 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
+ alloca_used = true;
+ }
+
+- dataset->head.allocsize = total + req->key_len;
+- dataset->head.recsize = total - offsetof (struct dataset, resp);
+- dataset->head.notfound = false;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+-
+- /* Compute the timeout time. */
+- dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
+- timeout = dataset->head.timeout = t + dataset->head.ttl;
++ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++ total - offsetof (struct dataset, resp),
++ he == NULL ? 0 : dh->nreloads + 1,
++ ttl == INT32_MAX ? db->postimeout : ttl);
+
+ dataset->resp.version = NSCD_VERSION;
+ dataset->resp.found = 1;
+diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
+index 1bf9f0d..361319f 100644
+--- a/nscd/initgrcache.c
++++ b/nscd/initgrcache.c
+@@ -213,14 +213,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
+ else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ + req->key_len), 1)) != 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;
++ timeout = datahead_init_neg (&dataset->head,
++ (sizeof (struct dataset)
++ + req->key_len), total,
++ db->negtimeout);
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, ¬found, total);
+@@ -276,14 +272,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
+ alloca_used = true;
+ }
+
+- dataset->head.allocsize = total + req->key_len;
+- dataset->head.recsize = total - offsetof (struct dataset, resp);
+- dataset->head.notfound = false;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+-
+- /* Compute the timeout time. */
+- timeout = dataset->head.timeout = time (NULL) + db->postimeout;
++ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++ total - offsetof (struct dataset, resp),
++ he == NULL ? 0 : dh->nreloads + 1,
++ db->postimeout);
+
+ dataset->resp.version = NSCD_VERSION;
+ dataset->resp.found = 1;
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 820d823..b3d40e9 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -90,15 +90,9 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
+ /* 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;
++ timeout = datahead_init_neg (&dataset->head,
++ sizeof (struct dataset) + req->key_len,
++ total, db->negtimeout);
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, ¬found, total);
+@@ -359,13 +353,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+
+ /* Fill in the dataset. */
+ dataset = (struct dataset *) buffer;
+- dataset->head.allocsize = total + req->key_len;
+- dataset->head.recsize = total - offsetof (struct dataset, resp);
+- dataset->head.notfound = false;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+- dataset->head.ttl = db->postimeout;
+- timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
++ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++ total - offsetof (struct dataset, resp),
++ he == NULL ? 0 : dh->nreloads + 1,
++ db->postimeout);
+
+ dataset->resp.version = NSCD_VERSION;
+ dataset->resp.found = 1;
+@@ -541,12 +532,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
+ dataset = &dataset_mem;
+ }
+
+- dataset->head.allocsize = sizeof (*dataset) + req->key_len;
+- dataset->head.recsize = sizeof (innetgroup_response_header);
++ datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len,
++ sizeof (innetgroup_response_header),
++ he == NULL ? 0 : dh->nreloads + 1, result->head.ttl);
++ /* Set the notfound status and timeout based on the result from
++ getnetgrent. */
+ dataset->head.notfound = result->head.notfound;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+- dataset->head.ttl = result->head.ttl;
+ dataset->head.timeout = timeout;
+
+ dataset->resp.version = NSCD_VERSION;
+diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
+index 98f77e7..ee16df6 100644
+--- a/nscd/nscd-client.h
++++ b/nscd/nscd-client.h
+@@ -236,6 +236,48 @@ struct datahead
+ } data[0];
+ };
+
++static inline time_t
++datahead_init_common (struct datahead *head, nscd_ssize_t allocsize,
++ nscd_ssize_t recsize, uint32_t ttl)
++{
++ /* Initialize so that we don't write out junk in uninitialized data to the
++ cache. */
++ memset (head, 0, sizeof (*head));
++
++ head->allocsize = allocsize;
++ head->recsize = recsize;
++ head->usable = true;
++
++ head->ttl = ttl;
++
++ /* Compute and return the timeout time. */
++ return head->timeout = time (NULL) + ttl;
++}
++
++static inline time_t
++datahead_init_pos (struct datahead *head, nscd_ssize_t allocsize,
++ nscd_ssize_t recsize, uint8_t nreloads, uint32_t ttl)
++{
++ time_t ret = datahead_init_common (head, allocsize, recsize, ttl);
++
++ head->notfound = false;
++ head->nreloads = nreloads;
++
++ return ret;
++}
++
++static inline time_t
++datahead_init_neg (struct datahead *head, nscd_ssize_t allocsize,
++ nscd_ssize_t recsize, uint32_t ttl)
++{
++ time_t ret = datahead_init_common (head, allocsize, recsize, ttl);
++
++ /* We don't need to touch nreloads here since it is set to our desired value
++ (0) when we clear the structure. */
++ head->notfound = true;
++
++ return ret;
++}
+
+ /* Structure for one hash table entry. */
+ struct hashentry
+diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
+index fa355c3..41c245b 100644
+--- a/nscd/pwdcache.c
++++ b/nscd/pwdcache.c
+@@ -135,14 +135,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
+ else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ + req->key_len), 1)) != 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 = t + db->negtimeout;
++ timeout = datahead_init_neg (&dataset->head,
++ (sizeof (struct dataset)
++ + req->key_len), total,
++ db->negtimeout);
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, ¬found, total);
+@@ -215,14 +211,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
+ alloca_used = true;
+ }
+
+- dataset->head.allocsize = total + n;
+- dataset->head.recsize = total - offsetof (struct dataset, resp);
+- dataset->head.notfound = false;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+-
+- /* Compute the timeout time. */
+- timeout = dataset->head.timeout = t + db->postimeout;
++ timeout = datahead_init_pos (&dataset->head, total + n,
++ total - offsetof (struct dataset, resp),
++ he == NULL ? 0 : dh->nreloads + 1,
++ db->postimeout);
+
+ dataset->resp.version = NSCD_VERSION;
+ dataset->resp.found = 1;
+diff --git a/nscd/servicescache.c b/nscd/servicescache.c
+index 12ce9b2..95bdcfe 100644
+--- a/nscd/servicescache.c
++++ b/nscd/servicescache.c
+@@ -120,14 +120,10 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req,
+ else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ + req->key_len), 1)) != 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 = t + db->negtimeout;
++ timeout = datahead_init_neg (&dataset->head,
++ (sizeof (struct dataset)
++ + req->key_len), total,
++ db->negtimeout);
+
+ /* This is the reply. */
+ memcpy (&dataset->resp, ¬found, total);
+@@ -207,14 +203,10 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req,
+ alloca_used = true;
+ }
+
+- dataset->head.allocsize = total + req->key_len;
+- dataset->head.recsize = total - offsetof (struct dataset, resp);
+- dataset->head.notfound = false;
+- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+- dataset->head.usable = true;
+-
+- /* Compute the timeout time. */
+- timeout = dataset->head.timeout = t + db->postimeout;
++ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++ total - offsetof (struct dataset, resp),
++ he == NULL ? 0 : dh->nreloads + 1,
++ db->postimeout);
+
+ dataset->resp.version = NSCD_VERSION;
+ dataset->resp.found = 1;
--- /dev/null
+commit ea7d8b95e2fcb81f68b04ed7787a3dbda023991a
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Thu Mar 27 19:48:15 2014 +0530
+
+ Avoid overlapping addresses to stpcpy calls in nscd (BZ #16760)
+
+ Calls to stpcpy from nscd netgroups code will have overlapping source
+ and destination when all three values in the returned triplet are
+ non-NULL and in the expected (host,user,domain) order. This is seen
+ in valgrind as:
+
+ ==3181== Source and destination overlap in stpcpy(0x19973b48, 0x19973b48)
+ ==3181== at 0x4C2F30A: stpcpy (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
+ ==3181== by 0x12567A: addgetnetgrentX (string3.h:111)
+ ==3181== by 0x12722D: addgetnetgrent (netgroupcache.c:665)
+ ==3181== by 0x11114C: nscd_run_worker (connections.c:1338)
+ ==3181== by 0x4E3C102: start_thread (pthread_create.c:309)
+ ==3181== by 0x59B81AC: clone (clone.S:111)
+ ==3181==
+
+ Fix this by using memmove instead of stpcpy.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 5d15aa4..820d823 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -216,6 +216,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ const char *nuser = data.val.triple.user;
+ const char *ndomain = data.val.triple.domain;
+
++ size_t hostlen = strlen (nhost ?: "") + 1;
++ size_t userlen = strlen (nuser ?: "") + 1;
++ size_t domainlen = strlen (ndomain ?: "") + 1;
++
+ if (nhost == NULL || nuser == NULL || ndomain == NULL
+ || nhost > nuser || nuser > ndomain)
+ {
+@@ -233,9 +237,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ : last + strlen (last) + 1 - buffer);
+
+ /* We have to make temporary copies. */
+- size_t hostlen = strlen (nhost ?: "") + 1;
+- size_t userlen = strlen (nuser ?: "") + 1;
+- size_t domainlen = strlen (ndomain ?: "") + 1;
+ size_t needed = hostlen + userlen + domainlen;
+
+ if (buflen - req->key_len - bufused < needed)
+@@ -269,9 +270,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ }
+
+ char *wp = buffer + buffilled;
+- wp = stpcpy (wp, nhost) + 1;
+- wp = stpcpy (wp, nuser) + 1;
+- wp = stpcpy (wp, ndomain) + 1;
++ wp = memmove (wp, nhost ?: "", hostlen);
++ wp += hostlen;
++ wp = memmove (wp, nuser ?: "", userlen);
++ wp += userlen;
++ wp = memmove (wp, ndomain ?: "", domainlen);
++ wp += domainlen;
+ buffilled = wp - buffer;
+ ++nentries;
+ }
--- /dev/null
+commit d41242129ba693cdbc8db85b846fcaccf9f0b7c4
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Thu Jan 2 10:03:12 2014 +0530
+
+ Fix infinite loop in nscd when netgroup is empty (bz #16365)
+
+ Currently, when a user looks up a netgroup that does not have any
+ members, nscd goes into an infinite loop trying to find members in the
+ group. This is because it does not handle cases when getnetgrent
+ returns an NSS_STATUS_NOTFOUND (which is what it does on empty group).
+ Fixed to handle this in the same way as NSS_STATUS_RETURN, similar to
+ what getgrent does by itself.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index baebdd7..50936ee 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -180,9 +180,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ 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)
+ {
--- /dev/null
+commit dd3022d75e6fb8957843d6d84257a5d8457822d5
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Thu Mar 27 19:49:51 2014 +0530
+
+ Return NULL for wildcard values in getnetgrent from nscd (BZ #16759)
+
+ getnetgrent is supposed to return NULL for values that are wildcards
+ in the (host, user, domain) triplet. This works correctly with nscd
+ disabled, but with it enabled, it returns a blank ("") instead of a
+ NULL. This is easily seen with the output of `getent netgroup foonet`
+ for a netgroup foonet defined as follows in /etc/netgroup:
+
+ foonet (,foo,)
+
+ The output with nscd disabled is:
+
+ foonet ( ,foo,)
+
+ while with nscd enabled, it is:
+
+ foonet (,foo,)
+
+ The extra space with nscd disabled is due to the fact that `getent
+ netgroup` adds it if the return value from getnetgrent is NULL for
+ either host or user.
+
+diff --git a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c
+index 62cdfda..f6d064d 100644
+--- a/inet/getnetgrent_r.c
++++ b/inet/getnetgrent_r.c
+@@ -235,6 +235,14 @@ endnetgrent (void)
+ libc_hidden_proto (internal_getnetgrent_r)
+
+
++static const char *
++get_nonempty_val (const char *in)
++{
++ if (*in == '\0')
++ return NULL;
++ return in;
++}
++
+ static enum nss_status
+ nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
+ int *errnop)
+@@ -243,11 +251,11 @@ nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
+ return NSS_STATUS_UNAVAIL;
+
+ datap->type = triple_val;
+- datap->val.triple.host = datap->cursor;
++ datap->val.triple.host = get_nonempty_val (datap->cursor);
+ datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+- datap->val.triple.user = datap->cursor;
++ datap->val.triple.user = get_nonempty_val (datap->cursor);
+ datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+- datap->val.triple.domain = datap->cursor;
++ datap->val.triple.domain = get_nonempty_val (datap->cursor);
+ datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+
+ return NSS_STATUS_SUCCESS;
--- /dev/null
+commit 58b930ae216bfa98cd60212b954b07b9963d6d04
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Wed Sep 10 21:51:50 2014 +0530
+
+ Return failure in getnetgrent only when all netgroups have been searched (#17363)
+
+ The netgroups lookup code fails when one of the groups in the search
+ tree is empty. In such a case it only returns the leaves of the tree
+ after the blank netgroup. This is because the line parser returns a
+ NOTFOUND status when the netgroup exists but is empty. The
+ __getnetgrent_internal implementation needs to be fixed to try
+ remaining groups if the current group is entry. This patch implements
+ this fix. Tested on x86_64.
+
+ [BZ #17363]
+ * inet/getnetgrent_r.c (__internal_getnetgrent_r): Try next
+ group if the current group is empty.
+
+diff --git a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c
+index f6d064d..e101537 100644
+--- a/inet/getnetgrent_r.c
++++ b/inet/getnetgrent_r.c
+@@ -297,7 +297,10 @@ __internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
+ {
+ status = (*fct) (datap, buffer, buflen, &errno);
+
+- if (status == NSS_STATUS_RETURN)
++ if (status == NSS_STATUS_RETURN
++ /* The service returned a NOTFOUND, but there are more groups that we
++ need to resolve before we give up. */
++ || (status == NSS_STATUS_NOTFOUND && datap->needed_groups != NULL))
+ {
+ /* This was the last one for this group. Look at next group
+ if available. */
--- /dev/null
+commit c3ec475c5dd16499aa040908e11d382c3ded9692
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Mon May 26 11:40:08 2014 +0530
+
+ Use NSS_STATUS_TRYAGAIN to indicate insufficient buffer (BZ #16878)
+
+ The netgroups nss modules in the glibc tree use NSS_STATUS_UNAVAIL
+ (with errno as ERANGE) when the supplied buffer does not have
+ sufficient space for the result. This is wrong, because the canonical
+ way to indicate insufficient buffer is to set the errno to ERANGE and
+ the status to NSS_STATUS_TRYAGAIN, as is used by all other modules.
+
+ This fixes nscd behaviour when the nss_ldap module returns
+ NSS_STATUS_TRYAGAIN to indicate that a netgroup entry is too long to
+ fit into the supplied buffer.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index b3d40e9..edab174 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -197,11 +197,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ int e;
+ status = getfct.f (&data, buffer + buffilled,
+ buflen - buffilled - req->key_len, &e);
+- 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)
+ {
+ if (data.type == triple_val)
+@@ -320,11 +315,18 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ }
+ }
+ }
+- else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
++ else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
+ {
+ buflen *= 2;
+ buffer = xrealloc (buffer, buflen);
+ }
++ else if (status == NSS_STATUS_RETURN
++ || status == NSS_STATUS_NOTFOUND
++ || status == NSS_STATUS_UNAVAIL)
++ /* This was either the last one for this group or the
++ group was empty or the NSS module had an internal
++ failure. Look at next group if available. */
++ break;
+ }
+
+ enum nss_status (*endfct) (struct __netgrent *);
+diff --git a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c
+index 34eae4c..bc0b367 100644
+--- a/nss/nss_files/files-netgrp.c
++++ b/nss/nss_files/files-netgrp.c
+@@ -252,7 +252,7 @@ _nss_netgroup_parseline (char **cursor, struct __netgrent *result,
+ if (cp - host > buflen)
+ {
+ *errnop = ERANGE;
+- status = NSS_STATUS_UNAVAIL;
++ status = NSS_STATUS_TRYAGAIN;
+ }
+ else
+ {
--- /dev/null
+diff --git a/resolv/arpa/nameser.h b/resolv/arpa/nameser.h
+index fb8513b..372d5cd 100644
+--- a/resolv/arpa/nameser.h
++++ b/resolv/arpa/nameser.h
+@@ -293,6 +293,9 @@ typedef enum __ns_type {
+ ns_t_sink = 40, /*%< Kitchen sink (experimentatl) */
+ ns_t_opt = 41, /*%< EDNS0 option (meta-RR) */
+ ns_t_apl = 42, /*%< Address prefix list (RFC3123) */
++ ns_t_rrsig = 46, /*%< DNSSEC RRset Signature (RFC4034) */
++ ns_t_nsec = 47, /*%< DNSSEC Next-Secure Record (RFC4034)*/
++ ns_t_dnskey = 48, /*%< DNSSEC key record (RFC4034) */
+ ns_t_tkey = 249, /*%< Transaction key */
+ ns_t_tsig = 250, /*%< Transaction signature. */
+ ns_t_ixfr = 251, /*%< Incremental zone transfer. */
+diff --git a/resolv/arpa/nameser_compat.h b/resolv/arpa/nameser_compat.h
+index d59c9e4..284bff7 100644
+--- a/resolv/arpa/nameser_compat.h
++++ b/resolv/arpa/nameser_compat.h
+@@ -164,6 +164,9 @@ typedef struct {
+ #define T_NAPTR ns_t_naptr
+ #define T_A6 ns_t_a6
+ #define T_DNAME ns_t_dname
++#define T_RRSIG ns_t_rrsig
++#define T_NSEC ns_t_nsec
++#define T_DNSKEY ns_t_dnskey
+ #define T_TSIG ns_t_tsig
+ #define T_IXFR ns_t_ixfr
+ #define T_AXFR ns_t_axfr
+diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c
+index a861a84..ae55fac 100644
+--- a/resolv/gethnamaddr.c
++++ b/resolv/gethnamaddr.c
+@@ -331,23 +331,36 @@ getanswer (const querybuf *answer, int anslen, const char *qname, int qtype)
+ buflen -= n;
+ continue;
+ }
+- if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)) {
+- /* We don't support DNSSEC yet. For now, ignore
+- * the record and send a low priority message
+- * to syslog.
+- */
+- syslog(LOG_DEBUG|LOG_AUTH,
++ if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)
++ || (type == T_RRSIG) || (type == T_NSEC)
++ || (type == T_DNSKEY)) {
++ /* We don't support DNSSEC responses yet, but we do
++ * allow setting the DO bit. If the DNS server sent us
++ * these records without us asking for it, ignore the
++ * record and send a low priority message to syslog.
++ */
++ if ((_res.options & RES_USE_DNSSEC) == 0) {
++ syslog(LOG_DEBUG|LOG_AUTH,
+ "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+- qname, p_class(C_IN), p_type(qtype),
+- p_type(type));
++ qname, p_class(C_IN), p_type(qtype),
++ p_type(type));
++ }
+ cp += n;
+ continue;
+ }
+ if (type != qtype) {
+- syslog(LOG_NOTICE|LOG_AUTH,
++ /* Skip logging if we received a DNAME when we have set
++ * the DO bit. DNAME records are a convenient way to
++ * set up DNSSEC records and such setups can make this
++ * log message needlessly noisy.
++ */
++ if (!((_res.options & RES_USE_DNSSEC)
++ && type == T_DNAME)) {
++ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+- qname, p_class(C_IN), p_type(qtype),
+- p_type(type));
++ qname, p_class(C_IN), p_type(qtype),
++ p_type(type));
++ }
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
+index f715ab0..510d388 100644
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -822,13 +822,20 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+ }
+ if (__builtin_expect (type == T_SIG, 0)
+ || __builtin_expect (type == T_KEY, 0)
+- || __builtin_expect (type == T_NXT, 0))
++ || __builtin_expect (type == T_NXT, 0)
++ || __builtin_expect (type == T_RRSIG, 0)
++ || __builtin_expect (type == T_NSEC, 0)
++ || __builtin_expect (type == T_DNSKEY, 0))
+ {
+- /* We don't support DNSSEC yet. For now, ignore the record
+- and send a low priority message to syslog. */
+- syslog (LOG_DEBUG | LOG_AUTH,
+- "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+- qname, p_class (C_IN), p_type(qtype), p_type (type));
++ /* We don't support DNSSEC responses yet, but we do allow setting the
++ DO bit. If the DNS server sent us these records without us asking
++ for it, ignore the record and send a low priority message to
++ syslog. */
++ if ((_res.options & RES_USE_DNSSEC) == 0)
++ syslog (LOG_DEBUG | LOG_AUTH,
++ "gethostby*.getanswer: asked for \"%s %s %s\", "
++ "got type \"%s\"",
++ qname, p_class (C_IN), p_type(qtype), p_type (type));
+ cp += n;
+ continue;
+ }
+@@ -837,9 +844,14 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+ have_to_map = 1;
+ else if (__builtin_expect (type != qtype, 0))
+ {
+- syslog (LOG_NOTICE | LOG_AUTH,
+- "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+- qname, p_class (C_IN), p_type (qtype), p_type (type));
++ /* Skip logging if we received a DNAME when we have set the DO bit.
++ DNAME records are a convenient way to set up DNSSEC records and
++ such setups can make this log message needlessly noisy. */
++ if (!((_res.options & RES_USE_DNSSEC) && type == T_DNAME))
++ syslog (LOG_NOTICE | LOG_AUTH,
++ "gethostby*.getanswer: asked for \"%s %s %s\", "
++ "got type \"%s\"",
++ qname, p_class (C_IN), p_type (qtype), p_type (type));
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+diff --git a/resolv/res_debug.c b/resolv/res_debug.c
+index 7843439..4a49629 100644
+--- a/resolv/res_debug.c
++++ b/resolv/res_debug.c
+@@ -450,6 +450,8 @@ const struct res_sym __p_type_syms[] = {
+ {ns_t_kx, "KX", "Key Exchange"},
+ {ns_t_cert, "CERT", "Certificate"},
+ {ns_t_any, "ANY", "\"any\""},
++ /* TODO Add RRSIG, NSEC and DNSKEY once we actually do something with
++ them. */
+ {0, NULL, NULL}
+ };
+ libresolv_hidden_data_def (__p_type_syms)
--- /dev/null
+commit 3cb26316b45b23dc5cfecbafdc489b28c3a52029
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Thu Jan 29 10:30:09 2015 +0530
+
+ Initialize nscd stats data [BZ #17892]
+
+ The padding bytes in the statsdata struct are not initialized, due to
+ which valgrind throws a warning:
+
+ ==11384== Memcheck, a memory error detector
+ ==11384== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
+ ==11384== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
+ ==11384== Command: nscd -d
+ ==11384==
+ Fri 25 Apr 2014 10:34:53 AM CEST - 11384: handle_request: request received (Version = 2) from PID 11396
+ Fri 25 Apr 2014 10:34:53 AM CEST - 11384: GETSTAT
+ ==11384== Thread 6:
+ ==11384== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
+ ==11384== at 0x4E4ACDC: send (in /lib64/libpthread-2.12.so)
+ ==11384== by 0x11AF6B: send_stats (in /usr/sbin/nscd)
+ ==11384== by 0x112F75: nscd_run_worker (in /usr/sbin/nscd)
+ ==11384== by 0x4E439D0: start_thread (in /lib64/libpthread-2.12.so)
+ ==11384== by 0x599AB6C: clone (in /lib64/libc-2.12.so)
+ ==11384== Address 0x15708395 is on thread 6's stack
+
+ Fix the warning by initializing the structure.
+
+diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
+index 0f1f3c0..7aaa21b 100644
+--- a/nscd/nscd_stat.c
++++ b/nscd/nscd_stat.c
+@@ -94,6 +94,8 @@ send_stats (int fd, struct database_dyn dbs[lastdb])
+ struct statdata data;
+ int cnt;
+
++ memset (&data, 0, sizeof (data));
++
+ memcpy (data.version, compilation, sizeof (compilation));
+ data.debug_level = debug_level;
+ data.runtime = time (NULL) - start_time;
--- /dev/null
+commit d6c33fda03457ca8ca87a562fa2681af16ca4ea5
+Author: Roland McGrath <roland@hack.frob.com>
+Date: Thu May 24 11:37:30 2012 -0700
+
+ Switch gettimeofday from INTUSE to libc_hidden_proto.
+
+diff --git a/include/sys/time.h b/include/sys/time.h
+index d5de942..599e189 100644
+--- a/include/sys/time.h
++++ b/include/sys/time.h
+@@ -4,9 +4,8 @@
+ /* Now document the internal interfaces. */
+ extern int __gettimeofday (struct timeval *__tv,
+ struct timezone *__tz);
+-extern int __gettimeofday_internal (struct timeval *__tv,
+- struct timezone *__tz)
+- attribute_hidden;
++libc_hidden_proto (__gettimeofday)
++libc_hidden_proto (gettimeofday)
+ extern int __settimeofday (__const struct timeval *__tv,
+ __const struct timezone *__tz)
+ attribute_hidden;
+@@ -22,8 +21,4 @@ extern int __utimes (const char *__file, const struct timeval __tvp[2])
+ attribute_hidden;
+ extern int __futimes (int fd, __const struct timeval tvp[2]) attribute_hidden;
+
+-#ifndef NOT_IN_libc
+-# define __gettimeofday(tv, tz) INTUSE(__gettimeofday) (tv, tz)
+-#endif
+-
+ #endif
+diff --git a/sysdeps/mach/gettimeofday.c b/sysdeps/mach/gettimeofday.c
+index 88dca8e..293a775 100644
+--- a/sysdeps/mach/gettimeofday.c
++++ b/sysdeps/mach/gettimeofday.c
+@@ -20,8 +20,6 @@
+ #include <sys/time.h>
+ #include <mach.h>
+
+-#undef __gettimeofday
+-
+ /* Get the current time of day and timezone information,
+ putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
+ Returns 0 on success, -1 on errors. */
+@@ -42,6 +40,6 @@ __gettimeofday (tv, tz)
+ }
+ return 0;
+ }
+-
+-INTDEF(__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/sysdeps/posix/gettimeofday.c b/sysdeps/posix/gettimeofday.c
+index 31b3dd3..1108ff0 100644
+--- a/sysdeps/posix/gettimeofday.c
++++ b/sysdeps/posix/gettimeofday.c
+@@ -19,8 +19,6 @@
+ #include <time.h>
+ #include <sys/time.h>
+
+-#undef __gettimeofday
+-
+ /* Get the current time of day and timezone information,
+ putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
+ Returns 0 on success, -1 on errors. */
+@@ -66,6 +64,6 @@ __gettimeofday (tv, tz)
+
+ return 0;
+ }
+-
+-INTDEF(__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
+index 39c40ed..bd780f5 100644
+--- a/sysdeps/unix/common/syscalls.list
++++ b/sysdeps/unix/common/syscalls.list
+@@ -5,7 +5,7 @@ getpid - getpid Ei: __getpid getpid
+ fchown - fchown i:iii __fchown fchown
+ ftruncate - ftruncate i:ii __ftruncate ftruncate
+ getrusage - getrusage i:ip __getrusage getrusage
+-gettimeofday - gettimeofday i:PP __gettimeofday gettimeofday __gettimeofday_internal
++gettimeofday - gettimeofday i:pP __gettimeofday gettimeofday
+ settimeofday - settimeofday i:PP __settimeofday settimeofday
+ setpgid - setpgrp i:ii __setpgid setpgid
+ setregid - setregid i:ii __setregid setregid
+diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+index b2ef2da..7376135 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
++++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+@@ -35,5 +35,6 @@ __gettimeofday (tv, tz)
+ }
+-
+-#endif
+-INTDEF (__gettimeofday)
++libc_hidden_def (__gettimeofday)
++
++#endif
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/sysdeps/unix/sysv/linux/s390/gettimeofday.c b/sysdeps/unix/sysv/linux/s390/gettimeofday.c
+index 63faef8..efbf1e8 100644
+--- a/sysdeps/unix/sysv/linux/s390/gettimeofday.c
++++ b/sysdeps/unix/sysv/linux/s390/gettimeofday.c
+@@ -22,7 +22,6 @@
+ #include <time.h>
+ #include <hp-timing.h>
+
+-#undef __gettimeofday
+ #include <bits/libc-vdso.h>
+
+ /* Get the current time of day and timezone information,
+@@ -36,6 +35,6 @@ __gettimeofday (tv, tz)
+ {
+ return INLINE_VSYSCALL (gettimeofday, 2, CHECK_1 (tv), CHECK_1 (tz));
+ }
+-
+-INTDEF (__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/time/gettimeofday.c b/time/gettimeofday.c
+index cfe6549..7eb770c 100644
+--- a/time/gettimeofday.c
++++ b/time/gettimeofday.c
+@@ -18,8 +18,6 @@
+ #include <errno.h>
+ #include <sys/time.h>
+
+-#undef __gettimeofday
+-
+ /* Get the current time of day and timezone information,
+ putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
+ Returns 0 on success, -1 on errors. */
+@@ -31,8 +29,9 @@ __gettimeofday (tv, tz)
+ __set_errno (ENOSYS);
+ return -1;
+ }
+-stub_warning (gettimeofday)
+-
+-INTDEF(__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
++
++stub_warning (gettimeofday)
+ #include <stub-tag.h>
+--- a/sysdeps/unix/sysv/linux/x86_64/gettimeofday.S 2014-07-28 14:40:24.640144825 +0530
++++ b/sysdeps/unix/sysv/linux/x86_64/gettimeofday.S 2014-07-28 14:40:21.320120072 +0530
+@@ -45,5 +45,6 @@
+ ret
+ PSEUDO_END(__gettimeofday)
+
+-strong_alias (__gettimeofday, __gettimeofday_internal)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
--- /dev/null
+commit 736c304a1ab4cee36a2f3343f1698bc0abae4608
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+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
+
--- /dev/null
+#
+# In rhel-6.x the Makerules are not entirely as mature as they are
+# in glibc 2.21 (from which the example link-libc-args is taken from).
+# In rhel-6.x the applications are not built like their counterpart
+# real applications, and because of that compiling DSOs that use TLS
+# will fail with undefined references to __tls_get_addr which resides
+# in ld.so and is never included in the link. This patch enhances
+# only the build-module and build-module-asneeded targets to include
+# a more fully and correct link line as the compiler driver would use
+# when constructing an application or DSO. We do not adjust the link
+# lines used to build lib* targets.
+#
+diff -urN glibc-2.12-2-gc4ccff1.orig/Makerules glibc-2.12-2-gc4ccff1/Makerules
+--- glibc-2.12-2-gc4ccff1.orig/Makerules 2015-02-18 19:53:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1/Makerules 2015-02-18 20:08:33.299000028 -0500
+@@ -443,6 +443,25 @@
+ load-map-file = $(map-file:%=-Wl,--version-script=%)
+ endif
+
++# Compiler arguments to use to link a shared object with libc and
++# ld.so. This is intended to be as similar as possible to a default
++# link with an installed libc.
++link-libc-args = -Wl,--start-group \
++ $(libc-for-link) \
++ $(common-objpfx)libc_nonshared.a \
++ $(as-needed) $(elf-objpfx)ld.so $(no-as-needed) \
++ -Wl,--end-group
++
++# The corresponding shared libc to use. This may be modified for a
++# particular target.
++libc-for-link = $(common-objpfx)libc.so
++
++# The corresponding dependencies. As these are used in dependencies,
++# not just commands, they cannot use target-specific variables so need
++# to name both possible libc.so objects.
++link-libc-deps = $(common-objpfx)libc.so $(common-objpfx)linkobj/libc.so \
++ $(common-objpfx)libc_nonshared.a $(elf-objpfx)ld.so
++
+ # Pattern rule to build a shared object from an archive of PIC objects.
+ # This must come after the installation rules so Make doesn't try to
+ # build shared libraries in place from the installed *_pic.a files.
+@@ -557,12 +576,13 @@
+ # not for shared objects
+ define build-module
+ $(build-module-helper) -o $@ -T $(common-objpfx)shlib.lds \
+- $(csu-objpfx)abi-note.o $(build-module-objlist)
++ $(csu-objpfx)abi-note.o $(build-module-objlist) $(link-libc-args)
+ endef
+ define build-module-asneeded
+ $(build-module-helper) -o $@ -T $(common-objpfx)shlib.lds \
+ $(csu-objpfx)abi-note.o \
+- -Wl,--as-needed $(build-module-objlist) -Wl,--no-as-needed
++ -Wl,--as-needed $(build-module-objlist) -Wl,--no-as-needed \
++ $(link-libc-args)
+ endef
+ else
+ ifneq (,$(findstring aix,$(config-os)))
--- /dev/null
+#
+# Based on this upstream commit:
+#
+# commit d8dd00805b8f3a011735d7a407097fb1c408d867
+# Author: H.J. Lu <hjl.tools@gmail.com>
+# Date: Fri Nov 28 07:54:07 2014 -0800
+#
+# Resize DTV if the current DTV isn't big enough
+#
+# This patch changes _dl_allocate_tls_init to resize DTV if the current DTV
+# isn't big enough. Tested on X86-64, x32 and ia32.
+#
+# [BZ #13862]
+# * elf/dl-tls.c: Include <atomic.h>.
+# (oom): Remove #ifdef SHARED/#endif.
+# (_dl_static_dtv, _dl_initial_dtv): Moved before ...
+# (_dl_resize_dtv): This. Extracted from _dl_update_slotinfo.
+# (_dl_allocate_tls_init): Resize DTV if the current DTV isn't
+# big enough.
+# (_dl_update_slotinfo): Call _dl_resize_dtv to resize DTV.
+# * nptl/Makefile (tests): Add tst-stack4.
+# (modules-names): Add tst-stack4mod.
+# ($(objpfx)tst-stack4): New.
+# (tst-stack4mod.sos): Likewise.
+# ($(objpfx)tst-stack4.out): Likewise.
+# ($(tst-stack4mod.sos)): Likewise.
+# (clean): Likewise.
+# * nptl/tst-stack4.c: New file.
+# * nptl/tst-stack4mod.c: Likewise.
+#
+diff -urN glibc-2.12-2-gc4ccff1/elf/dl-tls.c glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c
+--- glibc-2.12-2-gc4ccff1/elf/dl-tls.c 2015-02-18 14:15:28.078461873 -0500
++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c 2015-02-18 14:38:37.630374771 -0500
+@@ -24,6 +24,7 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <sys/param.h>
++#include <atomic.h>
+
+ #include <tls.h>
+ #include <dl-tls.h>
+@@ -35,14 +36,12 @@
+
+
+ /* Out-of-memory handler. */
+-#ifdef SHARED
+ static void
+ __attribute__ ((__noreturn__))
+ oom (void)
+ {
+ _dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n");
+ }
+-#endif
+
+
+ size_t
+@@ -392,6 +391,52 @@
+ return result;
+ }
+
++static dtv_t *
++_dl_resize_dtv (dtv_t *dtv)
++{
++ /* Resize the dtv. */
++ dtv_t *newp;
++ /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by
++ other threads concurrently. -- We don't have the required atomic
++ infrastructure to load dl_tls_max_dtv_idx atomically, but on all the
++ architectures we care about it should load atomically. If this had
++ an atomic_load_acquire we would still be missing the releases for
++ the writes. */
++ size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
++ size_t oldsize = dtv[-1].counter;
++
++#if SHARED
++ if (dtv == GL(dl_initial_dtv))
++ {
++ /* This is the initial dtv that was either statically allocated in
++ __libc_setup_tls or allocated during rtld startup using the
++ dl-minimal.c malloc instead of the real malloc. We can't free
++ it, we have to abandon the old storage. */
++
++ newp = malloc ((2 + newsize) * sizeof (dtv_t));
++ if (newp == NULL)
++ oom ();
++ memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
++ }
++ else
++#endif
++ {
++ newp = realloc (&dtv[-1],
++ (2 + newsize) * sizeof (dtv_t));
++ if (newp == NULL)
++ oom ();
++ }
++
++ newp[0].counter = newsize;
++
++ /* Clear the newly allocated part. */
++ memset (newp + 2 + oldsize, '\0',
++ (newsize - oldsize) * sizeof (dtv_t));
++
++ /* Return the generation counter. */
++ return &newp[1];
++}
++
+
+ void *
+ internal_function
+@@ -406,6 +451,16 @@
+ size_t total = 0;
+ size_t maxgen = 0;
+
++ /* Check if the current dtv is big enough. */
++ if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
++ {
++ /* Resize the dtv. */
++ dtv = _dl_resize_dtv (dtv);
++
++ /* Install this new dtv in the thread data structures. */
++ INSTALL_DTV (result, &dtv[-1]);
++ }
++
+ /* We have to prepare the dtv for all currently loaded modules using
+ TLS. For those which are dynamically loaded we add the values
+ indicating deferred allocation. */
+@@ -637,41 +692,10 @@
+ assert (total + cnt == modid);
+ if (dtv[-1].counter < modid)
+ {
+- /* Reallocate the dtv. */
+- dtv_t *newp;
+- size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
+- size_t oldsize = dtv[-1].counter;
+-
+- assert (map->l_tls_modid <= newsize);
+-
+- if (dtv == GL(dl_initial_dtv))
+- {
+- /* This is the initial dtv that was allocated
+- during rtld startup using the dl-minimal.c
+- malloc instead of the real malloc. We can't
+- free it, we have to abandon the old storage. */
+-
+- newp = malloc ((2 + newsize) * sizeof (dtv_t));
+- if (newp == NULL)
+- oom ();
+- memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
+- }
+- else
+- {
+- newp = realloc (&dtv[-1],
+- (2 + newsize) * sizeof (dtv_t));
+- if (newp == NULL)
+- oom ();
+- }
+-
+- newp[0].counter = newsize;
+-
+- /* Clear the newly allocated part. */
+- memset (newp + 2 + oldsize, '\0',
+- (newsize - oldsize) * sizeof (dtv_t));
++ /* Resize the dtv. */
++ dtv = _dl_resize_dtv (dtv);
+
+- /* Point dtv to the generation counter. */
+- dtv = &newp[1];
++ assert (modid <= dtv[-1].counter);
+
+ /* Install this new dtv in the thread data
+ structures. */
+diff -urN glibc-2.12-2-gc4ccff1/nptl/Makefile glibc-2.12-2-gc4ccff1.mod/nptl/Makefile
+--- glibc-2.12-2-gc4ccff1/nptl/Makefile 2015-02-18 14:15:28.073462028 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/Makefile 2015-02-18 14:15:49.817786667 -0500
+@@ -245,7 +245,7 @@
+ tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
+ tst-exit1 tst-exit2 tst-exit3 \
+ tst-stdio1 tst-stdio2 \
+- tst-stack1 tst-stack2 tst-stack3 \
++ tst-stack1 tst-stack2 tst-stack3 tst-stack4 \
+ tst-unload \
+ tst-dlsym1 \
+ tst-sysconf \
+@@ -304,7 +304,7 @@
+
+ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
+ tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
+- tst-tls5modd tst-tls5mode tst-tls5modf \
++ tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
+ tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod
+ extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o
+ test-extras += $(modules-names)
+@@ -459,6 +459,19 @@
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@
+ generated += tst-stack3-mem tst-stack3.mtrace
+
++$(objpfx)tst-stack4: $(libdl) $(shared-thread-library)
++tst-stack4mod.sos=$(shell for i in 0 1 2 3 4 5 6 7 8 9 10 \
++ 11 12 13 14 15 16 17 18 19; do \
++ for j in 0 1 2 3 4 5 6 7 8 9 10 \
++ 11 12 13 14 15 16 17 18 19; do \
++ echo $(objpfx)tst-stack4mod-$$i-$$j.so; \
++ done; done)
++$(objpfx)tst-stack4.out: $(tst-stack4mod.sos)
++$(tst-stack4mod.sos): $(objpfx)tst-stack4mod.so
++ cp -f $< $@
++clean:
++ rm -f $(tst-stack4mod.sos)
++
+ $(objpfx)tst-cleanup4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
+ $(objpfx)tst-cleanupx4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
+
+diff -urN glibc-2.12-2-gc4ccff1/nptl/tst-stack4.c glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-stack4.c 1969-12-31 19:00:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4.c 2015-02-18 14:15:49.817786667 -0500
+@@ -0,0 +1,159 @@
++/* Test DTV size oveflow when pthread_create reuses old DTV and TLS is
++ used by dlopened shared object.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdio.h>
++#include <stdint.h>
++#include <dlfcn.h>
++#include <assert.h>
++#include <pthread.h>
++
++/* The choices of thread count, and file counts are arbitary.
++ The point is simply to run enough threads that an exiting
++ thread has it's stack reused by another thread at the same
++ time as new libraries have been loaded. */
++#define DSO_SHARED_FILES 20
++#define DSO_OPEN_THREADS 20
++#define DSO_EXEC_THREADS 2
++
++/* Used to make sure that only one thread is calling dlopen and dlclose
++ at a time. */
++pthread_mutex_t g_lock;
++
++typedef void (*function) (void);
++
++void *
++dso_invoke(void *dso_fun)
++{
++ function *fun_vec = (function *) dso_fun;
++ int dso;
++
++ for (dso = 0; dso < DSO_SHARED_FILES; dso++)
++ (*fun_vec[dso]) ();
++
++ pthread_exit (NULL);
++}
++
++void *
++dso_process (void * p)
++{
++ void *handle[DSO_SHARED_FILES];
++ function fun_vec[DSO_SHARED_FILES];
++ char dso_path[DSO_SHARED_FILES][100];
++ int dso;
++ uintptr_t t = (uintptr_t) p;
++
++ /* Open DSOs and get a function. */
++ for (dso = 0; dso < DSO_SHARED_FILES; dso++)
++ {
++ sprintf (dso_path[dso], "tst-stack4mod-%i-%i.so", t, dso);
++
++ pthread_mutex_lock (&g_lock);
++
++ handle[dso] = dlopen (dso_path[dso], RTLD_NOW);
++ assert (handle[dso]);
++
++ fun_vec[dso] = (function) dlsym (handle[dso], "function");
++ assert (fun_vec[dso]);
++
++ pthread_mutex_unlock (&g_lock);
++ }
++
++ /* Spawn workers. */
++ pthread_t thread[DSO_EXEC_THREADS];
++ int i, ret;
++ uintptr_t result = 0;
++ for (i = 0; i < DSO_EXEC_THREADS; i++)
++ {
++ pthread_mutex_lock (&g_lock);
++ ret = pthread_create (&thread[i], NULL, dso_invoke, (void *) fun_vec);
++ if (ret != 0)
++ {
++ printf ("pthread_create failed: %d\n", ret);
++ result = 1;
++ }
++ pthread_mutex_unlock (&g_lock);
++ }
++
++ if (!result)
++ for (i = 0; i < DSO_EXEC_THREADS; i++)
++ {
++ ret = pthread_join (thread[i], NULL);
++ if (ret != 0)
++ {
++ printf ("pthread_join failed: %d\n", ret);
++ result = 1;
++ }
++ }
++
++ /* Close all DSOs. */
++ for (dso = 0; dso < DSO_SHARED_FILES; dso++)
++ {
++ pthread_mutex_lock (&g_lock);
++ dlclose (handle[dso]);
++ pthread_mutex_unlock (&g_lock);
++ }
++
++ /* Exit. */
++ pthread_exit ((void *) result);
++}
++
++static int
++do_test (void)
++{
++ pthread_t thread[DSO_OPEN_THREADS];
++ int i,j;
++ int ret;
++ int result = 0;
++
++ pthread_mutex_init (&g_lock, NULL);
++
++ /* 100 is arbitrary here and is known to trigger PR 13862. */
++ for (j = 0; j < 100; j++)
++ {
++ for (i = 0; i < DSO_OPEN_THREADS; i++)
++ {
++ ret = pthread_create (&thread[i], NULL, dso_process,
++ (void *) (uintptr_t) i);
++ if (ret != 0)
++ {
++ printf ("pthread_create failed: %d\n", ret);
++ result = 1;
++ }
++ }
++
++ if (result)
++ break;
++
++ for (i = 0; i < DSO_OPEN_THREADS; i++)
++ {
++ ret = pthread_join (thread[i], NULL);
++ if (ret != 0)
++ {
++ printf ("pthread_join failed: %d\n", ret);
++ result = 1;
++ }
++ }
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#define TIMEOUT 100
++#include "../test-skeleton.c"
+diff -urN glibc-2.12-2-gc4ccff1/nptl/tst-stack4mod.c glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4mod.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-stack4mod.c 1969-12-31 19:00:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4mod.c 2015-02-18 14:15:49.817786667 -0500
+@@ -0,0 +1,28 @@
++/* This tests DTV usage with TLS in dlopened shared object.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++/* 256 is arbitrary here and is known to trigger PR 13862. */
++__thread int var[256] attribute_hidden = {0};
++
++void
++function (void)
++{
++ int i;
++ for (i = 0; i < sizeof (var) / sizeof (int); i++)
++ var[i] = i;
++}
--- /dev/null
+#
+# Derived from this upstream commit:
+#
+# commit 58a1335e76a553e1cf4edeebc27f16fc9b53d6e6
+# Author: Petr Baudis <pasky@ucw.cz>
+# Date: Thu Mar 14 01:16:53 2013 +0100
+#
+# Fix __times() handling of EFAULT when buf is NULL
+#
+# 2013-03-14 Petr Baudis <pasky@ucw.cz>
+#
+# * sysdeps/unix/sysv/linux/times.c (__times): On EFAULT, test
+# for non-NULL pointer before the memory validity test. Pointed
+# out by Holger Brunck <holger.brunck@keymile.com>.
+#
+diff --git a/sysdeps/unix/sysv/linux/times.c b/sysdeps/unix/sysv/linux/times.c
+index f3b5f01..e59bb4e 100644
+--- a/sysdeps/unix/sysv/linux/times.c
++++ b/sysdeps/unix/sysv/linux/times.c
+@@ -26,13 +26,14 @@ __times (struct tms *buf)
+ INTERNAL_SYSCALL_DECL (err);
+ clock_t ret = INTERNAL_SYSCALL (times, err, 1, buf);
+ if (INTERNAL_SYSCALL_ERROR_P (ret, err)
+- && __builtin_expect (INTERNAL_SYSCALL_ERRNO (ret, err) == EFAULT, 0))
++ && __builtin_expect (INTERNAL_SYSCALL_ERRNO (ret, err) == EFAULT, 0)
++ && buf)
+ {
+ /* This might be an error or not. For architectures which have
+ no separate return value and error indicators we cannot
+ distinguish a return value of -1 from an error. Do it the
+- hard way. We crash applications which pass in an invalid BUF
+- pointer. */
++ hard way. We crash applications which pass in an invalid
++ non-NULL BUF pointer. Linux allows BUF to be NULL. */
+ #define touch(v) \
+ do { \
+ clock_t temp = v; \
+@@ -44,7 +45,8 @@ __times (struct tms *buf)
+ touch (buf->tms_cutime);
+ touch (buf->tms_cstime);
+
+- /* If we come here the memory is valid and the kernel did not
++ /* If we come here the memory is valid (or BUF is NULL, which is
++ * a valid condition for the kernel syscall) and the kernel did not
+ return an EFAULT error. Return the value given by the kernel. */
+ }
+
--- /dev/null
+commit a11892631d92f594c690d0d50a642b0d1aba58b8
+Author: Ondřej Bílka <neleai@seznam.cz>
+Date: Wed May 7 14:08:57 2014 +0200
+
+ Fix typo in nscd/selinux.c
+
+diff --git a/nscd/selinux.c b/nscd/selinux.c
+index 9a8a5a8..eaed6dd 100644
+--- a/nscd/selinux.c
++++ b/nscd/selinux.c
+@@ -372,7 +372,7 @@ nscd_request_avc_has_perm (int fd, request_type req)
+ /* Get the security class for nscd. If this fails we will likely be
+ unable to do anything unless avc_deny_unknown is 0. */
+ sc_nscd = string_to_security_class ("nscd");
+- if (perm == 0 && avc_deny_unknown == 1)
++ if (sc_nscd == 0 && avc_deny_unknown == 1)
+ dbg_log (_("Error getting security class for nscd."));
+
+ /* Convert permission to AVC bits. */
--- /dev/null
+commit e35c53e397e7abbd41fedacdedcfa5af7b5c2c52
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Tue Jul 8 16:40:24 2014 +0530
+
+ Check value at resplen2 if it is not NULL
+
+ There was a typo in the previous patch due to which resplen2 was
+ checked for non-zero instead of the value at resplen2. Fix that and
+ improve the condition by checking resplen2 for non-NULL (instead of
+ answerp2) and also adding the check in a third place.
+
+diff --git a/resolv/res_query.c b/resolv/res_query.c
+index 4e6612c..e4ee2a6 100644
+--- a/resolv/res_query.c
++++ b/resolv/res_query.c
+@@ -384,7 +384,7 @@ __libc_res_nsearch(res_state statp,
+ answerp2, nanswerp2, resplen2);
+ if (ret > 0 || trailing_dot
+ /* If the second response is valid then we use that. */
+- || (ret == 0 && answerp2 != NULL && resplen2 > 0))
++ || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
+ return (ret);
+ saved_herrno = h_errno;
+ tried_as_is++;
+@@ -424,8 +424,8 @@ __libc_res_nsearch(res_state statp,
+ answer, anslen, answerp,
+ answerp2, nanswerp2,
+ resplen2);
+- if (ret > 0 || (ret == 0 && answerp2 != NULL
+- && resplen2 > 0))
++ if (ret > 0 || (ret == 0 && resplen2 != NULL
++ && *resplen2 > 0))
+ return (ret);
+
+ if (answerp && *answerp != answer) {
+@@ -494,7 +494,8 @@ __libc_res_nsearch(res_state statp,
+ ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen, answerp,
+ answerp2, nanswerp2, resplen2);
+- if (ret > 0)
++ if (ret > 0 || (ret == 0 && resplen2 != NULL
++ && *resplen2 > 0))
+ return (ret);
+ }
+
--- /dev/null
+#
+# Based on this commit:
+#
+# commit 62058ce612ed3459501b4c4332e268edfe977f59
+# Author: Carlos O'Donell <carlos@redhat.com>
+# Date: Mon Sep 29 13:14:21 2014 -0400
+#
+# Correctly size profiling reloc table (bug 17411)
+#
+# During auditing or profiling modes the dynamic loader
+# builds a cache of the relocated PLT entries in order
+# to reuse them when called again through the same PLT
+# entry. This way the PLT entry is never completed and
+# the call into the resolver always results in profiling
+# or auditing code running.
+#
+# The problem is that the PLT relocation cache size
+# is not computed correctly. The size of the cache
+# should be "Size of a relocation result structure"
+# x "Number of PLT-related relocations". Instead the
+# code erroneously computes "Size of a relocation
+# result" x "Number of bytes worth of PLT-related
+# relocations". I can only assume this was a mistake
+# in the understanding of the value of DT_PLTRELSZ
+# which is the number of bytes of PLT-related relocs.
+# We do have a DT_RELACOUNT entry, which is a count
+# for dynamic relative relocs, but we have no
+# DT_PLTRELCOUNT and thus we need to compute it.
+#
+# This patch corrects the computation of the size of the
+# relocation table used by the glibc profiling code.
+#
+# For more details see:
+# https://sourceware.org/ml/libc-alpha/2014-09/msg00513.html
+#
+# [BZ #17411]
+# * elf/dl-reloc.c (_dl_relocate_object): Allocate correct amount for
+# l_reloc_result.
+#
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index d2c6dac..97a7119 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -279,8 +279,12 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ l->l_name);
+ }
+
+- l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
+- l->l_info[DT_PLTRELSZ]->d_un.d_val);
++ size_t sizeofrel = l->l_info[DT_PLTREL]->d_un.d_val == DT_RELA
++ ? sizeof (ElfW(Rela))
++ : sizeof (ElfW(Rel));
++ size_t relcount = l->l_info[DT_PLTRELSZ]->d_un.d_val / sizeofrel;
++ l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]), relcount);
++
+ if (l->l_reloc_result == NULL)
+ {
+ errstring = N_("\
--- /dev/null
+diff --git a/sunrpc/svc.c b/sunrpc/svc.c
+index ccf0902..30c3a93 100644
+--- a/sunrpc/svc.c
++++ b/sunrpc/svc.c
+@@ -97,8 +97,8 @@ xprt_register (SVCXPRT *xprt)
+
+ if (xports == NULL)
+ {
+- xports = (SVCXPRT **) malloc (_rpc_dtablesize () * sizeof (SVCXPRT *));
+- if (xports == NULL) /* Don´t add handle */
++ xports = (SVCXPRT **) calloc (_rpc_dtablesize (), sizeof (SVCXPRT *));
++ if (xports == NULL) /* Don't add handle */
+ return;
+ }
+
--- /dev/null
+commit 7d81e8d6db95c112c297930a8f2f9617c305529a
+Author: Florian Weimer <fweimer@redhat.com>
+Date: Tue Dec 23 16:16:32 2014 +0100
+
+ iconvdata/run-iconv-test.sh: Actually test iconv modules
+
+ Arjun Shankar noticed that this test case was not testing anything
+ because iconv was invoked without the required arguments.
+
+diff --git a/iconvdata/run-iconv-test.sh b/iconvdata/run-iconv-test.sh
+index 5dfb69f..1d0bf52 100755
+--- a/iconvdata/run-iconv-test.sh
++++ b/iconvdata/run-iconv-test.sh
+@@ -189,7 +189,7 @@ printf '\016\377\377\377\377\377\377\377' > $temp1
+ for from in $iconv_modules ; do
+ echo $ac_n "test decoder $from $ac_c"
+ PROG=`eval echo $ICONV`
+- if $PROG < $temp1 >/dev/null 2>&1 ; then
++ if $PROG -f $from -t UTF8 < $temp1 >/dev/null 2>&1 ; then
+ : # fall through
+ else
+ status=$?
Fix parsing of numeric hosts in gethostbyname_r
+diff --git a/nss/Makefile b/nss/Makefile
+index 449a258..553eafa 100644
+--- a/nss/Makefile
++++ b/nss/Makefile
+@@ -37,7 +37,7 @@ install-bin := getent makedb
+ others := getent
+ install-bin := getent
+
+-tests = test-netdb tst-nss-test1
++tests = test-netdb tst-nss-test1 test-digits-dots
+ xtests = bug-erange
+
+ include ../Makeconfig
diff --git a/nss/digits_dots.c b/nss/digits_dots.c
index 2b86295..e007ef4 100644
--- a/nss/digits_dots.c
--- /dev/null
+#
+# Based on AVX-512 support for glibc, but heavaily modified for rhel-6.7.
+# Without assembler support we drop all of the configure checks and simply
+# output using .byte directives the minimal AVX512 instructsion required
+# by the loader. Likewise testing is also impossible, so instead we use
+# the Intel emulator running in `-skx` (Skylake Xeon) emulation mode and
+# verify that a pre-built set of tests passes.
+#
+# commit 6986b98a18490e76b16911d1c6b1ba013598d40d
+# Author: Ulrich Drepper <drepper@gmail.com>
+# Date: Wed Jul 20 14:20:00 2011 -0400
+#
+# Force :a_x86_64_ymm to be 16-byte aligned
+#
+# commit aa4de9cea5c07d43caeaca9722c2d417e9a2919c
+# Author: H.J. Lu <hjl.tools@gmail.com>
+# Date: Fri Mar 14 08:51:25 2014 -0700
+#
+# Check AVX-512 assembler support first
+#
+# It checks AVX-512 assembler support first and sets libc_cv_cc_avx512 to
+# $libc_cv_asm_avx512, instead of yes. GCC won't support AVX-512 if
+# assembler doesn't support it.
+#
+# * sysdeps/x86_64/configure.ac: Check AVX-512 assembler support
+# first. Disable AVX-512 GCC support if assembler doesn't support
+# it.
+# * sysdeps/x86_64/configure: Regenerated.
+#
+# commit 2d63a517e4084ec80403cd9f278690fa8b676cc4
+# Author: Igor Zamyatin <igor.zamyatin@intel.com>
+# Date: Thu Mar 13 11:10:22 2014 -0700
+#
+# Save and restore AVX-512 zmm registers to x86-64 ld.so
+#
+# AVX-512 ISA adds 512-bit zmm registers. This patch updates
+# _dl_runtime_profile to pass zmm registers to run-time audit. It also
+# changes _dl_x86_64_save_sse and _dl_x86_64_restore_sse to upport zmm
+# registers, which are called when only when RTLD_PREPARE_FOREIGN_CALL
+# is used. Its performance impact is minimum.
+#
+# * config.h.in (HAVE_AVX512_SUPPORT): New #undef.
+# (HAVE_AVX512_ASM_SUPPORT): Likewise.
+# * sysdeps/x86_64/bits/link.h (La_x86_64_zmm): New.
+# (La_x86_64_vector): Add zmm.
+# * sysdeps/x86_64/Makefile (tests): Add tst-audit10.
+# (modules-names): Add tst-auditmod10a and tst-auditmod10b.
+# ($(objpfx)tst-audit10): New target.
+# ($(objpfx)tst-audit10.out): Likewise.
+# (tst-audit10-ENV): New.
+# (AVX512-CFLAGS): Likewise.
+# (CFLAGS-tst-audit10.c): Likewise.
+# (CFLAGS-tst-auditmod10a.c): Likewise.
+# (CFLAGS-tst-auditmod10b.c): Likewise.
+# * sysdeps/x86_64/configure.ac: Set config-cflags-avx512,
+# HAVE_AVX512_SUPPORT and HAVE_AVX512_ASM_SUPPORT.
+# * sysdeps/x86_64/configure: Regenerated.
+# * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_profile): Add
+# AVX-512 zmm register support.
+# (_dl_x86_64_save_sse): Likewise.
+# (_dl_x86_64_restore_sse): Likewise.
+# * sysdeps/x86_64/dl-trampoline.h: Updated to support different
+# size vector registers.
+# * sysdeps/x86_64/link-defines.sym (YMM_SIZE): New.
+# (ZMM_SIZE): Likewise.
+# * sysdeps/x86_64/tst-audit10.c: New file.
+# * sysdeps/x86_64/tst-auditmod10a.c: Likewise.
+# * sysdeps/x86_64/tst-auditmod10b.c: Likewise.
+#
+# In addition adds:
+# https://sourceware.org/ml/libc-alpha/2014-09/msg00228.html
+# To extend zmm register checking.
+#
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/bits/link.h glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/bits/link.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/bits/link.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/bits/link.h 2015-03-03 23:03:25.041829238 -0500
+@@ -65,7 +65,10 @@
+ /* Registers for entry into PLT on x86-64. */
+ # if __GNUC_PREREQ (4,0)
+ typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16)));
+-typedef float La_x86_64_ymm __attribute__ ((__vector_size__ (32)));
++typedef float La_x86_64_ymm __attribute__ ((__vector_size__ (32),
++ __aligned__ (16)));
++typedef double La_x86_64_zmm __attribute__ ((__vector_size__ (64),
++ __aligned__ (16)));
+ # else
+ typedef float La_x86_64_xmm __attribute__ ((__mode__ (__V4SF__)));
+ # endif
+@@ -74,9 +77,10 @@
+ {
+ # if __GNUC_PREREQ (4,0)
+ La_x86_64_ymm ymm[2];
++ La_x86_64_zmm zmm[1];
+ # endif
+ La_x86_64_xmm xmm[4];
+-} La_x86_64_vector __attribute__ ((aligned(16)));
++} La_x86_64_vector __attribute__ ((__aligned__(16)));
+
+ typedef struct La_x86_64_regs
+ {
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.h glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.h 2015-03-03 23:03:05.109457627 -0500
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.h 2015-03-03 23:06:58.434101818 -0500
+@@ -20,14 +20,26 @@
+
+ #ifdef RESTORE_AVX
+ /* This is to support AVX audit modules. */
+- vmovdqu %ymm0, (LR_VECTOR_OFFSET)(%rsp)
+- vmovdqu %ymm1, (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp)
+- vmovdqu %ymm2, (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp)
+- vmovdqu %ymm3, (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp)
+- vmovdqu %ymm4, (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp)
+- vmovdqu %ymm5, (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp)
+- vmovdqu %ymm6, (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp)
+- vmovdqu %ymm7, (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp)
++# if HAVE_NO_AVX512_ASM_SUPPORT
++ /* Restore AVX-512 registers. Use .byte becaues we lack assembler support. */
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x44,0x24,0x03 # vmovdqu64 %zmm0,0xc0(%rsp)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x4c,0x24,0x04 # vmovdqu64 %zmm1,0x100(%rsp)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x54,0x24,0x05 # vmovdqu64 %zmm2,0x140(%rsp)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x5c,0x24,0x06 # vmovdqu64 %zmm3,0x180(%rsp)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x64,0x24,0x07 # vmovdqu64 %zmm4,0x1c0(%rsp)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x6c,0x24,0x08 # vmovdqu64 %zmm5,0x200(%rsp)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x74,0x24,0x09 # vmovdqu64 %zmm6,0x240(%rsp)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x7c,0x24,0x0a # vmovdqu64 %zmm7,0x280(%rsp)
++# else
++ VMOV %VEC(0), (LR_VECTOR_OFFSET)(%rsp)
++ VMOV %VEC(1), (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp)
++ VMOV %VEC(2), (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp)
++ VMOV %VEC(3), (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp)
++ VMOV %VEC(4), (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp)
++ VMOV %VEC(5), (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp)
++ VMOV %VEC(6), (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp)
++ VMOV %VEC(7), (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp)
++# endif
+
+ /* Save xmm0-xmm7 registers to detect if any of them are
+ changed by audit module. */
+@@ -73,7 +85,11 @@
+ je 2f
+ vmovdqa %xmm0, (LR_VECTOR_OFFSET)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET)(%rsp), %ymm0
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x44,0x24,0x03 # vmovdqu64 0xc0(%rsp),%zmm0
++# else
++2: VMOV (LR_VECTOR_OFFSET)(%rsp), %VEC(0)
++# endif
+ vmovdqa %xmm0, (LR_XMM_OFFSET)(%rsp)
+
+ 1: vpcmpeqq (LR_SIZE + XMM_SIZE)(%rsp), %xmm1, %xmm8
+@@ -82,7 +98,11 @@
+ je 2f
+ vmovdqa %xmm1, (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp), %ymm1
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x4c,0x24,0x04 # vmovdqu64 0x100(%rsp),%zmm1
++# else
++2: VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp), %VEC(1)
++# endif
+ vmovdqa %xmm1, (LR_XMM_OFFSET + XMM_SIZE)(%rsp)
+
+ 1: vpcmpeqq (LR_SIZE + XMM_SIZE*2)(%rsp), %xmm2, %xmm8
+@@ -91,7 +111,11 @@
+ je 2f
+ vmovdqa %xmm2, (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp), %ymm2
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x54,0x24,0x05 # vmovdqu64 0x140(%rsp),%zmm2
++# else
++2: VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp), %VEC(2)
++# endif
+ vmovdqa %xmm2, (LR_XMM_OFFSET + XMM_SIZE*2)(%rsp)
+
+ 1: vpcmpeqq (LR_SIZE + XMM_SIZE*3)(%rsp), %xmm3, %xmm8
+@@ -100,7 +124,11 @@
+ je 2f
+ vmovdqa %xmm3, (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp), %ymm3
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x5c,0x24,0x06 # vmovdqu64 0x180(%rsp),%zmm3
++# else
++2: VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp), %VEC(3)
++# endif
+ vmovdqa %xmm3, (LR_XMM_OFFSET + XMM_SIZE*3)(%rsp)
+
+ 1: vpcmpeqq (LR_SIZE + XMM_SIZE*4)(%rsp), %xmm4, %xmm8
+@@ -109,7 +137,11 @@
+ je 2f
+ vmovdqa %xmm4, (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp), %ymm4
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x64,0x24,0x07 # vmovdqu64 0x1c0(%rsp),%zmm4
++# else
++2: VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp), %VEC(4)
++# endif
+ vmovdqa %xmm4, (LR_XMM_OFFSET + XMM_SIZE*4)(%rsp)
+
+ 1: vpcmpeqq (LR_SIZE + XMM_SIZE*5)(%rsp), %xmm5, %xmm8
+@@ -118,7 +150,11 @@
+ je 2f
+ vmovdqa %xmm5, (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp), %ymm5
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x6c,0x24,0x08 # vmovdqu64 0x200(%rsp),%zmm5
++# else
++2: VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp), %VEC(5)
++# endif
+ vmovdqa %xmm5, (LR_XMM_OFFSET + XMM_SIZE*5)(%rsp)
+
+ 1: vpcmpeqq (LR_SIZE + XMM_SIZE*6)(%rsp), %xmm6, %xmm8
+@@ -127,7 +163,11 @@
+ je 2f
+ vmovdqa %xmm6, (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp), %ymm6
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x74,0x24,0x09 # vmovdqu64 0x240(%rsp),%zmm6
++# else
++2: VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp), %VEC(6)
++# endif
+ vmovdqa %xmm6, (LR_XMM_OFFSET + XMM_SIZE*6)(%rsp)
+
+ 1: vpcmpeqq (LR_SIZE + XMM_SIZE*7)(%rsp), %xmm7, %xmm8
+@@ -136,7 +176,11 @@
+ je 2f
+ vmovdqa %xmm7, (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp)
+ jmp 1f
+-2: vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp), %ymm7
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2: .byte 0x62,0xf1,0xfe,0x48,0x6f,0x7c,0x24,0x0a # vmovdqu64 0x280(%rsp),%zmm7
++# else
++2: VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp), %VEC(7)
++# endif
+ vmovdqa %xmm7, (LR_XMM_OFFSET + XMM_SIZE*7)(%rsp)
+
+ 1:
+@@ -214,8 +258,13 @@
+
+ #ifdef RESTORE_AVX
+ /* This is to support AVX audit modules. */
+- vmovdqu %ymm0, LRV_VECTOR0_OFFSET(%rcx)
+- vmovdqu %ymm1, LRV_VECTOR1_OFFSET(%rcx)
++# if HAVE_NO_AVX512_ASM_SUPPORT
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x81,0x50,0x00,0x00,0x00 # vmovdqu64 %zmm0,0x50(%rcx)
++ .byte 0x62,0xf1,0xfe,0x48,0x7f,0x89,0x90,0x00,0x00,0x00 # vmovdqu64 %zmm1,0x90(%rcx)
++# else
++ VMOV %VEC(0), LRV_VECTOR0_OFFSET(%rcx)
++ VMOV %VEC(1), LRV_VECTOR1_OFFSET(%rcx)
++# endif
+
+ /* Save xmm0/xmm1 registers to detect if they are changed
+ by audit module. */
+@@ -244,13 +293,21 @@
+ vpmovmskb %xmm2, %esi
+ cmpl $0xffff, %esi
+ jne 1f
+- vmovdqu LRV_VECTOR0_OFFSET(%rsp), %ymm0
++# if HAVE_NO_AVX512_ASM_SUPPORT
++ .byte 0x62,0xf1,0xfe,0x48,0x6f,0x84,0x24,0x50,0x00,0x00,0x00 # vmovdqu64 0x50(%rsp),%zmm0
++# else
++ VMOV LRV_VECTOR0_OFFSET(%rsp), %VEC(0)
++# endif
+
+ 1: vpcmpeqq (LRV_SIZE + XMM_SIZE)(%rsp), %xmm1, %xmm2
+ vpmovmskb %xmm2, %esi
+ cmpl $0xffff, %esi
+ jne 1f
+- vmovdqu LRV_VECTOR1_OFFSET(%rsp), %ymm1
++# if HAVE_NO_AVX512_ASM_SUPPORT
++ .byte 0x62,0xf1,0xfe,0x48,0x6f,0x8c,0x24,0x90,0x00,0x00,0x00 # vmovdqu64 0x90(%rsp),%zmm1
++# else
++ VMOV LRV_VECTOR1_OFFSET(%rsp), %VEC(1)
++# endif
+
+ 1:
+ #endif
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.S glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.S
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.S 2015-03-03 23:03:05.108457659 -0500
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.S 2015-03-03 23:07:31.799049953 -0500
+@@ -134,7 +134,7 @@
+ .previous
+
+ cmpl $0, L(have_avx)(%rip)
+- jne 1f
++ jne L(defined)
+ movq %rbx, %r11 # Save rbx
+ movl $1, %eax
+ cpuid
+@@ -143,18 +143,51 @@
+ // AVX and XSAVE supported?
+ andl $((1 << 28) | (1 << 27)), %ecx
+ cmpl $((1 << 28) | (1 << 27)), %ecx
+- jne 2f
++ jne 10f
++ // AVX512 supported in processor?
++ movq %rbx, %r11 # Save rbx
++ xorl %ecx, %ecx
++ mov $0x7, %eax
++ cpuid
++ andl $(1 << 16), %ebx
+ xorl %ecx, %ecx
+ // Get XFEATURE_ENABLED_MASK
+ xgetbv
+- andl $0x6, %eax
+-2: subl $0x5, %eax
++ test %ebx, %ebx
++ movq %r11, %rbx # Restore rbx
++ je 20f
++ // Verify that XCR0[7:5] = '111b' and
++ // XCR0[2:1] = '11b' which means
++ // that zmm state is enabled
++ andl $0xe6, %eax
++ cmpl $0xe6, %eax
++ jne 20f
++ movl %eax, L(have_avx)(%rip)
++L(avx512):
++# define RESTORE_AVX
++# define HAVE_NO_AVX512_ASM_SUPPORT 1
++# define VMOV vmovdqu64
++# define VEC(i) zmm##i
++# define MORE_CODE
++# include "dl-trampoline.h"
++# undef VMOV
++# undef VEC
++# undef RESTORE_AVX
++# undef HAVE_NO_AVX512_ASM_SUPPORT
++20: andl $0x6, %eax
++10: subl $0x5, %eax
+ movl %eax, L(have_avx)(%rip)
+ cmpl $0, %eax
+
+-1: js L(no_avx)
++L(defined):
++ js L(no_avx)
++ cmpl $0xe6, L(have_avx)(%rip)
++ je L(avx512)
++
+
+ # define RESTORE_AVX
++# define VMOV vmovdqu
++# define VEC(i) ymm##i
+ # define MORE_CODE
+ # include "dl-trampoline.h"
+
+@@ -178,7 +211,7 @@
+ _dl_x86_64_save_sse:
+ # ifdef HAVE_AVX_SUPPORT
+ cmpl $0, L(have_avx)(%rip)
+- jne 1f
++ jne L(defined_5)
+ movq %rbx, %r11 # Save rbx
+ movl $1, %eax
+ cpuid
+@@ -187,21 +220,37 @@
+ // AVX and XSAVE supported?
+ andl $((1 << 28) | (1 << 27)), %ecx
+ cmpl $((1 << 28) | (1 << 27)), %ecx
+- jne 2f
++ jne 1f
++ // AVX512 supported in a processor?
++ movq %rbx, %r11 # Save rbx
++ xorl %ecx,%ecx
++ mov $0x7,%eax
++ cpuid
++ andl $(1 << 16), %ebx
+ xorl %ecx, %ecx
+ // Get XFEATURE_ENABLED_MASK
+ xgetbv
+- andl $0x6, %eax
+- cmpl $0x6, %eax
+- // Nonzero if SSE and AVX state saving is enabled.
+- sete %al
+-2: leal -1(%eax,%eax), %eax
++ test %ebx, %ebx
++ movq %r11, %rbx # Restore rbx
++ je 2f
++ // Verify that XCR0[7:5] = '111b' and
++ // XCR0[2:1] = '11b' which means
++ // that zmm state is enabled
++ andl $0xe6, %eax
+ movl %eax, L(have_avx)(%rip)
+- cmpl $0, %eax
++ cmpl $0xe6, %eax
++ je L(avx512_5)
+
+-1: js L(no_avx5)
++2: andl $0x6, %eax
++1: subl $0x5, %eax
++ movl %eax, L(have_avx)(%rip)
++ cmpl $0, %eax
+
+-# define YMM_SIZE 32
++L(defined_5):
++ js L(no_avx5)
++ cmpl $0xe6, L(have_avx)(%rip)
++ je L(avx512_5)
++
+ vmovdqa %ymm0, %fs:RTLD_SAVESPACE_SSE+0*YMM_SIZE
+ vmovdqa %ymm1, %fs:RTLD_SAVESPACE_SSE+1*YMM_SIZE
+ vmovdqa %ymm2, %fs:RTLD_SAVESPACE_SSE+2*YMM_SIZE
+@@ -211,6 +260,26 @@
+ vmovdqa %ymm6, %fs:RTLD_SAVESPACE_SSE+6*YMM_SIZE
+ vmovdqa %ymm7, %fs:RTLD_SAVESPACE_SSE+7*YMM_SIZE
+ ret
++L(avx512_5):
++# Original instructions:
++# vmovdqu64 %zmm0, %fs:RTLD_SAVESPACE_SSE+0*ZMM_SIZE
++# vmovdqu64 %zmm1, %fs:RTLD_SAVESPACE_SSE+1*ZMM_SIZE
++# vmovdqu64 %zmm2, %fs:RTLD_SAVESPACE_SSE+2*ZMM_SIZE
++# vmovdqu64 %zmm3, %fs:RTLD_SAVESPACE_SSE+3*ZMM_SIZE
++# vmovdqu64 %zmm4, %fs:RTLD_SAVESPACE_SSE+4*ZMM_SIZE
++# vmovdqu64 %zmm5, %fs:RTLD_SAVESPACE_SSE+5*ZMM_SIZE
++# vmovdqu64 %zmm6, %fs:RTLD_SAVESPACE_SSE+6*ZMM_SIZE
++# vmovdqu64 %zmm7, %fs:RTLD_SAVESPACE_SSE+7*ZMM_SIZE
++# Assembled instructions:
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x04,0x25,0x80,0x00,0x00,0x00 # vmovdqu64 %zmm0,%fs:0x80
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x0c,0x25,0xc0,0x00,0x00,0x00 # vmovdqu64 %zmm1,%fs:0xc0
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x14,0x25,0x00,0x01,0x00,0x00 # vmovdqu64 %zmm2,%fs:0x100
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x1c,0x25,0x40,0x01,0x00,0x00 # vmovdqu64 %zmm3,%fs:0x140
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x24,0x25,0x80,0x01,0x00,0x00 # vmovdqu64 %zmm4,%fs:0x180
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x2c,0x25,0xc0,0x01,0x00,0x00 # vmovdqu64 %zmm5,%fs:0x1c0
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x34,0x25,0x00,0x02,0x00,0x00 # vmovdqu64 %zmm6,%fs:0x200
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x3c,0x25,0x40,0x02,0x00,0x00 # vmovdqu64 %zmm7,%fs:0x240
++ ret
+ L(no_avx5):
+ # endif
+ movdqa %xmm0, %fs:RTLD_SAVESPACE_SSE+0*XMM_SIZE
+@@ -234,6 +303,8 @@
+ # ifdef HAVE_AVX_SUPPORT
+ cmpl $0, L(have_avx)(%rip)
+ js L(no_avx6)
++ cmpl $0xe6, L(have_avx)(%rip)
++ je L(avx512_6)
+
+ vmovdqa %fs:RTLD_SAVESPACE_SSE+0*YMM_SIZE, %ymm0
+ vmovdqa %fs:RTLD_SAVESPACE_SSE+1*YMM_SIZE, %ymm1
+@@ -244,6 +315,26 @@
+ vmovdqa %fs:RTLD_SAVESPACE_SSE+6*YMM_SIZE, %ymm6
+ vmovdqa %fs:RTLD_SAVESPACE_SSE+7*YMM_SIZE, %ymm7
+ ret
++L(avx512_6):
++# Original instructions:
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+0*ZMM_SIZE, %zmm0
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+1*ZMM_SIZE, %zmm1
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+2*ZMM_SIZE, %zmm2
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+3*ZMM_SIZE, %zmm3
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+4*ZMM_SIZE, %zmm4
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+5*ZMM_SIZE, %zmm5
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+6*ZMM_SIZE, %zmm6
++# vmovdqu64 %fs:RTLD_SAVESPACE_SSE+7*ZMM_SIZE, %zmm7
++# Assembled instructions:
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x04,0x25,0x80,0x00,0x00,0x00 # vmovdqu64 %fs:0x80,%zmm0
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x0c,0x25,0xc0,0x00,0x00,0x00 # vmovdqu64 %fs:0xc0,%zmm1
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x14,0x25,0x00,0x01,0x00,0x00 # vmovdqu64 %fs:0x100,%zmm2
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x1c,0x25,0x40,0x01,0x00,0x00 # vmovdqu64 %fs:0x140,%zmm3
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x24,0x25,0x80,0x01,0x00,0x00 # vmovdqu64 %fs:0x180,%zmm4
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x2c,0x25,0xc0,0x01,0x00,0x00 # vmovdqu64 %fs:0x1c0,%zmm5
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x34,0x25,0x00,0x02,0x00,0x00 # vmovdqu64 %fs:0x200,%zmm6
++ .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x3c,0x25,0x40,0x02,0x00,0x00 # vmovdqu64 %fs:0x240,%zmm7
++ ret
+ L(no_avx6):
+ # endif
+ movdqa %fs:RTLD_SAVESPACE_SSE+0*XMM_SIZE, %xmm0
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/link-defines.sym glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/link-defines.sym
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/link-defines.sym 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/link-defines.sym 2015-03-03 23:03:25.042829206 -0500
+@@ -4,6 +4,8 @@
+ --
+ VECTOR_SIZE sizeof (La_x86_64_vector)
+ XMM_SIZE sizeof (La_x86_64_xmm)
++YMM_SIZE sizeof (La_x86_64_ymm)
++ZMM_SIZE sizeof (La_x86_64_zmm)
+
+ LR_SIZE sizeof (struct La_x86_64_regs)
+ LR_RDX_OFFSET offsetof (struct La_x86_64_regs, lr_rdx)
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.new/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c 2015-04-10 12:02:54.011106386 +0530
++++ glibc-2.12-2-gc4ccff1.new/malloc/malloc.c 2015-04-10 12:02:35.867958292 +0530
+@@ -5850,7 +5850,7 @@ _int_valloc(av, bytes) mstate av; size_t
+ #endif
+ {
+ /* Ensure initialization/consolidation */
+- if (have_fastchunks(av)) malloc_consolidate(av);
++ if (av && have_fastchunks(av)) malloc_consolidate(av);
+ return _int_memalign(av, mp_.pagesize, bytes);
+ }
+
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.new/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c 2015-07-28 22:28:22.517107147 +0530
++++ glibc-2.12-2-gc4ccff1.new/malloc/malloc.c 2015-07-28 22:24:59.541394493 +0530
+@@ -4087,8 +4087,9 @@ public_cALLOc(size_t n, size_t elem_size
+ /* Maybe the failure is due to running out of mmapped areas. */
+ if(av != &main_arena) {
+ (void)mutex_unlock(&av->mutex);
+- (void)mutex_lock(&main_arena.mutex);
+- mem = _int_malloc(&main_arena, sz);
++ av = &main_arena;
++ (void)mutex_lock(&av->mutex);
++ mem = _int_malloc(av, sz);
+ } else {
+ #if USE_ARENAS
+ /* ... or sbrk() has failed and there is still a chance to mmap() */
--- /dev/null
+commit fdc0f374bcd2d0513569aa8d600f960e43e8af1d
+Author: Ulrich Drepper <drepper@redhat.com>
+Date: Sun Oct 24 22:37:00 2010 -0400
+
+ Fix perturbing in malloc on free.
+
+commit e8349efd466cfedc0aa98be61d88ca8795c9e565
+Author: Ondřej Bílka <neleai@seznam.cz>
+Date: Mon Dec 9 17:25:19 2013 +0100
+
+ Simplify perturb_byte logic.
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 4821deb..ac8c3f6 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1870,8 +1870,20 @@ static int check_action = DEFAULT_CHECK_ACTION;
+
+ static int perturb_byte;
+
+-#define alloc_perturb(p, n) memset (p, (perturb_byte ^ 0xff) & 0xff, n)
+-#define free_perturb(p, n) memset (p, perturb_byte & 0xff, n)
++static inline void
++alloc_perturb (char *p, size_t n)
++{
++ if (__glibc_unlikely (perturb_byte))
++ memset (p, perturb_byte ^ 0xff, n);
++}
++
++static inline void
++free_perturb (char *p, size_t n)
++{
++ if (__glibc_unlikely (perturb_byte))
++ memset (p, perturb_byte, n);
++}
++
+
+
+ /* ------------------- Support for multiple arenas -------------------- */
+@@ -3287,8 +3299,7 @@ _int_malloc(mstate av, size_t bytes)
+ #endif
+ check_remalloced_chunk(av, victim, nb);
+ void *p = chunk2mem(victim);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
++ alloc_perturb (p, bytes);
+ return p;
+ }
+ }
+@@ -3323,8 +3334,7 @@ _int_malloc(mstate av, size_t bytes)
+ victim->size |= NON_MAIN_ARENA;
+ check_malloced_chunk(av, victim, nb);
+ void *p = chunk2mem(victim);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
++ alloc_perturb (p, bytes);
+ return p;
+ }
+ }
+@@ -3403,8 +3413,7 @@ _int_malloc(mstate av, size_t bytes)
+
+ check_malloced_chunk(av, victim, nb);
+ void *p = chunk2mem(victim);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
++ alloc_perturb (p, bytes);
+ return p;
+ }
+
+@@ -3420,8 +3429,7 @@ _int_malloc(mstate av, size_t bytes)
+ victim->size |= NON_MAIN_ARENA;
+ check_malloced_chunk(av, victim, nb);
+ void *p = chunk2mem(victim);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
++ alloc_perturb (p, bytes);
+ return p;
+ }
+
+@@ -3545,8 +3553,7 @@ _int_malloc(mstate av, size_t bytes)
+ }
+ check_malloced_chunk(av, victim, nb);
+ void *p = chunk2mem(victim);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
++ alloc_perturb (p, bytes);
+ return p;
+ }
+ }
+@@ -3649,8 +3656,7 @@ _int_malloc(mstate av, size_t bytes)
+ }
+ check_malloced_chunk(av, victim, nb);
+ void *p = chunk2mem(victim);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
++ alloc_perturb (p, bytes);
+ return p;
+ }
+ }
+@@ -3684,8 +3690,7 @@ _int_malloc(mstate av, size_t bytes)
+
+ check_malloced_chunk(av, victim, nb);
+ void *p = chunk2mem(victim);
+- if (__builtin_expect (perturb_byte, 0))
+- alloc_perturb (p, bytes);
++ alloc_perturb (p, bytes);
+ return p;
+ }
+
+@@ -3705,7 +3710,7 @@ _int_malloc(mstate av, size_t bytes)
+ */
+ else {
+ void *p = sYSMALLOc(nb, av);
+- if (p != NULL && __builtin_expect (perturb_byte, 0))
++ if (p != NULL)
+ alloc_perturb (p, bytes);
+ return p;
+ }
+@@ -3798,8 +3803,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
+ #endif
+ }
+
+- if (__builtin_expect (perturb_byte, 0))
+- free_perturb (chunk2mem(p), size - SIZE_SZ);
++ free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+
+ set_fastchunks(av);
+ unsigned int idx = fastbin_index(size);
+@@ -3881,8 +3885,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
+ goto errout;
+ }
+
+- if (__builtin_expect (perturb_byte, 0))
+- free_perturb (chunk2mem(p), size - SIZE_SZ);
++ free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+
+ /* consolidate backward */
+ if (!prev_inuse(p)) {
--- /dev/null
+commit 55765a349a96482207fbf927d3666a51878f973b
+Author: Josef Bacik <josef@toxicpanda.com>
+Date: Wed Aug 19 14:06:56 2015 +0530
+
+ Don't fall back to mmap if the original arena is not corrupt
+
+ The new logic to find an uncontended non-corrupt arena misses a case
+ where the current arena is contended, but is not corrupt. In the
+ degenerate case, this is the only arena. In both cases, the logic
+ falls back to using mmap despite there being an available arena.
+
+ Attached patch by Josef Bacik makes sure that all arenas are indeed
+ corrupt before falling back to malloc. Verified on x86_64.
+
+ * malloc/arena.c (reused_arena): return NULL only if all
+ arenas are corrupt.
+
+diff --git a/malloc/arena.c b/malloc/arena.c
+index 21ecc5a1..0424273 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -823,16 +823,21 @@ reused_arena (mstate avoid_arena)
+
+ /* Make sure that the arena we get is not corrupted. */
+ mstate begin = result;
++ bool looped = false;
++
+ while (arena_is_corrupt (result))
+ {
+ result = result->next;
+ if (result == begin)
+- break;
++ {
++ looped = true;
++ break;
++ }
+ }
+
+ /* We could not find any arena that was either not corrupted or not the one
+ we wanted to avoid. */
+- if (result == begin)
++ if (looped)
+ return NULL;
+
+ /* No arena available without contention. Wait for the next in line. */
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.v2/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c 2015-07-24 19:29:37.679907396 +0530
++++ glibc-2.12-2-gc4ccff1.v2/malloc/malloc.c 2015-07-24 18:59:59.928055174 +0530
+@@ -3737,8 +3737,7 @@ public_mALLOc(size_t bytes)
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes, true);
+- if(ar_ptr)
+- victim = _int_malloc(ar_ptr, bytes);
++ victim = _int_malloc(ar_ptr, bytes);
+ #endif
+ }
+ }
+@@ -3968,8 +3967,7 @@ public_mEMALIGn(size_t alignment, size_t
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes, true);
+- if(ar_ptr)
+- p = _int_memalign(ar_ptr, alignment, bytes);
++ p = _int_memalign(ar_ptr, alignment, bytes);
+ #endif
+ }
+ }
+@@ -4024,8 +4022,7 @@ public_vALLOc(size_t bytes)
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes, true);
+- if(ar_ptr)
+- p = _int_memalign(ar_ptr, pagesz, bytes);
++ p = _int_memalign(ar_ptr, pagesz, bytes);
+ #endif
+ }
+ }
+@@ -4080,8 +4077,7 @@ public_pVALLOc(size_t bytes)
+ mstate prev = ar_ptr->next ? ar_ptr : 0;
+ (void)mutex_unlock(&ar_ptr->mutex);
+ ar_ptr = arena_get2(prev, bytes + 2*pagesz + MINSIZE, true);
+- if(ar_ptr)
+- p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
++ p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
+ #endif
+ }
+ }
+@@ -4180,11 +4176,9 @@ public_cALLOc(size_t n, size_t elem_size
+ mstate prev = av->next ? av : 0;
+ (void)mutex_unlock(&av->mutex);
+ av = arena_get2(prev, sz, true);
+- if(av)
+- mem = _int_malloc(av, sz);
++ mem = _int_malloc(av, sz);
+ #endif
+ }
+- if (mem == 0) return 0;
+ }
+
+ if (av != NULL)
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.new/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c 2015-08-19 23:13:52.826205930 +0530
++++ glibc-2.12-2-gc4ccff1.new/malloc/malloc.c 2015-08-19 23:13:40.021049289 +0530
+@@ -5867,7 +5867,7 @@ _int_pvalloc(av, bytes) mstate av, size_
+ size_t pagesz;
+
+ /* Ensure initialization/consolidation */
+- if (have_fastchunks(av)) malloc_consolidate(av);
++ if (av && have_fastchunks(av)) malloc_consolidate(av);
+ pagesz = mp_.pagesize;
+ return _int_memalign(av, pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));
+ }
--- /dev/null
+commit 5c44738353ecaa1c81efca063ee8b55e092d7a43
+Author: Alexandre Oliva <aoliva@redhat.com>
+Date: Wed Sep 5 15:43:04 2012 -0300
+
+ Don't change no_dyn_threshold on mallopt failure
+
+ * malloc/malloc.c (__libc_mallopt) <M_MMAP_THRESHOLD>: Do not
+ change internal state upon failure.
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index bd562df..c69e281 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -4769,8 +4769,10 @@ int __libc_mallopt(int param_number, int value)
+ res = 0;
+ else
+ #endif
+- mp_.mmap_threshold = value;
+- mp_.no_dyn_threshold = 1;
++ {
++ mp_.mmap_threshold = value;
++ mp_.no_dyn_threshold = 1;
++ }
+ break;
+
+ case M_MMAP_MAX:
--- /dev/null
+Description: Allow loading more libraries with static TLS.
+Author: Carlos O'Donell <codonell@redhat.com>
+Origin: PATCH
+Bug-RHEL: #1291270 (rhel-6.7.z), #1198802 (rhel-6.8), #1202952 (rhel-7.2)
+Bug-Fedora: #1124987 (F21)
+Bug-Upstream: #17090, #17620, #17621, #17628 (2.22)
+Upstream status: not-needed
+#
+# The correct fix for this is already upstream and involves
+# changing the heuristics for DTV slot increases. In RHEL6
+# we take the conservative approach and provide a larger
+# slot surplus. This matches what was done in Fedora 21 before
+# we had the upstream fix: f8aeae347377f3dfa8cbadde057adf1827fb1d44.
+# In RHEL7 we have the upstream fix. This is fixed upstream as of
+# glibc 2.22.
+#
+Index: glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/sysdeps/generic/ldsodefs.h
++++ glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h
+@@ -496,8 +496,18 @@ struct rtld_global
+ have to iterate beyond the first element in the slotinfo list. */
+ #define TLS_SLOTINFO_SURPLUS (62)
+
+-/* Number of additional slots in the dtv allocated. */
+-#define DTV_SURPLUS (14)
++/* Number of additional allocated dtv slots. This was initially
++ 14, but problems with python, MESA, and X11's uses of static TLS meant
++ that most distributions were very close to this limit when they loaded
++ dynamically interpreted languages that used graphics. The simplest
++ solution was to roughly double the number of slots. The actual static
++ image space usage was relatively small, for example in MESA you
++ had only two dispatch pointers for a total of 16 bytes. If we hit up
++ against this limit again we should start a campaign with the
++ distributions to coordinate the usage of static TLS. Any user of this
++ resource is effectively coordinating a global resource since this
++ surplus is allocated for each thread at startup. */
++#define DTV_SURPLUS (32)
+
+ /* Initial dtv of the main thread, not allocated with normal malloc. */
+ EXTERN void *_dl_initial_dtv;
--- /dev/null
+Sourceware bug 16574
+
+commit d668061994a7486a3ba9c7d5e7882d85a2883707
+Author: Andreas Schwab <schwab@suse.de>
+Date: Thu Feb 13 11:01:57 2014 +0100
+
+ Fix memory leak in _nss_dns_gethostbyname4_r with big DNS answer
+
+commit ab7ac0f2cf8731fe4c3f3aea6088a7c0127b5725
+Author: Ondřej Bílka <neleai@seznam.cz>
+Date: Sun Feb 16 12:59:23 2014 +0100
+
+ Deduplicate resolv/nss_dns/dns-host.c
+
+ In resolv/nss_dns/dns-host.c one of code path duplicated code after
+ that. We merge these paths.
+
+commit ab09bf616ad527b249aca5f2a4956fd526f0712f
+Author: Andreas Schwab <schwab@suse.de>
+Date: Tue Feb 18 10:57:25 2014 +0100
+
+ Properly fix memory leak in _nss_dns_gethostbyname4_r with big DNS answer
+
+ Instead of trying to guess whether the second buffer needs to be freed
+ set a flag at the place it is allocated
+
+Index: glibc-2.12-2-gc4ccff1/include/resolv.h
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/include/resolv.h
++++ glibc-2.12-2-gc4ccff1/include/resolv.h
+@@ -58,11 +58,11 @@ libc_hidden_proto (__res_randomid)
+ libc_hidden_proto (__res_state)
+
+ int __libc_res_nquery (res_state, const char *, int, int, u_char *, int,
+- u_char **, u_char **, int *, int *);
++ u_char **, u_char **, int *, int *, int *);
+ int __libc_res_nsearch (res_state, const char *, int, int, u_char *, int,
+- u_char **, u_char **, int *, int *);
++ u_char **, u_char **, int *, int *, int *);
+ int __libc_res_nsend (res_state, const u_char *, int, const u_char *, int,
+- u_char *, int, u_char **, u_char **, int *, int *)
++ u_char *, int, u_char **, u_char **, int *, int *, int *)
+ attribute_hidden;
+
+ libresolv_hidden_proto (_sethtent)
+Index: glibc-2.12-2-gc4ccff1/resolv/gethnamaddr.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/gethnamaddr.c
++++ glibc-2.12-2-gc4ccff1/resolv/gethnamaddr.c
+@@ -634,7 +634,7 @@ gethostbyname2(name, af)
+ buf.buf = origbuf = (querybuf *) alloca (1024);
+
+ if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
+- &buf.ptr, NULL, NULL, NULL)) < 0) {
++ &buf.ptr, NULL, NULL, NULL, NULL)) < 0) {
+ if (buf.buf != origbuf)
+ free (buf.buf);
+ Dprintf("res_nsearch failed (%d)\n", n);
+@@ -729,12 +729,12 @@ gethostbyaddr(addr, len, af)
+ buf.buf = orig_buf = (querybuf *) alloca (1024);
+
+ n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
+- &buf.ptr, NULL, NULL, NULL);
++ &buf.ptr, NULL, NULL, NULL, NULL);
+ if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
+ strcpy(qp, "ip6.int");
+ n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
+ buf.buf != orig_buf ? MAXPACKET : 1024,
+- &buf.ptr, NULL, NULL, NULL);
++ &buf.ptr, NULL, NULL, NULL, NULL);
+ }
+ if (n < 0) {
+ if (buf.buf != orig_buf)
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-canon.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-canon.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-canon.c
+@@ -62,7 +62,7 @@ _nss_dns_getcanonname_r (const char *nam
+ {
+ int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
+ buf, sizeof (buf), &ansp.ptr, NULL, NULL,
+- NULL);
++ NULL, NULL);
+ if (r > 0)
+ {
+ /* We need to decode the response. Just one question record.
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-host.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+@@ -191,7 +191,7 @@ _nss_dns_gethostbyname3_r (const char *n
+ host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+
+ n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
+- 1024, &host_buffer.ptr, NULL, NULL, NULL);
++ 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+ if (n < 0)
+ {
+ switch (errno)
+@@ -221,7 +221,7 @@ _nss_dns_gethostbyname3_r (const char *n
+ n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
+ host_buffer.buf != orig_host_buffer
+ ? MAXPACKET : 1024, &host_buffer.ptr,
+- NULL, NULL, NULL);
++ NULL, NULL, NULL, NULL);
+
+ if (n < 0)
+ {
+@@ -304,13 +304,20 @@ _nss_dns_gethostbyname4_r (const char *n
+ u_char *ans2p = NULL;
+ int nans2p = 0;
+ int resplen2 = 0;
++ int ans2p_malloced = 0;
+
+ int olderr = errno;
+ enum nss_status status;
+ int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
+ host_buffer.buf->buf, 2048, &host_buffer.ptr,
+- &ans2p, &nans2p, &resplen2);
+- if (n < 0)
++ &ans2p, &nans2p, &resplen2, &ans2p_malloced);
++ if (n >= 0)
++ {
++ status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
++ resplen2, name, pat, buffer, buflen,
++ errnop, herrnop, ttlp);
++ }
++ else
+ {
+ if (errno == ESRCH)
+ {
+@@ -325,16 +332,11 @@ _nss_dns_gethostbyname4_r (const char *n
+ *errnop = EAGAIN;
+ else
+ __set_errno (olderr);
+-
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
+-
+- return status;
+ }
+
+- status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
+- resplen2, name, pat, buffer, buflen,
+- errnop, herrnop, ttlp);
++ /* Check whether ans2p was separately allocated. */
++ if (ans2p_malloced)
++ free (ans2p);
+
+ if (host_buffer.buf != orig_host_buffer)
+ free (host_buffer.buf);
+@@ -444,7 +446,7 @@ _nss_dns_gethostbyaddr2_r (const void *a
+ strcpy (qp, "].ip6.arpa");
+ n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
+ host_buffer.buf->buf, 1024, &host_buffer.ptr,
+- NULL, NULL, NULL);
++ NULL, NULL, NULL, NULL);
+ if (n >= 0)
+ goto got_it_already;
+ }
+@@ -465,14 +467,14 @@ _nss_dns_gethostbyaddr2_r (const void *a
+ }
+
+ n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+- 1024, &host_buffer.ptr, NULL, NULL, NULL);
++ 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+ if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
+ {
+ strcpy (qp, "ip6.int");
+ n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+ host_buffer.buf != orig_host_buffer
+ ? MAXPACKET : 1024, &host_buffer.ptr,
+- NULL, NULL, NULL);
++ NULL, NULL, NULL, NULL);
+ }
+ if (n < 0)
+ {
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-network.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-network.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-network.c
+@@ -130,7 +130,7 @@ _nss_dns_getnetbyname_r (const char *nam
+ net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+
+ anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+- 1024, &net_buffer.ptr, NULL, NULL, NULL);
++ 1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+ if (anslen < 0)
+ {
+ /* Nothing found. */
+@@ -206,7 +206,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, i
+ net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+
+ anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+- 1024, &net_buffer.ptr, NULL, NULL, NULL);
++ 1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+ if (anslen < 0)
+ {
+ /* Nothing found. */
+Index: glibc-2.12-2-gc4ccff1/resolv/res_query.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_query.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_query.c
+@@ -98,7 +98,7 @@ static int
+ __libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
+ int class, int type, u_char *answer, int anslen,
+ u_char **answerp, u_char **answerp2, int *nanswerp2,
+- int *resplen2);
++ int *resplen2, int *answerp2_malloced);
+
+ /*
+ * Formulate a normal query, send, and await answer.
+@@ -119,7 +119,8 @@ __libc_res_nquery(res_state statp,
+ u_char **answerp, /* if buffer needs to be enlarged */
+ u_char **answerp2,
+ int *nanswerp2,
+- int *resplen2)
++ int *resplen2,
++ int *answerp2_malloced)
+ {
+ HEADER *hp = (HEADER *) answer;
+ HEADER *hp2;
+@@ -224,7 +225,8 @@ __libc_res_nquery(res_state statp,
+ }
+ assert (answerp == NULL || (void *) *answerp == (void *) answer);
+ n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
+- anslen, answerp, answerp2, nanswerp2, resplen2);
++ anslen, answerp, answerp2, nanswerp2, resplen2,
++ answerp2_malloced);
+ if (use_malloc)
+ free (buf);
+ if (n < 0) {
+@@ -316,7 +318,7 @@ res_nquery(res_state statp,
+ int anslen) /* size of answer buffer */
+ {
+ return __libc_res_nquery(statp, name, class, type, answer, anslen,
+- NULL, NULL, NULL, NULL);
++ NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nquery)
+
+@@ -335,7 +337,8 @@ __libc_res_nsearch(res_state statp,
+ u_char **answerp,
+ u_char **answerp2,
+ int *nanswerp2,
+- int *resplen2)
++ int *resplen2,
++ int *answerp2_malloced)
+ {
+ const char *cp, * const *domain;
+ HEADER *hp = (HEADER *) answer;
+@@ -359,7 +362,7 @@ __libc_res_nsearch(res_state statp,
+ if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+ return (__libc_res_nquery(statp, cp, class, type, answer,
+ anslen, answerp, answerp2,
+- nanswerp2, resplen2));
++ nanswerp2, resplen2, answerp2_malloced));
+
+ #ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+@@ -376,7 +379,8 @@ __libc_res_nsearch(res_state statp,
+ if (dots >= statp->ndots || trailing_dot) {
+ ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen, answerp,
+- answerp2, nanswerp2, resplen2);
++ answerp2, nanswerp2, resplen2,
++ answerp2_malloced);
+ if (ret > 0 || trailing_dot
+ /* If the second response is valid then we use that. */
+ || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
+@@ -387,12 +391,12 @@ __libc_res_nsearch(res_state statp,
+ answer = *answerp;
+ anslen = MAXPACKET;
+ }
+- if (answerp2
+- && (*answerp2 < answer || *answerp2 >= answer + anslen))
++ if (answerp2 && *answerp2_malloced)
+ {
+ free (*answerp2);
+ *nanswerp2 = 0;
+ *answerp2 = NULL;
++ *answerp2_malloced = 0;
+ }
+ }
+
+@@ -418,7 +422,7 @@ __libc_res_nsearch(res_state statp,
+ class, type,
+ answer, anslen, answerp,
+ answerp2, nanswerp2,
+- resplen2);
++ resplen2, answerp2_malloced);
+ if (ret > 0 || (ret == 0 && resplen2 != NULL
+ && *resplen2 > 0))
+ return (ret);
+@@ -427,13 +431,12 @@ __libc_res_nsearch(res_state statp,
+ answer = *answerp;
+ anslen = MAXPACKET;
+ }
+- if (answerp2
+- && (*answerp2 < answer
+- || *answerp2 >= answer + anslen))
++ if (answerp2 && *answerp2_malloced)
+ {
+ free (*answerp2);
+ *nanswerp2 = 0;
+ *answerp2 = NULL;
++ *answerp2_malloced = 0;
+ }
+
+ /*
+@@ -489,7 +492,8 @@ __libc_res_nsearch(res_state statp,
+ if (dots && !(tried_as_is || root_on_list)) {
+ ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen, answerp,
+- answerp2, nanswerp2, resplen2);
++ answerp2, nanswerp2, resplen2,
++ answerp2_malloced);
+ if (ret > 0 || (ret == 0 && resplen2 != NULL
+ && *resplen2 > 0))
+ return (ret);
+@@ -502,11 +506,12 @@ __libc_res_nsearch(res_state statp,
+ * else send back meaningless H_ERRNO, that being the one from
+ * the last DNSRCH we did.
+ */
+- if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
++ if (answerp2 && *answerp2_malloced)
+ {
+ free (*answerp2);
+- *nanswerp2 = NULL;
++ *nanswerp2 = 0;
+ *answerp2 = NULL;
++ *answerp2_malloced = 0;
+ }
+ if (saved_herrno != -1)
+ RES_SET_H_ERRNO(statp, saved_herrno);
+@@ -526,7 +531,7 @@ res_nsearch(res_state statp,
+ int anslen) /* size of answer */
+ {
+ return __libc_res_nsearch(statp, name, class, type, answer,
+- anslen, NULL, NULL, NULL, NULL);
++ anslen, NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nsearch)
+
+@@ -544,7 +549,8 @@ __libc_res_nquerydomain(res_state statp,
+ u_char **answerp,
+ u_char **answerp2,
+ int *nanswerp2,
+- int *resplen2)
++ int *resplen2,
++ int *answerp2_malloced)
+ {
+ char nbuf[MAXDNAME];
+ const char *longname = nbuf;
+@@ -582,7 +588,7 @@ __libc_res_nquerydomain(res_state statp,
+ }
+ return (__libc_res_nquery(statp, longname, class, type, answer,
+ anslen, answerp, answerp2, nanswerp2,
+- resplen2));
++ resplen2, answerp2_malloced));
+ }
+
+ int
+@@ -594,7 +600,8 @@ res_nquerydomain(res_state statp,
+ int anslen) /* size of answer */
+ {
+ return __libc_res_nquerydomain(statp, name, domain, class, type,
+- answer, anslen, NULL, NULL, NULL, NULL);
++ answer, anslen, NULL, NULL, NULL, NULL,
++ NULL);
+ }
+ libresolv_hidden_def (res_nquerydomain)
+
+Index: glibc-2.12-2-gc4ccff1/resolv/res_send.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_send.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_send.c
+@@ -203,12 +203,12 @@ evNowTime(struct timespec *res) {
+ static int send_vc(res_state, const u_char *, int,
+ const u_char *, int,
+ u_char **, int *, int *, int, u_char **,
+- u_char **, int *, int *);
++ u_char **, int *, int *, int *);
+ static int send_dg(res_state, const u_char *, int,
+ const u_char *, int,
+ u_char **, int *, int *, int,
+ int *, int *, u_char **,
+- u_char **, int *, int *);
++ u_char **, int *, int *, int *);
+ #ifdef DEBUG
+ static void Aerror(const res_state, FILE *, const char *, int,
+ const struct sockaddr *);
+@@ -360,7 +360,7 @@ int
+ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
+ const u_char *buf2, int buflen2,
+ u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
+- int *nansp2, int *resplen2)
++ int *nansp2, int *resplen2, int *ansp2_malloced)
+ {
+ int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+
+@@ -565,7 +565,8 @@ __libc_res_nsend(res_state statp, const
+ try = statp->retry;
+ n = send_vc(statp, buf, buflen, buf2, buflen2,
+ &ans, &anssiz, &terrno,
+- ns, ansp, ansp2, nansp2, resplen2);
++ ns, ansp, ansp2, nansp2, resplen2,
++ ansp2_malloced);
+ if (n < 0)
+ return (-1);
+ if (n == 0 && (buf2 == NULL || *resplen2 == 0))
+@@ -575,7 +576,7 @@ __libc_res_nsend(res_state statp, const
+ n = send_dg(statp, buf, buflen, buf2, buflen2,
+ &ans, &anssiz, &terrno,
+ ns, &v_circuit, &gotsomewhere, ansp,
+- ansp2, nansp2, resplen2);
++ ansp2, nansp2, resplen2, ansp2_malloced);
+ if (n < 0)
+ return (-1);
+ if (n == 0 && (buf2 == NULL || *resplen2 == 0))
+@@ -665,7 +666,7 @@ res_nsend(res_state statp,
+ const u_char *buf, int buflen, u_char *ans, int anssiz)
+ {
+ return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
+- NULL, NULL, NULL, NULL);
++ NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nsend)
+
+@@ -747,7 +748,7 @@ send_vc(res_state statp,
+ const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+ u_char **ansp, int *anssizp,
+ int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
+- int *resplen2)
++ int *resplen2, int *ansp2_malloced)
+ {
+ const HEADER *hp = (HEADER *) buf;
+ const HEADER *hp2 = (HEADER *) buf2;
+@@ -896,6 +897,8 @@ send_vc(res_state statp,
+ }
+ *thisanssizp = MAXPACKET;
+ *thisansp = newp;
++ if (thisansp == ansp2)
++ *ansp2_malloced = 1;
+ anhp = (HEADER *) newp;
+ /* A uint16_t can't be larger than MAXPACKET
+ thus it's safe to allocate MAXPACKET but
+@@ -1128,7 +1131,7 @@ send_dg(res_state statp,
+ const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+ u_char **ansp, int *anssizp,
+ int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
+- u_char **ansp2, int *anssizp2, int *resplen2)
++ u_char **ansp2, int *anssizp2, int *resplen2, int *ansp2_malloced)
+ {
+ const HEADER *hp = (HEADER *) buf;
+ const HEADER *hp2 = (HEADER *) buf2;
+@@ -1289,6 +1292,8 @@ send_dg(res_state statp,
+ if (newp != NULL) {
+ *thisanssizp = MAXPACKET;
+ *thisansp = newp;
++ if (thisansp == ansp2)
++ *ansp2_malloced = 1;
+ }
+ }
+ /* We could end up with truncation if anscp was NULL
--- /dev/null
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-host.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+@@ -1043,7 +1043,10 @@ gaih_getanswer_slice (const querybuf *an
+ int h_namelen = 0;
+
+ if (ancount == 0)
+- return NSS_STATUS_NOTFOUND;
++ {
++ *h_errnop = HOST_NOT_FOUND;
++ return NSS_STATUS_NOTFOUND;
++ }
+
+ while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+ {
+@@ -1217,7 +1220,14 @@ gaih_getanswer_slice (const querybuf *an
+ /* Special case here: if the resolver sent a result but it only
+ contains a CNAME while we are looking for a T_A or T_AAAA record,
+ we fail with NOTFOUND instead of TRYAGAIN. */
+- return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
++ if (canon != NULL)
++ {
++ *h_errnop = HOST_NOT_FOUND;
++ return NSS_STATUS_NOTFOUND;
++ }
++
++ *h_errnop = NETDB_INTERNAL;
++ return NSS_STATUS_TRYAGAIN;
+ }
+
+
+@@ -1231,11 +1241,101 @@ gaih_getanswer (const querybuf *answer1,
+
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+
++ /* Combining the NSS status of two distinct queries requires some
++ compromise and attention to symmetry (A or AAAA queries can be
++ returned in any order). What follows is a breakdown of how this
++ code is expected to work and why. We discuss only SUCCESS,
++ TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
++ that apply (though RETURN and MERGE exist). We make a distinction
++ between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
++ A recoverable TRYAGAIN is almost always due to buffer size issues
++ and returns ERANGE in errno and the caller is expected to retry
++ with a larger buffer.
++
++ Lastly, you may be tempted to make significant changes to the
++ conditions in this code to bring about symmetry between responses.
++ Please don't change anything without due consideration for
++ expected application behaviour. Some of the synthesized responses
++ aren't very well thought out and sometimes appear to imply that
++ IPv4 responses are always answer 1, and IPv6 responses are always
++ answer 2, but that's not true (see the implemetnation of send_dg
++ and send_vc to see response can arrive in any order, particlarly
++ for UDP). However, we expect it holds roughly enough of the time
++ that this code works, but certainly needs to be fixed to make this
++ a more robust implementation.
++
++ ----------------------------------------------
++ | Answer 1 Status / | Synthesized | Reason |
++ | Answer 2 Status | Status | |
++ |--------------------------------------------|
++ | SUCCESS/SUCCESS | SUCCESS | [1] |
++ | SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
++ | SUCCESS/TRYAGAIN' | SUCCESS | [1] |
++ | SUCCESS/NOTFOUND | SUCCESS | [1] |
++ | SUCCESS/UNAVAIL | SUCCESS | [1] |
++ | TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
++ | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
++ | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
++ | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
++ | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
++ | TRYAGAIN'/SUCCESS | SUCCESS | [3] |
++ | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
++ | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
++ | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
++ | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
++ | NOTFOUND/SUCCESS | SUCCESS | [3] |
++ | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
++ | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
++ | NOTFOUND/NOTFOUND | NOTFOUND | [3] |
++ | NOTFOUND/UNAVAIL | UNAVAIL | [3] |
++ | UNAVAIL/SUCCESS | UNAVAIL | [4] |
++ | UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
++ | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
++ | UNAVAIL/NOTFOUND | UNAVAIL | [4] |
++ | UNAVAIL/UNAVAIL | UNAVAIL | [4] |
++ ----------------------------------------------
++
++ [1] If the first response is a success we return success.
++ This ignores the state of the second answer and in fact
++ incorrectly sets errno and h_errno to that of the second
++ answer. However because the response is a success we ignore
++ *errnop and *h_errnop (though that means you touched errno on
++ success). We are being conservative here and returning the
++ likely IPv4 response in the first answer as a success.
++
++ [2] If the first response is a recoverable TRYAGAIN we return
++ that instead of looking at the second response. The
++ expectation here is that we have failed to get an IPv4 response
++ and should retry both queries.
++
++ [3] If the first response was not a SUCCESS and the second
++ response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
++ or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
++ result from the second response, otherwise the first responses
++ status is used. Again we have some odd side-effects when the
++ second response is NOTFOUND because we overwrite *errnop and
++ *h_errnop that means that a first answer of NOTFOUND might see
++ its *errnop and *h_errnop values altered. Whether it matters
++ in practice that a first response NOTFOUND has the wrong
++ *errnop and *h_errnop is undecided.
++
++ [4] If the first response is UNAVAIL we return that instead of
++ looking at the second response. The expectation here is that
++ it will have failed similarly e.g. configuration failure.
++
++ [5] Testing this code is complicated by the fact that truncated
++ second response buffers might be returned as SUCCESS if the
++ first answer is a SUCCESS. To fix this we add symmetry to
++ TRYAGAIN with the second response. If the second response
++ is a recoverable error we now return TRYAGIN even if the first
++ response was SUCCESS. */
++
+ if (anslen1 > 0)
+ status = gaih_getanswer_slice(answer1, anslen1, qname,
+ &pat, &buffer, &buflen,
+ errnop, h_errnop, ttlp,
+ &first);
++
+ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
+ || (status == NSS_STATUS_TRYAGAIN
+ && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
+@@ -1245,8 +1345,15 @@ gaih_getanswer (const querybuf *answer1,
+ &pat, &buffer, &buflen,
+ errnop, h_errnop, ttlp,
+ &first);
++ /* Use the second response status in some cases. */
+ if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
+ status = status2;
++ /* Do not return a truncated second response (unless it was
++ unavoidable e.g. unrecoverable TRYAGAIN). */
++ if (status == NSS_STATUS_SUCCESS
++ && (status2 == NSS_STATUS_TRYAGAIN
++ && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
++ status = NSS_STATUS_TRYAGAIN;
+ }
+
+ return status;
+Index: glibc-2.12-2-gc4ccff1/resolv/res_send.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_send.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_send.c
+@@ -1,3 +1,20 @@
++/* Copyright (C) 2016 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
++ <http://www.gnu.org/licenses/>. */
++
+ /*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+@@ -360,6 +377,8 @@ __libc_res_nsend(res_state statp, const
+ #ifdef USE_HOOKS
+ if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
+ if (anssiz < MAXPACKET && ansp) {
++ /* Always allocate MAXPACKET, callers expect
++ this specific size. */
+ u_char *buf = malloc (MAXPACKET);
+ if (buf == NULL)
+ return (-1);
+@@ -652,6 +671,77 @@ libresolv_hidden_def (res_nsend)
+
+ /* Private */
+
++/* The send_vc function is responsible for sending a DNS query over TCP
++ to the nameserver numbered NS from the res_state STATP i.e.
++ EXT(statp).nssocks[ns]. The function supports sending both IPv4 and
++ IPv6 queries at the same serially on the same socket.
++
++ Please note that for TCP there is no way to disable sending both
++ queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP
++ and sends the queries serially and waits for the result after each
++ sent query. This implemetnation should be corrected to honour these
++ options.
++
++ Please also note that for TCP we send both queries over the same
++ socket one after another. This technically violates best practice
++ since the server is allowed to read the first query, respond, and
++ then close the socket (to service another client). If the server
++ does this, then the remaining second query in the socket data buffer
++ will cause the server to send the client an RST which will arrive
++ asynchronously and the client's OS will likely tear down the socket
++ receive buffer resulting in a potentially short read and lost
++ response data. This will force the client to retry the query again,
++ and this process may repeat until all servers and connection resets
++ are exhausted and then the query will fail. It's not known if this
++ happens with any frequency in real DNS server implementations. This
++ implementation should be corrected to use two sockets by default for
++ parallel queries.
++
++ The query stored in BUF of BUFLEN length is sent first followed by
++ the query stored in BUF2 of BUFLEN2 length. Queries are sent
++ serially on the same socket.
++
++ Answers to the query are stored firstly in *ANSP up to a max of
++ *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
++ is non-NULL (to indicate that modifying the answer buffer is allowed)
++ then malloc is used to allocate a new response buffer and ANSCP and
++ ANSP will both point to the new buffer. If more than *ANSSIZP bytes
++ are needed but ANSCP is NULL, then as much of the response as
++ possible is read into the buffer, but the results will be truncated.
++ When truncation happens because of a small answer buffer the DNS
++ packets header feild TC will bet set to 1, indicating a truncated
++ message and the rest of the socket data will be read and discarded.
++
++ Answers to the query are stored secondly in *ANSP2 up to a max of
++ *ANSSIZP2 bytes, with the actual response length stored in
++ *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
++ is non-NULL (required for a second query) then malloc is used to
++ allocate a new response buffer, *ANSSIZP2 is set to the new buffer
++ size and *ANSP2_MALLOCED is set to 1.
++
++ The ANSP2_MALLOCED argument will eventually be removed as the
++ change in buffer pointer can be used to detect the buffer has
++ changed and that the caller should use free on the new buffer.
++
++ Note that the answers may arrive in any order from the server and
++ therefore the first and second answer buffers may not correspond to
++ the first and second queries.
++
++ It is not supported to call this function with a non-NULL ANSP2
++ but a NULL ANSCP. Put another way, you can call send_vc with a
++ single unmodifiable buffer or two modifiable buffers, but no other
++ combination is supported.
++
++ It is the caller's responsibility to free the malloc allocated
++ buffers by detecting that the pointers have changed from their
++ original values i.e. *ANSCP or *ANSP2 has changed.
++
++ If errors are encountered then *TERRNO is set to an appropriate
++ errno value and a zero result is returned for a recoverable error,
++ and a less-than zero result is returned for a non-recoverable error.
++
++ If no errors are encountered then *TERRNO is left unmodified and
++ a the length of the first response in bytes is returned. */
+ static int
+ send_vc(res_state statp,
+ const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+@@ -661,11 +751,7 @@ send_vc(res_state statp,
+ {
+ const HEADER *hp = (HEADER *) buf;
+ const HEADER *hp2 = (HEADER *) buf2;
+- u_char *ans = *ansp;
+- int orig_anssizp = *anssizp;
+- // XXX REMOVE
+- // int anssiz = *anssizp;
+- HEADER *anhp = (HEADER *) ans;
++ HEADER *anhp = (HEADER *) *ansp;
+ struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
+ int truncating, connreset, resplen, n;
+ struct iovec iov[4];
+@@ -741,6 +827,8 @@ send_vc(res_state statp,
+ * Receive length & response
+ */
+ int recvresp1 = 0;
++ /* Skip the second response if there is no second query.
++ To do that we mark the second response as received. */
+ int recvresp2 = buf2 == NULL;
+ uint16_t rlen16;
+ read_len:
+@@ -777,33 +865,14 @@ send_vc(res_state statp,
+ u_char **thisansp;
+ int *thisresplenp;
+ if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
++ /* We have not received any responses
++ yet or we only have one response to
++ receive. */
+ thisanssizp = anssizp;
+ thisansp = anscp ?: ansp;
+ assert (anscp != NULL || ansp2 == NULL);
+ thisresplenp = &resplen;
+ } else {
+- if (*anssizp != MAXPACKET) {
+- /* No buffer allocated for the first
+- reply. We can try to use the rest
+- of the user-provided buffer. */
+-#ifdef _STRING_ARCH_unaligned
+- *anssizp2 = orig_anssizp - resplen;
+- *ansp2 = *ansp + resplen;
+-#else
+- int aligned_resplen
+- = ((resplen + __alignof__ (HEADER) - 1)
+- & ~(__alignof__ (HEADER) - 1));
+- *anssizp2 = orig_anssizp - aligned_resplen;
+- *ansp2 = *ansp + aligned_resplen;
+-#endif
+- } else {
+- /* The first reply did not fit into the
+- user-provided buffer. Maybe the second
+- answer will. */
+- *anssizp2 = orig_anssizp;
+- *ansp2 = *ansp;
+- }
+-
+ thisanssizp = anssizp2;
+ thisansp = ansp2;
+ thisresplenp = resplen2;
+@@ -811,10 +880,14 @@ send_vc(res_state statp,
+ anhp = (HEADER *) *thisansp;
+
+ *thisresplenp = rlen;
+- if (rlen > *thisanssizp) {
+- /* Yes, we test ANSCP here. If we have two buffers
+- both will be allocatable. */
+- if (__builtin_expect (anscp != NULL, 1)) {
++ /* Is the answer buffer too small? */
++ if (*thisanssizp < rlen) {
++ /* If the current buffer is non-NULL and it's not
++ pointing at the static user-supplied buffer then
++ we can reallocate it. */
++ if (thisansp != NULL && thisansp != ansp) {
++ /* Always allocate MAXPACKET, callers expect
++ this specific size. */
+ u_char *newp = malloc (MAXPACKET);
+ if (newp == NULL) {
+ *terrno = ENOMEM;
+@@ -824,6 +897,9 @@ send_vc(res_state statp,
+ *thisanssizp = MAXPACKET;
+ *thisansp = newp;
+ anhp = (HEADER *) newp;
++ /* A uint16_t can't be larger than MAXPACKET
++ thus it's safe to allocate MAXPACKET but
++ read RLEN bytes instead. */
+ len = rlen;
+ } else {
+ Dprint(statp->options & RES_DEBUG,
+@@ -987,6 +1063,66 @@ reopen (res_state statp, int *terrno, in
+ return 1;
+ }
+
++/* The send_dg function is responsible for sending a DNS query over UDP
++ to the nameserver numbered NS from the res_state STATP i.e.
++ EXT(statp).nssocks[ns]. The function supports IPv4 and IPv6 queries
++ along with the ability to send the query in parallel for both stacks
++ (default) or serially (RES_SINGLKUP). It also supports serial lookup
++ with a close and reopen of the socket used to talk to the server
++ (RES_SNGLKUPREOP) to work around broken name servers.
++
++ The query stored in BUF of BUFLEN length is sent first followed by
++ the query stored in BUF2 of BUFLEN2 length. Queries are sent
++ in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP).
++
++ Answers to the query are stored firstly in *ANSP up to a max of
++ *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
++ is non-NULL (to indicate that modifying the answer buffer is allowed)
++ then malloc is used to allocate a new response buffer and ANSCP and
++ ANSP will both point to the new buffer. If more than *ANSSIZP bytes
++ are needed but ANSCP is NULL, then as much of the response as
++ possible is read into the buffer, but the results will be truncated.
++ When truncation happens because of a small answer buffer the DNS
++ packets header feild TC will bet set to 1, indicating a truncated
++ message, while the rest of the UDP packet is discarded.
++
++ Answers to the query are stored secondly in *ANSP2 up to a max of
++ *ANSSIZP2 bytes, with the actual response length stored in
++ *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
++ is non-NULL (required for a second query) then malloc is used to
++ allocate a new response buffer, *ANSSIZP2 is set to the new buffer
++ size and *ANSP2_MALLOCED is set to 1.
++
++ The ANSP2_MALLOCED argument will eventually be removed as the
++ change in buffer pointer can be used to detect the buffer has
++ changed and that the caller should use free on the new buffer.
++
++ Note that the answers may arrive in any order from the server and
++ therefore the first and second answer buffers may not correspond to
++ the first and second queries.
++
++ It is not supported to call this function with a non-NULL ANSP2
++ but a NULL ANSCP. Put another way, you can call send_vc with a
++ single unmodifiable buffer or two modifiable buffers, but no other
++ combination is supported.
++
++ It is the caller's responsibility to free the malloc allocated
++ buffers by detecting that the pointers have changed from their
++ original values i.e. *ANSCP or *ANSP2 has changed.
++
++ If an answer is truncated because of UDP datagram DNS limits then
++ *V_CIRCUIT is set to 1 and the return value non-zero to indicate to
++ the caller to retry with TCP. The value *GOTSOMEWHERE is set to 1
++ if any progress was made reading a response from the nameserver and
++ is used by the caller to distinguish between ECONNREFUSED and
++ ETIMEDOUT (the latter if *GOTSOMEWHERE is 1).
++
++ If errors are encountered then *TERRNO is set to an appropriate
++ errno value and a zero result is returned for a recoverable error,
++ and a less-than zero result is returned for a non-recoverable error.
++
++ If no errors are encountered then *TERRNO is left unmodified and
++ a the length of the first response in bytes is returned. */
+ static int
+ send_dg(res_state statp,
+ const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+@@ -996,8 +1132,6 @@ send_dg(res_state statp,
+ {
+ const HEADER *hp = (HEADER *) buf;
+ const HEADER *hp2 = (HEADER *) buf2;
+- u_char *ans = *ansp;
+- int orig_anssizp = *anssizp;
+ struct timespec now, timeout, finish;
+ struct pollfd pfd[1];
+ int ptimeout;
+@@ -1029,6 +1163,8 @@ send_dg(res_state statp,
+ int need_recompute = 0;
+ int nwritten = 0;
+ int recvresp1 = 0;
++ /* Skip the second response if there is no second query.
++ To do that we mark the second response as received. */
+ int recvresp2 = buf2 == NULL;
+ pfd[0].fd = EXT(statp).nssocks[ns];
+ pfd[0].events = POLLOUT;
+@@ -1125,50 +1261,52 @@ send_dg(res_state statp,
+ int *thisresplenp;
+
+ if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
++ /* We have not received any responses
++ yet or we only have one response to
++ receive. */
+ thisanssizp = anssizp;
+ thisansp = anscp ?: ansp;
+ assert (anscp != NULL || ansp2 == NULL);
+ thisresplenp = &resplen;
+ } else {
+- if (*anssizp != MAXPACKET) {
+- /* No buffer allocated for the first
+- reply. We can try to use the rest
+- of the user-provided buffer. */
+-#ifdef _STRING_ARCH_unaligned
+- *anssizp2 = orig_anssizp - resplen;
+- *ansp2 = *ansp + resplen;
+-#else
+- int aligned_resplen
+- = ((resplen + __alignof__ (HEADER) - 1)
+- & ~(__alignof__ (HEADER) - 1));
+- *anssizp2 = orig_anssizp - aligned_resplen;
+- *ansp2 = *ansp + aligned_resplen;
+-#endif
+- } else {
+- /* The first reply did not fit into the
+- user-provided buffer. Maybe the second
+- answer will. */
+- *anssizp2 = orig_anssizp;
+- *ansp2 = *ansp;
+- }
+-
+ thisanssizp = anssizp2;
+ thisansp = ansp2;
+ thisresplenp = resplen2;
+ }
+
+ if (*thisanssizp < MAXPACKET
+- /* Yes, we test ANSCP here. If we have two buffers
+- both will be allocatable. */
+- && anscp
++ /* If the current buffer is non-NULL and it's not
++ pointing at the static user-supplied buffer then
++ we can reallocate it. */
++ && (thisansp != NULL && thisansp != ansp)
++ /* Is the size too small? */
+ && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
+- || *thisanssizp < *thisresplenp)) {
++ || *thisanssizp < *thisresplenp)
++ ) {
++ /* Always allocate MAXPACKET, callers expect
++ this specific size. */
+ u_char *newp = malloc (MAXPACKET);
+ if (newp != NULL) {
+- *anssizp = MAXPACKET;
+- *thisansp = ans = newp;
++ *thisanssizp = MAXPACKET;
++ *thisansp = newp;
+ }
+ }
++ /* We could end up with truncation if anscp was NULL
++ (not allowed to change caller's buffer) and the
++ response buffer size is too small. This isn't a
++ reliable way to detect truncation because the ioctl
++ may be an inaccurate report of the UDP message size.
++ Therefore we use this only to issue debug output.
++ To do truncation accurately with UDP we need
++ MSG_TRUNC which is only available on Linux. We
++ can abstract out the Linux-specific feature in the
++ future to detect truncation. */
++ if (__glibc_unlikely (*thisanssizp < *thisresplenp)) {
++ Dprint(statp->options & RES_DEBUG,
++ (stdout, ";; response may be truncated (UDP)\n")
++ );
++ }
++
+ HEADER *anhp = (HEADER *) *thisansp;
+ socklen_t fromlen = sizeof(struct sockaddr_in6);
+ assert (sizeof(from) <= fromlen);
+Index: glibc-2.12-2-gc4ccff1/resolv/res_query.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_query.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_query.c
+@@ -391,6 +391,7 @@ __libc_res_nsearch(res_state statp,
+ && (*answerp2 < answer || *answerp2 >= answer + anslen))
+ {
+ free (*answerp2);
++ *nanswerp2 = 0;
+ *answerp2 = NULL;
+ }
+ }
+@@ -431,6 +432,7 @@ __libc_res_nsearch(res_state statp,
+ || *answerp2 >= answer + anslen))
+ {
+ free (*answerp2);
++ *nanswerp2 = 0;
+ *answerp2 = NULL;
+ }
+
+@@ -503,6 +505,7 @@ __libc_res_nsearch(res_state statp,
+ if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
+ {
+ free (*answerp2);
++ *nanswerp2 = NULL;
+ *answerp2 = NULL;
+ }
+ if (saved_herrno != -1)
--- /dev/null
+commit 2c1094bd700e63a8d7f547b3f5495bedb55c0a08
+Author: Ulrich Drepper <drepper@gmail.com>
+Date: Thu Dec 22 22:43:39 2011 -0500
+
+ Create internal threads with sufficient stack size
+
+Index: glibc-2.12-2-gc4ccff1/nptl/Versions
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/Versions
++++ glibc-2.12-2-gc4ccff1/nptl/Versions
+@@ -255,6 +255,6 @@ libpthread {
+ GLIBC_PRIVATE {
+ __pthread_initialize_minimal;
+ __pthread_clock_gettime; __pthread_clock_settime;
+- __pthread_unwind;
++ __pthread_unwind; __pthread_get_minstack;
+ }
+ }
+Index: glibc-2.12-2-gc4ccff1/nptl/nptl-init.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/nptl-init.c
++++ glibc-2.12-2-gc4ccff1/nptl/nptl-init.c
+@@ -507,3 +507,13 @@ __pthread_initialize_minimal_internal (i
+ }
+ strong_alias (__pthread_initialize_minimal_internal,
+ __pthread_initialize_minimal)
++
++
++size_t
++__pthread_get_minstack (const pthread_attr_t *attr)
++{
++ struct pthread_attr *iattr = (struct pthread_attr *) attr;
++
++ return (GLRO(dl_pagesize) + __static_tls_size + PTHREAD_STACK_MIN
++ + iattr->guardsize);
++}
+Index: glibc-2.12-2-gc4ccff1/nptl/pthreadP.h
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/pthreadP.h
++++ glibc-2.12-2-gc4ccff1/nptl/pthreadP.h
+@@ -397,6 +397,7 @@ weak_function;
+
+ extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
+
++extern size_t __pthread_get_minstack (const pthread_attr_t *attr);
+
+ /* Namespace save aliases. */
+ extern int __pthread_getschedparam (pthread_t thread_id, int *policy,
+Index: glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/timer_routines.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/sysdeps/unix/sysv/linux/timer_routines.c
++++ glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/timer_routines.c
+@@ -165,7 +165,7 @@ __start_helper_thread (void)
+ and should go away automatically when canceled. */
+ pthread_attr_t attr;
+ (void) pthread_attr_init (&attr);
+- (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
++ (void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
+
+ /* Block all signals in the helper thread but SIGSETXID. To do this
+ thoroughly we temporarily have to block all signals here. The
--- /dev/null
+commit 232872379ee82cd040a52a48cbbae65a249b5765
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date: Sun Jan 8 19:56:52 2012 -0500
+
+ Use __pthread_get_minstack for AIO helper thread
+
+diff --git a/nptl/sysdeps/unix/sysv/linux/aio_misc.h b/nptl/sysdeps/unix/sysv/linux/aio_misc.h
+index 406d96e..8011c3e 100644
+--- a/nptl/sysdeps/unix/sysv/linux/aio_misc.h
++++ b/nptl/sysdeps/unix/sysv/linux/aio_misc.h
+@@ -47,7 +47,7 @@ __aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *),
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+ /* The helper thread needs only very little resources. */
+- (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
++ (void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
+
+ /* Block all signals in the helper thread. To do this thoroughly we
+ temporarily have to block all signals here. */
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/Makefile glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile
+--- glibc-2.12-2-gc4ccff1/nptl/Makefile 2013-07-09 10:18:22.267421846 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile 2013-07-09 10:16:22.043427519 +0530
+@@ -207,7 +207,8 @@ tests = tst-typesizes \
+ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
+ tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
+ tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
+- tst-cond20 tst-cond21 tst-cond22 tst-cond23 \
++ tst-cond20 tst-cond21 tst-cond22 tst-cond23 tst-cond24 tst-cond25 \
++ tst-cond-except \
+ tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
+ tst-robust6 tst-robust7 tst-robust8 tst-robust9 \
+ tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 tst-robustpi5 \
+@@ -275,6 +276,8 @@ gen-as-const-headers = pthread-errnos.sy
+
+ LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
+
++LDFLAGS-tst-cond24 = -lrt
++LDFLAGS-tst-cond25 = -lrt
+
+ include ../Makeconfig
+
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S 2013-07-09 10:16:22.044427519 +0530
+@@ -203,9 +203,11 @@ __pthread_cond_timedwait:
+ 42: leal (%ebp), %esi
+ movl 28(%esp), %edx
+ addl $cond_futex, %ebx
++.Ladd_cond_futex_pi:
+ movl $SYS_futex, %eax
+ ENTER_KERNEL
+ subl $cond_futex, %ebx
++.Lsub_cond_futex_pi:
+ movl %eax, %esi
+ /* Set the pi-requeued flag only if the kernel has returned 0. The
+ kernel does not hold the mutex on ETIMEDOUT or any other error. */
+@@ -213,8 +215,23 @@ __pthread_cond_timedwait:
+ sete 24(%esp)
+ je 41f
+
+- /* Normal and PI futexes dont mix. Use normal futex functions only
+- if the kernel does not support the PI futex functions. */
++ /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++ successfully, it has already locked the mutex for us and the
++ pi_flag (24(%esp)) is set to denote that fact. However, if another
++ thread changed the futex value before we entered the wait, the
++ syscall may return an EAGAIN and the mutex is not locked. We go
++ ahead with a success anyway since later we look at the pi_flag to
++ decide if we got the mutex or not. The sequence numbers then make
++ sure that only one of the threads actually wake up. We retry using
++ normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++ and PI futexes don't mix.
++
++ Note that we don't check for EAGAIN specifically; we assume that the
++ only other error the futex function could return is EAGAIN (barring
++ the ETIMEOUT of course, for the timeout case in futex) since
++ anything else would mean an error in our function. It is too
++ expensive to do that check for every call (which is quite common in
++ case of a large number of threads), so it has been skipped. */
+ cmpl $-ENOSYS, %eax
+ jne 41f
+ xorl %ecx, %ecx
+@@ -274,9 +291,24 @@ __pthread_cond_timedwait:
+ jne 9f
+
+ 15: cmpl $-ETIMEDOUT, %esi
+- jne 8b
++ je 28f
+
+- addl $1, wakeup_seq(%ebx)
++ /* We need to go back to futex_wait. If we're using requeue_pi, then
++ release the mutex we had acquired and go back. */
++ movl 24(%esp), %edx
++ test %edx, %edx
++ jz 8b
++
++ /* Adjust the mutex values first and then unlock it. The unlock
++ should always succeed or else the kernel did not lock the mutex
++ correctly. */
++ movl dep_mutex(%ebx), %eax
++ call __pthread_mutex_cond_lock_adjust
++ xorl %edx, %edx
++ call __pthread_mutex_unlock_usercnt
++ jmp 8b
++
++28: addl $1, wakeup_seq(%ebx)
+ adcl $0, wakeup_seq+4(%ebx)
+ addl $1, cond_futex(%ebx)
+ movl $ETIMEDOUT, %esi
+@@ -644,10 +676,27 @@ __condvar_tw_cleanup:
+ movl $0x7fffffff, %edx
+ ENTER_KERNEL
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movl 24+FRAME_SIZE(%esp), %eax
+- call __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%eax), %ebx
++ andl $(ROBUST_BIT|PI_BIT), %ebx
++ cmpl $PI_BIT, %ebx
++ jne 8f
++
++ movl (%eax), %ebx
++ andl $TID_MASK, %ebx
++ cmpl %ebx, %gs:TID
++ jne 8f
++ /* We managed to get the lock. Fix it up before returning. */
++ call __pthread_mutex_cond_lock_adjust
++ jmp 9f
++
++8: call __pthread_mutex_cond_lock
+
+- movl %esi, (%esp)
++9: movl %esi, (%esp)
+ .LcallUR:
+ call _Unwind_Resume
+ hlt
+@@ -665,7 +714,15 @@ __condvar_tw_cleanup:
+ .uleb128 .Lcstend-.Lcstbegin
+ .Lcstbegin:
+ .long .LcleanupSTART-.LSTARTCODE
+- .long .Ladd_cond_futex-.LcleanupSTART
++ .long .Ladd_cond_futex_pi-.LcleanupSTART
++ .long __condvar_tw_cleanup-.LSTARTCODE
++ .uleb128 0
++ .long .Ladd_cond_futex_pi-.LSTARTCODE
++ .long .Lsub_cond_futex_pi-.Ladd_cond_futex_pi
++ .long __condvar_tw_cleanup2-.LSTARTCODE
++ .uleb128 0
++ .long .Lsub_cond_futex_pi-.LSTARTCODE
++ .long .Ladd_cond_futex-.Lsub_cond_futex_pi
+ .long __condvar_tw_cleanup-.LSTARTCODE
+ .uleb128 0
+ .long .Ladd_cond_futex-.LSTARTCODE
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S 2013-07-09 10:16:22.046427519 +0530
+@@ -138,17 +138,33 @@ __pthread_cond_wait:
+ movl %ebp, %edx
+ xorl %esi, %esi
+ addl $cond_futex, %ebx
++.Ladd_cond_futex_pi:
+ movl $SYS_futex, %eax
+ ENTER_KERNEL
+ subl $cond_futex, %ebx
++.Lsub_cond_futex_pi:
+ /* Set the pi-requeued flag only if the kernel has returned 0. The
+ kernel does not hold the mutex on error. */
+ cmpl $0, %eax
+ sete 16(%esp)
+ je 19f
+
+- /* Normal and PI futexes dont mix. Use normal futex functions only
+- if the kernel does not support the PI futex functions. */
++ /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++ successfully, it has already locked the mutex for us and the
++ pi_flag (16(%esp)) is set to denote that fact. However, if another
++ thread changed the futex value before we entered the wait, the
++ syscall may return an EAGAIN and the mutex is not locked. We go
++ ahead with a success anyway since later we look at the pi_flag to
++ decide if we got the mutex or not. The sequence numbers then make
++ sure that only one of the threads actually wake up. We retry using
++ normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++ and PI futexes don't mix.
++
++ Note that we don't check for EAGAIN specifically; we assume that the
++ only other error the futex function could return is EAGAIN since
++ anything else would mean an error in our function. It is too
++ expensive to do that check for every call (which is quite common in
++ case of a large number of threads), so it has been skipped. */
+ cmpl $-ENOSYS, %eax
+ jne 19f
+ xorl %ecx, %ecx
+@@ -198,12 +214,12 @@ __pthread_cond_wait:
+ cmpl 8(%esp), %edx
+ jne 7f
+ cmpl 4(%esp), %edi
+- je 8b
++ je 22f
+
+ 7: cmpl %ecx, %edx
+ jne 9f
+ cmp %eax, %edi
+- je 8b
++ je 22f
+
+ 9: addl $1, woken_seq(%ebx)
+ adcl $0, woken_seq+4(%ebx)
+@@ -279,6 +295,22 @@ __pthread_cond_wait:
+ jmp 20b
+
+ cfi_adjust_cfa_offset(-FRAME_SIZE);
++
++ /* We need to go back to futex_wait. If we're using requeue_pi, then
++ release the mutex we had acquired and go back. */
++22: movl 16(%esp), %edx
++ test %edx, %edx
++ jz 8b
++
++ /* Adjust the mutex values first and then unlock it. The unlock
++ should always succeed or else the kernel did not lock the mutex
++ correctly. */
++ movl dep_mutex(%ebx), %eax
++ call __pthread_mutex_cond_lock_adjust
++ xorl %edx, %edx
++ call __pthread_mutex_unlock_usercnt
++ jmp 8b
++
+ /* Initial locking failed. */
+ 1:
+ #if cond_lock == 0
+@@ -391,6 +423,7 @@ __pthread_cond_wait:
+ #endif
+ call __lll_unlock_wake
+ jmp 11b
++
+ .size __pthread_cond_wait, .-__pthread_cond_wait
+ versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
+ GLIBC_2_3_2)
+@@ -531,10 +564,27 @@ __condvar_w_cleanup:
+ movl $0x7fffffff, %edx
+ ENTER_KERNEL
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movl 24+FRAME_SIZE(%esp), %eax
+- call __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%eax), %ebx
++ andl $(ROBUST_BIT|PI_BIT), %ebx
++ cmpl $PI_BIT, %ebx
++ jne 8f
++
++ movl (%eax), %ebx
++ andl $TID_MASK, %ebx
++ cmpl %ebx, %gs:TID
++ jne 8f
++ /* We managed to get the lock. Fix it up before returning. */
++ call __pthread_mutex_cond_lock_adjust
++ jmp 9f
+
+- movl %esi, (%esp)
++8: call __pthread_mutex_cond_lock
++
++9: movl %esi, (%esp)
+ .LcallUR:
+ call _Unwind_Resume
+ hlt
+@@ -552,7 +602,15 @@ __condvar_w_cleanup:
+ .uleb128 .Lcstend-.Lcstbegin
+ .Lcstbegin:
+ .long .LcleanupSTART-.LSTARTCODE
+- .long .Ladd_cond_futex-.LcleanupSTART
++ .long .Ladd_cond_futex_pi-.LcleanupSTART
++ .long __condvar_w_cleanup-.LSTARTCODE
++ .uleb128 0
++ .long .Ladd_cond_futex_pi-.LSTARTCODE
++ .long .Lsub_cond_futex_pi-.Ladd_cond_futex_pi
++ .long __condvar_w_cleanup2-.LSTARTCODE
++ .uleb128 0
++ .long .Lsub_cond_futex_pi-.LSTARTCODE
++ .long .Ladd_cond_futex-.Lsub_cond_futex_pi
+ .long __condvar_w_cleanup-.LSTARTCODE
+ .uleb128 0
+ .long .Ladd_cond_futex-.LSTARTCODE
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym 2013-07-09 10:16:22.047427519 +0530
+@@ -6,3 +6,4 @@ MUTEX_KIND offsetof (pthread_mutex_t, __
+ ROBUST_BIT PTHREAD_MUTEX_ROBUST_NORMAL_NP
+ PI_BIT PTHREAD_MUTEX_PRIO_INHERIT_NP
+ PS_BIT PTHREAD_MUTEX_PSHARED_BIT
++TID_MASK FUTEX_TID_MASK
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S 2013-07-09 10:18:22.506421835 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S 2013-07-09 10:16:22.048427519 +0530
+@@ -104,6 +104,8 @@ __pthread_cond_timedwait:
+ movq %rsi, dep_mutex(%rdi)
+
+ 22:
++ xorb %r15b, %r15b
++
+ #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+ # ifdef PIC
+ cmpl $0, __have_futex_clock_realtime(%rip)
+@@ -189,18 +191,39 @@ __pthread_cond_timedwait:
+ movl $SYS_futex, %eax
+ syscall
+
+- movl $1, %r15d
++ cmpl $0, %eax
++ sete %r15b
++
+ #ifdef __ASSUME_REQUEUE_PI
+ jmp 62f
+ #else
+- cmpq $-4095, %rax
+- jnae 62f
++ je 62f
++
++ /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++ successfully, it has already locked the mutex for us and the
++ pi_flag (%r15b) is set to denote that fact. However, if another
++ thread changed the futex value before we entered the wait, the
++ syscall may return an EAGAIN and the mutex is not locked. We go
++ ahead with a success anyway since later we look at the pi_flag to
++ decide if we got the mutex or not. The sequence numbers then make
++ sure that only one of the threads actually wake up. We retry using
++ normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++ and PI futexes don't mix.
++
++ Note that we don't check for EAGAIN specifically; we assume that the
++ only other error the futex function could return is EAGAIN (barring
++ the ETIMEOUT of course, for the timeout case in futex) since
++ anything else would mean an error in our function. It is too
++ expensive to do that check for every call (which is quite common in
++ case of a large number of threads), so it has been skipped. */
++ cmpl $-ENOSYS, %eax
++ jne 62f
+
+ subq $cond_futex, %rdi
+ #endif
+
+ 61: movl $(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi
+-60: xorl %r15d, %r15d
++60: xorb %r15b, %r15b
+ xorl %eax, %eax
+ /* The following only works like this because we only support
+ two clocks, represented using a single bit. */
+@@ -247,7 +270,23 @@ __pthread_cond_timedwait:
+ ja 39f
+
+ 45: cmpq $-ETIMEDOUT, %r14
+- jne 38b
++ je 99f
++
++ /* We need to go back to futex_wait. If we're using requeue_pi, then
++ release the mutex we had acquired and go back. */
++ test %r15b, %r15b
++ jz 38b
++
++ /* Adjust the mutex values first and then unlock it. The unlock
++ should always succeed or else the kernel did not lock the
++ mutex correctly. */
++ movq %r8, %rdi
++ callq __pthread_mutex_cond_lock_adjust
++ xorl %esi, %esi
++ callq __pthread_mutex_unlock_usercnt
++ /* Reload cond_var. */
++ movq 8(%rsp), %rdi
++ jmp 38b
+
+ 99: incq wakeup_seq(%rdi)
+ incl cond_futex(%rdi)
+@@ -297,7 +336,7 @@ __pthread_cond_timedwait:
+ /* If requeue_pi is used the kernel performs the locking of the
+ mutex. */
+ 41: movq 16(%rsp), %rdi
+- testl %r15d, %r15d
++ testb %r15b, %r15b
+ jnz 64f
+
+ callq __pthread_mutex_cond_lock
+@@ -405,8 +444,6 @@ __pthread_cond_timedwait:
+
+ #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+ .Lreltmo:
+- xorl %r15d, %r15d
+-
+ /* Get internal lock. */
+ movl $1, %esi
+ xorl %eax, %eax
+@@ -765,10 +802,27 @@ __condvar_cleanup2:
+ movl $SYS_futex, %eax
+ syscall
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movq 16(%rsp), %rdi
+- callq __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%rdi), %eax
++ andl $(ROBUST_BIT|PI_BIT), %eax
++ cmpl $PI_BIT, %eax
++ jne 7f
++
++ movl (%rdi), %eax
++ andl $TID_MASK, %eax
++ cmpl %eax, %fs:TID
++ jne 7f
++ /* We managed to get the lock. Fix it up before returning. */
++ callq __pthread_mutex_cond_lock_adjust
++ jmp 8f
++
++7: callq __pthread_mutex_cond_lock
+
+- movq 24(%rsp), %rdi
++8: movq 24(%rsp), %rdi
+ movq FRAME_SIZE(%rsp), %r15
+ movq FRAME_SIZE+8(%rsp), %r14
+ movq FRAME_SIZE+16(%rsp), %r13
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S 2013-07-09 10:18:22.507421834 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S 2013-07-09 10:16:22.048427519 +0530
+@@ -23,6 +23,7 @@
+ #include <lowlevelcond.h>
+ #include <tcb-offsets.h>
+ #include <pthread-pi-defines.h>
++#include <pthread-errnos.h>
+
+ #include <kernel-features.h>
+
+@@ -137,12 +138,32 @@ __pthread_cond_wait:
+ movl $SYS_futex, %eax
+ syscall
+
+- movl $1, %r8d
++ cmpl $0, %eax
++ sete %r8b
++
+ #ifdef __ASSUME_REQUEUE_PI
+ jmp 62f
+ #else
+- cmpq $-4095, %rax
+- jnae 62f
++ je 62f
++
++ /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++ successfully, it has already locked the mutex for us and the
++ pi_flag (%r8b) is set to denote that fact. However, if another
++ thread changed the futex value before we entered the wait, the
++ syscall may return an EAGAIN and the mutex is not locked. We go
++ ahead with a success anyway since later we look at the pi_flag to
++ decide if we got the mutex or not. The sequence numbers then make
++ sure that only one of the threads actually wake up. We retry using
++ normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++ and PI futexes don't mix.
++
++ Note that we don't check for EAGAIN specifically; we assume that the
++ only other error the futex function could return is EAGAIN since
++ anything else would mean an error in our function. It is too
++ expensive to do that check for every call (which is quite common in
++ case of a large number of threads), so it has been skipped. */
++ cmpl $-ENOSYS, %eax
++ jne 62f
+
+ # ifndef __ASSUME_PRIVATE_FUTEX
+ movl $FUTEX_WAIT, %esi
+@@ -155,7 +176,7 @@ __pthread_cond_wait:
+ #else
+ orl %fs:PRIVATE_FUTEX, %esi
+ #endif
+-60: xorl %r8d, %r8d
++60: xorb %r8b, %r8b
+ movl $SYS_futex, %eax
+ syscall
+
+@@ -185,10 +206,10 @@ __pthread_cond_wait:
+ jne 16f
+
+ cmpq 24(%rsp), %r9
+- jbe 8b
++ jbe 19f
+
+ cmpq %rax, %r9
+- jna 8b
++ jna 19f
+
+ incq woken_seq(%rdi)
+
+@@ -230,7 +251,7 @@ __pthread_cond_wait:
+ /* If requeue_pi is used the kernel performs the locking of the
+ mutex. */
+ 11: movq 16(%rsp), %rdi
+- testl %r8d, %r8d
++ testb %r8b, %r8b
+ jnz 18f
+
+ callq __pthread_mutex_cond_lock
+@@ -247,6 +268,23 @@ __pthread_cond_wait:
+ xorl %eax, %eax
+ jmp 14b
+
++ /* We need to go back to futex_wait. If we're using requeue_pi, then
++ release the mutex we had acquired and go back. */
++19: testb %r8b, %r8b
++ jz 8b
++
++ /* Adjust the mutex values first and then unlock it. The unlock
++ should always succeed or else the kernel did not lock the mutex
++ correctly. */
++ movq 16(%rsp), %rdi
++ callq __pthread_mutex_cond_lock_adjust
++ movq %rdi, %r8
++ xorl %esi, %esi
++ callq __pthread_mutex_unlock_usercnt
++ /* Reload cond_var. */
++ movq 8(%rsp), %rdi
++ jmp 8b
++
+ /* Initial locking failed. */
+ 1:
+ #if cond_lock != 0
+@@ -324,6 +362,7 @@ __pthread_cond_wait:
+
+ 13: movq %r10, %rax
+ jmp 14b
++
+ .size __pthread_cond_wait, .-__pthread_cond_wait
+ versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
+ GLIBC_2_3_2)
+@@ -454,10 +493,28 @@ __condvar_cleanup1:
+ movl $SYS_futex, %eax
+ syscall
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movq 16(%rsp), %rdi
+- callq __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%rdi), %eax
++ andl $(ROBUST_BIT|PI_BIT), %eax
++ cmpl $PI_BIT, %eax
++ jne 7f
++
++ movl (%rdi), %eax
++ andl $TID_MASK, %eax
++ cmpl %eax, %fs:TID
++ jne 7f
++ /* We managed to get the lock. Fix it up before returning. */
++ callq __pthread_mutex_cond_lock_adjust
++ jmp 8f
++
+
+- movq 24(%rsp), %rdi
++7: callq __pthread_mutex_cond_lock
++
++8: movq 24(%rsp), %rdi
+ .LcallUR:
+ call _Unwind_Resume@PLT
+ hlt
+@@ -476,11 +533,11 @@ __condvar_cleanup1:
+ .uleb128 .LcleanupSTART-.LSTARTCODE
+ .uleb128 .LcleanupEND-.LcleanupSTART
+ .uleb128 __condvar_cleanup1-.LSTARTCODE
+- .uleb128 0
++ .uleb128 0
+ .uleb128 .LcallUR-.LSTARTCODE
+ .uleb128 .LENDCODE-.LcallUR
+ .uleb128 0
+- .uleb128 0
++ .uleb128 0
+ .Lcstend:
+
+
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-cond24.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond24.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-cond24.c 1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond24.c 2013-07-09 10:19:10.008419593 +0530
+@@ -0,0 +1,249 @@
++/* Verify that condition variables synchronized by PI mutexes don't hang.
++ Copyright (C) 2012-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
++ <http://www.gnu.org/licenses/>. */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/syscall.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include <time.h>
++
++#define THREADS_NUM 5
++#define MAXITER 50000
++
++static pthread_mutex_t mutex;
++static pthread_mutexattr_t mutex_attr;
++static pthread_cond_t cond;
++static pthread_t threads[THREADS_NUM];
++static int pending = 0;
++
++typedef void * (*threadfunc) (void *);
++
++void *
++thread_fun_timed (void *arg)
++{
++ int *ret = arg;
++ int rv, i;
++
++ printf ("Started thread_fun_timed[%d]\n", *ret);
++
++ for (i = 0; i < MAXITER / THREADS_NUM; i++)
++ {
++ rv = pthread_mutex_lock (&mutex);
++ if (rv)
++ {
++ printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
++ *ret = 1;
++ goto out;
++ }
++
++ while (!pending)
++ {
++ struct timespec ts;
++ clock_gettime(CLOCK_REALTIME, &ts);
++ ts.tv_sec += 20;
++ rv = pthread_cond_timedwait (&cond, &mutex, &ts);
++
++ /* There should be no timeout either. */
++ if (rv)
++ {
++ printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
++ *ret = 1;
++ goto out;
++ }
++ }
++
++ pending--;
++
++ rv = pthread_mutex_unlock (&mutex);
++ if (rv)
++ {
++ printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
++ *ret = 1;
++ goto out;
++ }
++ }
++
++ *ret = 0;
++
++out:
++ return ret;
++}
++
++void *
++thread_fun (void *arg)
++{
++ int *ret = arg;
++ int rv, i;
++
++ printf ("Started thread_fun[%d]\n", *ret);
++
++ for (i = 0; i < MAXITER / THREADS_NUM; i++)
++ {
++ rv = pthread_mutex_lock (&mutex);
++ if (rv)
++ {
++ printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
++ *ret = 1;
++ goto out;
++ }
++
++ while (!pending)
++ {
++ rv = pthread_cond_wait (&cond, &mutex);
++
++ if (rv)
++ {
++ printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
++ *ret = 1;
++ goto out;
++ }
++ }
++
++ pending--;
++
++ rv = pthread_mutex_unlock (&mutex);
++ if (rv)
++ {
++ printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
++ *ret = 1;
++ goto out;
++ }
++ }
++
++ *ret = 0;
++
++out:
++ return ret;
++}
++
++static int
++do_test_wait (threadfunc f)
++{
++ int i;
++ int rv;
++ int counter = 0;
++ int retval[THREADS_NUM];
++
++ puts ("Starting test");
++
++ rv = pthread_mutexattr_init (&mutex_attr);
++ if (rv)
++ {
++ printf ("pthread_mutexattr_init: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++
++ rv = pthread_mutexattr_setprotocol (&mutex_attr, PTHREAD_PRIO_INHERIT);
++ if (rv)
++ {
++ printf ("pthread_mutexattr_setprotocol: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++
++ rv = pthread_mutex_init (&mutex, &mutex_attr);
++ if (rv)
++ {
++ printf ("pthread_mutex_init: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++
++ rv = pthread_cond_init (&cond, NULL);
++ if (rv)
++ {
++ printf ("pthread_cond_init: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++
++ for (i = 0; i < THREADS_NUM; i++)
++ {
++ retval[i] = i;
++ rv = pthread_create (&threads[i], NULL, f, &retval[i]);
++ if (rv)
++ {
++ printf ("pthread_create: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++ }
++
++ for (; counter < MAXITER; counter++)
++ {
++ rv = pthread_mutex_lock (&mutex);
++ if (rv)
++ {
++ printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++
++ if (!(counter % 100))
++ printf ("counter: %d\n", counter);
++ pending += 1;
++
++ rv = pthread_cond_signal (&cond);
++ if (rv)
++ {
++ printf ("pthread_cond_signal: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++
++ rv = pthread_mutex_unlock (&mutex);
++ if (rv)
++ {
++ printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++ }
++
++ for (i = 0; i < THREADS_NUM; i++)
++ {
++ void *ret;
++ rv = pthread_join (threads[i], &ret);
++ if (rv)
++ {
++ printf ("pthread_join: %s(%d)\n", strerror (rv), rv);
++ return 1;
++ }
++ if (ret && *(int *)ret)
++ {
++ printf ("Thread %d returned with an error\n", i);
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++static int
++do_test (void)
++{
++ puts ("Testing pthread_cond_wait");
++ int ret = do_test_wait (thread_fun);
++ if (ret)
++ return ret;
++
++ puts ("Testing pthread_cond_timedwait");
++ return do_test_wait (thread_fun_timed);
++}
++
++#define TIMEOUT 20
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-cond25.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond25.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-cond25.c 1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond25.c 2013-07-09 10:19:15.472419335 +0530
+@@ -0,0 +1,281 @@
++/* Verify that condition variables synchronized by PI mutexes don't hang on
++ on cancellation.
++ Copyright (C) 2012-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
++ <http://www.gnu.org/licenses/>. */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/syscall.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include <time.h>
++
++#define NUM 5
++#define ITERS 10000
++#define COUNT 100
++
++typedef void *(*thr_func) (void *);
++
++pthread_mutex_t mutex;
++pthread_cond_t cond;
++
++void cleanup (void *u)
++{
++ /* pthread_cond_wait should always return with the mutex locked. */
++ if (pthread_mutex_unlock (&mutex))
++ abort ();
++}
++
++void *
++signaller (void *u)
++{
++ int i, ret = 0;
++ void *tret = NULL;
++
++ for (i = 0; i < ITERS; i++)
++ {
++ if ((ret = pthread_mutex_lock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("signaller:mutex_lock failed: %s\n", strerror (ret));
++ goto out;
++ }
++ if ((ret = pthread_cond_signal (&cond)) != 0)
++ {
++ tret = (void *)1;
++ printf ("signaller:signal failed: %s\n", strerror (ret));
++ goto unlock_out;
++ }
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("signaller:mutex_unlock failed: %s\n", strerror (ret));
++ goto out;
++ }
++ pthread_testcancel ();
++ }
++
++out:
++ return tret;
++
++unlock_out:
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ printf ("signaller:mutex_unlock[2] failed: %s\n", strerror (ret));
++ goto out;
++}
++
++void *
++waiter (void *u)
++{
++ int i, ret = 0;
++ void *tret = NULL;
++ int seq = (uintptr_t) u;
++
++ for (i = 0; i < ITERS / NUM; i++)
++ {
++ if ((ret = pthread_mutex_lock (&mutex)) != 0)
++ {
++ tret = (void *) (uintptr_t) 1;
++ printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_push (cleanup, NULL);
++
++ if ((ret = pthread_cond_wait (&cond, &mutex)) != 0)
++ {
++ tret = (void *) (uintptr_t) 1;
++ printf ("waiter[%u]:wait failed: %s\n", seq, strerror (ret));
++ goto unlock_out;
++ }
++
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ {
++ tret = (void *) (uintptr_t) 1;
++ printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_pop (0);
++ }
++
++out:
++ puts ("waiter tests done");
++ return tret;
++
++unlock_out:
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ printf ("waiter:mutex_unlock[2] failed: %s\n", strerror (ret));
++ goto out;
++}
++
++void *
++timed_waiter (void *u)
++{
++ int i, ret;
++ void *tret = NULL;
++ int seq = (uintptr_t) u;
++
++ for (i = 0; i < ITERS / NUM; i++)
++ {
++ struct timespec ts;
++
++ if ((ret = clock_gettime(CLOCK_REALTIME, &ts)) != 0)
++ {
++ tret = (void *) (uintptr_t) 1;
++ printf ("%u:clock_gettime failed: %s\n", seq, strerror (errno));
++ goto out;
++ }
++ ts.tv_sec += 20;
++
++ if ((ret = pthread_mutex_lock (&mutex)) != 0)
++ {
++ tret = (void *) (uintptr_t) 1;
++ printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_push (cleanup, NULL);
++
++ /* We should not time out either. */
++ if ((ret = pthread_cond_timedwait (&cond, &mutex, &ts)) != 0)
++ {
++ tret = (void *) (uintptr_t) 1;
++ printf ("waiter[%u]:timedwait failed: %s\n", seq, strerror (ret));
++ goto unlock_out;
++ }
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ {
++ tret = (void *) (uintptr_t) 1;
++ printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_pop (0);
++ }
++
++out:
++ puts ("timed_waiter tests done");
++ return tret;
++
++unlock_out:
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ printf ("waiter[%u]:mutex_unlock[2] failed: %s\n", seq, strerror (ret));
++ goto out;
++}
++
++int
++do_test_wait (thr_func f)
++{
++ pthread_t w[NUM];
++ pthread_t s;
++ pthread_mutexattr_t attr;
++ int i, j, ret = 0;
++ void *thr_ret;
++
++ for (i = 0; i < COUNT; i++)
++ {
++ if ((ret = pthread_mutexattr_init (&attr)) != 0)
++ {
++ printf ("mutexattr_init failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_mutexattr_setprotocol (&attr,
++ PTHREAD_PRIO_INHERIT)) != 0)
++ {
++ printf ("mutexattr_setprotocol failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_cond_init (&cond, NULL)) != 0)
++ {
++ printf ("cond_init failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_mutex_init (&mutex, &attr)) != 0)
++ {
++ printf ("mutex_init failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ for (j = 0; j < NUM; j++)
++ if ((ret = pthread_create (&w[j], NULL,
++ f, (void *) (uintptr_t) j)) != 0)
++ {
++ printf ("waiter[%d]: create failed: %s\n", j, strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_create (&s, NULL, signaller, NULL)) != 0)
++ {
++ printf ("signaller: create failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ for (j = 0; j < NUM; j++)
++ {
++ pthread_cancel (w[j]);
++
++ if ((ret = pthread_join (w[j], &thr_ret)) != 0)
++ {
++ printf ("waiter[%d]: join failed: %s\n", j, strerror (ret));
++ goto out;
++ }
++
++ if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
++ {
++ ret = 1;
++ goto out;
++ }
++ }
++
++ /* The signalling thread could have ended before it was cancelled. */
++ pthread_cancel (s);
++
++ if ((ret = pthread_join (s, &thr_ret)) != 0)
++ {
++ printf ("signaller: join failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
++ {
++ ret = 1;
++ goto out;
++ }
++ }
++
++out:
++ return ret;
++}
++
++int
++do_test (int argc, char **argv)
++{
++ int ret = do_test_wait (waiter);
++
++ if (ret)
++ return ret;
++
++ return do_test_wait (timed_waiter);
++}
++
++#define TIMEOUT 5
++#include "../test-skeleton.c"
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-cond-except.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond-except.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-cond-except.c 1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond-except.c 2013-07-09 10:19:01.334420002 +0530
+@@ -0,0 +1,110 @@
++/* Verify that exception table for pthread_cond_wait is correct.
++ Copyright (C) 2012-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
++ <http://www.gnu.org/licenses/>. */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++
++pthread_mutex_t mutex;
++pthread_cond_t cond;
++
++#define CHECK_RETURN_VAL_OR_FAIL(ret,str) \
++ ({ if ((ret) != 0) \
++ { \
++ printf ("%s failed: %s\n", (str), strerror (ret)); \
++ ret = 1; \
++ goto out; \
++ } \
++ })
++
++
++void
++clean (void *arg)
++{
++ puts ("clean: Unlocking mutex...");
++ pthread_mutex_unlock ((pthread_mutex_t *) arg);
++ puts ("clean: Mutex unlocked...");
++}
++
++void *
++thr (void *arg)
++{
++ int ret = 0;
++ pthread_mutexattr_t mutexAttr;
++ ret = pthread_mutexattr_init (&mutexAttr);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_init");
++
++ ret = pthread_mutexattr_setprotocol (&mutexAttr, PTHREAD_PRIO_INHERIT);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_setprotocol");
++
++ ret = pthread_mutex_init (&mutex, &mutexAttr);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_init");
++
++ ret = pthread_cond_init (&cond, 0);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_init");
++
++ puts ("th: Init done, entering wait...");
++
++ pthread_cleanup_push (clean, (void *) &mutex);
++ ret = pthread_mutex_lock (&mutex);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_lock");
++ while (1)
++ {
++ ret = pthread_cond_wait (&cond, &mutex);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_wait");
++ }
++ pthread_cleanup_pop (1);
++
++out:
++ return (void *) (uintptr_t) ret;
++}
++
++int
++do_test (void)
++{
++ pthread_t thread;
++ int ret = 0;
++ void *thr_ret = 0;
++ ret = pthread_create (&thread, 0, thr, &thr_ret);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_create");
++
++ puts ("main: Thread created, waiting a bit...");
++ sleep (2);
++
++ puts ("main: Cancelling thread...");
++ ret = pthread_cancel (thread);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cancel");
++
++ puts ("main: Joining th...");
++ ret = pthread_join (thread, NULL);
++ CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_join");
++
++ if (thr_ret != NULL)
++ return 1;
++
++ puts ("main: Joined thread, done!");
++
++out:
++ return ret;
++}
++
++#define TEST_FUNCTION do_test ()
++#define TIMEOUT 5
++#include "../test-skeleton.c"
--- /dev/null
+commit 50fd745b4dec07e8e213cf2703b5cabcfa128225
+Author: Andreas Schwab <schwab@suse.de>
+Date: Mon Jun 10 14:39:09 2013 +0200
+
+ Fix handling of netgroup cache in nscd
+
+diff --git a/nscd/connections.c b/nscd/connections.c
+index 7099215..69e3e7d 100644
+--- a/nscd/connections.c
++++ b/nscd/connections.c
+@@ -1779,7 +1779,7 @@ nscd_run_worker (void *p)
+ else
+ {
+ /* Get the key. */
+- char keybuf[MAXKEYLEN];
++ char keybuf[MAXKEYLEN + 1];
+
+ if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
+ req.key_len))
+@@ -1791,6 +1791,7 @@ nscd_run_worker (void *p)
+ strerror_r (errno, buf, sizeof (buf)));
+ goto close_and_out;
+ }
++ keybuf[req.key_len] = '\0';
+
+ if (__builtin_expect (debug_level, 0) > 0)
+ {
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 2d6c5aa..dd06ce4 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -192,18 +192,26 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ const char *nuser = data.val.triple.user;
+ const char *ndomain = data.val.triple.domain;
+
+- if (data.val.triple.host > data.val.triple.user
+- || data.val.triple.user > data.val.triple.domain)
++ if (nhost == NULL || nuser == NULL || ndomain == NULL
++ || nhost > nuser || nuser > ndomain)
+ {
+- const char *last = MAX (nhost,
+- MAX (nuser, ndomain));
+- size_t bufused = (last + strlen (last) + 1
+- - buffer);
++ const char *last = nhost;
++ if (last == NULL
++ || (nuser != NULL && nuser > last))
++ last = nuser;
++ if (last == NULL
++ || (ndomain != NULL && ndomain > last))
++ last = ndomain;
++
++ size_t bufused
++ = (last == NULL
++ ? buffilled
++ : last + strlen (last) + 1 - buffer);
+
+ /* We have to make temporary copies. */
+- size_t hostlen = strlen (nhost) + 1;
+- size_t userlen = strlen (nuser) + 1;
+- size_t domainlen = strlen (ndomain) + 1;
++ size_t hostlen = strlen (nhost ?: "") + 1;
++ size_t userlen = strlen (nuser ?: "") + 1;
++ size_t domainlen = strlen (ndomain ?: "") + 1;
+ size_t needed = hostlen + userlen + domainlen;
+
+ if (buflen - req->key_len - bufused < needed)
+@@ -226,11 +234,11 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+ }
+
+ nhost = memcpy (buffer + bufused,
+- nhost, hostlen);
++ nhost ?: "", hostlen);
+ nuser = memcpy ((char *) nhost + hostlen,
+- nuser, userlen);
++ nuser ?: "", userlen);
+ ndomain = memcpy ((char *) nuser + userlen,
+- ndomain, domainlen);
++ ndomain ?: "", domainlen);
+ }
+
+ char *wp = buffer + buffilled;
+diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
+index cac4ebf..acb2c81 100644
+--- a/nscd/nscd_netgroup.c
++++ b/nscd/nscd_netgroup.c
+@@ -48,7 +48,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap)
+ {
+ int gc_cycle;
+ int nretries = 0;
+- size_t group_len = strlen (group);
++ size_t group_len = strlen (group) + 1;
+
+ /* If the mapping is available, try to search there instead of
+ communicating with the nscd. */
--- /dev/null
+diff -Nrup a/grp/initgroups.c b/grp/initgroups.c
+--- a/grp/initgroups.c 2012-08-06 15:07:48.935060494 -0600
++++ b/grp/initgroups.c 2012-08-23 14:19:49.370442142 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1989,91,93,1996-2005,2006,2008 Free Software Foundation, Inc.
++/* Copyright (C) 1989,91,93,1996-2006,2008,2010 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
+@@ -58,7 +58,8 @@ internal_getgrouplist (const char *user,
+ if (__nss_not_use_nscd_group > 0
+ && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
+ __nss_not_use_nscd_group = 0;
+- if (!__nss_not_use_nscd_group)
++ if (!__nss_not_use_nscd_group
++ && !__nss_database_custom[NSS_DBSIDX_group])
+ {
+ int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
+ if (n >= 0)
+diff -Nrup a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c
+--- a/inet/getnetgrent_r.c 2010-05-04 05:27:23.000000000 -0600
++++ b/inet/getnetgrent_r.c 2012-08-06 15:10:05.865520055 -0600
+@@ -28,6 +28,7 @@
+ #include "netgroup.h"
+ #include "nsswitch.h"
+ #include <sysdep.h>
++#include <nscd/nscd_proto.h>
+
+
+ /* Protect above variable against multiple uses at the same time. */
+@@ -101,7 +102,7 @@ endnetgrent_hook (struct __netgrent *dat
+ {
+ enum nss_status (*endfct) (struct __netgrent *);
+
+- if (datap->nip == NULL)
++ if (datap->nip == NULL || datap->nip == (service_user *) -1l)
+ return;
+
+ endfct = __nss_lookup_function (datap->nip, "endnetgrent");
+@@ -189,8 +190,21 @@ setnetgrent (const char *group)
+
+ __libc_lock_lock (lock);
+
++ if (__nss_not_use_nscd_netgroup > 0
++ && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
++ __nss_not_use_nscd_netgroup = 0;
++
++ if (!__nss_not_use_nscd_netgroup
++ && !__nss_database_custom[NSS_DBSIDX_netgroup])
++ {
++ result = __nscd_setnetgrent (group, &dataset);
++ if (result >= 0)
++ goto out;
++ }
++
+ result = internal_setnetgrent (group, &dataset);
+
++ out:
+ __libc_lock_unlock (lock);
+
+ return result;
+@@ -226,6 +240,26 @@ int internal_getnetgrent_r (char **hostp
+ char *buffer, size_t buflen, int *errnop);
+ libc_hidden_proto (internal_getnetgrent_r)
+
++
++static enum nss_status
++nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
++ int *errnop)
++{
++ if (datap->cursor >= datap->data + datap->data_size)
++ return NSS_STATUS_UNAVAIL;
++
++ datap->type = triple_val;
++ datap->val.triple.host = datap->cursor;
++ datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
++ datap->val.triple.user = datap->cursor;
++ datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
++ datap->val.triple.domain = datap->cursor;
++ datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
++
++ return NSS_STATUS_SUCCESS;
++}
++
++
+ int
+ internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
+ struct __netgrent *datap,
+@@ -239,9 +273,18 @@ internal_getnetgrent_r (char **hostp, ch
+ /* Run through available functions, starting with the same function last
+ run. We will repeat each function as long as it succeeds, and then go
+ on to the next service action. */
+- int no_more = (datap->nip == NULL
+- || (fct = __nss_lookup_function (datap->nip, "getnetgrent_r"))
+- == NULL);
++ int no_more = datap->nip == NULL;
++ if (! no_more)
++ {
++ if (datap->nip == (service_user *) -1l)
++ fct = nscd_getnetgrent;
++ else
++ {
++ fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
++ no_more = fct == NULL;
++ }
++ }
++
+ while (! no_more)
+ {
+ status = (*fct) (datap, buffer, buflen, &errno);
+@@ -337,6 +380,18 @@ int
+ innetgr (const char *netgroup, const char *host, const char *user,
+ const char *domain)
+ {
++ if (__nss_not_use_nscd_netgroup > 0
++ && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
++ __nss_not_use_nscd_netgroup = 0;
++
++ if (!__nss_not_use_nscd_netgroup
++ && !__nss_database_custom[NSS_DBSIDX_netgroup])
++ {
++ int result = __nscd_innetgr (netgroup, host, user, domain);
++ if (result >= 0)
++ return result;
++ }
++
+ union
+ {
+ int (*f) (const char *, struct __netgrent *);
+@@ -444,7 +499,7 @@ innetgr (const char *netgroup, const cha
+ entry.needed_groups = tmp->next;
+ tmp->next = entry.known_groups;
+ entry.known_groups = tmp;
+- current_group = entry.known_groups->name;
++ current_group = tmp->name;
+ continue;
+ }
+
+diff -Nrup a/nscd/Makefile b/nscd/Makefile
+--- a/nscd/Makefile 2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/Makefile 2012-08-06 15:08:19.045941627 -0600
+@@ -22,7 +22,7 @@
+ subdir := nscd
+
+ routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
+- nscd_initgroups nscd_getserv_r
++ nscd_initgroups nscd_getserv_r nscd_netgroup
+ aux := nscd_helper
+
+ include ../Makeconfig
+@@ -34,7 +34,8 @@ nscd-modules := nscd connections pwdcach
+ getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
+ getsrvbynm_r getsrvbypt_r servicescache \
+ dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
+- xmalloc xstrdup aicache initgrcache gai res_hconf
++ xmalloc xstrdup aicache initgrcache gai res_hconf \
++ netgroupcache
+
+ ifeq ($(have-thread-library),yes)
+
+@@ -122,6 +123,7 @@ CFLAGS-servicescache.c += $(nscd-cflags)
+ CFLAGS-getsrvbynm_r.c += $(nscd-cflags)
+ CFLAGS-getsrvbypt_r.c += $(nscd-cflags)
+ CFLAGS-res_hconf.c += $(nscd-cflags)
++CFLAGS-netgroupcache.c += $(nscd-cflags)
+
+ ifeq (yesyes,$(have-fpie)$(build-shared))
+ relro-LDFLAGS += -Wl,-z,now
+diff -Nrup a/nscd/cache.c b/nscd/cache.c
+--- a/nscd/cache.c 2012-08-06 15:07:48.973060344 -0600
++++ b/nscd/cache.c 2012-08-06 15:08:19.046941626 -0600
+@@ -60,7 +60,9 @@ static time_t (*const readdfcts[LASTREQ]
+ [GETAI] = readdhstai,
+ [INITGROUPS] = readdinitgroups,
+ [GETSERVBYNAME] = readdservbyname,
+- [GETSERVBYPORT] = readdservbyport
++ [GETSERVBYPORT] = readdservbyport,
++ [GETNETGRENT] = readdgetnetgrent,
++ [INNETGR] = readdinnetgr
+ };
+
+
+@@ -70,7 +72,7 @@ static time_t (*const readdfcts[LASTREQ]
+
+ This function must be called with the read-lock held. */
+ struct datahead *
+-cache_search (request_type type, void *key, size_t len,
++cache_search (request_type type, const void *key, size_t len,
+ struct database_dyn *table, uid_t owner)
+ {
+ unsigned long int hash = __nis_hash (key, len) % table->head->module;
+diff -Nrup a/nscd/connections.c b/nscd/connections.c
+--- a/nscd/connections.c 2012-08-06 15:07:49.076059937 -0600
++++ b/nscd/connections.c 2012-08-21 21:36:10.210358578 -0600
+@@ -57,11 +57,6 @@
+ #endif
+
+
+-/* Wrapper functions with error checking for standard functions. */
+-extern void *xmalloc (size_t n);
+-extern void *xcalloc (size_t n, size_t s);
+-extern void *xrealloc (void *o, size_t n);
+-
+ /* Support to run nscd as an unprivileged user */
+ const char *server_user;
+ static uid_t server_uid;
+@@ -100,7 +95,10 @@ const char *const serv2str[LASTREQ] =
+ [INITGROUPS] = "INITGROUPS",
+ [GETSERVBYNAME] = "GETSERVBYNAME",
+ [GETSERVBYPORT] = "GETSERVBYPORT",
+- [GETFDSERV] = "GETFDSERV"
++ [GETFDSERV] = "GETFDSERV",
++ [GETNETGRENT] = "GETNETGRENT",
++ [INNETGR] = "INNETGR",
++ [GETFDNETGR] = "GETFDNETGR"
+ };
+
+ /* The control data structures for the services. */
+@@ -189,6 +187,27 @@ struct database_dyn dbs[lastdb] =
+ .wr_fd = -1,
+ .ro_fd = -1,
+ .mmap_used = false
++ },
++ [netgrdb] = {
++ .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
++ .prune_lock = PTHREAD_MUTEX_INITIALIZER,
++ .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
++ .enabled = 0,
++ .check_file = 1,
++ .persistent = 0,
++ .propagate = 0, /* Not used. */
++ .shared = 0,
++ .max_db_size = DEFAULT_MAX_DB_SIZE,
++ .suggested_module = DEFAULT_SUGGESTED_MODULE,
++ .reset_res = 0,
++ .filename = "/etc/netgroup",
++ .db_filename = _PATH_NSCD_NETGROUP_DB,
++ .disabled_iov = &netgroup_iov_disabled,
++ .postimeout = 28800,
++ .negtimeout = 20,
++ .wr_fd = -1,
++ .ro_fd = -1,
++ .mmap_used = false
+ }
+ };
+
+@@ -218,7 +237,10 @@ static struct
+ [INITGROUPS] = { true, &dbs[grpdb] },
+ [GETSERVBYNAME] = { true, &dbs[servdb] },
+ [GETSERVBYPORT] = { true, &dbs[servdb] },
+- [GETFDSERV] = { false, &dbs[servdb] }
++ [GETFDSERV] = { false, &dbs[servdb] },
++ [GETNETGRENT] = { true, &dbs[netgrdb] },
++ [INNETGR] = { true, &dbs[netgrdb] },
++ [GETFDNETGR] = { false, &dbs[netgrdb] }
+ };
+
+
+@@ -366,7 +388,8 @@ check_use (const char *data, nscd_ssize_
+ static int
+ verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
+ {
+- assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb);
++ assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb
++ || dbnr == netgrdb);
+
+ time_t now = time (NULL);
+
+@@ -1241,6 +1264,14 @@ request from '%s' [%ld] not handled due
+ addservbyport (db, fd, req, key, uid);
+ break;
+
++ case GETNETGRENT:
++ addgetnetgrent (db, fd, req, key, uid);
++ break;
++
++ case INNETGR:
++ addinnetgr (db, fd, req, key, uid);
++ break;
++
+ case GETSTAT:
+ case SHUTDOWN:
+ case INVALIDATE:
+@@ -1287,6 +1318,7 @@ request from '%s' [%ld] not handled due
+ case GETFDGR:
+ case GETFDHST:
+ case GETFDSERV:
++ case GETFDNETGR:
+ #ifdef SCM_RIGHTS
+ send_ro_fd (reqinfo[req->type].db, key, fd);
+ #endif
+diff -Nrup a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+--- a/nscd/netgroupcache.c 1969-12-31 17:00:00.000000000 -0700
++++ b/nscd/netgroupcache.c 2012-08-24 11:38:05.118254176 -0600
+@@ -0,0 +1,667 @@
++/* Cache handling for netgroup lookup.
++ Copyright (C) 2011 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published
++ by the Free Software Foundation; version 2 of the License, or
++ (at your option) any later version.
++
++ This program 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 General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software Foundation,
++ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
++
++#include <alloca.h>
++#include <assert.h>
++#include <errno.h>
++#include <libintl.h>
++#include <stdbool.h>
++#include <unistd.h>
++#include <sys/mman.h>
++
++#include "../inet/netgroup.h"
++#include "nscd.h"
++#include "dbg_log.h"
++#ifdef HAVE_SENDFILE
++# include <kernel-features.h>
++#endif
++
++
++/* This is the standard reply in case the service is disabled. */
++static const netgroup_response_header disabled =
++{
++ .version = NSCD_VERSION,
++ .found = -1,
++ .nresults = 0,
++ .result_len = 0
++};
++
++/* This is the struct describing how to write this record. */
++const struct iovec netgroup_iov_disabled =
++{
++ .iov_base = (void *) &disabled,
++ .iov_len = sizeof (disabled)
++};
++
++
++/* This is the standard reply in case we haven't found the dataset. */
++static const netgroup_response_header notfound =
++{
++ .version = NSCD_VERSION,
++ .found = 0,
++ .nresults = 0,
++ .result_len = 0
++};
++
++
++struct dataset
++{
++ struct datahead head;
++ netgroup_response_header resp;
++ char strdata[0];
++};
++
++
++static time_t
++addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
++ const char *key, uid_t uid, struct hashentry *he,
++ struct datahead *dh, struct dataset **resultp)
++{
++ if (__builtin_expect (debug_level > 0, 0))
++ {
++ if (he == NULL)
++ dbg_log (_("Haven't found \"%s\" in netgroup cache!"), key);
++ else
++ dbg_log (_("Reloading \"%s\" in netgroup cache!"), key);
++ }
++
++ static service_user *netgroup_database;
++ time_t timeout;
++ struct dataset *dataset;
++ bool cacheable = false;
++ ssize_t total;
++
++ char *key_copy = NULL;
++ struct __netgrent data;
++ size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
++ size_t buffilled = sizeof (*dataset);
++ char *buffer = NULL;
++ size_t nentries = 0;
++ bool use_malloc = false;
++ size_t group_len = strlen (key) + 1;
++ union
++ {
++ struct name_list elem;
++ char mem[sizeof (struct name_list) + group_len];
++ } first_needed;
++
++ if (netgroup_database == NULL
++ && __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;
++ }
++
++ goto writeout;
++ }
++
++ memset (&data, '\0', sizeof (data));
++ buffer = alloca (buflen);
++ first_needed.elem.next = &first_needed.elem;
++ memcpy (first_needed.elem.name, key, group_len);
++ data.needed_groups = &first_needed.elem;
++
++ while (data.needed_groups != NULL)
++ {
++ /* Add the next group to the list of those which are known. */
++ struct name_list *this_group = data.needed_groups->next;
++ if (this_group == data.needed_groups)
++ data.needed_groups = NULL;
++ else
++ data.needed_groups->next = this_group->next;
++ this_group->next = data.known_groups;
++ data.known_groups = this_group;
++
++ union
++ {
++ enum nss_status (*f) (const char *, struct __netgrent *);
++ void *ptr;
++ } setfct;
++
++ service_user *nip = netgroup_database;
++ int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr);
++ while (!no_more)
++ {
++ enum nss_status status
++ = DL_CALL_FCT (*setfct.f, (data.known_groups->name, &data));
++
++ if (status == NSS_STATUS_SUCCESS)
++ {
++ union
++ {
++ enum nss_status (*f) (struct __netgrent *, char *, size_t,
++ int *);
++ void *ptr;
++ } getfct;
++ getfct.ptr = __nss_lookup_function (nip, "getnetgrent_r");
++ if (getfct.f != NULL)
++ while (1)
++ {
++ 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. */
++ break;
++ if (status == NSS_STATUS_SUCCESS)
++ {
++ if (data.type == triple_val)
++ {
++ const char *nhost = data.val.triple.host;
++ const char *nuser = data.val.triple.user;
++ const char *ndomain = data.val.triple.domain;
++
++ if (data.val.triple.host > data.val.triple.user
++ || data.val.triple.user > data.val.triple.domain)
++ {
++ const char *last = MAX (nhost,
++ MAX (nuser, ndomain));
++ size_t bufused = (last + strlen (last) + 1
++ - buffer);
++
++ /* We have to make temporary copies. */
++ size_t hostlen = strlen (nhost) + 1;
++ size_t userlen = strlen (nuser) + 1;
++ size_t domainlen = strlen (ndomain) + 1;
++ size_t needed = hostlen + userlen + domainlen;
++
++ if (buflen - req->key_len - bufused < needed)
++ {
++ size_t newsize = MAX (2 * buflen,
++ buflen + 2 * needed);
++ if (use_malloc || newsize > 1024 * 1024)
++ {
++ buflen = newsize;
++ char *newbuf = xrealloc (use_malloc
++ ? buffer
++ : NULL,
++ buflen);
++
++ buffer = newbuf;
++ use_malloc = true;
++ }
++ else
++ extend_alloca (buffer, buflen, newsize);
++ }
++
++ nhost = memcpy (buffer + bufused,
++ nhost, hostlen);
++ nuser = memcpy ((char *) nhost + hostlen,
++ nuser, userlen);
++ ndomain = memcpy ((char *) nuser + userlen,
++ ndomain, domainlen);
++ }
++
++ char *wp = buffer + buffilled;
++ wp = stpcpy (wp, nhost) + 1;
++ wp = stpcpy (wp, nuser) + 1;
++ wp = stpcpy (wp, ndomain) + 1;
++ buffilled = wp - buffer;
++ ++nentries;
++ }
++ else
++ {
++ /* Check that the group has not been
++ requested before. */
++ struct name_list *runp = data.needed_groups;
++ if (runp != NULL)
++ while (1)
++ {
++ if (strcmp (runp->name, data.val.group) == 0)
++ break;
++
++ runp = runp->next;
++ if (runp == data.needed_groups)
++ {
++ runp = NULL;
++ break;
++ }
++ }
++
++ if (runp == NULL)
++ {
++ runp = data.known_groups;
++ while (runp != NULL)
++ if (strcmp (runp->name, data.val.group) == 0)
++ break;
++ else
++ runp = runp->next;
++ }
++
++ if (runp == NULL)
++ {
++ /* A new group is requested. */
++ size_t namelen = strlen (data.val.group) + 1;
++ struct name_list *newg = alloca (sizeof (*newg)
++ + namelen);
++ memcpy (newg->name, data.val.group, namelen);
++ if (data.needed_groups == NULL)
++ data.needed_groups = newg->next = newg;
++ else
++ {
++ newg->next = data.needed_groups->next;
++ data.needed_groups->next = newg;
++ data.needed_groups = newg;
++ }
++ }
++ }
++ }
++ else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
++ {
++ size_t newsize = 2 * buflen;
++ if (use_malloc || newsize > 1024 * 1024)
++ {
++ buflen = newsize;
++ char *newbuf = xrealloc (use_malloc
++ ? buffer : NULL, buflen);
++
++ buffer = newbuf;
++ use_malloc = true;
++ }
++ else
++ extend_alloca (buffer, buflen, newsize);
++ }
++ }
++
++ enum nss_status (*endfct) (struct __netgrent *);
++ endfct = __nss_lookup_function (nip, "endnetgrent");
++ if (endfct != NULL)
++ (void) DL_CALL_FCT (*endfct, (&data));
++
++ break;
++ }
++
++ no_more = __nss_next2 (&nip, "setnetgrent", NULL, &setfct.ptr,
++ status, 0);
++ }
++ }
++
++ total = buffilled;
++
++ /* Fill in the dataset. */
++ dataset = (struct dataset *) buffer;
++ dataset->head.allocsize = total + req->key_len;
++ dataset->head.recsize = total - offsetof (struct dataset, resp);
++ dataset->head.notfound = false;
++ dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
++ dataset->head.usable = true;
++ dataset->head.ttl = db->postimeout;
++ timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
++
++ dataset->resp.version = NSCD_VERSION;
++ dataset->resp.found = 1;
++ dataset->resp.nresults = nentries;
++ dataset->resp.result_len = buffilled - sizeof (*dataset);
++
++ assert (buflen - buffilled >= req->key_len);
++ key_copy = memcpy (buffer + buffilled, key, req->key_len);
++ buffilled += req->key_len;
++
++ /* Now we can determine whether on refill we have to create a new
++ record or not. */
++ if (he != NULL)
++ {
++ assert (fd == -1);
++
++ if (dataset->head.allocsize == dh->allocsize
++ && dataset->head.recsize == dh->recsize
++ && memcmp (&dataset->resp, dh->data,
++ dh->allocsize - offsetof (struct dataset, resp)) == 0)
++ {
++ /* The data has not changed. We will just bump the timeout
++ value. Note that the new record has been allocated on
++ the stack and need not be freed. */
++ dh->timeout = dataset->head.timeout;
++ dh->ttl = dataset->head.ttl;
++ ++dh->nreloads;
++ dataset = (struct dataset *) dh;
++
++ goto out;
++ }
++ }
++
++ {
++ struct dataset *newp
++ = (struct dataset *) mempool_alloc (db, total + req->key_len, 1);
++ if (__builtin_expect (newp != NULL, 1))
++ {
++ /* Adjust pointer into the memory block. */
++ key_copy = (char *) newp + (key_copy - buffer);
++
++ dataset = memcpy (newp, dataset, total + req->key_len);
++ cacheable = true;
++
++ if (he != NULL)
++ /* Mark the old record as obsolete. */
++ dh->usable = false;
++ }
++ }
++
++ if (he == NULL && fd != -1)
++ {
++ /* We write the dataset before inserting it to the database
++ since while inserting this thread might block and so would
++ unnecessarily let the receiver wait. */
++ writeout:
++#ifdef HAVE_SENDFILE
++ if (__builtin_expect (db->mmap_used, 1) && cacheable)
++ {
++ assert (db->wr_fd != -1);
++ assert ((char *) &dataset->resp > (char *) db->data);
++ assert ((char *) dataset - (char *) db->head + total
++ <= (sizeof (struct database_pers_head)
++ + db->head->module * sizeof (ref_t)
++ + db->head->data_size));
++# ifndef __ASSUME_SENDFILE
++ ssize_t written =
++# endif
++ sendfileall (fd, db->wr_fd, (char *) &dataset->resp
++ - (char *) db->head, dataset->head.recsize);
++# ifndef __ASSUME_SENDFILE
++ if (written == -1 && errno == ENOSYS)
++ goto use_write;
++# endif
++ }
++ else
++#endif
++ {
++#if defined HAVE_SENDFILE && !defined __ASSUME_SENDFILE
++ use_write:
++#endif
++ writeall (fd, &dataset->resp, dataset->head.recsize);
++ }
++ }
++
++ if (cacheable)
++ {
++ /* If necessary, we also propagate the data to disk. */
++ if (db->persistent)
++ {
++ // XXX async OK?
++ uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
++ msync ((void *) pval,
++ ((uintptr_t) dataset & pagesize_m1) + total + req->key_len,
++ MS_ASYNC);
++ }
++
++ (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
++ true, db, uid, he == NULL);
++
++ pthread_rwlock_unlock (&db->lock);
++
++ /* Mark the old entry as obsolete. */
++ if (dh != NULL)
++ dh->usable = false;
++ }
++
++ out:
++ if (use_malloc)
++ free (buffer);
++
++ *resultp = dataset;
++
++ return timeout;
++}
++
++
++static time_t
++addinnetgrX (struct database_dyn *db, int fd, request_header *req,
++ char *key, uid_t uid, struct hashentry *he,
++ struct datahead *dh)
++{
++ const char *group = key;
++ key = (char *) rawmemchr (key, '\0') + 1;
++ size_t group_len = key - group - 1;
++ const char *host = *key++ ? key : NULL;
++ if (host != NULL)
++ key = (char *) rawmemchr (key, '\0') + 1;
++ const char *user = *key++ ? key : NULL;
++ if (user != NULL)
++ key = (char *) rawmemchr (key, '\0') + 1;
++ const char *domain = *key++ ? key : NULL;
++
++ if (__builtin_expect (debug_level > 0, 0))
++ {
++ if (he == NULL)
++ dbg_log (_("Haven't found \"%s (%s,%s,%s)\" in netgroup cache!"),
++ group, host ?: "", user ?: "", domain ?: "");
++ else
++ dbg_log (_("Reloading \"%s (%s,%s,%s)\" in netgroup cache!"),
++ group, host ?: "", user ?: "", domain ?: "");
++ }
++
++ struct dataset *result = (struct dataset *) cache_search (GETNETGRENT,
++ group, group_len,
++ db, uid);
++ time_t timeout;
++ if (result != NULL)
++ timeout = result->head.timeout;
++ else
++ {
++ request_header req_get =
++ {
++ .type = GETNETGRENT,
++ .key_len = group_len
++ };
++ timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
++ &result);
++ }
++
++ struct indataset
++ {
++ struct datahead head;
++ innetgroup_response_header resp;
++ } *dataset
++ = (struct indataset *) mempool_alloc (db,
++ sizeof (*dataset) + req->key_len,
++ 1);
++ struct indataset dataset_mem;
++ bool cacheable = true;
++ if (__builtin_expect (dataset == NULL, 0))
++ {
++ cacheable = false;
++ dataset = &dataset_mem;
++ }
++
++ dataset->head.allocsize = sizeof (*dataset) + req->key_len;
++ dataset->head.recsize = sizeof (innetgroup_response_header);
++ dataset->head.notfound = result->head.notfound;
++ dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
++ dataset->head.usable = true;
++ dataset->head.ttl = result->head.ttl;
++ dataset->head.timeout = timeout;
++
++ dataset->resp.version = NSCD_VERSION;
++ dataset->resp.found = result->resp.found;
++ /* Until we find a matching entry the result is 0. */
++ dataset->resp.result = 0;
++
++ char *key_copy = memcpy ((char *) (dataset + 1), group, req->key_len);
++
++ if (dataset->resp.found)
++ {
++ const char *triplets = (const char *) (&result->resp + 1);
++
++ for (nscd_ssize_t i = result->resp.nresults; i > 0; --i)
++ {
++ bool success = true;
++
++ if (host != NULL)
++ success = strcmp (host, triplets) == 0;
++ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
++
++ if (success && user != NULL)
++ success = strcmp (user, triplets) == 0;
++ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
++
++ if (success && (domain == NULL || strcmp (domain, triplets) == 0))
++ {
++ dataset->resp.result = 1;
++ break;
++ }
++ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
++ }
++ }
++
++ if (he != NULL && dh->data[0].innetgroupdata.result == dataset->resp.result)
++ {
++ /* The data has not changed. We will just bump the timeout
++ value. Note that the new record has been allocated on
++ the stack and need not be freed. */
++ dh->timeout = timeout;
++ dh->ttl = dataset->head.ttl;
++ ++dh->nreloads;
++ return timeout;
++ }
++
++ if (he == NULL)
++ {
++ /* We write the dataset before inserting it to the database
++ since while inserting this thread might block and so would
++ unnecessarily let the receiver wait. */
++ assert (fd != -1);
++
++#ifdef HAVE_SENDFILE
++ if (__builtin_expect (db->mmap_used, 1) && cacheable)
++ {
++ assert (db->wr_fd != -1);
++ assert ((char *) &dataset->resp > (char *) db->data);
++ assert ((char *) dataset - (char *) db->head + sizeof (*dataset)
++ <= (sizeof (struct database_pers_head)
++ + db->head->module * sizeof (ref_t)
++ + db->head->data_size));
++# ifndef __ASSUME_SENDFILE
++ ssize_t written =
++# endif
++ sendfileall (fd, db->wr_fd,
++ (char *) &dataset->resp - (char *) db->head,
++ sizeof (innetgroup_response_header));
++# ifndef __ASSUME_SENDFILE
++ if (written == -1 && errno == ENOSYS)
++ goto use_write;
++# endif
++ }
++ else
++# ifndef __ASSUME_SENDFILE
++ use_write:
++# endif
++#endif
++ writeall (fd, &dataset->resp, sizeof (innetgroup_response_header));
++ }
++
++ if (cacheable)
++ {
++ /* If necessary, we also propagate the data to disk. */
++ if (db->persistent)
++ {
++ // XXX async OK?
++ uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
++ msync ((void *) pval,
++ ((uintptr_t) dataset & pagesize_m1) + sizeof (*dataset)
++ + req->key_len,
++ MS_ASYNC);
++ }
++
++ (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
++ true, db, uid, he == NULL);
++
++ pthread_rwlock_unlock (&db->lock);
++
++ /* Mark the old entry as obsolete. */
++ if (dh != NULL)
++ dh->usable = false;
++ }
++
++ return timeout;
++}
++
++
++void
++addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
++ void *key, uid_t uid)
++{
++ struct dataset *ignore;
++
++ addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
++}
++
++
++time_t
++readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
++ struct datahead *dh)
++{
++ request_header req =
++ {
++ .type = GETNETGRENT,
++ .key_len = he->len
++ };
++ struct dataset *ignore;
++
++ return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
++ &ignore);
++}
++
++
++void
++addinnetgr (struct database_dyn *db, int fd, request_header *req,
++ void *key, uid_t uid)
++{
++ addinnetgrX (db, fd, req, key, uid, NULL, NULL);
++}
++
++
++time_t
++readdinnetgr (struct database_dyn *db, struct hashentry *he,
++ struct datahead *dh)
++{
++ request_header req =
++ {
++ .type = INNETGR,
++ .key_len = he->len
++ };
++
++ return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
++}
+diff -Nrup a/nscd/nscd-client.h b/nscd/nscd-client.h
+--- a/nscd/nscd-client.h 2012-08-06 15:07:49.082059915 -0600
++++ b/nscd/nscd-client.h 2012-08-06 15:08:19.090941456 -0600
+@@ -70,6 +70,9 @@ typedef enum
+ GETSERVBYNAME,
+ GETSERVBYPORT,
+ GETFDSERV,
++ GETNETGRENT,
++ INNETGR,
++ GETFDNETGR,
+ LASTREQ
+ } request_type;
+
+@@ -171,6 +174,24 @@ typedef struct
+ } serv_response_header;
+
+
++/* Structure send in reply to netgroup query. Note that this struct is
++ sent also if the service is disabled or there is no record found. */
++typedef struct
++{
++ int32_t version;
++ int32_t found;
++ nscd_ssize_t nresults;
++ nscd_ssize_t result_len;
++} netgroup_response_header;
++
++typedef struct
++{
++ int32_t version;
++ int32_t found;
++ int32_t result;
++} innetgroup_response_header;
++
++
+ /* Type for offsets in data part of database. */
+ typedef uint32_t ref_t;
+ /* Value for invalid/no reference. */
+@@ -210,6 +231,8 @@ struct datahead
+ ai_response_header aidata;
+ initgr_response_header initgrdata;
+ serv_response_header servdata;
++ netgroup_response_header netgroupdata;
++ innetgroup_response_header innetgroupdata;
+ nscd_ssize_t align1;
+ nscd_time_t align2;
+ } data[0];
+diff -Nrup a/nscd/nscd.conf b/nscd/nscd.conf
+--- a/nscd/nscd.conf 2012-08-06 15:07:48.553062002 -0600
++++ b/nscd/nscd.conf 2012-08-06 15:08:19.091941452 -0600
+@@ -77,3 +77,12 @@
+ persistent services yes
+ shared services yes
+ max-db-size services 33554432
++
++ enable-cache netgroup yes
++ positive-time-to-live netgroup 28800
++ negative-time-to-live netgroup 20
++ suggested-size netgroup 211
++ check-files netgroup yes
++ persistent netgroup yes
++ shared netgroup yes
++ max-db-size netgroup 33554432
+diff -Nrup a/nscd/nscd.h b/nscd/nscd.h
+--- a/nscd/nscd.h 2012-08-06 15:07:49.085059903 -0600
++++ b/nscd/nscd.h 2012-08-06 15:08:19.093941443 -0600
+@@ -38,6 +38,7 @@ typedef enum
+ grpdb,
+ hstdb,
+ servdb,
++ netgrdb,
+ lastdb
+ } dbtype;
+
+@@ -107,6 +108,7 @@ struct database_dyn
+ #define _PATH_NSCD_GROUP_DB "/var/db/nscd/group"
+ #define _PATH_NSCD_HOSTS_DB "/var/db/nscd/hosts"
+ #define _PATH_NSCD_SERVICES_DB "/var/db/nscd/services"
++#define _PATH_NSCD_NETGROUP_DB "/var/db/nscd/netgroup"
+
+ /* Path used when not using persistent storage. */
+ #define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
+@@ -140,6 +142,7 @@ extern const struct iovec pwd_iov_disabl
+ extern const struct iovec grp_iov_disabled;
+ extern const struct iovec hst_iov_disabled;
+ extern const struct iovec serv_iov_disabled;
++extern const struct iovec netgroup_iov_disabled;
+
+
+ /* Initial number of threads to run. */
+@@ -185,6 +188,11 @@ extern gid_t old_gid;
+
+ /* Prototypes for global functions. */
+
++/* Wrapper functions with error checking for standard functions. */
++extern void *xmalloc (size_t n);
++extern void *xcalloc (size_t n, size_t s);
++extern void *xrealloc (void *o, size_t n);
++
+ /* nscd.c */
+ extern void termination_handler (int signum) __attribute__ ((__noreturn__));
+ extern int nscd_open_socket (void);
+@@ -203,8 +211,8 @@ extern void send_stats (int fd, struct d
+ extern int receive_print_stats (void) __attribute__ ((__noreturn__));
+
+ /* cache.c */
+-extern struct datahead *cache_search (request_type, void *key, size_t len,
+- struct database_dyn *table,
++extern struct datahead *cache_search (request_type, const void *key,
++ size_t len, struct database_dyn *table,
+ uid_t owner);
+ extern int cache_add (int type, const void *key, size_t len,
+ struct datahead *packet, bool first,
+@@ -273,6 +281,16 @@ extern void addservbyport (struct databa
+ extern time_t readdservbyport (struct database_dyn *db, struct hashentry *he,
+ struct datahead *dh);
+
++/* netgroupcache.c */
++extern void addinnetgr (struct database_dyn *db, int fd, request_header *req,
++ void *key, uid_t uid);
++extern time_t readdinnetgr (struct database_dyn *db, struct hashentry *he,
++ struct datahead *dh);
++extern void addgetnetgrent (struct database_dyn *db, int fd,
++ request_header *req, void *key, uid_t uid);
++extern time_t readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
++ struct datahead *dh);
++
+ /* mem.c */
+ extern void *mempool_alloc (struct database_dyn *db, size_t len,
+ int data_alloc);
+diff -Nrup a/nscd/nscd_conf.c b/nscd/nscd_conf.c
+--- a/nscd/nscd_conf.c 2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/nscd_conf.c 2012-08-06 15:08:19.093941443 -0600
+@@ -43,7 +43,8 @@ const char *const dbnames[lastdb] =
+ [pwddb] = "passwd",
+ [grpdb] = "group",
+ [hstdb] = "hosts",
+- [servdb] = "services"
++ [servdb] = "services",
++ [netgrdb] = "netgroup"
+ };
+
+
+diff -Nrup a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
+--- a/nscd/nscd_netgroup.c 1969-12-31 17:00:00.000000000 -0700
++++ b/nscd/nscd_netgroup.c 2012-08-06 15:08:19.094941439 -0600
+@@ -0,0 +1,290 @@
++/* Copyright (C) 2011 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
++
++ 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <alloca.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <not-cancel.h>
++
++#include "nscd-client.h"
++#include "nscd_proto.h"
++
++int __nss_not_use_nscd_netgroup;
++
++
++libc_locked_map_ptr (static, map_handle);
++/* Note that we only free the structure if necessary. The memory
++ mapping is not removed since it is not visible to the malloc
++ handling. */
++libc_freeres_fn (pw_map_free)
++{
++ if (map_handle.mapped != NO_MAPPING)
++ {
++ void *p = map_handle.mapped;
++ map_handle.mapped = NO_MAPPING;
++ free (p);
++ }
++}
++
++
++int
++__nscd_setnetgrent (const char *group, struct __netgrent *datap)
++{
++ int gc_cycle;
++ int nretries = 0;
++ size_t group_len = strlen (group);
++
++ /* If the mapping is available, try to search there instead of
++ communicating with the nscd. */
++ struct mapped_database *mapped;
++ mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
++
++ retry:;
++ char *respdata = NULL;
++ int retval = -1;
++ netgroup_response_header netgroup_resp;
++
++ if (mapped != NO_MAPPING)
++ {
++ struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
++ group_len, mapped,
++ sizeof netgroup_resp);
++ if (found != NULL)
++ {
++ respdata = (char *) (&found->data[0].netgroupdata + 1);
++ netgroup_resp = found->data[0].netgroupdata;
++ /* Now check if we can trust pw_resp fields. If GC is
++ in progress, it can contain anything. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out;
++ }
++ }
++ }
++
++ int sock = -1;
++ if (respdata == NULL)
++ {
++ sock = __nscd_open_socket (group, group_len, GETNETGRENT,
++ &netgroup_resp, sizeof (netgroup_resp));
++ if (sock == -1)
++ {
++ /* nscd not running or wrong version. */
++ __nss_not_use_nscd_netgroup = 1;
++ goto out;
++ }
++ }
++
++ if (netgroup_resp.found == 1)
++ {
++ size_t datalen = netgroup_resp.result_len;
++
++ /* If we do not have to read the data here it comes from the
++ mapped data and does not have to be freed. */
++ if (respdata == NULL)
++ {
++ /* The data will come via the socket. */
++ respdata = malloc (datalen);
++ if (respdata == NULL)
++ goto out_close;
++
++ if ((size_t) __readall (sock, respdata, datalen) != datalen)
++ {
++ free (respdata);
++ goto out_close;
++ }
++ }
++
++ datap->data = respdata;
++ datap->data_size = datalen;
++ datap->cursor = respdata;
++ datap->first = 1;
++ datap->nip = (service_user *) -1l;
++ datap->known_groups = NULL;
++ datap->needed_groups = NULL;
++
++ retval = 1;
++ }
++ else
++ {
++ if (__builtin_expect (netgroup_resp.found == -1, 0))
++ {
++ /* The daemon does not cache this database. */
++ __nss_not_use_nscd_netgroup = 1;
++ goto out_close;
++ }
++
++ /* Set errno to 0 to indicate no error, just no found record. */
++ __set_errno (0);
++ /* Even though we have not found anything, the result is zero. */
++ retval = 0;
++ }
++
++ out_close:
++ if (sock != -1)
++ close_not_cancel_no_status (sock);
++ out:
++ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
++ {
++ /* When we come here this means there has been a GC cycle while we
++ were looking for the data. This means the data might have been
++ inconsistent. Retry if possible. */
++ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
++ {
++ /* nscd is just running gc now. Disable using the mapping. */
++ if (atomic_decrement_val (&mapped->counter) == 0)
++ __nscd_unmap (mapped);
++ mapped = NO_MAPPING;
++ }
++
++ if (retval != -1)
++ goto retry;
++ }
++
++ return retval;
++}
++
++
++int
++__nscd_innetgr (const char *netgroup, const char *host, const char *user,
++ const char *domain)
++{
++ size_t key_len = (strlen (netgroup) + strlen (host ?: "")
++ + strlen (user ?: "") + strlen (domain ?: "") + 7);
++ char *key;
++ bool use_alloca = __libc_use_alloca (key_len);
++ if (use_alloca)
++ key = alloca (key_len);
++ else
++ {
++ key = malloc (key_len);
++ if (key == NULL)
++ return -1;
++ }
++ char *wp = stpcpy (key, netgroup) + 1;
++ if (host != NULL)
++ {
++ *wp++ = '\1';
++ wp = stpcpy (wp, host) + 1;
++ }
++ else
++ *wp++ = '\0';
++ if (user != NULL)
++ {
++ *wp++ = '\1';
++ wp = stpcpy (wp, user) + 1;
++ }
++ else
++ *wp++ = '\0';
++ if (domain != NULL)
++ {
++ *wp++ = '\1';
++ wp = stpcpy (wp, domain) + 1;
++ }
++ else
++ *wp++ = '\0';
++ key_len = wp - key;
++
++ /* If the mapping is available, try to search there instead of
++ communicating with the nscd. */
++ int gc_cycle;
++ int nretries = 0;
++ struct mapped_database *mapped;
++ mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
++
++ retry:;
++ int retval = -1;
++ innetgroup_response_header innetgroup_resp;
++ int sock = -1;
++
++ if (mapped != NO_MAPPING)
++ {
++ struct datahead *found = __nscd_cache_search (INNETGR, key,
++ key_len, mapped,
++ sizeof innetgroup_resp);
++ if (found != NULL)
++ {
++ innetgroup_resp = found->data[0].innetgroupdata;
++ /* Now check if we can trust pw_resp fields. If GC is
++ in progress, it can contain anything. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out;
++ }
++
++ goto found_entry;
++ }
++ }
++
++ sock = __nscd_open_socket (key, key_len, INNETGR,
++ &innetgroup_resp, sizeof (innetgroup_resp));
++ if (sock == -1)
++ {
++ /* nscd not running or wrong version. */
++ __nss_not_use_nscd_netgroup = 1;
++ goto out;
++ }
++
++ found_entry:
++ if (innetgroup_resp.found == 1)
++ retval = innetgroup_resp.result;
++ else
++ {
++ if (__builtin_expect (innetgroup_resp.found == -1, 0))
++ {
++ /* The daemon does not cache this database. */
++ __nss_not_use_nscd_netgroup = 1;
++ goto out_close;
++ }
++
++ /* Set errno to 0 to indicate no error, just no found record. */
++ __set_errno (0);
++ /* Even though we have not found anything, the result is zero. */
++ retval = 0;
++ }
++
++ out_close:
++ if (sock != -1)
++ close_not_cancel_no_status (sock);
++ out:
++ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
++ {
++ /* When we come here this means there has been a GC cycle while we
++ were looking for the data. This means the data might have been
++ inconsistent. Retry if possible. */
++ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
++ {
++ /* nscd is just running gc now. Disable using the mapping. */
++ if (atomic_decrement_val (&mapped->counter) == 0)
++ __nscd_unmap (mapped);
++ mapped = NO_MAPPING;
++ }
++
++ if (retval != -1)
++ goto retry;
++ }
++
++ if (! use_alloca)
++ free (key);
++
++ return retval;
++}
+diff -Nrup a/nscd/nscd_proto.h b/nscd/nscd_proto.h
+--- a/nscd/nscd_proto.h 2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/nscd_proto.h 2012-08-06 15:14:24.446648305 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1998-2000, 2002, 2004, 2007 Free Software Foundation, Inc.
++/* Copyright (C) 1998-2000,2002,2004,2007,2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
+
+@@ -36,6 +36,7 @@ extern int __nss_not_use_nscd_passwd att
+ extern int __nss_not_use_nscd_group attribute_hidden;
+ extern int __nss_not_use_nscd_hosts attribute_hidden;
+ extern int __nss_not_use_nscd_services attribute_hidden;
++extern int __nss_not_use_nscd_netgroup attribute_hidden;
+
+ extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf,
+ char *buffer, size_t buflen,
+@@ -71,5 +72,9 @@ extern int __nscd_getservbyname_r (const
+ extern int __nscd_getservbyport_r (int port, const char *proto,
+ struct servent *result_buf, char *buf,
+ size_t buflen, struct servent **result);
++extern int __nscd_innetgr (const char *netgroup, const char *host,
++ const char *user, const char *domain);
++extern int __nscd_setnetgrent (const char *group, struct __netgrent *datap);
++
+
+ #endif /* _NSCD_PROTO_H */
+diff -Nrup a/nscd/selinux.c b/nscd/selinux.c
+--- a/nscd/selinux.c 2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/selinux.c 2012-08-06 15:08:19.096941431 -0600
+@@ -1,5 +1,5 @@
+ /* SELinux access controls for nscd.
+- Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
++ Copyright (C) 2004,2005,2006,2007,2009,2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
+
+@@ -46,7 +46,7 @@
+ int selinux_enabled;
+
+ /* Define mappings of access vector permissions to request types. */
+-static const int perms[LASTREQ] =
++static const access_vector_t perms[LASTREQ] =
+ {
+ [GETPWBYNAME] = NSCD__GETPWD,
+ [GETPWBYUID] = NSCD__GETPWD,
+@@ -69,6 +69,11 @@ static const int perms[LASTREQ] =
+ [GETSERVBYPORT] = NSCD__GETSERV,
+ [GETFDSERV] = NSCD__SHMEMSERV,
+ #endif
++#ifdef NSCD__GETNETGRP
++ [GETNETGRENT] = NSCD__GETNETGRP,
++ [INNETGR] = NSCD__GETNETGRP,
++ [GETFDNETGR] = NSCD__SHMEMNETGRP,
++#endif
+ };
+
+ /* Store an entry ref to speed AVC decisions. */
+diff -Nrup a/nss/Makefile b/nss/Makefile
+--- a/nss/Makefile 2012-08-06 15:07:48.938060482 -0600
++++ b/nss/Makefile 2012-08-23 14:19:49.382442094 -0600
+@@ -1,4 +1,5 @@
+-# Copyright (C) 1996-1998,2000-2002,2007,2009 Free Software Foundation, Inc.
++# Copyright (C) 1996-1998,2000-2002,2007,2009,2010
++# 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
+@@ -39,7 +40,7 @@ databases = proto service hosts network
+ others := getent
+ install-bin := getent
+
+-tests = test-netdb
++tests = test-netdb tst-nss-test1
+ xtests = bug-erange
+
+ include ../Makeconfig
+@@ -85,3 +86,14 @@ endif
+ # a statically-linked program that hasn't already loaded it.
+ $(services:%=$(objpfx)libnss_%.so): $(common-objpfx)libc.so \
+ $(common-objpfx)libc_nonshared.a
++
++
++distribute += nss_test1.c
++
++CFLAGS-nss_test1.c = -DNOT_IN_libc=1
++$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(common-objpfx)libc.so \
++ $(common-objpfx)libc_nonshared.a
++ $(build-module)
++$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so
++ $(make-link)
++$(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version)
+diff -Nrup a/nss/Versions b/nss/Versions
+--- a/nss/Versions 2012-08-06 15:07:48.939060479 -0600
++++ b/nss/Versions 2012-08-06 15:08:19.096941431 -0600
+@@ -12,7 +12,7 @@ libc {
+ __nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent;
+
+ __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2;
+- __nss_services_lookup2; __nss_next2;
++ __nss_services_lookup2; __nss_next2; __nss_lookup;
+ }
+ }
+
+diff -Nrup a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
+--- a/nss/getXXbyYY_r.c 2010-05-04 05:27:23.000000000 -0600
++++ b/nss/getXXbyYY_r.c 2012-08-23 14:19:49.403442011 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1996-2004, 2006, 2007, 2009 Free Software Foundation, Inc.
++/* Copyright (C) 1996-2004,2006,2007,2009,2010 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+@@ -87,6 +87,8 @@
+ # define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
+ # define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
+ # define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
++# define CONCAT2(arg1, arg2) CONCAT2_2 (arg1, arg2)
++# define CONCAT2_2(arg1, arg2) arg1##arg2
+ #endif
+
+ #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
+@@ -186,7 +188,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L
+ if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
+ NOT_USENSCD_NAME = 0;
+
+- if (!NOT_USENSCD_NAME)
++ if (!NOT_USENSCD_NAME
++ && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)])
+ {
+ nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
+ H_ERRNO_VAR);
+diff -Nrup a/nss/getent.c b/nss/getent.c
+--- a/nss/getent.c 2010-05-04 05:27:23.000000000 -0600
++++ b/nss/getent.c 2012-08-06 15:15:06.479427609 -0600
+@@ -466,7 +466,6 @@ static int
+ netgroup_keys (int number, char *key[])
+ {
+ int result = 0;
+- int i;
+
+ if (number == 0)
+ {
+@@ -474,18 +473,28 @@ netgroup_keys (int number, char *key[])
+ return 3;
+ }
+
+- for (i = 0; i < number; ++i)
++ if (number == 4)
+ {
+- if (!setnetgrent (key[i]))
++ char *host = strcmp (key[1], "*") == 0 ? NULL : key[1];
++ char *user = strcmp (key[2], "*") == 0 ? NULL : key[2];
++ char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3];
++
++ printf ("%-21s (%s,%s,%s) = %d\n",
++ key[0], host ?: "", user ?: "", domain ?: "",
++ innetgr (key[0], host, user, domain));
++ }
++ else if (number == 1)
++ {
++ if (!setnetgrent (key[0]))
+ result = 2;
+ else
+ {
+ char *p[3];
+
+- printf ("%-21s", key[i]);
++ printf ("%-21s", key[0]);
+
+ while (getnetgrent (p, p + 1, p + 2))
+- printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
++ printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
+ putchar_unlocked ('\n');
+ }
+ }
+diff -Nrup a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c
+--- a/nss/nss_files/files-parse.c 2010-05-04 05:27:23.000000000 -0600
++++ b/nss/nss_files/files-parse.c 2012-08-23 14:19:49.418441951 -0600
+@@ -1,5 +1,5 @@
+ /* Common code for file-based database parsers in nss_files module.
+- Copyright (C) 1996-2000, 2003, 2004, 2009 Free Software Foundation, Inc.
++ Copyright (C) 1996-2000,2003,2004,2009,2010 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
+@@ -29,7 +29,7 @@
+ DATABASE -- string of the database file's name ("hosts", "passwd").
+
+ ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store
+- things pointed to by the resultant `struct STRUCTURE'.
++ things pointed to by the resultant `struct STRUCTURE'.
+
+ NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+
+@@ -229,7 +229,7 @@ strtou32 (const char *nptr, char **endpt
+ char **list = parse_list (&line, buf_start, buf_end, '\0', errnop); \
+ if (list) \
+ result->TRAILING_LIST_MEMBER = list; \
+- else \
++ else \
+ return -1; /* -1 indicates we ran out of space. */ \
+ }
+
+diff -Nrup a/nss/nss_test1.c b/nss/nss_test1.c
+--- a/nss/nss_test1.c 1969-12-31 17:00:00.000000000 -0700
++++ b/nss/nss_test1.c 2012-08-23 14:19:49.418441951 -0600
+@@ -0,0 +1,154 @@
++#include <errno.h>
++#include <nss.h>
++#include <pthread.h>
++#include <string.h>
++
++
++#define COPY_IF_ROOM(s) \
++ ({ size_t len_ = strlen (s) + 1; \
++ char *start_ = cp; \
++ buflen - (cp - buffer) < len_ \
++ ? NULL \
++ : (cp = mempcpy (cp, s, len_), start_); })
++
++
++/* Password handling. */
++#include <pwd.h>
++
++static struct passwd pwd_data[] =
++ {
++#define PWD(u) \
++ { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u, \
++ .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*", \
++ .pw_shell = (char *) "*" }
++ PWD (100),
++ PWD (30),
++ PWD (200),
++ PWD (60),
++ PWD (20000)
++ };
++#define npwd_data (sizeof (pwd_data) / sizeof (pwd_data[0]))
++
++static size_t pwd_iter;
++#define CURPWD pwd_data[pwd_iter]
++
++static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER;
++
++
++enum nss_status
++_nss_test1_setpwent (int stayopen)
++{
++ pwd_iter = 0;
++ return NSS_STATUS_SUCCESS;
++}
++
++
++enum nss_status
++_nss_test1_endpwent (void)
++{
++ return NSS_STATUS_SUCCESS;
++}
++
++
++enum nss_status
++_nss_test1_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
++ int *errnop)
++{
++ char *cp = buffer;
++ int res = NSS_STATUS_SUCCESS;
++
++ pthread_mutex_lock (&pwd_lock);
++
++ if (pwd_iter >= npwd_data)
++ res = NSS_STATUS_NOTFOUND;
++ else
++ {
++ result->pw_name = COPY_IF_ROOM (CURPWD.pw_name);
++ result->pw_passwd = COPY_IF_ROOM (CURPWD.pw_passwd);
++ result->pw_uid = CURPWD.pw_uid;
++ result->pw_gid = CURPWD.pw_gid;
++ result->pw_gecos = COPY_IF_ROOM (CURPWD.pw_gecos);
++ result->pw_dir = COPY_IF_ROOM (CURPWD.pw_dir);
++ result->pw_shell = COPY_IF_ROOM (CURPWD.pw_shell);
++
++ if (result->pw_name == NULL || result->pw_passwd == NULL
++ || result->pw_gecos == NULL || result->pw_dir == NULL
++ || result->pw_shell == NULL)
++ {
++ *errnop = ERANGE;
++ res = NSS_STATUS_TRYAGAIN;
++ }
++
++ ++pwd_iter;
++ }
++
++ pthread_mutex_unlock (&pwd_lock);
++
++ return res;
++}
++
++
++enum nss_status
++_nss_test1_getpwuid_r (uid_t uid, struct passwd *result, char *buffer,
++ size_t buflen, int *errnop)
++{
++ for (size_t idx = 0; idx < npwd_data; ++idx)
++ if (pwd_data[idx].pw_uid == uid)
++ {
++ char *cp = buffer;
++ int res = NSS_STATUS_SUCCESS;
++
++ result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
++ result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
++ result->pw_uid = pwd_data[idx].pw_uid;
++ result->pw_gid = pwd_data[idx].pw_gid;
++ result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
++ result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
++ result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
++
++ if (result->pw_name == NULL || result->pw_passwd == NULL
++ || result->pw_gecos == NULL || result->pw_dir == NULL
++ || result->pw_shell == NULL)
++ {
++ *errnop = ERANGE;
++ res = NSS_STATUS_TRYAGAIN;
++ }
++
++ return res;
++ }
++
++ return NSS_STATUS_NOTFOUND;
++}
++
++
++enum nss_status
++_nss_test1_getpwnam_r (const char *name, struct passwd *result, char *buffer,
++ size_t buflen, int *errnop)
++{
++ for (size_t idx = 0; idx < npwd_data; ++idx)
++ if (strcmp (pwd_data[idx].pw_name, name) == 0)
++ {
++ char *cp = buffer;
++ int res = NSS_STATUS_SUCCESS;
++
++ result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
++ result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
++ result->pw_uid = pwd_data[idx].pw_uid;
++ result->pw_gid = pwd_data[idx].pw_gid;
++ result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
++ result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
++ result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
++
++ if (result->pw_name == NULL || result->pw_passwd == NULL
++ || result->pw_gecos == NULL || result->pw_dir == NULL
++ || result->pw_shell == NULL)
++ {
++ *errnop = ERANGE;
++ res = NSS_STATUS_TRYAGAIN;
++ }
++
++ return res;
++ }
++
++ return NSS_STATUS_NOTFOUND;
++}
+diff -Nrup a/nss/nsswitch.c b/nss/nsswitch.c
+--- a/nss/nsswitch.c 2010-05-04 05:27:23.000000000 -0600
++++ b/nss/nsswitch.c 2012-08-23 14:19:49.430441903 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1996-1999, 2001-2007, 2009 Free Software Foundation, Inc.
++/* Copyright (C) 1996-1999,2001-2007,2009,2010 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+@@ -71,6 +71,9 @@ static const struct
+ };
+ #define ndatabases (sizeof (databases) / sizeof (databases[0]))
+
++/* Flags whether custom rules for database is set. */
++bool __nss_database_custom[NSS_DBSIDX_max];
++
+
+ __libc_lock_define_initialized (static, lock)
+
+@@ -165,6 +168,7 @@ __nss_lookup (service_user **ni, const c
+
+ return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
+ }
++libc_hidden_def (__nss_lookup)
+
+
+ /* -1 == not found
+@@ -265,6 +269,7 @@ __nss_configure_lookup (const char *dbna
+
+ /* Install new rules. */
+ *databases[cnt].dbp = new_db;
++ __nss_database_custom[cnt] = true;
+
+ __libc_lock_unlock (lock);
+
+@@ -729,6 +734,7 @@ __nss_disable_nscd (void)
+ __nss_not_use_nscd_group = -1;
+ __nss_not_use_nscd_hosts = -1;
+ __nss_not_use_nscd_services = -1;
++ __nss_not_use_nscd_netgroup = -1;
+ }
+
+
+diff -Nrup a/nss/nsswitch.h b/nss/nsswitch.h
+--- a/nss/nsswitch.h 2010-05-04 05:27:23.000000000 -0600
++++ b/nss/nsswitch.h 2012-08-23 14:19:49.431441899 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007
++/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+@@ -28,6 +28,7 @@
+ #include <resolv.h>
+ #include <search.h>
+ #include <dlfcn.h>
++#include <stdbool.h>
+
+ /* Actions performed after lookup finished. */
+ typedef enum
+@@ -96,6 +97,19 @@ typedef struct name_database
+ } name_database;
+
+
++/* Indices into DATABASES in nsswitch.c and __NSS_DATABASE_CUSTOM. */
++enum
++ {
++#define DEFINE_DATABASE(arg) NSS_DBSIDX_##arg,
++#include "databases.def"
++#undef DEFINE_DATABASE
++ NSS_DBSIDX_max
++ };
++
++/* Flags whether custom rules for database is set. */
++extern bool __nss_database_custom[NSS_DBSIDX_max];
++
++
+ /* Interface functions for NSS. */
+
+ /* Get the data structure representing the specified database.
+@@ -111,7 +125,8 @@ libc_hidden_proto (__nss_database_lookup
+ position is remembered in NI. The function returns a value < 0 if
+ an error occurred or no such function exists. */
+ extern int __nss_lookup (service_user **ni, const char *fct_name,
+- const char *fct2_name, void **fctp) attribute_hidden;
++ const char *fct2_name, void **fctp);
++libc_hidden_proto (__nss_lookup)
+
+ /* Determine the next step in the lookup process according to the
+ result STATUS of the call to the last function returned by
+diff -Nrup a/nss/tst-nss-test1.c b/nss/tst-nss-test1.c
+--- a/nss/tst-nss-test1.c 1969-12-31 17:00:00.000000000 -0700
++++ b/nss/tst-nss-test1.c 2012-08-23 14:19:49.432441895 -0600
+@@ -0,0 +1,72 @@
++#include <nss.h>
++#include <pwd.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++
++static int
++do_test (void)
++{
++ int retval = 0;
++
++ __nss_configure_lookup ("passwd", "test1");
++
++ static const unsigned int pwdids[] = { 100, 30, 200, 60, 20000 };
++#define npwdids (sizeof (pwdids) / sizeof (pwdids[0]))
++ setpwent ();
++
++ const unsigned int *np = pwdids;
++ for (struct passwd *p = getpwent (); p != NULL; ++np, p = getpwent ())
++ if (p->pw_uid != *np || strncmp (p->pw_name, "name", 4) != 0
++ || atol (p->pw_name + 4) != *np)
++ {
++ printf ("passwd entry %ju wrong (%s, %u)\n",
++ np - pwdids, p->pw_name, p->pw_uid);
++ retval = 1;
++ break;
++ }
++
++ endpwent ();
++
++ for (int i = npwdids - 1; i >= 0; --i)
++ {
++ char buf[30];
++ snprintf (buf, sizeof (buf), "name%u", pwdids[i]);
++
++ struct passwd *p = getpwnam (buf);
++ if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
++ {
++ printf ("passwd entry \"%s\" wrong\n", buf);
++ retval = 1;
++ }
++
++ p = getpwuid (pwdids[i]);
++ if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
++ {
++ printf ("passwd entry %u wrong\n", pwdids[i]);
++ retval = 1;
++ }
++
++ snprintf (buf, sizeof (buf), "name%u", pwdids[i] + 1);
++
++ p = getpwnam (buf);
++ if (p != NULL)
++ {
++ printf ("passwd entry \"%s\" wrong\n", buf);
++ retval = 1;
++ }
++
++ p = getpwuid (pwdids[i] + 1);
++ if (p != NULL)
++ {
++ printf ("passwd entry %u wrong\n", pwdids[i] + 1);
++ retval = 1;
++ }
++ }
++
++ return retval;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+diff -Nrup a/shlib-versions b/shlib-versions
+--- a/shlib-versions 2010-05-04 05:27:23.000000000 -0600
++++ b/shlib-versions 2012-08-23 14:19:49.473441732 -0600
+@@ -114,6 +114,10 @@ alpha.*-.*-linux.* libresolv=2.1
+ .*-.*-.* libnss_ldap=2
+ .*-.*-.* libnss_hesiod=2
+
++# Tests for NSS. They must have the same NSS_SHLIB_REVISION number as
++# the rest.
++.*-.*-.* libnss_test1=2
++
+ # Version for libnsl with YP and NIS+ functions.
+ alpha.*-.*-linux.* libnsl=1.1
+ .*-.*-.* libnsl=1
+diff -Nrup a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+--- a/sysdeps/posix/getaddrinfo.c 2012-08-06 15:07:49.571057983 -0600
++++ b/sysdeps/posix/getaddrinfo.c 2012-08-23 14:19:49.541441461 -0600
+@@ -669,7 +669,8 @@ gaih_inet (const char *name, const struc
+ && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
+ __nss_not_use_nscd_hosts = 0;
+
+- if (!__nss_not_use_nscd_hosts)
++ if (!__nss_not_use_nscd_hosts
++ && !__nss_database_custom[NSS_DBSIDX_hosts])
+ {
+ /* Try to use nscd. */
+ struct nscd_ai_result *air = NULL;
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/csu/libc-start.c glibc-2.12-2-gc4ccff1.fixed/csu/libc-start.c
+--- glibc-2.12-2-gc4ccff1/csu/libc-start.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/csu/libc-start.c 2013-07-09 23:34:59.596859295 +0530
+@@ -33,7 +33,7 @@ extern int __libc_multiple_libcs;
+ #include <tls.h>
+ #ifndef SHARED
+ # include <dl-osinfo.h>
+-extern void __pthread_initialize_minimal (void);
++extern void __pthread_initialize_minimal (int, char **, char **);
+ # ifndef THREAD_SET_STACK_GUARD
+ /* Only exported for architectures that don't store the stack guard canary
+ in thread local area. */
+@@ -143,7 +143,7 @@ LIBC_START_MAIN (int (*main) (int, char
+ /* Initialize the thread library at least a bit since the libgcc
+ functions are using thread functions if these are available and
+ we need to setup errno. */
+- __pthread_initialize_minimal ();
++ __pthread_initialize_minimal (argc, argv, __environ);
+
+ /* Set up the stack checker's canary. */
+ uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
+diff -pruN glibc-2.12-2-gc4ccff1/csu/libc-tls.c glibc-2.12-2-gc4ccff1.fixed/csu/libc-tls.c
+--- glibc-2.12-2-gc4ccff1/csu/libc-tls.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/csu/libc-tls.c 2013-07-09 23:34:59.596859295 +0530
+@@ -244,7 +244,7 @@ _dl_tls_setup (void)
+ not used. */
+ void
+ __attribute__ ((weak))
+-__pthread_initialize_minimal (void)
++__pthread_initialize_minimal (int argc, char **argv, char **envp)
+ {
+ __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
+ }
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/Makefile glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile
+--- glibc-2.12-2-gc4ccff1/nptl/Makefile 2013-07-09 23:35:21.692858252 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile 2013-07-09 23:34:59.597859295 +0530
+@@ -197,7 +197,7 @@ CFLAGS-pt-system.c = -fexceptions
+
+
+ tests = tst-typesizes \
+- tst-attr1 tst-attr2 tst-attr3 \
++ tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
+ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
+ tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
+ tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
+@@ -279,6 +279,13 @@ LDFLAGS-pthread.so = -Wl,--enable-new-dt
+ LDFLAGS-tst-cond24 = -lrt
+ LDFLAGS-tst-cond25 = -lrt
+
++# The size is 1MB + 4KB. The extra 4KB has been added to prevent allocatestack
++# from resizing the input size to avoid the 64K aliasing conflict on Intel
++# processors.
++DEFAULT_STACKSIZE=1052672
++CFLAGS-tst-default-attr.c = -DDEFAULT_STACKSIZE=$(DEFAULT_STACKSIZE)
++tst-default-attr-ENV = GLIBC_PTHREAD_STACKSIZE=$(DEFAULT_STACKSIZE)
++
+ include ../Makeconfig
+
+ ifeq ($(have-forced-unwind),yes)
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/nptl-init.c glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c
+--- glibc-2.12-2-gc4ccff1/nptl/nptl-init.c 2013-07-09 23:35:21.723858250 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c 2013-07-09 23:36:35.070854789 +0530
+@@ -36,6 +36,7 @@
+ #include <smp.h>
+ #include <lowlevellock.h>
+ #include <kernel-features.h>
++#include <libc-internal.h>
+
+
+ /* Size and alignment of static TLS block. */
+@@ -288,8 +289,28 @@ extern void **__libc_dl_error_tsd (void)
+ /* This can be set by the debugger before initialization is complete. */
+ static bool __nptl_initial_report_events __attribute_used__;
+
++/* Validate and set the default stacksize. */
++static void
++set_default_stacksize (size_t stacksize)
++{
++ if (stacksize < PTHREAD_STACK_MIN)
++ stacksize = PTHREAD_STACK_MIN;
++
++ /* Make sure it meets the minimum size that allocate_stack
++ (allocatestack.c) will demand, which depends on the page size. */
++ const uintptr_t pagesz = GLRO(dl_pagesize);
++ const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
++
++ if (stacksize < minstack)
++ stacksize = minstack;
++
++ /* Round the resource limit up to page size. */
++ stacksize = ALIGN_UP (stacksize, pagesz);
++ __default_pthread_attr.stacksize = stacksize;
++}
++
+ void
+-__pthread_initialize_minimal_internal (void)
++__pthread_initialize_minimal_internal (int argc, char **argv, char **envp)
+ {
+ #ifndef SHARED
+ /* Unlike in the dynamically linked case the dynamic linker has not
+@@ -413,29 +434,44 @@ __pthread_initialize_minimal_internal (v
+
+ __static_tls_size = roundup (__static_tls_size, static_tls_align);
+
+- /* Determine the default allowed stack size. This is the size used
+- in case the user does not specify one. */
+- struct rlimit limit;
+- if (getrlimit (RLIMIT_STACK, &limit) != 0
+- || limit.rlim_cur == RLIM_INFINITY)
+- /* The system limit is not usable. Use an architecture-specific
+- default. */
+- limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
+- else if (limit.rlim_cur < PTHREAD_STACK_MIN)
+- /* The system limit is unusably small.
+- Use the minimal size acceptable. */
+- limit.rlim_cur = PTHREAD_STACK_MIN;
++ /* Initialize the environment. libc.so gets initialized after us due to a
++ circular dependency and hence __environ is not available otherwise. */
++ __environ = envp;
+
+- /* Make sure it meets the minimum size that allocate_stack
+- (allocatestack.c) will demand, which depends on the page size. */
+- const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
+- const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
+- if (limit.rlim_cur < minstack)
+- limit.rlim_cur = minstack;
++#ifndef SHARED
++ __libc_init_secure ();
++#endif
+
+- /* Round the resource limit up to page size. */
+- limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz;
+- __default_pthread_attr.stacksize = limit.rlim_cur;
++ /* Get the default stack size from the environment variable if it is set and
++ is valid. */
++ size_t stacksize = 0;
++ char *envval = __secure_getenv ("GLIBC_PTHREAD_STACKSIZE");
++
++ if (__builtin_expect (envval != NULL && envval[0] != '\0', 0))
++ {
++ char *env_conv = envval;
++ size_t ret = strtoul (envval, &env_conv, 0);
++
++ if (*env_conv == '\0' && env_conv != envval)
++ stacksize = ret;
++ }
++
++ if (stacksize == 0)
++ {
++ /* Determine the default allowed stack size. */
++ struct rlimit limit;
++ if (getrlimit (RLIMIT_STACK, &limit) != 0
++ || limit.rlim_cur == RLIM_INFINITY)
++ /* The system limit is not usable. Use an architecture-specific
++ default. */
++ stacksize = ARCH_STACK_DEFAULT_SIZE;
++ else
++ stacksize = limit.rlim_cur;
++ }
++
++ /* Finally, set the default stack size. This size is used when the user does
++ not specify a stack size during thread creation. */
++ set_default_stacksize (stacksize);
+ __default_pthread_attr.guardsize = GLRO (dl_pagesize);
+
+ #ifdef SHARED
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-default-attr.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-default-attr.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-default-attr.c 1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-default-attr.c 2013-07-09 23:34:59.598859295 +0530
+@@ -0,0 +1,109 @@
++/* Verify that default stack size gets set correctly from the environment
++ variable.
++
++ Copyright (C) 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++#include <errno.h>
++
++#define RETURN_IF_FAIL(f, ...) \
++ ({ \
++ int ret = f (__VA_ARGS__); \
++ if (ret != 0) \
++ { \
++ printf ("%s:%d: %s returned %d (errno = %d)\n", __FILE__, __LINE__, \
++ #f, ret, errno); \
++ return ret; \
++ } \
++ })
++
++/* DEFAULT_STACKSIZE macro is defined in the Makefile. */
++static size_t stacksize = DEFAULT_STACKSIZE;
++
++static int
++verify_stacksize_result (pthread_attr_t *attr)
++{
++ size_t stack;
++
++ RETURN_IF_FAIL (pthread_attr_getstacksize, attr, &stack);
++
++ if (stacksize != stack)
++ {
++ printf ("failed to set default stacksize (%zu, %zu)\n", stacksize, stack);
++ return 1;
++ }
++
++ return 0;
++}
++
++static void *
++thr (void *unused __attribute__ ((unused)))
++{
++ pthread_attr_t attr;
++ int ret;
++
++ memset (&attr, 0xab, sizeof attr);
++ /* To verify that the attributes actually got applied. */
++ if ((ret = pthread_getattr_np (pthread_self (), &attr)) != 0)
++ {
++ printf ("pthread_getattr_np failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ ret = verify_stacksize_result (&attr);
++
++out:
++ return (void *) (uintptr_t) ret;
++}
++
++static int
++run_threads (void)
++{
++ pthread_t t;
++ void *tret = NULL;
++
++ /* Run twice to ensure that the attributes do not get overwritten in the
++ first run somehow. */
++ for (int i = 0; i < 2; i++)
++ {
++ RETURN_IF_FAIL (pthread_create, &t, NULL, thr, NULL);
++ RETURN_IF_FAIL (pthread_join, t, &tret);
++
++ if (tret != NULL)
++ {
++ puts ("Thread failed");
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++static int
++do_test (void)
++{
++ RETURN_IF_FAIL (run_threads);
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/pt-initfini.c glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/pthread/pt-initfini.c
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/pt-initfini.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/pthread/pt-initfini.c 2013-07-22 21:52:03.519184065 +0530
+@@ -63,21 +63,21 @@ asm ("\n/*@TESTS_END*/");
+ asm ("\n/*@_init_PROLOG_BEGINS*/");
+
+ static void
+-call_initialize_minimal (void)
++call_initialize_minimal (int argc, char **argv, char **envp)
+ {
+- extern void __pthread_initialize_minimal_internal (void)
++ extern void __pthread_initialize_minimal_internal (int, char **, char **)
+ __attribute ((visibility ("hidden")));
+
+- __pthread_initialize_minimal_internal ();
++ __pthread_initialize_minimal_internal (argc, argv, envp);
+ }
+
+ SECTION (".init");
+-extern void __attribute__ ((section (".init"))) _init (void);
++extern void __attribute__ ((section (".init"))) _init (int, char **, char **);
+ void
+-_init (void)
++_init (int argc, char **argv, char **envp)
+ {
+ /* The very first thing we must do is to set up the registers. */
+- call_initialize_minimal ();
++ call_initialize_minimal (argc, argv, envp);
+
+ asm ("ALIGN");
+ asm("END_INIT");
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/include/libc-internal.h glibc-2.12-2-gc4ccff1.fixed/include/libc-internal.h
+--- glibc-2.12-2-gc4ccff1/include/libc-internal.h 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/include/libc-internal.h 2013-07-09 23:44:00.272833779 +0530
+@@ -34,4 +34,24 @@ extern void __libc_thread_freeres (void)
+ /* Define and initialize `__progname' et. al. */
+ extern void __init_misc (int, char **, char **);
+
++/* Align a value by rounding down to closest size.
++ e.g. Using size of 4096, we get this behavior:
++ {4095, 4096, 4097} = {0, 4096, 4096}. */
++#define ALIGN_DOWN(base, size) ((base) & -((__typeof__ (base)) (size)))
++
++/* Align a value by rounding up to closest size.
++ e.g. Using size of 4096, we get this behavior:
++ {4095, 4096, 4097} = {4096, 4096, 8192}.
++
++ Note: The size argument has side effects (expanded multiple times). */
++#define ALIGN_UP(base, size) ALIGN_DOWN ((base) + (size) - 1, (size))
++
++/* Same as ALIGN_DOWN(), but automatically casts when base is a pointer. */
++#define PTR_ALIGN_DOWN(base, size) \
++ ((__typeof__ (base)) ALIGN_DOWN ((uintptr_t) (base), (size)))
++
++/* Same as ALIGN_UP(), but automatically casts when base is a pointer. */
++#define PTR_ALIGN_UP(base, size) \
++ ((__typeof__ (base)) ALIGN_UP ((uintptr_t) (base), (size)))
++
+ #endif /* _LIBC_INTERNAL */
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/allocatestack.c glibc-2.12-2-gc4ccff1.fixed/nptl/allocatestack.c
+--- glibc-2.12-2-gc4ccff1/nptl/allocatestack.c 2013-07-09 23:43:09.427836179 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/allocatestack.c 2013-07-09 23:43:52.727834136 +0530
+@@ -351,7 +351,7 @@ allocate_stack (const struct pthread_att
+
+ /* Get the stack size from the attribute if it is set. Otherwise we
+ use the default we determined at start time. */
+- size = attr->stacksize ?: __default_stacksize;
++ size = attr->stacksize ?: __default_pthread_attr.stacksize;
+
+ /* Get memory for the stack. */
+ if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/nptl-init.c glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c
+--- glibc-2.12-2-gc4ccff1/nptl/nptl-init.c 2013-07-09 23:43:09.553836173 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c 2013-07-09 23:43:52.728834135 +0530
+@@ -435,7 +435,8 @@ __pthread_initialize_minimal_internal (v
+
+ /* Round the resource limit up to page size. */
+ limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz;
+- __default_stacksize = limit.rlim_cur;
++ __default_pthread_attr.stacksize = limit.rlim_cur;
++ __default_pthread_attr.guardsize = GLRO (dl_pagesize);
+
+ #ifdef SHARED
+ /* Transfer the old value from the dynamic linker's internal location. */
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_attr_getstacksize.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_attr_getstacksize.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_attr_getstacksize.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_attr_getstacksize.c 2013-07-09 23:43:52.817834131 +0530
+@@ -33,7 +33,7 @@ __pthread_attr_getstacksize (attr, stack
+
+ /* If the user has not set a stack size we return what the system
+ will use as the default. */
+- *stacksize = iattr->stacksize ?: __default_stacksize;
++ *stacksize = iattr->stacksize ?: __default_pthread_attr.stacksize;
+
+ return 0;
+ }
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_barrier_init.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_barrier_init.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_barrier_init.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_barrier_init.c 2013-07-09 23:43:52.821834131 +0530
+@@ -23,7 +23,7 @@
+ #include <kernel-features.h>
+
+
+-static const struct pthread_barrierattr default_attr =
++static const struct pthread_barrierattr default_barrierattr =
+ {
+ .pshared = PTHREAD_PROCESS_PRIVATE
+ };
+@@ -43,7 +43,7 @@ pthread_barrier_init (barrier, attr, cou
+ const struct pthread_barrierattr *iattr
+ = (attr != NULL
+ ? iattr = (struct pthread_barrierattr *) attr
+- : &default_attr);
++ : &default_barrierattr);
+
+ if (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+ && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0))
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_create.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_create.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_create.c 2013-07-09 23:43:09.542836173 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_create.c 2013-07-09 23:43:52.822834131 +0530
+@@ -425,15 +425,6 @@ start_thread (void *arg)
+ }
+
+
+-/* Default thread attributes for the case when the user does not
+- provide any. */
+-static const struct pthread_attr default_attr =
+- {
+- /* Just some value > 0 which gets rounded to the nearest page size. */
+- .guardsize = 1,
+- };
+-
+-
+ int
+ __pthread_create_2_1 (newthread, attr, start_routine, arg)
+ pthread_t *newthread;
+@@ -447,7 +438,7 @@ __pthread_create_2_1 (newthread, attr, s
+ if (iattr == NULL)
+ /* Is this the best idea? On NUMA machines this could mean
+ accessing far-away memory. */
+- iattr = &default_attr;
++ iattr = &__default_pthread_attr;
+
+ struct pthread *pd = NULL;
+ int err = ALLOCATE_STACK (iattr, &pd);
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_mutex_init.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_mutex_init.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_mutex_init.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_mutex_init.c 2013-07-09 23:43:52.822834131 +0530
+@@ -24,7 +24,7 @@
+ #include <kernel-features.h>
+ #include "pthreadP.h"
+
+-static const struct pthread_mutexattr default_attr =
++static const struct pthread_mutexattr default_mutexattr =
+ {
+ /* Default is a normal mutex, not shared between processes. */
+ .mutexkind = PTHREAD_MUTEX_NORMAL
+@@ -45,7 +45,8 @@ __pthread_mutex_init (mutex, mutexattr)
+
+ assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T);
+
+- imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
++ imutexattr = ((const struct pthread_mutexattr *) mutexattr
++ ?: &default_mutexattr);
+
+ /* Sanity checks. */
+ switch (__builtin_expect (imutexattr->mutexkind
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthreadP.h glibc-2.12-2-gc4ccff1.fixed/nptl/pthreadP.h
+--- glibc-2.12-2-gc4ccff1/nptl/pthreadP.h 2013-07-09 23:43:09.553836173 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthreadP.h 2013-07-09 23:43:52.823834131 +0530
+@@ -148,8 +148,8 @@ enum
+ /* Internal variables. */
+
+
+-/* Default stack size. */
+-extern size_t __default_stacksize attribute_hidden;
++/* Default pthread attributes. */
++extern struct pthread_attr __default_pthread_attr attribute_hidden;
+
+ /* Size and alignment of static TLS block. */
+ extern size_t __static_tls_size attribute_hidden;
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_rwlock_init.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_rwlock_init.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_rwlock_init.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_rwlock_init.c 2013-07-09 23:43:52.823834131 +0530
+@@ -21,7 +21,7 @@
+ #include <kernel-features.h>
+
+
+-static const struct pthread_rwlockattr default_attr =
++static const struct pthread_rwlockattr default_rwlockattr =
+ {
+ .lockkind = PTHREAD_RWLOCK_DEFAULT_NP,
+ .pshared = PTHREAD_PROCESS_PRIVATE
+@@ -35,7 +35,7 @@ __pthread_rwlock_init (rwlock, attr)
+ {
+ const struct pthread_rwlockattr *iattr;
+
+- iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr;
++ iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_rwlockattr;
+
+ memset (rwlock, '\0', sizeof (*rwlock));
+
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/vars.c glibc-2.12-2-gc4ccff1.fixed/nptl/vars.c
+--- glibc-2.12-2-gc4ccff1/nptl/vars.c 2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/vars.c 2013-07-09 23:43:52.824834131 +0530
+@@ -21,13 +21,9 @@
+ #include <tls.h>
+ #include <unistd.h>
+
+-/* Default stack size. */
+-size_t __default_stacksize attribute_hidden
+-#ifdef SHARED
+-;
+-#else
+- = PTHREAD_STACK_MIN;
+-#endif
++/* Default thread attributes for the case when the user does not
++ provide any. */
++struct pthread_attr __default_pthread_attr attribute_hidden;
+
+ /* Flag whether the machine is SMP or not. */
+ int __is_smp attribute_hidden;
-diff -rcp a/nscd/grpcache.c b/nscd/grpcache.c
-*** a/nscd/grpcache.c Wed Apr 11 12:50:07 2012
---- b/nscd/grpcache.c Wed Apr 11 21:45:58 2012
-*************** cache_addgr (struct database_dyn *db, in
-*** 178,184 ****
- char *cp;
- const size_t key_len = strlen (key);
- const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
-! char *buf = alloca (buf_len);
- ssize_t n;
- size_t cnt;
-
---- 178,185 ----
- char *cp;
- const size_t key_len = strlen (key);
- const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
-! size_t alloca_used = 0;
-! char *buf = alloca_account (buf_len, alloca_used);
- ssize_t n;
- size_t cnt;
-
-*************** cache_addgr (struct database_dyn *db, in
-*** 190,196 ****
- /* Determine the length of all members. */
- while (grp->gr_mem[gr_mem_cnt])
- ++gr_mem_cnt;
-! gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
- for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
- {
- gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
---- 191,198 ----
- /* Determine the length of all members. */
- while (grp->gr_mem[gr_mem_cnt])
- ++gr_mem_cnt;
-! gr_mem_len = (uint32_t *) alloca_account (gr_mem_cnt * sizeof (uint32_t),
-! alloca_used);
- for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
- {
- gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
-*************** cache_addgr (struct database_dyn *db, in
-*** 205,214 ****
- change. Allocate memory on the cache since it is likely
- discarded anyway. If it turns out to be necessary to have a
- new record we can still allocate real memory. */
-! bool alloca_used = false;
- dataset = NULL;
-
-! if (he == NULL)
- dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
-
- if (dataset == NULL)
---- 207,216 ----
- change. Allocate memory on the cache since it is likely
- discarded anyway. If it turns out to be necessary to have a
- new record we can still allocate real memory. */
-! bool dataset_in_stack_or_freed = false;
- dataset = NULL;
-
-! if (he == NULL || ! __libc_use_alloca (alloca_used + total + n))
- dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
-
- if (dataset == NULL)
-*************** cache_addgr (struct database_dyn *db, in
-*** 216,225 ****
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
-! dataset = (struct dataset *) alloca (total + n);
-
- /* We cannot add this record to the permanent database. */
-! alloca_used = true;
- }
-
- dataset->head.allocsize = total + n;
---- 218,227 ----
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
-! dataset = (struct dataset *) alloca_account (total + n, alloca_used);
-
- /* We cannot add this record to the permanent database. */
-! dataset_in_stack_or_freed = true;
- }
-
- dataset->head.allocsize = total + n;
-*************** cache_addgr (struct database_dyn *db, in
-*** 273,278 ****
---- 275,288 ----
- allocated on the stack and need not be freed. */
- dh->timeout = dataset->head.timeout;
- ++dh->nreloads;
-+
-+ /* If the new record was not allocated on the stack, then it must
-+ be freed. Note that it can no longer be used. */
-+ if (! dataset_in_stack_or_freed)
-+ {
-+ free (dataset);
-+ dataset_in_stack_or_freed = true;
-+ }
- }
- else
- {
-*************** cache_addgr (struct database_dyn *db, in
-*** 288,294 ****
- key_copy = (char *) newp + (key_copy - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + n);
-! alloca_used = false;
- }
-
- /* Mark the old record as obsolete. */
---- 298,304 ----
- key_copy = (char *) newp + (key_copy - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + n);
-! dataset_in_stack_or_freed = false;
- }
-
- /* Mark the old record as obsolete. */
-*************** cache_addgr (struct database_dyn *db, in
-*** 303,309 ****
- assert (fd != -1);
-
- #ifdef HAVE_SENDFILE
-! if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
---- 313,319 ----
- assert (fd != -1);
-
- #ifdef HAVE_SENDFILE
-! if (__builtin_expect (db->mmap_used, 1) && !dataset_in_stack_or_freed)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
-*************** cache_addgr (struct database_dyn *db, in
-*** 330,336 ****
-
- /* Add the record to the database. But only if it has not been
- stored on the stack. */
-! if (! alloca_used)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
---- 340,346 ----
-
- /* Add the record to the database. But only if it has not been
- stored on the stack. */
-! if (! dataset_in_stack_or_freed)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
+Index: glibc-2.12-2-gc4ccff1/nscd/grpcache.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nscd/grpcache.c
++++ glibc-2.12-2-gc4ccff1/nscd/grpcache.c
+@@ -178,7 +178,8 @@ cache_addgr (struct database_dyn *db, in
+ char *cp;
+ const size_t key_len = strlen (key);
+ const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
+- char *buf = alloca (buf_len);
++ size_t alloca_used = 0;
++ char *buf = alloca_account (buf_len, alloca_used);
+ ssize_t n;
+ size_t cnt;
+
+@@ -190,7 +191,8 @@ cache_addgr (struct database_dyn *db, in
+ /* Determine the length of all members. */
+ while (grp->gr_mem[gr_mem_cnt])
+ ++gr_mem_cnt;
+- gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
++ gr_mem_len = (uint32_t *) alloca_account (gr_mem_cnt * sizeof (uint32_t),
++ alloca_used);
+ for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
+ {
+ gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
+@@ -205,10 +207,10 @@ cache_addgr (struct database_dyn *db, in
+ change. Allocate memory on the cache since it is likely
+ discarded anyway. If it turns out to be necessary to have a
+ new record we can still allocate real memory. */
+- bool alloca_used = false;
++ bool dataset_in_stack_or_freed = false;
+ dataset = NULL;
+
+- if (he == NULL)
++ if (he == NULL || ! __libc_use_alloca (alloca_used + total + n))
+ dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
+
+ if (dataset == NULL)
+@@ -216,10 +218,10 @@ cache_addgr (struct database_dyn *db, in
+ /* We cannot permanently add the result in the moment. But
+ we can provide the result as is. Store the data in some
+ temporary memory. */
+- dataset = (struct dataset *) alloca (total + n);
++ dataset = (struct dataset *) alloca_account (total + n, alloca_used);
+
+ /* We cannot add this record to the permanent database. */
+- alloca_used = true;
++ dataset_in_stack_or_freed = true;
+ }
+
+ dataset->head.allocsize = total + n;
+@@ -273,6 +275,14 @@ cache_addgr (struct database_dyn *db, in
+ allocated on the stack and need not be freed. */
+ dh->timeout = dataset->head.timeout;
+ ++dh->nreloads;
++
++ /* If the new record was not allocated on the stack, then it must
++ be freed. Note that it can no longer be used. */
++ if (! dataset_in_stack_or_freed)
++ {
++ free (dataset);
++ dataset_in_stack_or_freed = true;
++ }
+ }
+ else
+ {
+@@ -288,7 +298,7 @@ cache_addgr (struct database_dyn *db, in
+ key_copy = (char *) newp + (key_copy - (char *) dataset);
+
+ dataset = memcpy (newp, dataset, total + n);
+- alloca_used = false;
++ dataset_in_stack_or_freed = false;
+ }
+
+ /* Mark the old record as obsolete. */
+@@ -303,7 +313,7 @@ cache_addgr (struct database_dyn *db, in
+ assert (fd != -1);
+
+ #ifdef HAVE_SENDFILE
+- if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
++ if (__builtin_expect (db->mmap_used, 1) && !dataset_in_stack_or_freed)
+ {
+ assert (db->wr_fd != -1);
+ assert ((char *) &dataset->resp > (char *) db->data);
+@@ -330,7 +340,7 @@ cache_addgr (struct database_dyn *db, in
+
+ /* Add the record to the database. But only if it has not been
+ stored on the stack. */
+- if (! alloca_used)
++ if (! dataset_in_stack_or_freed)
+ {
+ /* If necessary, we also propagate the data to disk. */
+ if (db->persistent)
--- /dev/null
+commit 16b293a7a6f65d8ff348a603d19e8fd4372fa3a9
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Wed Apr 30 11:48:43 2014 +0530
+
+ Do not fail if one of the two responses to AF_UNSPEC fails (BZ #14308)
+
+ [Fixes BZ #14308, #12994, #13651]
+
+ AF_UNSPEC results in sending two queries in parallel, one for the A
+ record and the other for the AAAA record. If one of these is a
+ referral, then the query fails, which is wrong. It should return at
+ least the one successful response.
+
+ The fix has two parts. The first part makes the referral fall back to
+ the SERVFAIL path, which results in using the successful response.
+ There is a bug in that path however, due to which the second part is
+ necessary. The bug here is that if the first response is a failure
+ and the second succeeds, __libc_res_nsearch does not detect that and
+ assumes a failure. The case where the first response is a success and
+ the second fails, works correctly.
+
+ This condition is produced by buggy routers, so here's a crude
+ interposable library that can simulate such a condition. The library
+ overrides the recvfrom syscall and modifies the header of the packet
+ received to reproduce this scenario. It has two key variables:
+ mod_packet and first_error.
+
+ The mod_packet variable when set to 0, results in odd packets being
+ modified to be a referral. When set to 1, even packets are modified
+ to be a referral.
+
+ The first_error causes the first response to be a failure so that a
+ domain-appended search is performed to test the second part of the
+ __libc_nsearch fix.
+
+ The driver for this fix is a simple getaddrinfo program that does an
+ AF_UNSPEC query. I have omitted this since it should be easy to
+ implement.
+
+ I have tested this on x86_64.
+
+ The interceptor library source:
+
+ /* Override recvfrom and modify the header of the first DNS response to make it
+ a referral and reproduce bz #845218. We have to resort to this ugly hack
+ because we cannot make bind return the buggy response of a referral for the
+ AAAA record and an authoritative response for the A record. */
+ #define _GNU_SOURCE
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <stdio.h>
+ #include <stdbool.h>
+ #include <endian.h>
+ #include <dlfcn.h>
+ #include <stdlib.h>
+
+ /* Lifted from resolv/arpa/nameser_compat.h. */
+ typedef struct {
+ unsigned id :16; /*%< query identification number */
+ #if BYTE_ORDER == BIG_ENDIAN
+ /* fields in third byte */
+ unsigned qr: 1; /*%< response flag */
+ unsigned opcode: 4; /*%< purpose of message */
+ unsigned aa: 1; /*%< authoritive answer */
+ unsigned tc: 1; /*%< truncated message */
+ unsigned rd: 1; /*%< recursion desired */
+ /* fields
+ * in
+ * fourth
+ * byte
+ * */
+ unsigned ra: 1; /*%< recursion available */
+ unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */
+ unsigned ad: 1; /*%< authentic data from named */
+ unsigned cd: 1; /*%< checking disabled by resolver */
+ unsigned rcode :4; /*%< response code */
+ #endif
+ #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+ /* fields
+ * in
+ * third
+ * byte
+ * */
+ unsigned rd :1; /*%< recursion desired */
+ unsigned tc :1; /*%< truncated message */
+ unsigned aa :1; /*%< authoritive answer */
+ unsigned opcode :4; /*%< purpose of message */
+ unsigned qr :1; /*%< response flag */
+ /* fields
+ * in
+ * fourth
+ * byte
+ * */
+ unsigned rcode :4; /*%< response code */
+ unsigned cd: 1; /*%< checking disabled by resolver */
+ unsigned ad: 1; /*%< authentic data from named */
+ unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */
+ unsigned ra :1; /*%< recursion available */
+ #endif
+ /* remaining
+ * bytes
+ * */
+ unsigned qdcount :16; /*%< number of question entries */
+ unsigned ancount :16; /*%< number of answer entries */
+ unsigned nscount :16; /*%< number of authority entries */
+ unsigned arcount :16; /*%< number of resource entries */
+ } HEADER;
+
+ static int done = 0;
+
+ /* Packets to modify. 0 for the odd packets and 1 for even packets. */
+ static const int mod_packet = 0;
+
+ /* Set to true if the first request should result in an error, resulting in a
+ search query. */
+ static bool first_error = true;
+
+ static ssize_t (*real_recvfrom) (int sockfd, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen);
+
+ void
+ __attribute__ ((constructor))
+ init (void)
+ {
+ real_recvfrom = dlsym (RTLD_NEXT, "recvfrom");
+
+ if (real_recvfrom == NULL)
+ {
+ printf ("Failed to get reference to recvfrom: %s\n", dlerror ());
+ printf ("Cannot simulate test\n");
+ abort ();
+ }
+ }
+
+ /* Modify the second packet that we receive to set the header in a manner as to
+ reproduce BZ #845218. */
+ static void
+ mod_buf (HEADER *h, int port)
+ {
+ if (done % 2 == mod_packet || (first_error && done == 1))
+ {
+ printf ("(Modifying header)");
+
+ if (first_error && done == 1)
+ h->rcode = 3;
+ else
+ h->rcode = 0; /* NOERROR == 0. */
+ h->ancount = 0;
+ h->aa = 0;
+ h->ra = 0;
+ h->arcount = 0;
+ }
+ done++;
+ }
+
+ ssize_t
+ recvfrom (int sockfd, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen)
+ {
+ ssize_t ret = real_recvfrom (sockfd, buf, len, flags, src_addr, addrlen);
+ int port = htons (((struct sockaddr_in *) src_addr)->sin_port);
+ struct in_addr addr = ((struct sockaddr_in *) src_addr)->sin_addr;
+ const char *host = inet_ntoa (addr);
+ printf ("\n*** From %s:%d: ", host, port);
+
+ mod_buf (buf, port);
+
+ printf ("returned %zd\n", ret);
+ return ret;
+ }
+
+diff --git a/resolv/res_query.c b/resolv/res_query.c
+index a9db837..4e6612c 100644
+--- a/resolv/res_query.c
++++ b/resolv/res_query.c
+@@ -382,7 +382,9 @@ __libc_res_nsearch(res_state statp,
+ ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen, answerp,
+ answerp2, nanswerp2, resplen2);
+- if (ret > 0 || trailing_dot)
++ if (ret > 0 || trailing_dot
++ /* If the second response is valid then we use that. */
++ || (ret == 0 && answerp2 != NULL && resplen2 > 0))
+ return (ret);
+ saved_herrno = h_errno;
+ tried_as_is++;
+@@ -422,7 +424,8 @@ __libc_res_nsearch(res_state statp,
+ answer, anslen, answerp,
+ answerp2, nanswerp2,
+ resplen2);
+- if (ret > 0)
++ if (ret > 0 || (ret == 0 && answerp2 != NULL
++ && resplen2 > 0))
+ return (ret);
+
+ if (answerp && *answerp != answer) {
+diff --git a/resolv/res_send.c b/resolv/res_send.c
+index 60743df..3273d55 100644
+--- a/resolv/res_send.c
++++ b/resolv/res_send.c
+@@ -1351,6 +1351,7 @@ send_dg(res_state statp,
+ (*thisresplenp > *thisanssizp)
+ ? *thisanssizp : *thisresplenp);
+
++ next_ns:
+ if (recvresp1 || (buf2 != NULL && recvresp2)) {
+ *resplen2 = 0;
+ return resplen;
+@@ -1368,7 +1369,6 @@ send_dg(res_state statp,
+ goto wait;
+ }
+
+- next_ns:
+ __res_iclose(statp, false);
+ /* don't retry if called from dig */
+ if (!statp->pfcode)
--- /dev/null
+2013-04-30 Patsy Franklin <pfrankli@redhat.com>
+
+ * nis/yp_xdr.c: Defined XDRMAXNAME and XDRMAXRECORD.
+ (xdr_domainname): Use XDRMAXNAME as maxsize.
+ (xdr_mapname): Use XDRMAXNAME as maxsize.
+ (xdr_peername): Use XDRMAXNAME as maxsize.
+ (xdr_keydat): Use XDRMAXRECORD as maxsize.
+ (xdr_valdat): Use XDRMAXRECORD as maxsize.
+
+diff -Nrup a/nis/yp_xdr.c b/nis/yp_xdr.c
+--- a/nis/yp_xdr.c 2012-06-30 15:12:34.000000000 -0400
++++ b/nis/yp_xdr.c 2013-04-30 05:36:02.492835503 -0400
+@@ -32,6 +32,14 @@
+ #include <rpcsvc/yp.h>
+ #include <rpcsvc/ypclnt.h>
+
++/* The specification suggests 1024 as a maximum length of all fields,
++ but current linux systems usually don't use any limits. So, to stay
++ as much compatible as possible with recent linux systems we choose
++ limits large enough to avoid problems. */
++
++#define XDRMAXNAME 1024
++#define XDRMAXRECORD 16 * 1024 * 1024
++
+ bool_t
+ xdr_ypstat (XDR *xdrs, ypstat *objp)
+ {
+@@ -49,21 +57,21 @@ libnsl_hidden_def (xdr_ypxfrstat)
+ bool_t
+ xdr_domainname (XDR *xdrs, domainname *objp)
+ {
+- return xdr_string (xdrs, objp, ~0);
++ return xdr_string (xdrs, objp, XDRMAXNAME);
+ }
+ libnsl_hidden_def (xdr_domainname)
+
+ bool_t
+ xdr_mapname (XDR *xdrs, mapname *objp)
+ {
+- return xdr_string (xdrs, objp, ~0);
++ return xdr_string (xdrs, objp, XDRMAXNAME);
+ }
+ libnsl_hidden_def (xdr_mapname)
+
+ bool_t
+ xdr_peername (XDR *xdrs, peername *objp)
+ {
+- return xdr_string (xdrs, objp, ~0);
++ return xdr_string (xdrs, objp, XDRMAXNAME);
+ }
+ libnsl_hidden_def (xdr_peername)
+
+@@ -71,7 +79,7 @@ bool_t
+ xdr_keydat (XDR *xdrs, keydat *objp)
+ {
+ return xdr_bytes (xdrs, (char **) &objp->keydat_val,
+- (u_int *) &objp->keydat_len, ~0);
++ (u_int *) &objp->keydat_len, XDRMAXRECORD);
+ }
+ libnsl_hidden_def (xdr_keydat)
+
+@@ -79,7 +87,7 @@ bool_t
+ xdr_valdat (XDR *xdrs, valdat *objp)
+ {
+ return xdr_bytes (xdrs, (char **) &objp->valdat_val,
+- (u_int *) &objp->valdat_len, ~0);
++ (u_int *) &objp->valdat_len, XDRMAXRECORD);
+ }
+ libnsl_hidden_def (xdr_valdat)
+
--- /dev/null
+commit 050af9c4e86eeecd484ed44b7765e750523276eb
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Wed Aug 29 10:03:39 2012 +0530
+
+ Don't make ttyname* fail if proc filesystem is not available
+
+ The ttyname and ttyname_r functions on Linux now fall back to
+ searching for the tty file descriptor in /dev/pts or /dev if /proc is
+ not available. This allows creation of chroots without the procfs
+ mounted on /proc.
+
+ Fixes BZ #14516.
+
+ 2012-08-29 Siddhesh Poyarekar <siddhesh@redhat.com>
+
+ [BZ #14516]
+ * sysdeps/unix/sysv/linux/ttyname.c (ttyname): Don't return
+ failure if reading from procfs failed.
+ * sysdeps/unix/sysv/linux/ttyname_r.c (ttyname_r): Likewise.
+
+diff -rup a/sysdeps/unix/sysv/linux/ttyname.c b/sysdeps/unix/sysv/linux/ttyname.c
+--- a/sysdeps/unix/sysv/linux/ttyname.c 2010-05-04 05:27:23.000000000 -0600
++++ b/sysdeps/unix/sysv/linux/ttyname.c 2012-08-27 10:53:29.326671475 -0600
+@@ -146,12 +146,6 @@ ttyname (int fd)
+ }
+
+ ssize_t len = __readlink (procname, ttyname_buf, buflen);
+- if (__builtin_expect (len == -1 && errno == ENOENT, 0))
+- {
+- __set_errno (EBADF);
+- return NULL;
+- }
+-
+ if (__builtin_expect (len != -1
+ #ifndef __ASSUME_PROC_SELF_FD_SYMLINK
+ /* This is for Linux 2.0. */
+diff -rup a/sysdeps/unix/sysv/linux/ttyname_r.c b/sysdeps/unix/sysv/linux/ttyname_r.c
+--- a/sysdeps/unix/sysv/linux/ttyname_r.c 2010-05-04 05:27:23.000000000 -0600
++++ b/sysdeps/unix/sysv/linux/ttyname_r.c 2012-08-27 10:54:05.406528501 -0600
+@@ -126,12 +126,6 @@ __ttyname_r (int fd, char *buf, size_t b
+ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0';
+
+ ssize_t ret = __readlink (procname, buf, buflen - 1);
+- if (__builtin_expect (ret == -1 && errno == ENOENT, 0))
+- {
+- __set_errno (EBADF);
+- return EBADF;
+- }
+-
+ if (__builtin_expect (ret == -1 && errno == ENAMETOOLONG, 0))
+ {
+ __set_errno (ERANGE);
--- /dev/null
+#
+# Based on the following patch:
+#
+# Upstream bug: https://sourceware.org/bugzilla/show_bug.cgi?id=14906
+# URL: https://sourceware.org/ml/libc-alpha/2015-02/msg00504.html
+#
+# 2015-02-17 Carlos O'Donell <carlos@redhat.com>
+#
+# [BZ #14906]
+# * nscd/cache.c (prune_cache): Use TRACED_FILE. Compare and update
+# traced file mtime. Use consistent log message.
+# * nscd/connections.c [HAVE_INOTIFY] (install_watches): New function.
+# (register_traced_file): Call install_watches. Always set mtime.
+# (invalidate_cache): Iterate over all trace files. Call install_watches.
+# (inotify_check_files): Don't inline. Handle watching parent
+# directories and configuration file movement in and out.
+# (handle_inotify_events): New function.
+# (main_loop_poll): Call handle_inotify_events.
+# (main_loop_epoll): Likewise.
+# * nscd/nscd.h: Define TRACED_FILE, TRACED_DIR, and PATH_MAX.
+# (struct traced_file): Use array of inotify fds. Add parent directory,
+# and basename.
+# (struct database_dyn): Remove unused file_mtime.
+# (init_traced_file): New inline function.
+# (define_traced_file): New macro.
+# * nss/nss_db/db-init.c: Use define_traced_file.
+# (_nss_db_init): Use init_traced_file.
+# * nss/nss_files/files-init.c: Use define_traced_file.
+# (_nss_files_init): Use init_traced_file.
+#
+diff -urN glibc-2.12-2-gc4ccff1.orig/misc/sys/cdefs.h glibc-2.12-2-gc4ccff1.mod1/misc/sys/cdefs.h
+--- glibc-2.12-2-gc4ccff1.orig/misc/sys/cdefs.h 2015-02-18 04:42:12.115187116 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/misc/sys/cdefs.h 2015-02-18 04:02:03.635159090 -0500
+@@ -362,6 +362,14 @@
+ # endif
+ #endif
+
++#if __GNUC__ >= 3
++# define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
++# define __glibc_likely(cond) __builtin_expect ((cond), 1)
++#else
++# define __glibc_unlikely(cond) (cond)
++# define __glibc_likely(cond) (cond)
++#endif
++
+ #include <bits/wordsize.h>
+
+ #if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH
+diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/cache.c glibc-2.12-2-gc4ccff1.mod1/nscd/cache.c
+--- glibc-2.12-2-gc4ccff1.orig/nscd/cache.c 2015-02-18 04:42:12.329180362 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/nscd/cache.c 2015-02-18 04:02:03.635159090 -0500
+@@ -266,29 +266,52 @@
+
+ /* If we check for the modification of the underlying file we invalidate
+ the entries also in this case. */
+- if (table->inotify_descr < 0 && table->check_file && now != LONG_MAX)
++ if (table->check_file && now != LONG_MAX)
+ {
+- struct stat64 st;
++ struct traced_file *runp = table->traced_files;
+
+- if (stat64 (table->filename, &st) < 0)
++ while (runp != NULL)
+ {
+- char buf[128];
+- /* We cannot stat() the file, disable file checking if the
+- file does not exist. */
+- dbg_log (_("cannot stat() file `%s': %s"),
+- table->filename, strerror_r (errno, buf, sizeof (buf)));
+- if (errno == ENOENT)
+- table->check_file = 0;
+- }
+- else
+- {
+- if (st.st_mtime != table->file_mtime)
++#ifdef HAVE_INOTIFY
++ if (runp->inotify_descr[TRACED_FILE] == -1)
++#endif
+ {
+- /* The file changed. Invalidate all entries. */
+- now = LONG_MAX;
+- table->file_mtime = st.st_mtime;
++ struct stat64 st;
++
++ if (stat64 (runp->fname, &st) < 0)
++ {
++ /* Print a diagnostic that the traced file was missing.
++ We must not disable tracing since the file might return
++ shortly and we want to reload it at the next pruning.
++ Disabling tracing here would go against the configuration
++ as specified by the user via check-files. */
++ char buf[128];
++ dbg_log (_("checking for monitored file `%s': %s"),
++ runp->fname, strerror_r (errno, buf, sizeof (buf)));
++ }
++ else
++ {
++ /* This must be `!=` to catch cases where users turn the
++ clocks back and we still want to detect any time difference
++ in mtime. */
++ if (st.st_mtime != runp->mtime)
++ {
++ dbg_log (_("monitored file `%s` changed (mtime)"),
++ runp->fname);
++ /* The file changed. Invalidate all entries. */
++ now = LONG_MAX;
++ runp->mtime = st.st_mtime;
++#ifdef HAVE_INOTIFY
++ /* Attempt to install a watch on the file. */
++ install_watches (runp);
++#endif
++ }
++ }
+ }
++
++ runp = runp->next;
+ }
++
+ }
+
+ /* We run through the table and find values which are not valid anymore.
+diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/connections.c glibc-2.12-2-gc4ccff1.mod1/nscd/connections.c
+--- glibc-2.12-2-gc4ccff1.orig/nscd/connections.c 2015-02-18 04:42:12.333180236 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/nscd/connections.c 2015-02-18 04:40:51.674726008 -0500
+@@ -74,6 +74,25 @@
+ static void begin_drop_privileges (void);
+ static void finish_drop_privileges (void);
+
++/* Define the traced files. */
++#define PWD_FILENAME "/etc/passwd"
++define_traced_file (pwd, PWD_FILENAME);
++
++#define GRP_FILENAME "/etc/group"
++define_traced_file (grp, GRP_FILENAME);
++
++#define HST_FILENAME "/etc/hosts"
++define_traced_file (hst, HST_FILENAME);
++
++#define RESOLV_FILENAME "/etc/resolv.conf"
++define_traced_file (resolv, RESOLV_FILENAME);
++
++#define SERV_FILENAME "/etc/services"
++define_traced_file (serv, SERV_FILENAME);
++
++#define NETGR_FILENAME "/etc/netgroup"
++define_traced_file (netgr, NETGR_FILENAME);
++
+ /* Map request type to a string. */
+ const char *const serv2str[LASTREQ] =
+ {
+@@ -115,8 +134,6 @@
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .suggested_module = DEFAULT_SUGGESTED_MODULE,
+- .reset_res = 0,
+- .filename = "/etc/passwd",
+ .db_filename = _PATH_NSCD_PASSWD_DB,
+ .disabled_iov = &pwd_iov_disabled,
+ .postimeout = 3600,
+@@ -136,8 +153,6 @@
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .suggested_module = DEFAULT_SUGGESTED_MODULE,
+- .reset_res = 0,
+- .filename = "/etc/group",
+ .db_filename = _PATH_NSCD_GROUP_DB,
+ .disabled_iov = &grp_iov_disabled,
+ .postimeout = 3600,
+@@ -157,8 +172,6 @@
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .suggested_module = DEFAULT_SUGGESTED_MODULE,
+- .reset_res = 1,
+- .filename = "/etc/hosts",
+ .db_filename = _PATH_NSCD_HOSTS_DB,
+ .disabled_iov = &hst_iov_disabled,
+ .postimeout = 3600,
+@@ -178,8 +191,6 @@
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .suggested_module = DEFAULT_SUGGESTED_MODULE,
+- .reset_res = 0,
+- .filename = "/etc/services",
+ .db_filename = _PATH_NSCD_SERVICES_DB,
+ .disabled_iov = &serv_iov_disabled,
+ .postimeout = 28800,
+@@ -199,8 +210,6 @@
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .suggested_module = DEFAULT_SUGGESTED_MODULE,
+- .reset_res = 0,
+- .filename = "/etc/netgroup",
+ .db_filename = _PATH_NSCD_NETGROUP_DB,
+ .disabled_iov = &netgroup_iov_disabled,
+ .postimeout = 28800,
+@@ -863,41 +872,26 @@
+ dbs[cnt].shared = 0;
+ assert (dbs[cnt].ro_fd == -1);
+ }
++ }
+
+- dbs[cnt].inotify_descr = -1;
+- if (dbs[cnt].check_file)
+- {
+-#ifdef HAVE_INOTIFY
+- if (inotify_fd < 0
+- || (dbs[cnt].inotify_descr
+- = inotify_add_watch (inotify_fd, dbs[cnt].filename,
+- IN_DELETE_SELF | IN_MODIFY)) < 0)
+- /* We cannot notice changes in the main thread. */
+-#endif
+- {
+- /* We need the modification date of the file. */
+- struct stat64 st;
++ /* Initialize and register the traced files. */
++ init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0);
++ register_traced_file (pwddb, &pwd_traced_file.file);
+
+- if (stat64 (dbs[cnt].filename, &st) < 0)
+- {
+- /* We cannot stat() the file, disable file checking. */
+- dbg_log (_("cannot stat() file `%s': %s"),
+- dbs[cnt].filename, strerror (errno));
+- dbs[cnt].check_file = 0;
+- }
+- else
+- dbs[cnt].file_mtime = st.st_mtime;
+- }
+- }
++ init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0);
++ register_traced_file (grpdb, &grp_traced_file.file);
+
+-#ifdef HAVE_INOTIFY
+- if (cnt == hstdb && inotify_fd >= -1)
+- /* We also monitor the resolver configuration file. */
+- resolv_conf_descr = inotify_add_watch (inotify_fd,
+- _PATH_RESCONF,
+- IN_DELETE_SELF | IN_MODIFY);
+-#endif
+- }
++ init_traced_file (&hst_traced_file.file, HST_FILENAME, 0);
++ register_traced_file (hstdb, &hst_traced_file.file);
++
++ init_traced_file (&resolv_traced_file.file, RESOLV_FILENAME, 1);
++ register_traced_file (hstdb, &resolv_traced_file.file);
++
++ init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0);
++ register_traced_file (servdb, &serv_traced_file.file);
++
++ init_traced_file (&netgr_traced_file.file, NETGR_FILENAME, 0);
++ register_traced_file (netgrdb, &netgr_traced_file.file);
+
+ /* Create the socket. */
+ #ifndef __ASSUME_SOCK_CLOEXEC
+@@ -968,6 +962,92 @@
+ finish_drop_privileges ();
+ }
+
++#ifdef HAVE_INOTIFY
++#define TRACED_FILE_MASK (IN_DELETE_SELF | IN_CLOSE_WRITE | IN_MOVE_SELF)
++#define TRACED_DIR_MASK (IN_DELETE_SELF | IN_CREATE | IN_MOVED_TO | IN_MOVE_SELF)
++void
++install_watches (struct traced_file *finfo)
++{
++ /* If we have inotify support use it exclusively with no fallback
++ to stat. This is a design decision to make the implementation
++ sipmler. Either we use fstat for the file name or we use inotify
++ for both the file and parent directory. */
++ if (finfo->inotify_descr[TRACED_FILE] < 0)
++ finfo->inotify_descr[TRACED_FILE] = inotify_add_watch (inotify_fd,
++ finfo->fname,
++ TRACED_FILE_MASK);
++ if (finfo->inotify_descr[TRACED_FILE] < 0)
++ {
++ dbg_log (_("disabled inotify-based monitoring for file `%s': %s"),
++ finfo->fname, strerror (errno));
++ return;
++ }
++ dbg_log (_("monitoring file `%s` (%d)"),
++ finfo->fname, finfo->inotify_descr[TRACED_FILE]);
++ /* Additionally listen for IN_CREATE events in the files parent
++ directory. We do this because the file to be watched might be
++ deleted and then added back again. When it is added back again
++ we must re-add the watch. We must also cover IN_MOVED_TO to
++ detect a file being moved into the directory. */
++ if (finfo->inotify_descr[TRACED_DIR] < 0)
++ finfo->inotify_descr[TRACED_DIR] = inotify_add_watch (inotify_fd,
++ finfo->dname,
++ TRACED_DIR_MASK);
++ if (finfo->inotify_descr[TRACED_DIR] < 0)
++ {
++ dbg_log (_("disabled inotify-based monitoring for directory `%s': %s"),
++ finfo->fname, strerror (errno));
++ return;
++ }
++ dbg_log (_("monitoring directory `%s` (%d)"),
++ finfo->dname, finfo->inotify_descr[TRACED_DIR]);
++}
++#endif
++
++/* Register the file in FINFO as a traced file for the database DBS[DBIX].
++
++ We support registering multiple files per database. Each call to
++ register_traced_file adds to the list of registered files.
++
++ When we prune the database, either through timeout or a request to
++ invalidate, we will check to see if any of the registered files has changed.
++ When we accept new connections to handle a cache request we will also
++ check to see if any of the registered files has changed.
++
++ If we have inotify support then we install an inotify fd to notify us of
++ file deletion or modification, both of which will require we invalidate
++ the cache for the database. Without inotify support we stat the file and
++ store st_mtime to determine if the file has been modified. */
++void
++register_traced_file (size_t dbidx, struct traced_file *finfo)
++{
++ /* If the database is disabled or file checking is disabled
++ then ignore the registration. */
++ if (! dbs[dbidx].enabled || ! dbs[dbidx].check_file)
++ return;
++
++ if (__glibc_unlikely (debug_level > 0))
++ dbg_log (_("monitoring file %s for database %s"),
++ finfo->fname, dbnames[dbidx]);
++
++#ifdef HAVE_INOTIFY
++ install_watches (finfo);
++#endif
++ struct stat64 st;
++ if (stat64 (finfo->fname, &st) < 0)
++ {
++ /* We cannot stat() the file, disable file checking. */
++ dbg_log (_("disabled monitoring for file `%s': %s"),
++ finfo->fname, strerror (errno));
++ finfo->mtime = 0;
++ }
++ else
++ finfo->mtime = st.st_mtime;
++
++ /* Queue up the file name. */
++ finfo->next = dbs[dbidx].traced_files;
++ dbs[dbidx].traced_files = finfo;
++}
+
+ /* Close the connections. */
+ void
+@@ -986,9 +1066,25 @@
+ for (number = pwddb; number < lastdb; ++number)
+ if (strcmp (key, dbnames[number]) == 0)
+ {
+- if (dbs[number].reset_res)
+- res_init ();
+-
++ struct traced_file *runp = dbs[number].traced_files;
++ while (runp != NULL)
++ {
++ /* Make sure we reload from file when checking mtime. */
++ runp->mtime = 0;
++#ifdef HAVE_INOTIFY
++ /* During an invalidation we try to reload the traced
++ file watches. This allows the user to re-sync if
++ inotify events were lost. Similar to what we do during
++ pruning. */
++ install_watches (runp);
++#endif
++ if (runp->call_res_init)
++ {
++ res_init ();
++ break;
++ }
++ runp = runp->next;
++ }
+ break;
+ }
+
+@@ -1817,6 +1913,231 @@
+ /* Array for times a connection was accepted. */
+ static time_t *starttime;
+
++#ifdef HAVE_INOTIFY
++/* Inotify event for changed file. */
++union __inev
++{
++ struct inotify_event i;
++# ifndef PATH_MAX
++# define PATH_MAX 1024
++# endif
++ char buf[sizeof (struct inotify_event) + PATH_MAX];
++};
++
++/* Returns 0 if the file is there and matches the last mtime
++ on record, otherwise -1. */
++int
++check_file (struct traced_file *finfo)
++{
++ struct stat64 st;
++ if (stat64 (finfo->fname, &st) < 0)
++ return -1;
++ return 0;
++}
++
++/* Process the inotify event in INEV. If the event matches any of the files
++ registered with a database then mark that database as requiring its cache
++ to be cleared. We indicate the cache needs clearing by setting
++ TO_CLEAR[DBCNT] to true for the matching database. */
++static void
++inotify_check_files (bool *to_clear, union __inev *inev)
++{
++ /* Check which of the files changed. */
++ for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
++ {
++ struct traced_file *finfo = dbs[dbcnt].traced_files;
++
++ while (finfo != NULL)
++ {
++ /* The configuration file was moved or deleted.
++ We stop watching it at that point, and reinitialize. */
++ if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
++ && ((inev->i.mask & IN_MOVE_SELF)
++ || (inev->i.mask & IN_DELETE_SELF)
++ || (inev->i.mask & IN_IGNORED)))
++ {
++ int ret;
++ bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
++
++ if (check_file (finfo) == 0)
++ {
++ dbg_log (_("ignored out of order inotify event for `%s`"),
++ finfo->fname);
++ return;
++ }
++
++ dbg_log (_("monitored file `%s` was %s, removing watch"),
++ finfo->fname, moved ? "moved" : "deleted");
++ /* File was moved out, remove the watch. Watches are
++ automatically removed when the file is deleted. */
++ if (moved)
++ {
++ ret = inotify_rm_watch (inotify_fd, inev->i.wd);
++ if (ret < 0)
++ dbg_log (_("failed to remove file watch `%s`: %s"),
++ finfo->fname, strerror (errno));
++ }
++ finfo->inotify_descr[TRACED_FILE] = -1;
++ to_clear[dbcnt] = true;
++ if (finfo->call_res_init)
++ res_init ();
++ return;
++ }
++ /* The configuration file was open for writing and has just closed.
++ We reset the cache and reinitialize. */
++ if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
++ && inev->i.mask & IN_CLOSE_WRITE)
++ {
++ /* Mark cache as needing to be cleared and reinitialize. */
++ dbg_log (_("monitored file `%s` was written to"), finfo->fname);
++ to_clear[dbcnt] = true;
++ if (finfo->call_res_init)
++ res_init ();
++ return;
++ }
++ /* The parent directory was moved or deleted. There is no coming
++ back from this. We do not track the parent of the parent, and
++ once this happens we trigger one last invalidation. You must
++ restart nscd to track subsequent changes. We track this to
++ do one last robust re-initialization and then we're done. */
++ if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
++ && ((inev->i.mask & IN_DELETE_SELF)
++ || (inev->i.mask & IN_MOVE_SELF)
++ || (inev->i.mask & IN_IGNORED)))
++ {
++ bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
++ /* The directory watch may have already been removed
++ but we don't know so we just remove it again and
++ ignore the error. Then we remove the file watch.
++ Note: watches are automatically removed for deleted
++ files. */
++ if (moved)
++ inotify_rm_watch (inotify_fd, inev->i.wd);
++ if (finfo->inotify_descr[TRACED_FILE] != -1)
++ {
++ dbg_log (_("monitored parent directory `%s` was %s, removing watch on `%s`"),
++ finfo->dname, moved ? "moved" : "deleted", finfo->fname);
++ if (inotify_rm_watch (inotify_fd, finfo->inotify_descr[TRACED_FILE]) < 0)
++ dbg_log (_("failed to remove file watch `%s`: %s"),
++ finfo->dname, strerror (errno));
++ }
++ finfo->inotify_descr[TRACED_FILE] = -1;
++ finfo->inotify_descr[TRACED_DIR] = -1;
++ to_clear[dbcnt] = true;
++ if (finfo->call_res_init)
++ res_init ();
++ /* Continue to the next entry since this might be the
++ parent directory for multiple registered files and
++ we want to remove watches for all registered files. */
++ continue;
++ }
++ /* The parent directory had a create or moved to event. */
++ if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
++ && ((inev->i.mask & IN_MOVED_TO)
++ || (inev->i.mask & IN_CREATE))
++ && strcmp (inev->i.name, finfo->sfname) == 0)
++ {
++ /* We detected a directory change. We look for the creation
++ of the file we are tracking or the move of the same file
++ into the directory. */
++ int ret;
++ dbg_log (_("monitored file `%s` was %s, adding watch"),
++ finfo->fname,
++ inev->i.mask & IN_CREATE ? "created" : "moved into place");
++ /* File was moved in or created. Regenerate the watch. */
++ if (finfo->inotify_descr[TRACED_FILE] != -1)
++ inotify_rm_watch (inotify_fd,
++ finfo->inotify_descr[TRACED_FILE]);
++
++ ret = inotify_add_watch (inotify_fd,
++ finfo->fname,
++ TRACED_FILE_MASK);
++ if (ret < 0)
++ dbg_log (_("failed to add file watch `%s`: %s"),
++ finfo->fname, strerror (errno));
++
++ finfo->inotify_descr[TRACED_FILE] = ret;
++
++ /* The file is new or moved so mark cache as needing to
++ be cleared and reinitialize. */
++ to_clear[dbcnt] = true;
++ if (finfo->call_res_init)
++ res_init ();
++
++ /* Done re-adding the watch. Don't return, we may still
++ have other files in this same directory, same watch
++ descriptor, and need to process them. */
++ }
++ /* Other events are ignored, and we move on to the next file. */
++ finfo = finfo->next;
++ }
++ }
++}
++
++/* If an entry in the array of booleans TO_CLEAR is TRUE then clear the cache
++ for the associated database, otherwise do nothing. The TO_CLEAR array must
++ have LASTDB entries. */
++static inline void
++clear_db_cache (bool *to_clear)
++{
++ for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
++ if (to_clear[dbcnt])
++ {
++ pthread_mutex_lock (&dbs[dbcnt].prune_lock);
++ dbs[dbcnt].clear_cache = 1;
++ pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
++ pthread_cond_signal (&dbs[dbcnt].prune_cond);
++ }
++}
++
++int
++handle_inotify_events (void)
++{
++ bool to_clear[lastdb] = { false, };
++ union __inev inev;
++
++ /* Read all inotify events for files registered via
++ register_traced_file(). */
++ while (1)
++ {
++ /* Potentially read multiple events into buf. */
++ ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd,
++ &inev.buf,
++ sizeof (inev)));
++ if (nb < (ssize_t) sizeof (struct inotify_event))
++ {
++ /* Not even 1 event. */
++ if (__glibc_unlikely (nb == -1 && errno != EAGAIN))
++ return -1;
++ /* Done reading events that are ready. */
++ break;
++ }
++ /* Process all events. The normal inotify interface delivers
++ complete events on a read and never a partial event. */
++ char *eptr = &inev.buf[0];
++ ssize_t count;
++ while (1)
++ {
++ /* Check which of the files changed. */
++ inotify_check_files (to_clear, &inev);
++ count = sizeof (struct inotify_event) + inev.i.len;
++ eptr += count;
++ nb -= count;
++ if (nb >= (ssize_t) sizeof (struct inotify_event))
++ memcpy (&inev, eptr, nb);
++ else
++ break;
++ }
++ continue;
++ }
++ /* Actually perform the cache clearing. */
++ clear_db_cache (to_clear);
++ return 0;
++}
++
++
++#endif
++
+
+ static void
+ __attribute__ ((__noreturn__))
+@@ -1910,66 +2231,21 @@
+ {
+ if (conns[1].revents != 0)
+ {
+- bool to_clear[lastdb] = { false, };
+- union
+- {
+-# ifndef PATH_MAX
+-# define PATH_MAX 1024
+-# endif
+- struct inotify_event i;
+- char buf[sizeof (struct inotify_event) + PATH_MAX];
+- } inev;
++ int ret;
++ ret = handle_inotify_events ();
+
+- while (1)
++ if (ret == -1)
+ {
+- ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
+- sizeof (inev)));
+- if (nb < (ssize_t) sizeof (struct inotify_event))
+- {
+- if (__builtin_expect (nb == -1 && errno != EAGAIN,
+- 0))
+- {
+- /* Something went wrong when reading the inotify
+- data. Better disable inotify. */
+- dbg_log (_("\
+-disabled inotify after read error %d"),
+- errno);
+- conns[1].fd = -1;
+- firstfree = 1;
+- if (nused == 2)
+- nused = 1;
+- close (inotify_fd);
+- inotify_fd = -1;
+- }
+- break;
+- }
+-
+- /* Check which of the files changed. */
+- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+- if (inev.i.wd == dbs[dbcnt].inotify_descr)
+- {
+- to_clear[dbcnt] = true;
+- goto next;
+- }
+-
+- if (inev.i.wd == resolv_conf_descr)
+- {
+- res_init ();
+- to_clear[hstdb] = true;
+- }
+- next:;
++ /* Something went wrong when reading the inotify
++ data. Better disable inotify. */
++ dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
++ conns[1].fd = -1;
++ firstfree = 1;
++ if (nused == 2)
++ nused = 1;
++ close (inotify_fd);
++ inotify_fd = -1;
+ }
+-
+- /* Actually perform the cache clearing. */
+- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+- if (to_clear[dbcnt])
+- {
+- pthread_mutex_lock (&dbs[dbcnt].prune_lock);
+- dbs[dbcnt].clear_cache = 1;
+- pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
+- pthread_cond_signal (&dbs[dbcnt].prune_cond);
+- }
+-
+ --n;
+ }
+
+@@ -2112,58 +2388,18 @@
+ # ifdef HAVE_INOTIFY
+ else if (revs[cnt].data.fd == inotify_fd)
+ {
+- bool to_clear[lastdb] = { false, };
+- union
+- {
+- struct inotify_event i;
+- char buf[sizeof (struct inotify_event) + PATH_MAX];
+- } inev;
+-
+- while (1)
++ int ret;
++ ret = handle_inotify_events ();
++ if (ret == -1)
+ {
+- ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
+- sizeof (inev)));
+- if (nb < (ssize_t) sizeof (struct inotify_event))
+- {
+- if (__builtin_expect (nb == -1 && errno != EAGAIN, 0))
+- {
+- /* Something went wrong when reading the inotify
+- data. Better disable inotify. */
+- dbg_log (_("disabled inotify after read error %d"),
+- errno);
+- (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd,
+- NULL);
+- close (inotify_fd);
+- inotify_fd = -1;
+- }
+- break;
+- }
+-
+- /* Check which of the files changed. */
+- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+- if (inev.i.wd == dbs[dbcnt].inotify_descr)
+- {
+- to_clear[dbcnt] = true;
+- goto next;
+- }
+-
+- if (inev.i.wd == resolv_conf_descr)
+- {
+- res_init ();
+- to_clear[hstdb] = true;
+- }
+- next:;
++ /* Something went wrong when reading the inotify
++ data. Better disable inotify. */
++ dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
++ (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd, NULL);
++ close (inotify_fd);
++ inotify_fd = -1;
++ break;
+ }
+-
+- /* Actually perform the cache clearing. */
+- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+- if (to_clear[dbcnt])
+- {
+- pthread_mutex_lock (&dbs[dbcnt].prune_lock);
+- dbs[dbcnt].clear_cache = 1;
+- pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
+- pthread_cond_signal (&dbs[dbcnt].prune_cond);
+- }
+ }
+ # endif
+ else
+diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/nscd.h glibc-2.12-2-gc4ccff1.mod1/nscd/nscd.h
+--- glibc-2.12-2-gc4ccff1.orig/nscd/nscd.h 2015-02-18 04:42:12.329180362 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/nscd/nscd.h 2015-02-18 04:02:03.636159059 -0500
+@@ -62,6 +62,67 @@
+ 80% of the thread stack size. */
+ #define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
+
++/* Records the file registered per database that when changed
++ or modified requires invalidating the database. */
++struct traced_file
++{
++ /* Tracks the last modified time of the traced file. */
++ time_t mtime;
++ /* Support multiple registered files per database. */
++ struct traced_file *next;
++ int call_res_init;
++ /* Requires Inotify support to do anything useful. */
++#define TRACED_FILE 0
++#define TRACED_DIR 1
++ int inotify_descr[2];
++# ifndef PATH_MAX
++# define PATH_MAX 1024
++# endif
++ /* The parent directory is used to scan for creation/deletion. */
++ char dname[PATH_MAX];
++ /* Just the name of the file with no directory component. */
++ char *sfname;
++ /* The full-path name of the registered file. */
++ char fname[];
++};
++
++/* Initialize a `struct traced_file`. As input we need the name
++ of the file, and if invalidation requires calling res_init.
++ If CRINIT is 1 then res_init will be called after invalidation
++ or if the traced file is changed in any way, otherwise it will
++ not. */
++static inline void
++init_traced_file(struct traced_file *file, const char *fname, int crinit)
++{
++ char *dname;
++ file->mtime = 0;
++ file->inotify_descr[TRACED_FILE] = -1;
++ file->inotify_descr[TRACED_DIR] = -1;
++ strcpy (file->fname, fname);
++ /* Compute the parent directory name and store a copy. The copy makes
++ it much faster to add/remove watches while nscd is running instead
++ of computing this over and over again in a temp buffer. */
++ file->dname[0] = '\0';
++ dname = strrchr (fname, '/');
++ if (dname != NULL)
++ {
++ size_t len = (size_t)(dname - fname);
++ if (len > sizeof (file->dname))
++ abort ();
++ strncpy (file->dname, file->fname, len);
++ file->dname[len] = '\0';
++ }
++ /* The basename is the name just after the last forward slash. */
++ file->sfname = &dname[1];
++ file->call_res_init = crinit;
++}
++
++#define define_traced_file(id, filename) \
++static union \
++{ \
++ struct traced_file file; \
++ char buf[sizeof (struct traced_file) + sizeof (filename)]; \
++} id##_traced_file;
+
+ /* Structure describing dynamic part of one database. */
+ struct database_dyn
+@@ -74,15 +135,12 @@
+
+ int enabled;
+ int check_file;
+- int inotify_descr;
+ int clear_cache;
+ int persistent;
+ int shared;
+ int propagate;
+- int reset_res;
+- const char filename[16];
++ struct traced_file *traced_files;
+ const char *db_filename;
+- time_t file_mtime;
+ size_t suggested_module;
+ size_t max_db_size;
+
+@@ -199,6 +257,10 @@
+
+ /* connections.c */
+ extern void nscd_init (void);
++extern void register_traced_file (size_t dbidx, struct traced_file *finfo);
++#ifdef HAVE_INOTIFY
++extern void install_watches (struct traced_file *finfo);
++#endif
+ extern void close_sockets (void);
+ extern void start_threads (void) __attribute__ ((__noreturn__));
--- /dev/null
+From bc5fb0374c3ce6eca92f44d13a55b066e707c4a0 Mon Sep 17 00:00:00 2001
+From: Andreas Schwab <schwab@redhat.com>
+Date: Wed, 15 Sep 2010 07:20:57 -0700
+Subject: [PATCH] Don't try to free rpath strings allocated during startup
+
+---
+ ChangeLog | 10 ++++++++++
+ elf/dl-load.c | 3 ---
+ elf/dl-support.c | 3 +++
+ elf/rtld.c | 4 ++++
+ 4 files changed, 17 insertions(+), 3 deletions(-)
+
+ 2010-09-13 Andreas Schwab <schwab@redhat.com>
+ Ulrich Drepper <drepper@redhat.com>
+
+ * elf/rtld.c (dl_main): Set GLRO(dl_init_all_dirs) just before
+ re-relocationg ld.so.
+ * elf/dl-support.c (_dl_non_dynamic_init): And here after the
+ _dl_init_paths call.
+ * elf/dl-load.c (_dl_init_paths). Don't set GLRO(dl_init_all_dirs)
+ here anymore.
+
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index 0adddf5..a7162eb 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -787,9 +787,6 @@ _dl_init_paths (const char *llp)
+ }
+ else
+ env_path_list.dirs = (void *) -1;
+-
+- /* Remember the last search directory added at startup. */
+- GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
+ }
+
+
+diff --git a/elf/dl-support.c b/elf/dl-support.c
+index f94d2c4..5897b32 100644
+--- a/elf/dl-support.c
++++ b/elf/dl-support.c
+@@ -264,6 +264,9 @@ _dl_non_dynamic_init (void)
+ objects. */
+ _dl_init_paths (getenv ("LD_LIBRARY_PATH"));
+
++ /* Remember the last search directory added at startup. */
++ _dl_init_all_dirs = GL(dl_all_dirs);
++
+ _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0';
+
+ _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0';
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 90f3ff1..5ecc4fe 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2291,6 +2291,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ lossage);
+ }
+
++ /* Remember the last search directory added at startup, now that
++ malloc will no longer be the one from dl-minimal.c. */
++ GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
++
+ if (! prelinked && rtld_multiple_ref)
+ {
+ /* There was an explicit ref to the dynamic linker as a shared lib.
+--
+1.7.1
+
--- /dev/null
+diff -pruN glibc-2.12-2-gc4ccff1/sysdeps/posix/getaddrinfo.c glibc-2.12-2-gc4ccff1.fixed/sysdeps/posix/getaddrinfo.c
+--- glibc-2.12-2-gc4ccff1/sysdeps/posix/getaddrinfo.c 2013-07-23 15:23:42.011941780 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/sysdeps/posix/getaddrinfo.c 2013-07-23 15:24:54.032938976 +0530
+@@ -562,8 +562,8 @@ gaih_inet (const char *name, const struc
+
+ /* If we do not have to look for IPv6 addresses, use
+ the simple, old functions, which do not support
+- IPv6 scope ids. */
+- if (req->ai_family == AF_INET)
++ IPv6 scope ids, nor retrieving the canonical name. */
++ if (req->ai_family == AF_INET && (req->ai_flags & AI_CANONNAME) == 0)
+ {
+ /* Add room for struct host_data in resolv/nss_dns/dns-host.c */
+ size_t tmpbuflen = 512 + (MAX_NR_ALIASES+MAX_NR_ADDRS+1)*sizeof(char*)
--- /dev/null
+commit 9fab36eb583c0e585e83a01253299afed9ea9a11
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date: Tue Sep 25 14:10:29 2012 +0530
+
+ Shrink heap on linux when overcommit_memory == 2
+
+ Using madvise with MADV_DONTNEED to release memory back to the kernel
+ is not sufficient to change the commit charge accounted against the
+ process on Linux. It is OK however, when overcommit is enabled or is
+ heuristic. However, when overcommit is restricted to a percentage of
+ memory setting the contents of /proc/sys/vm/overcommit_memory as 2, it
+ makes a difference since memory requests will fail. Hence, we do what
+ we do with secure exec binaries, which is to call mmap on the region
+ to be dropped with MAP_FIXED. This internally unmaps the pages in
+ question and reduces the amount of memory accounted against the
+ process.
+
+diff --git a/malloc/arena.c b/malloc/arena.c
+index f24e76c..b209e3b 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -19,6 +19,9 @@
+
+ #include <stdbool.h>
+
++/* Get the implementation for check_may_shrink_heap. */
++#include <malloc-sysdep.h>
++
+ /* Compile-time constants. */
+
+ #define HEAP_MIN_SIZE (32*1024)
+@@ -621,10 +624,10 @@ shrink_heap(heap_info *h, long diff)
+ new_size = (long)h->size - diff;
+ if(new_size < (long)sizeof(*h))
+ return -1;
+- /* Try to re-map the extra heap space freshly to save memory, and
+- make it inaccessible. */
+ #ifdef _LIBC
+- if (__builtin_expect (__libc_enable_secure, 0))
++ /* Try to re-map the extra heap space freshly to save memory, and make it
++ inaccessible. See malloc-sysdep.h to know when this is true. */
++ if (__builtin_expect (check_may_shrink_heap (), 0))
+ #else
+ if (1)
+ #endif
+diff --git a/sysdeps/generic/malloc-sysdep.h b/sysdeps/generic/malloc-sysdep.h
+new file mode 100644
+index 0000000..bbc48c0
+--- /dev/null
++++ b/sysdeps/generic/malloc-sysdep.h
+@@ -0,0 +1,25 @@
++/* System-specific malloc support functions. Generic version.
++ Copyright (C) 2012 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
++ <http://www.gnu.org/licenses/>. */
++
++/* Force an unmap when the heap shrinks in a secure exec. This ensures that
++ the old data pages immediately cease to be accessible. */
++static inline bool
++check_may_shrink_heap (void)
++{
++ return __libc_enable_secure;
++}
+diff --git a/sysdeps/unix/sysv/linux/malloc-sysdep.h b/sysdeps/unix/sysv/linux/malloc-sysdep.h
+new file mode 100644
+index 0000000..f926aea
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/malloc-sysdep.h
+@@ -0,0 +1,57 @@
++/* System-specific malloc support functions. Linux version.
++ Copyright (C) 2012 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <fcntl.h>
++#include <not-cancel.h>
++
++/* The Linux kernel overcommits address space by default and if there is not
++ enough memory available, it uses various parameters to decide the process to
++ kill. It is however possible to disable or curb this overcommit behavior
++ by setting the proc sysctl vm.overcommit_memory to the value '2' and with
++ that, a process is only allowed to use the maximum of a pre-determined
++ fraction of the total address space. In such a case, we want to make sure
++ that we are judicious with our heap usage as well, and explicitly give away
++ the freed top of the heap to reduce our commit charge. See the proc(5) man
++ page to know more about overcommit behavior.
++
++ Other than that, we also force an unmap in a secure exec. */
++static inline bool
++check_may_shrink_heap (void)
++{
++ static int may_shrink_heap = -1;
++
++ if (__builtin_expect (may_shrink_heap >= 0, 1))
++ return may_shrink_heap;
++
++ may_shrink_heap = __libc_enable_secure;
++
++ if (__builtin_expect (may_shrink_heap == 0, 1))
++ {
++ int fd = open_not_cancel_2 ("/proc/sys/vm/overcommit_memory",
++ O_RDONLY | O_CLOEXEC);
++ if (fd >= 0)
++ {
++ char val;
++ ssize_t n = read_not_cancel (fd, &val, 1);
++ may_shrink_heap = n > 0 && val == '2';
++ close_not_cancel_no_status (fd);
++ }
++ }
++
++ return may_shrink_heap;
++}
--- /dev/null
+From d6f67f7d833b4e2039f832355fb0edd65522c9f4 Mon Sep 17 00:00:00 2001
+From: Ulrich Drepper <drepper@gmail.com>
+Date: Sat, 14 May 2011 10:46:17 -0400
+Subject: [PATCH] Handle recursive calls in backtrace better
+
+---
+ ChangeLog | 7 +++++++
+ NEWS | 12 ++++++------
+ sysdeps/ia64/backtrace.c | 27 +++++++++++++++++++++++----
+ 3 files changed, 36 insertions(+), 10 deletions(-)
+
+ 2011-05-14 Ulrich Drepper <drepper@gmail.com>
+
+ [BZ #12432]
+ * sysdeps/ia64/backtrace.c (struct trace_reg): Add cfa element.
+ (dummy_getcfa): New function.
+ (init): Get _Unwind_GetCFA address, use dummy if not found.
+ (backtrace_helper): In recursion check, also check whether CFA changes.
+ (__backtrace): Completely initialize arg.
+
+diff --git a/sysdeps/ia64/backtrace.c b/sysdeps/ia64/backtrace.c
+index 5cefb86..d4ff291 100644
+--- a/sysdeps/ia64/backtrace.c
++++ b/sysdeps/ia64/backtrace.c
+@@ -1,5 +1,5 @@
+ /* Return backtrace of current program state.
+- Copyright (C) 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
++ Copyright (C) 2003-2005, 2007, 2009, 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+@@ -27,14 +27,26 @@
+ struct trace_arg
+ {
+ void **array;
+- int cnt, size;
++ _Unwind_Word cfa;
++ int cnt;
++ int size;
+ };
+
+ #ifdef SHARED
+ static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
+ static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
++static _Unwind_Word (*unwind_getcfa) (struct _Unwind_Context *);
+ static void *libgcc_handle;
+
++
++/* Dummy version in case libgcc_s does not contain the real code. */
++static _Unwind_Word
++dummy_getcfa (struct _Unwind_Context *ctx __attribute__ ((unused)))
++{
++ return 0;
++}
++
++
+ static void
+ init (void)
+ {
+@@ -47,10 +59,13 @@ init (void)
+ unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
+ if (unwind_getip == NULL)
+ unwind_backtrace = NULL;
++ unwind_getcfa = (__libc_dlsym (libgcc_handle, "_Unwind_GetCFA")
++ ?: dummy_getcfa);
+ }
+ #else
+ # define unwind_backtrace _Unwind_Backtrace
+ # define unwind_getip _Unwind_GetIP
++# define unwind_getcfa _Unwind_GetCFA
+ #endif
+
+ static _Unwind_Reason_Code
+@@ -65,8 +80,12 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
+ arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+
+ /* Check whether we make any progress. */
+- if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt])
++ _Unwind_Word cfa = unwind_getcfa (ctx);
++
++ if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
++ && cfa == arg->cfa)
+ return _URC_END_OF_STACK;
++ arg->cfa = cfa;
+ }
+ if (++arg->cnt == arg->size)
+ return _URC_END_OF_STACK;
+@@ -78,7 +97,7 @@ __backtrace (array, size)
+ void **array;
+ int size;
+ {
+- struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
++ struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
+ #ifdef SHARED
+ __libc_once_define (static, once);
+
+--
+1.7.1
+
--- /dev/null
+diff -pruN a/nptl/sysdeps/pthread/unwind-forcedunwind.c b/nptl/sysdeps/pthread/unwind-forcedunwind.c
+--- a/nptl/sysdeps/pthread/unwind-forcedunwind.c 2010-05-04 16:57:23.000000000 +0530
++++ b/nptl/sysdeps/pthread/unwind-forcedunwind.c 2014-06-02 23:00:02.901013275 +0530
+@@ -45,8 +45,10 @@ pthread_cancel_init (void)
+
+ if (__builtin_expect (libgcc_s_handle != NULL, 1))
+ {
+- /* Force gcc to reload all values. */
+- asm volatile ("" ::: "memory");
++ /* Order reads so as to prevent speculation of loads
++ of libgcc_s_{resume,personality,forcedunwind,getcfa}
++ to points prior to the write barrier. */
++ atomic_read_barrier ();
+ return;
+ }
+
+@@ -72,9 +74,14 @@ pthread_cancel_init (void)
+ libgcc_s_forcedunwind = forcedunwind;
+ PTR_MANGLE (getcfa);
+ libgcc_s_getcfa = getcfa;
+- /* Make sure libgcc_s_handle is written last. Otherwise,
+- pthread_cancel_init might return early even when the pointer the
+- caller is interested in is not initialized yet. */
++ /* At the point at which any thread writes the handle
++ to libgcc_s_handle, the initialization is complete.
++ The writing of libgcc_s_handle is atomic. All other
++ threads reading libgcc_s_handle do so atomically. Any
++ thread that does not execute this function must issue
++ a read barrier to ensure that all of the above has
++ actually completed and that the values of the
++ function pointers are correct. */
+ atomic_write_barrier ();
+ libgcc_s_handle = handle;
+ }
+@@ -91,11 +98,19 @@ __unwind_freeres (void)
+ }
+ }
+
+-void
+-_Unwind_Resume (struct _Unwind_Exception *exc)
++static __always_inline void
++_maybe_pthread_cancel_init (void)
+ {
+ if (__builtin_expect (libgcc_s_handle == NULL, 0))
+ pthread_cancel_init ();
++ else
++ atomic_read_barrier ();
++}
++
++void
++_Unwind_Resume (struct _Unwind_Exception *exc)
++{
++ _maybe_pthread_cancel_init ();
+
+ void (*resume) (struct _Unwind_Exception *exc) = libgcc_s_resume;
+ PTR_DEMANGLE (resume);
+@@ -108,8 +123,7 @@ __gcc_personality_v0 (int version, _Unwi
+ struct _Unwind_Exception *ue_header,
+ struct _Unwind_Context *context)
+ {
+- if (__builtin_expect (libgcc_s_handle == NULL, 0))
+- pthread_cancel_init ();
++ _maybe_pthread_cancel_init ();
+
+ _Unwind_Reason_Code (*personality)
+ (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+@@ -122,8 +136,7 @@ _Unwind_Reason_Code
+ _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
+ void *stop_argument)
+ {
+- if (__builtin_expect (libgcc_s_handle == NULL, 0))
+- pthread_cancel_init ();
++ _maybe_pthread_cancel_init ();
+
+ _Unwind_Reason_Code (*forcedunwind)
+ (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *)
+@@ -135,8 +148,7 @@ _Unwind_ForcedUnwind (struct _Unwind_Exc
+ _Unwind_Word
+ _Unwind_GetCFA (struct _Unwind_Context *context)
+ {
+- if (__builtin_expect (libgcc_s_handle == NULL, 0))
+- pthread_cancel_init ();
++ _maybe_pthread_cancel_init ();
+
+ _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa;
+ PTR_DEMANGLE (getcfa);
+diff -pruN a/sysdeps/gnu/unwind-resume.c b/sysdeps/gnu/unwind-resume.c
+--- a/sysdeps/gnu/unwind-resume.c 2010-05-04 16:57:23.000000000 +0530
++++ b/sysdeps/gnu/unwind-resume.c 2014-06-02 23:02:26.812007078 +0530
+@@ -20,8 +20,11 @@
+ #include <dlfcn.h>
+ #include <stdio.h>
+ #include <unwind.h>
++#include <pthreadP.h>
++#include <sysdep.h>
+ #include <libgcc_s.h>
+
++static void *libgcc_s_handle;
+ static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+ static _Unwind_Reason_Code (*libgcc_s_personality)
+ (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+@@ -42,13 +45,32 @@ init (void)
+
+ libgcc_s_resume = resume;
+ libgcc_s_personality = personality;
++ atomic_write_barrier ();
++ /* At the point at which any thread writes the handle
++ to libgcc_s_handle, the initialization is complete.
++ The writing of libgcc_s_handle is atomic. All other
++ threads reading libgcc_s_handle do so atomically. Any
++ thread that does not execute this function must issue
++ a read barrier to ensure that all of the above has
++ actually completed and that the values of the
++ function pointers are correct. */
++ libgcc_s_handle = handle;
+ }
+
++static __always_inline void
++_maybe_init (void)
++{
++ if (__builtin_expect (libgcc_s_handle == NULL, 0))
++ init ();
++ else
++ atomic_read_barrier ();
++}
++
++
+ void
+ _Unwind_Resume (struct _Unwind_Exception *exc)
+ {
+- if (__builtin_expect (libgcc_s_resume == NULL, 0))
+- init ();
++ _maybe_init ();
+ libgcc_s_resume (exc);
+ }
+
+@@ -58,8 +80,7 @@ __gcc_personality_v0 (int version, _Unwi
+ struct _Unwind_Exception *ue_header,
+ struct _Unwind_Context *context)
+ {
+- if (__builtin_expect (libgcc_s_personality == NULL, 0))
+- init ();
++ _maybe_init ();
+ return libgcc_s_personality (version, actions, exception_class,
+ ue_header, context);
+ }
--- /dev/null
+From decadad73858bc108828eed5540c7955dc2a977b Mon Sep 17 00:00:00 2001
+From: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date: Fri, 7 Jun 2013 14:44:58 -0500
+Subject: [PATCH 1/2] PowerPC: Change sched_getcpu to use vDSO getcpu instead of syscall.
+
+Backport of d5e0b9bd6e296f3ec5263fa296d39f3fed9b8fa2 from master.
+---
+ sysdeps/unix/sysv/linux/powerpc/Versions | 1 +
+ sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h | 2 +
+ sysdeps/unix/sysv/linux/powerpc/init-first.c | 3 ++
+ sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c | 30 ++++++++++++++++++++++
+ 4 files changed, 36 insertions(+), 0 deletions(-)
+ create mode 100644 sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
+
+diff --git a/sysdeps/unix/sysv/linux/powerpc/Versions b/sysdeps/unix/sysv/linux/powerpc/Versions
+index 1ef53b9..396a423 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/Versions
++++ b/sysdeps/unix/sysv/linux/powerpc/Versions
+@@ -3,5 +3,6 @@ libc {
+ __vdso_get_tbfreq;
+ __vdso_clock_gettime;
+ __vdso_clock_getres;
++ __vdso_getcpu;
+ }
+ }
+diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+index 746d9ce..c3026d5 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
++++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+@@ -31,6 +31,8 @@ extern void *__vdso_clock_getres;
+
+ extern void *__vdso_get_tbfreq;
+
++extern void *__vdso_getcpu;
++
+ #endif
+
+ #endif /* _LIBC_VDSO_H */
+diff --git a/sysdeps/unix/sysv/linux/powerpc/init-first.c b/sysdeps/unix/sysv/linux/powerpc/init-first.c
+index 92dacc7..cfed655 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/init-first.c
++++ b/sysdeps/unix/sysv/linux/powerpc/init-first.c
+@@ -27,6 +27,7 @@ void *__vdso_gettimeofday attribute_hidden;
+ void *__vdso_clock_gettime;
+ void *__vdso_clock_getres;
+ void *__vdso_get_tbfreq;
++void *__vdso_getcpu;
+
+
+ static inline void
+@@ -41,6 +42,8 @@ _libc_vdso_platform_setup (void)
+ __vdso_clock_getres = _dl_vdso_vsym ("__kernel_clock_getres", &linux2615);
+
+ __vdso_get_tbfreq = _dl_vdso_vsym ("__kernel_vdso_get_tbfreq", &linux2615);
++
++ __vdso_getcpu = _dl_vdso_vsym ("__kernel_getcpu", &linux2615);
+ }
+
+ # define VDSO_SETUP _libc_vdso_platform_setup
+diff --git a/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c b/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
+new file mode 100644
+index 0000000..617e6f1
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
+@@ -0,0 +1,30 @@
++/* Copyright (C) 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <sched.h>
++#include <sysdep.h>
++#include <bits/libc-vdso.h>
++
++
++int
++sched_getcpu (void)
++{
++ unsigned int cpu;
++ int r = INLINE_VSYSCALL (getcpu, 3, &cpu, NULL, NULL);
++
++ return r == -1 ? r : cpu;
++}
+--
+1.7.1
+
--- /dev/null
+Patch attached to bugzilla by Ankit Patel, from Red Hat translation team.
+
+Index: glibc-2.12-2-gc4ccff1/po/de.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/de.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/de.po 2013-07-23 20:35:03.213177408 -0300
+@@ -2396,14 +2396,14 @@ msgstr "Zu viele Benutzer"
+ msgid "Disk quota exceeded"
+ msgstr "Der zugewiesene Plattenplatz (Quota) ist überschritten"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "Veraltete NFS-Dateizugriffsnummer"
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Veraltetes Datei-Handle"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/es.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/es.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/es.po 2013-07-23 20:35:03.243175029 -0300
+@@ -2533,14 +2533,14 @@ msgstr "Se ha excedido la cuota de disco
+ # Muy bien, he buscado "stale" y por lo que parece es algo que "caduca"
+ # o que "vence", como las letras comerciales. Me he decidido por "en desuso".
+ #
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "`handle' de fichero NFS en desuso"
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Identificador de archivos obsoletos"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/fr.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/fr.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/fr.po 2013-07-23 20:35:03.250174474 -0300
+@@ -5802,13 +5802,14 @@ msgstr "Trop d'usagers"
+ msgid "Disk quota exceeded"
+ msgstr "Débordement du quota d'espace disque"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr "Panne d'accès au fichier NFS"
++msgid "Stale file handle"
++msgstr "Gestionnaire de fichiers périmés"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/it.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/it.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/it.po 2013-07-23 20:35:03.253174237 -0300
+@@ -1662,6 +1662,15 @@ msgstr "Superata la quota di disco"
+ msgid "Disk quota exceeded"
+ msgstr "Superata la quota di disco"
+
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Gestione file obsoleti"
++
+ #: nscd/nscd.c:86
+ msgid "Do not fork and display messages on the current tty"
+ msgstr "Non fa fork e stampa i messaggi sul tty corrente"
+Index: glibc-2.12-2-gc4ccff1/po/ja.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/ja.po 2013-07-23 04:01:34.628665260 -0300
++++ glibc-2.12-2-gc4ccff1/po/ja.po 2013-07-23 20:35:03.304170193 -0300
+@@ -2333,14 +2333,14 @@ msgstr "¥æ¡¼¥¶¤¬Â¿¤¹¤®¤Þ¤¹"
+ msgid "Disk quota exceeded"
+ msgstr "¥Ç¥£¥¹¥¯»ÈÍÑÎÌÀ©¸Â¤òĶ²á¤·¤Þ¤·¤¿"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "¼Â¸úÀ¤Î¤Ê¤¤NFS¥Õ¥¡¥¤¥ë¥Ï¥ó¥É¥ë¤Ç¤¹"
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "¸Å¤¤¥Õ¥¡¥¤¥ë¥Ï¥ó¥É¥ë¤Ç¤¹"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/ko.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/ko.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/ko.po 2013-07-23 20:35:03.311169638 -0300
+@@ -5803,13 +5803,14 @@ msgstr "사용자가 너무 많음"
+ msgid "Disk quota exceeded"
+ msgstr "디스크 할당량이 초과됨"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr "끊어진 NFS 파일 핸들"
++msgid "Stale file handle"
++msgstr "오래된 파일 처리"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/libc.pot
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/libc.pot 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/libc.pot 2013-07-23 20:35:03.326168449 -0300
+@@ -5696,12 +5696,13 @@ msgstr ""
+ msgid "Disk quota exceeded"
+ msgstr ""
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
++msgid "Stale file handle"
+ msgstr ""
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+Index: glibc-2.12-2-gc4ccff1/po/pt_BR.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/pt_BR.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/pt_BR.po 2013-07-23 20:35:03.331168053 -0300
+@@ -2287,13 +2287,14 @@ msgstr "Erro de Srmount"
+ msgid "Stack fault"
+ msgstr "Falha de pilha"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:506
+-msgid "Stale NFS file handle"
+-msgstr "Manipulador de arquivo NFS corrompido"
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Manipulador de arquivo obsoleto"
+
+ #: nscd/nscd.c:81
+ msgid "Start NUMBER threads"
+Index: glibc-2.12-2-gc4ccff1/po/ru.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/ru.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/ru.po 2013-07-23 20:35:03.338167498 -0300
+@@ -5798,13 +5798,14 @@ msgstr "Слишком много пол
+ msgid "Disk quota exceeded"
+ msgstr "Превышена дисковая квота"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr "Устаревший хэндл файла NFS"
++msgid "Stale file handle"
++msgstr "Устаревший дескриптор файла"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/zh_CN.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/zh_CN.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/zh_CN.po 2013-07-23 20:35:03.344167022 -0300
+@@ -5519,13 +5519,14 @@ msgstr "用户过多"
+ msgid "Disk quota exceeded"
+ msgstr "超出磁盘限额"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr ""
++msgid "Stale file handle"
++msgstr "失效文件句柄"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/zh_TW.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/zh_TW.po 2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/zh_TW.po 2013-07-23 20:35:03.349166626 -0300
+@@ -2333,14 +2333,14 @@ msgstr "太多使用者"
+ msgid "Disk quota exceeded"
+ msgstr "硬碟 quota 滿了"
+
+-#. TRANS Stale NFS file handle. This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "過舊的 NFS 檔案控制碼"
++#. TRANS Stale file handle. This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "過舊的檔案處理"
+
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
--- /dev/null
+#
+# Based on commit e6c61494125126d2ba77e5d99f83887a2ed49783.
+#
+# 2011-04-10 Ulrich Drepper <drepper@gmail.com>
+#
+# [BZ #12650]
+# * sysdeps/i386/dl-tls.h: Define TLS_DTV_UNALLOCATED.
+# * sysdeps/ia64/dl-tls.h: Likewise.
+# * sysdeps/powerpc/dl-tls.h: Likewise.
+# * sysdeps/s390/dl-tls.h: Likewise.
+# * sysdeps/sh/dl-tls.h: Likewise.
+# * sysdeps/sparc/dl-tls.h: Likewise.
+# * sysdeps/x86_64/dl-tls.h: Likewise.
+# * elf/dl-tls.c: Don't define TLS_DTV_UNALLOCATED here.
+#
+diff -urN glibc-2.12-2-gc4ccff1/elf/dl-tls.c glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c
+--- glibc-2.12-2-gc4ccff1/elf/dl-tls.c 2015-02-18 05:16:56.087096028 -0500
++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c 2015-02-18 05:21:04.018424445 -0500
+@@ -33,9 +33,6 @@
+ to allow dynamic loading of modules defining IE-model TLS data. */
+ #define TLS_STATIC_SURPLUS 64 + DL_NNS * 100
+
+-/* Value used for dtv entries for which the allocation is delayed. */
+-#define TLS_DTV_UNALLOCATED ((void *) -1l)
+-
+
+ /* Out-of-memory handler. */
+ #ifdef SHARED
+diff -urN glibc-2.12-2-gc4ccff1/nptl/allocatestack.c glibc-2.12-2-gc4ccff1.mod/nptl/allocatestack.c
+--- glibc-2.12-2-gc4ccff1/nptl/allocatestack.c 2015-02-18 05:16:56.101095594 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/allocatestack.c 2015-02-18 05:21:04.019424414 -0500
+@@ -26,6 +26,7 @@
+ #include <sys/mman.h>
+ #include <sys/param.h>
+ #include <dl-sysdep.h>
++#include <dl-tls.h>
+ #include <tls.h>
+ #include <list.h>
+ #include <lowlevellock.h>
+@@ -242,6 +243,10 @@
+
+ /* Clear the DTV. */
+ dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
++ for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
++ if (! dtv[1 + cnt].pointer.is_static
++ && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
++ free (dtv[1 + cnt].pointer.val);
+ memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+
+ /* Re-initialize the TLS. */
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/i386/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/i386/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/i386/dl-tls.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/i386/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -58,3 +58,6 @@
+
+ # endif
+ #endif
++
++/* Value used for dtv entries for which the allocation is delayed. */
++#define TLS_DTV_UNALLOCATED ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/ia64/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/ia64/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/ia64/dl-tls.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/ia64/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -28,3 +28,6 @@
+ #define DONT_USE_TLS_INDEX 1
+
+ extern void *__tls_get_addr (size_t m, size_t offset);
++
++/* Value used for dtv entries for which the allocation is delayed. */
++#define TLS_DTV_UNALLOCATED ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/powerpc/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/powerpc/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/powerpc/dl-tls.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/powerpc/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -47,3 +47,6 @@
+ # define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET)
+ # define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
+ #endif
++
++/* Value used for dtv entries for which the allocation is delayed. */
++#define TLS_DTV_UNALLOCATED ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/s390/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/s390/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/s390/dl-tls.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/s390/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -72,6 +72,9 @@
+ # 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 (); })
++ + (unsigned long) __builtin_thread_pointer (); })
+
+ #endif
++
++/* Value used for dtv entries for which the allocation is delayed. */
++#define TLS_DTV_UNALLOCATED ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/sh/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/sh/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/sh/dl-tls.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/sh/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -27,3 +27,6 @@
+
+
+ extern void *__tls_get_addr (tls_index *ti);
++
++/* Value used for dtv entries for which the allocation is delayed. */
++#define TLS_DTV_UNALLOCATED ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/sparc/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/sparc/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/sparc/dl-tls.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/sparc/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -27,3 +27,6 @@
+
+
+ extern void *__tls_get_addr (tls_index *ti);
++
++/* Value used for dtv entries for which the allocation is delayed. */
++#define TLS_DTV_UNALLOCATED ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-tls.h 2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -27,3 +27,6 @@
+
+
+ extern void *__tls_get_addr (tls_index *ti);
++
++/* Value used for dtv entries for which the allocation is delayed. */
++#define TLS_DTV_UNALLOCATED ((void *) -1l)
--- /dev/null
+commit 2e96f1c73b06e81da59ef7fffa426dc201875f31
+Author: Andreas Schwab <schwab@redhat.com>
+Date: Thu Aug 4 15:42:10 2011 -0400
+
+ Fix encoding name for IDN in getaddrinfo
+
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index 6d574c5..a5aafe9 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -432,7 +432,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ /* In case the output string is the same as the input string
+ no new string has been allocated. */
+ if (p != name)
+- malloc_name = true;
++ {
++ name = p;
++ malloc_name = true;
++ }
+ }
+ #endif
+
--- /dev/null
+commit e23fe25b33324a9ea992276c1a4f04127bf9ba4b
+Author: Andreas Schwab <schwab@redhat.com>
+Date: Sun Feb 20 07:24:56 2011 -0500
+
+ Move setting variable in relro data earlier in ld.so.
+
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 8510380..174954b 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2179,6 +2179,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ we need it in the memory handling later. */
+ GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist;
+
++ /* Remember the last search directory added at startup, now that
++ malloc will no longer be the one from dl-minimal.c. */
++ GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
++
+ if (prelinked)
+ {
+ if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
+@@ -2298,9 +2302,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ lossage);
+ }
+
+- /* Remember the last search directory added at startup, now that
+- malloc will no longer be the one from dl-minimal.c. */
+- GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
++ /* Make sure no new search directories have been added. */
++ assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
+
+ if (! prelinked && rtld_multiple_ref)
+ {