summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--Makerules4
-rwxr-xr-xautolock.sh45
-rw-r--r--config.make.in1
-rw-r--r--configure.in2
-rw-r--r--nss.h1
-rw-r--r--nss/Makefile5
-rw-r--r--nss/XXX-lookup.c11
-rw-r--r--nss/databases.def31
-rw-r--r--nss/nss.h54
-rw-r--r--nss/nsswitch.c116
-rw-r--r--nss/nsswitch.h15
-rw-r--r--string/Makefile2
-rw-r--r--sysdeps/alpha/divrem.h4
-rw-r--r--sysdeps/alpha/dl-machine.h28
-rw-r--r--sysdeps/generic/sbrk.c21
16 files changed, 271 insertions, 79 deletions
diff --git a/ChangeLog b/ChangeLog
index ac5bb966b6..c563e74df9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Aug 12 04:33:09 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	* nss/nsswitch.c (__nss_database_lookup): Always release locks
+ 	before returning.  Reported by Miles Bader.
+
 Mon Aug 12 03:31:58 1996  Ulrich Drepper  <drepper@cygnus.com>
 
 	* nss/nsswitch.c (__nss_configure_lookup):  New function.
@@ -11,7 +16,7 @@ Mon Aug 12 03:31:58 1996  Ulrich Drepper  <drepper@cygnus.com>
 	* nss.h: New file.  Wrapper around nss/nss.h.
 
 	* nss/Makefile (headers): Add nss.h.
-	(distributes): Add databases.h.
+	(distributes): Add databases.def.
 
 Sun Aug 11 16:19:42 1996  Ulrich Drepper  <drepper@cygnus.com>
 
@@ -27,9 +32,6 @@ Sun Aug 11 16:19:42 1996  Ulrich Drepper  <drepper@cygnus.com>
 
 	* string/Makefile: Add -fno-builtin for tst-strlen.c, too.
 
-	* elf/dl-lookup.c (_dl_lookup_symbol): Allow self-referencing.
-	Patch by David Mosberger-Tang.
-
 Sun Aug 11 01:12:38 1996  Richard Henderson  <rth@tamu.edu>
 
 	* sysdeps/alpha/dl-machine.h (elf_alpha_fix_plt): Optimize LD_BIND_NOW
diff --git a/Makerules b/Makerules
index f2d190a57a..4248dad91c 100644
--- a/Makerules
+++ b/Makerules
@@ -455,8 +455,8 @@ object-suffixes-left := $(object-suffixes)
 include $(o-iterator)
 define do-ar
 $(patsubst %,cd %;,$(objdir)) \
-$(AR) cru$(verbose) ${O%-lib} \
-      $(patsubst $(objpfx)%,%,$^)
+$(AUTOLOCK) ${O%-lib}.lck $(AR) cru$(verbose) ${O%-lib} \
+				$(patsubst $(objpfx)%,%,$^)
 rm -f $@
 touch $@
 endef
diff --git a/autolock.sh b/autolock.sh
new file mode 100755
index 0000000000..88e27332e6
--- /dev/null
+++ b/autolock.sh
@@ -0,0 +1,45 @@
+#! /bin/sh
+# interlock - wrap program invocation in lock to allow
+#             parallel builds to work.
+# Written by Tom Tromey <tromey@cygnus.com>, Aug 10 1996
+#
+# 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; either version 2, 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.
+
+# Usage:
+#   interlock lock-dir-name program args-to-program...
+
+dirname="$1"
+program="$2"
+
+shift
+shift
+
+while (mkdir $dirname > /dev/null 2>&1 && exit 1 || exit 0); do
+   # Wait a bit.
+   sleep 1
+done
+
+# Race condition here: if interrupted after the loop but before this
+# trap, the lock can be left around.
+trap "rmdir $dirname > /dev/null 2>&1" 1 2 3 15
+
+# We have the lock, so run the program.
+$program ${1+"$@"}
+ret=$?
+
+# Release the lock.
+rmdir $dirname > /dev/null 2>&1
+
+exit $ret
diff --git a/config.make.in b/config.make.in
index b099199c36..a496e29f0d 100644
--- a/config.make.in
+++ b/config.make.in
@@ -34,6 +34,7 @@ CC = @CC@
 BUILD_CC = @BUILD_CC@
 CFLAGS = @CFLAGS@
 AR = @AR@
+AUTOLOCK = @AUTOLOCK@
 RANLIB = @RANLIB@
 AS = $(CC) -c
 
diff --git a/configure.in b/configure.in
index 631a035e92..aebc785904 100644
--- a/configure.in
+++ b/configure.in
@@ -308,6 +308,8 @@ fi
 AC_PROG_CPP
 AC_CHECK_TOOL(AR, ar)
 AC_CHECK_TOOL(RANLIB, ranlib, :)
+AUTOLOCK="`(cd $srcdir; pwd)`/autolock.sh"
+AC_SUBST(AUTOLOCK)
 
 AC_CACHE_CHECK(for signed size_t type, libc_cv_signed_size_t, [dnl
 echo '#include <stddef.h>
diff --git a/nss.h b/nss.h
new file mode 100644
index 0000000000..0541335c18
--- /dev/null
+++ b/nss.h
@@ -0,0 +1 @@
+#include <nss/nss.h>
diff --git a/nss/Makefile b/nss/Makefile
index f23f5f3fbb..5dcae4d40e 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -21,13 +21,16 @@
 #
 subdir	:= nss
 
+headers			:= nss.h
 distribute		:= nsswitch.h XXX-lookup.c getXXbyYY.c getXXbyYY_r.c \
-			   getXXent.c getXXent_r.c
+			   getXXent.c getXXent_r.c databases.def
 
 # This is the trivial part which goes into libc itself.
 routines		= nsswitch $(addsuffix -lookup,$(databases))
 
 # These are the databases that go through nss dispatch.
+# Caution: if you add a database here, you must add its real name
+# in databases.def, too.
 databases		= proto service hosts network grp pwd rpc ethers \
 			  spwd
 
diff --git a/nss/XXX-lookup.c b/nss/XXX-lookup.c
index 4a2d25cb42..1b43018d47 100644
--- a/nss/XXX-lookup.c
+++ b/nss/XXX-lookup.c
@@ -35,25 +35,26 @@ Boston, MA 02111-1307, USA.  */
 #define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
 #define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
 
+#define DATABASE_NAME_SYMBOL CONCAT3_1 (__nss_, DATABASE_NAME, _database)
 #define DATABASE_NAME_STRING STRINGIFY1 (DATABASE_NAME)
 #define STRINGIFY1(Name) STRINGIFY2 (Name)
 #define STRINGIFY2(Name) #Name
 
 #ifndef DEFAULT_CONFIG
-#define DEFAULT_CONFIG 0
+#define DEFAULT_CONFIG NULL
 #endif
 
-static service_user *database = NULL;
+service_user *DATABASE_NAME_SYMBOL = NULL;
 
 int
 DB_LOOKUP_FCT (service_user **ni, const char *fct_name, void **fctp)
 {
-  if (database == NULL
+  if (DATABASE_NAME_SYMBOL == NULL
       && __nss_database_lookup (DATABASE_NAME_STRING, DEFAULT_CONFIG,
-				&database) < 0)
+				&DATABASE_NAME_SYMBOL) < 0)
     return -1;
 
-  *ni = database;
+  *ni = DATABASE_NAME_SYMBOL;
 
   return __nss_lookup (ni, fct_name, fctp);
 }
diff --git a/nss/databases.def b/nss/databases.def
new file mode 100644
index 0000000000..98772bac76
--- /dev/null
+++ b/nss/databases.def
@@ -0,0 +1,31 @@
+/* List of all databases defined for the NSS in GNU C Library.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* This list must be kept sorted!!!  */
+
+DEFINE_DATABASE (ethers)
+DEFINE_DATABASE (group)
+DEFINE_DATABASE (hosts)
+DEFINE_DATABASE (networks)
+DEFINE_DATABASE (passwd)
+DEFINE_DATABASE (protocols)
+DEFINE_DATABASE (rpc)
+DEFINE_DATABASE (services)
+DEFINE_DATABASE (shadow)
diff --git a/nss/nss.h b/nss/nss.h
new file mode 100644
index 0000000000..e9acb93bcc
--- /dev/null
+++ b/nss/nss.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 1996 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Define interface to NSS.  This is meant for the interface functions
+   and for implementors of new services.  */
+
+#ifndef _NSS_H
+
+#define _NSS_H	1
+#include <features.h>
+
+/* Revision number of NSS interface (must be a string).  */
+#define NSS_SHLIB_REVISION ".1"
+
+
+__BEGIN_DECLS
+
+/* Possible results of lookup using a nss_* function.  */
+enum nss_status
+{
+  NSS_STATUS_TRYAGAIN = -2,
+  NSS_STATUS_UNAVAIL,
+  NSS_STATUS_NOTFOUND,
+  NSS_STATUS_SUCCESS,
+};
+
+
+/* Overwrite service selection for database DBNAME using specification
+   in STRING.
+   This function should only be used by system programs which have to
+   work around non-existing services (e.e., while booting).
+   Attention: Using this function repeatedly will slowly eat up the
+   whole memory since previous selection data cannot be freed.  */
+extern int __nss_configure_lookup __P ((__const char *__dbname,
+					__const char *__string));
+
+__END_DECLS
+
+#endif /* nss.h */
diff --git a/nss/nsswitch.c b/nss/nsswitch.c
index 1349e0ca08..0a4c9482d2 100644
--- a/nss/nsswitch.c
+++ b/nss/nsswitch.c
@@ -19,6 +19,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <ctype.h>
 #include <dlfcn.h>
+#include <errno.h>
 #include <netdb.h>
 #include <libc-lock.h>
 #include <search.h>
@@ -30,7 +31,6 @@ Boston, MA 02111-1307, USA.  */
 #include "../elf/link.h"	/* We need some help from ld.so.  */
 
 /* Prototypes for the local functions.  */
-static void nss_init (void);
 static void *nss_lookup_function (service_user *ni, const char *fct_name);
 static name_database *nss_parse_file (const char *fname);
 static name_database_entry *nss_getline (char *line);
@@ -39,6 +39,27 @@ static service_library *nss_new_service (name_database *database,
 					 const char *name);
 
 
+/* Declare external database variables.  */
+#define DEFINE_DATABASE(name)						      \
+  extern service_user *__nss_##name##_database;				      \
+  weak_extern (__nss_##name##_database)
+#include "databases.def"
+#undef DEFINE_DATABASE
+
+/* Structure to map database name to variable.  */
+static struct
+{
+  const char *name;
+  service_user **dbp;
+} databases[] =
+{
+#define DEFINE_DATABASE(name)						      \
+  { #name, &__nss_##name##_database },
+#include "databases.def"
+#undef DEFINE_DATABASE
+};
+
+
 __libc_lock_define_initialized (static, lock)
 
 
@@ -50,35 +71,29 @@ static int nss_initialized;
 static name_database *service_table;
 
 
-static void
-nss_init (void)
-{
-  /* Prevent multiple threads to change the service table.  */
-  __libc_lock_lock (lock);
-
-  if (service_table == NULL)
-    service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
-
-  __libc_lock_unlock (lock);
-}
-
-
 /* -1 == database not found
     0 == database entry pointer stored */
 int
 __nss_database_lookup (const char *database, const char *defconfig,
 		       service_user **ni)
 {
-  name_database_entry *entry;
+  /* Prevent multiple threads to change the service table.  */
+  __libc_lock_lock (lock);
 
-  if (nss_initialized == 0)
-    nss_init ();
+  /* Reconsider database variable in case some other thread called
+     `__nss_configure_lookup' while we waited for the lock.  */
+  if (*ni != NULL)
+    return 0;
+
+  if (nss_initialized == 0 && service_table == NULL)
+    /* Read config file.  */
+    service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
 
   /* Test whether configuration data is available.  */
-  if (service_table)
+  if (service_table != NULL)
     {
-      /* Return first `service_user' entry for DATABASE.
-	 XXX Will use perfect hashing function for known databases.  */
+      /* Return first `service_user' entry for DATABASE.  */
+      name_database_entry *entry;
 
       /* XXX Could use some faster mechanism here.  But each database is
 	 only requested once and so this might not be critical.  */
@@ -91,17 +106,14 @@ __nss_database_lookup (const char *database, const char *defconfig,
     }
 
   /* No configuration data is available, either because nsswitch.conf
-     doesn't exist or because it doesn't have a line for this database.  */
-  entry = malloc (sizeof *entry);
-  if (entry == NULL)
-    return -1;
-  entry->name = database;
-  /* DEFCONFIG specifies the default service list for this database,
+     doesn't exist or because it doesn't has a line for this database.
+
+     DEFCONFIG specifies the default service list for this database,
      or null to use the most common default.  */
-  entry->service = nss_parse_service_list (defconfig ?:
-					   "compat [NOTFOUND=return] files");
+  *ni = nss_parse_service_list (defconfig ?: "compat [NOTFOUND=return] files");
+
+  __libc_lock_unlock (lock);
 
-  *ni = entry->service;
   return 0;
 }
 
@@ -168,6 +180,48 @@ __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
 }
 
 
+int
+__nss_configure_lookup (const char *dbname, const char *service_line)
+{
+  service_user *new_db;
+  size_t cnt;
+
+  for (cnt = 0; cnt < sizeof databases; ++cnt)
+    if (strcmp (dbname, databases[cnt].name) == 0)
+      break;
+
+  if (cnt == sizeof databases)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* Test whether it is really used.  */
+  if (databases[cnt].dbp == NULL)
+    /* Nothing to do, but we could do.  */
+    return 0;
+
+  /* Try to generate new data.  */
+  new_db = nss_parse_service_list (service_line);
+  if (new_db == NULL)
+    {
+      /* Illegal service specification.  */
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* Prevent multiple threads to change the service table.  */
+  __libc_lock_lock (lock);
+
+  /* Install new rules.  */
+  *databases[cnt].dbp = new_db;
+
+  __libc_lock_unlock (lock);
+
+  return 0;
+}
+
+
 static int
 nss_dlerror_run (void (*operate) (void))
 {
@@ -385,7 +439,9 @@ nss_parse_file (const char *fname)
 }
 
 
-/* Read the source names: `<source> ( "[" <status> "=" <action> "]" )*'.  */
+/* Read the source names:
+	`( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
+   */
 static service_user *
 nss_parse_service_list (const char *line)
 {
diff --git a/nss/nsswitch.h b/nss/nsswitch.h
index c4d4d11193..0c99f147fd 100644
--- a/nss/nsswitch.h
+++ b/nss/nsswitch.h
@@ -23,24 +23,11 @@ Boston, MA 02111-1307, USA.  */
 
 #include <arpa/nameser.h>
 #include <netinet/in.h>
+#include <nss.h>
 #include <resolv.h>
 #include <search.h>
 
 
-/* Revision number of NSS interface (must be a string).  */
-#define NSS_SHLIB_REVISION ".1"
-
-
-/* Possible results of lookup using a nss_* function.  */
-enum nss_status
-{
-  NSS_STATUS_TRYAGAIN = -2,
-  NSS_STATUS_UNAVAIL,
-  NSS_STATUS_NOTFOUND,
-  NSS_STATUS_SUCCESS,
-};
-
-
 /* Actions performed after lookup finished.  */
 typedef enum
 {
diff --git a/string/Makefile b/string/Makefile
index f67e7247d4..c120b7da2c 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -45,3 +45,5 @@ distribute	:= memcopy.h pagecopy.h
 include ../Rules
 
 tester-ENV = LANGUAGE=C
+CFLAGS-tester.c = -fno-builtin
+CFLAGS-tst-strlen.c = -fno-builtin
diff --git a/sysdeps/alpha/divrem.h b/sysdeps/alpha/divrem.h
index b5b66ae10b..eaf892b3c6 100644
--- a/sysdeps/alpha/divrem.h
+++ b/sysdeps/alpha/divrem.h
@@ -29,8 +29,8 @@ division.  The C compiler expects the functions
 
 These are not normal C functions: instead of the normal calling
 sequence, these expect their arguments in registers t10 and t11, and
-return the result in t12 (aka pv). Registers AT and v0 may be
-clobbered (assembly temporary), anything else must be saved.  */
+return the result in t12 (aka pv). Register AT may be clobbered
+(assembly temporary), anything else must be saved.  */
 
 #include <sysdep.h>
 
diff --git a/sysdeps/alpha/dl-machine.h b/sysdeps/alpha/dl-machine.h
index b900b769ee..a75011fccb 100644
--- a/sysdeps/alpha/dl-machine.h
+++ b/sysdeps/alpha/dl-machine.h
@@ -135,8 +135,8 @@ _dl_runtime_resolve:
 	stq	$29, 160($sp)
 	.mask	0x27ff01ff, -168
 	/* Set up our $gp */
-	br	$gp, .+4
-	ldgp	$gp, 0($gp)
+	br	$gp, 0f
+0:	ldgp	$gp, 0($gp)
 	.prologue 1
 	/* Set up the arguments for _dl_runtime_resolve. */
 	/* $16 = link_map out of plt0 */
@@ -145,7 +145,7 @@ _dl_runtime_resolve:
 	mov	$28, $17
 	/* Do the fixup */
 	bsr	$26, fixup..ng
-	/* Move the destination address to a safe place.  */
+	/* Move the destination address into position.  */
 	mov	$0, $27
 	/* Restore program registers.  */
 	ldq	$26, 0($sp)
@@ -169,19 +169,16 @@ _dl_runtime_resolve:
 	ldq	$24, 144($sp)
 	ldq	$25, 152($sp)
 	ldq	$29, 160($sp)
+	/* Flush the Icache after having modified the .plt code.  */
+	imb
 	/* Clean up and turn control to the destination */
 	lda	$sp, 168($sp)
 	jmp	$31, ($27)
 	.end _dl_runtime_resolve");
 
-/* The PLT uses Elf_Rel relocs.  */
+/* The PLT uses Elf64_Rela relocs.  */
 #define elf_machine_relplt elf_machine_rela
 
-/* Mask identifying addresses reserved for the user program,
-   where the dynamic linker should not map anything.  */
-/* FIXME */
-#define ELF_MACHINE_USER_ADDRESS_MASK	(~0x1FFFFFFFFUL)
-
 /* Initial entry point code for the dynamic linker.
    The C function `_dl_start' is the real entry point;
    its return value is the user program's entry point.  */
@@ -191,8 +188,8 @@ _dl_runtime_resolve:
 	.globl _start
 	.globl _dl_start_user
 _start:
-	br	$gp,.+4
-	ldgp	$gp, 0($gp)
+	br	$gp,0f
+0:	ldgp	$gp, 0($gp)
 	/* Pass pointer to argument block to _dl_start.  */
 	mov	$sp, $16
 	bsr	$26, _dl_start..ng
@@ -226,7 +223,7 @@ _dl_start_user:
 	mov	$9, $27
 	jmp	($9)");
 
-/* Nonzero iff TYPE describes relocation of a PLT entry, so 
+/* Nonzero iff TYPE describes relocation of a PLT entry, so
    PLT entries should not be allowed to define the value.  */
 #define elf_machine_pltrel_p(type)  ((type) == R_ALPHA_JMP_SLOT)
 
@@ -302,9 +299,10 @@ elf_alpha_fix_plt(struct link_map *l,
       plte[2] = 0x6bfb0000;
     }
 
-  /* Flush the instruction cache now that we've diddled.   Tag it as
-     modifying memory to checkpoint memory writes during optimization.  */
-  asm volatile("call_pal 0x86" : : : "memory");
+  /* At this point, if we've been doing runtime resolution, Icache is dirty.
+     This will be taken care of in _dl_runtime_resolve.  If instead we are
+     doing this as part of non-lazy startup relocation, that bit of code
+     hasn't made it into Icache yet, so there's nothing to clean up.  */
 }
 
 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
diff --git a/sysdeps/generic/sbrk.c b/sysdeps/generic/sbrk.c
index 698f814e2b..92ad8c4102 100644
--- a/sysdeps/generic/sbrk.c
+++ b/sysdeps/generic/sbrk.c
@@ -22,6 +22,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern void *__curbrk;
 extern int __brk (void *addr);
 
+#ifdef PIC
+extern int __libc_is_static;
+weak_extern (__libc_is_static)
+#endif
+
 /* Extend the process's data space by INCREMENT.
    If INCREMENT is negative, shrink data space by - INCREMENT.
    Return start of new space allocated, or -1 for errors.  */
@@ -30,12 +35,16 @@ __sbrk (ptrdiff_t increment)
 {
   void *oldbrk;
 
-  /* Always update __curbrk from the kernel's brk value.  That way two
-     separate instances of __brk and __sbrk can share the heap, returning
-     interleaved pieces of it.  This happens when libc.so is loaded by
-     dlopen in a statically-linked program that already uses __brk.  */
-  if (__brk (0) < 0)
-    return (void *) -1;
+  /* If this is not part of the dynamic library or the library is used
+     via dynamic loading in a statically linked program update
+     __curbrk from the kernel's brk value.  That way two separate
+     instances of __brk and __sbrk can share the heap, returning
+     interleaved pieces of it.  */
+#ifdef PIC
+  if (__curbrk == NULL || &__libc_is_static == NULL)
+#endif
+    if (__brk (0) < 0)
+      return (void *) -1;
 
   if (increment == 0)
     return __curbrk;