about summary refs log tree commit diff
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)
downloadglibc-958f238f3619373d3dbc106d3cda3c467b3419b1.tar.gz
glibc-958f238f3619373d3dbc106d3cda3c467b3419b1.tar.xz
glibc-958f238f3619373d3dbc106d3cda3c467b3419b1.zip
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