+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.
* 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>
* 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
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
--- /dev/null
+#! /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
BUILD_CC = @BUILD_CC@
CFLAGS = @CFLAGS@
AR = @AR@
+AUTOLOCK = @AUTOLOCK@
RANLIB = @RANLIB@
AS = $(CC) -c
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>
--- /dev/null
+#include <nss/nss.h>
#
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
#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);
}
--- /dev/null
+/* 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)
--- /dev/null
+/* 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 */
#include <ctype.h>
#include <dlfcn.h>
+#include <errno.h>
#include <netdb.h>
#include <libc-lock.h>
#include <search.h>
#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);
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)
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. */
}
/* 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;
}
}
+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))
{
}
-/* Read the source names: `<source> ( "[" <status> "=" <action> "]" )*'. */
+/* Read the source names:
+ `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
+ */
static service_user *
nss_parse_service_list (const char *line)
{
#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
{
include ../Rules
tester-ENV = LANGUAGE=C
+CFLAGS-tester.c = -fno-builtin
+CFLAGS-tst-strlen.c = -fno-builtin
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>
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 */
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)
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. */
.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
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)
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).
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. */
{
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;