summaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux/init-first.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1999-05-26 23:37:38 +0000
committerUlrich Drepper <drepper@redhat.com>1999-05-26 23:37:38 +0000
commit958f238f3619373d3dbc106d3cda3c467b3419b1 (patch)
tree9d15d47658aeaae08ee7e5e5e9d4a63d034caa49 /sysdeps/unix/sysv/linux/init-first.c
parent475e390e80a950a8746dc0b88341742dc99014e4 (diff)
Update.
1999-05-26 Ulrich Drepper <drepper@cygnus.com> * config.h.in: Add __LINUX_KERNEL_VERSION. * configure.in: Recognize --enable-kernel. * sysdeps/unix/sysv/linux/configure.in: Check for correct kernel headers if --enable-kernel is given and set __LINUX_KERNEL_VERSION appropriately. * sysdeps/unix/sysv/linux/init-first.c: If minimal kernel version is given perform runtime test. * sysdeps/unix/sysv/linux/kernel-features.h: New file. * sysdeps/unix/sysv/linux/getcwd.c: Elide compatibility code if minimal supported kernel is known to have the feature. * sysdeps/unix/sysv/linux/poll.c: Likewise. * sysdeps/unix/sysv/linux/pread.c: Likewise. * sysdeps/unix/sysv/linux/pread64.c: Likewise. * sysdeps/unix/sysv/linux/pwrite.c: Likewise. * sysdeps/unix/sysv/linux/pwrite64.c: Likewise. * sysdeps/unix/sysv/linux/seteuid.c: Likewise. * sysdeps/unix/sysv/linux/sigaction.c: Likewise. * sysdeps/unix/sysv/linux/sigprocmask.c: Likewise. * sysdeps/unix/sysv/linux/sigsuspend.c: Likewise. * sysdeps/unix/sysv/linux/testrtsig.h: Likewise. * sysdeps/unix/sysv/linux/i386/chown.c: Likewise. * sysdeps/unix/sysv/linux/i386/pread.c: Likewise. * sysdeps/unix/sysv/linux/i386/pread64.c: Likewise. * sysdeps/unix/sysv/linux/i386/pwrite.c: Likewise. * sysdeps/unix/sysv/linux/i386/pwrite64.c: Likewise. * sysdeps/unix/sysv/linux/sysctl.c: Add __sysctl alias.
Diffstat (limited to 'sysdeps/unix/sysv/linux/init-first.c')
-rw-r--r--sysdeps/unix/sysv/linux/init-first.c74
1 files changed, 73 insertions, 1 deletions
diff --git a/sysdeps/unix/sysv/linux/init-first.c b/sysdeps/unix/sysv/linux/init-first.c
index 01395baf75..b8ee2bdf14 100644
--- a/sysdeps/unix/sysv/linux/init-first.c
+++ b/sysdeps/unix/sysv/linux/init-first.c
@@ -1,5 +1,5 @@
/* Initialization code run first thing by the ELF startup code. Linux version.
- Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999 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
@@ -17,12 +17,17 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include <stdio.h>
+#include <fcntl.h>
#include <unistd.h>
#include <sysdep.h>
#include <fpu_control.h>
#include <linux/personality.h>
#include <init-first.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
#include <sys/types.h>
+#include "kernel-features.h"
extern void __libc_init_secure (void);
extern void __libc_init (int, char **, char **);
@@ -31,6 +36,10 @@ extern void __libc_global_ctors (void);
/* The function is called from assembly stubs the compiler can't see. */
static void init (int, char **, char **) __attribute__ ((unused));
+/* The function we use to get the kernel revision. */
+extern int __sysctl (int *name, int nlen, void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen);
+
extern int _dl_starting_up;
weak_extern (_dl_starting_up)
@@ -56,6 +65,69 @@ init (int argc, char **argv, char **envp)
/* We must not call `personality' twice. */
if (!__libc_multiple_libcs)
{
+ /* Test whether the kernel is new enough. This test is only
+ performed if the library is not compiled to run on all
+ kernels. */
+ if (__LINUX_KERNEL_VERSION > 0)
+ {
+ static const int sysctl_args[] = { CTL_KERN, KERN_OSRELEASE };
+ char buf[64];
+ size_t reslen = sizeof (buf);
+ unsigned int version;
+ int parts;
+ char *cp;
+
+ /* Try reading the number using `sysctl' first. */
+ if (__sysctl ((int *) sysctl_args,
+ sizeof (sysctl_args) / sizeof (sysctl_args[0]),
+ buf, &reslen, NULL, 0) < 0)
+ {
+ /* This was not successful. Now try reading the /proc
+ filesystem. */
+ int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY);
+ if (fd == -1
+ || (reslen = __read (fd, buf, sizeof (buf))) <= 0)
+ /* This also didn't work. We give up since we cannot
+ make sure the library can actually work. */
+ __libc_fatal ("FATAL: cannot determine library version\n");
+
+ __close (fd);
+ }
+ buf[MIN (reslen, sizeof (buf) - 1)] = '\0';
+
+ /* Now convert it into a number. The string consists of at most
+ three parts. */
+ version = 0;
+ parts = 0;
+ cp = buf;
+ while ((*cp >= '0') && (*cp <= '9'))
+ {
+ unsigned int here = *cp++ - '0';
+
+ while ((*cp >= '0') && (*cp <= '9'))
+ {
+ here *= 10;
+ here += *cp++ - '0';
+ }
+
+ ++parts;
+ version <<= 8;
+ version |= here;
+
+ if (*cp++ != '.')
+ /* Another part following? */
+ break;
+ }
+
+ if (parts < 3)
+ version <<= 8 * (3 - parts);
+
+ /* Now we can test with the required version. */
+ if (version < __LINUX_KERNEL_VERSION)
+ /* Not sufficent. */
+ __libc_fatal ("FATAL: kernel too old\n");
+ }
+
/* The `personality' system call takes one argument that chooses
the "personality", i.e. the set of system calls and such. We
must make this call first thing to disable emulation of some