Include <stdlib.h> for abort prototype.
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / init-first.c
1 /* Initialization code run first thing by the ELF startup code.  Linux version.
2    Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sysdep.h>
25 #include <fpu_control.h>
26 #include <sys/param.h>
27 #include <sys/sysctl.h>
28 #include <sys/types.h>
29 #include "kernel-features.h"
30
31 extern void __libc_init_secure (void);
32 extern void __libc_init (int, char **, char **);
33 extern void __libc_global_ctors (void);
34
35 /* The function is called from assembly stubs the compiler can't see.  */
36 static void init (int, char **, char **) __attribute__ ((unused));
37
38 /* The function we use to get the kernel revision.  */
39 extern int __sysctl (int *name, int nlen, void *oldval, size_t *oldlenp,
40                      void *newval, size_t newlen);
41
42 extern int _dl_starting_up;
43 weak_extern (_dl_starting_up)
44
45 extern fpu_control_t _dl_fpu_control;
46 extern int _dl_fpu_control_set;
47
48 /* Set nonzero if we have to be prepared for more then one libc being
49    used in the process.  Safe assumption if initializer never runs.  */
50 int __libc_multiple_libcs = 1;
51
52 /* Remember the command line argument and enviroment contents for
53    later calls of initializers for dynamic libraries.  */
54 int __libc_argc;
55 char **__libc_argv;
56
57
58 static void
59 init (int argc, char **argv, char **envp)
60 {
61   extern void __getopt_clean_environment (char **);
62   /* The next variable is only here to work around a bug in gcc <= 2.7.2.2.
63      If the address would be taken inside the expression the optimizer
64      would try to be too smart and throws it away.  Grrr.  */
65   int *dummy_addr = &_dl_starting_up;
66
67   __libc_multiple_libcs = dummy_addr && !_dl_starting_up;
68
69   /* Make sure we don't initialize twice.  */
70   if (!__libc_multiple_libcs)
71     {
72       /* Test whether the kernel is new enough.  This test is only
73          performed if the library is not compiled to run on all
74          kernels.  */
75       if (__LINUX_KERNEL_VERSION > 0)
76         {
77           static const int sysctl_args[] = { CTL_KERN, KERN_OSRELEASE };
78           char buf[64];
79           size_t reslen = sizeof (buf);
80           unsigned int version;
81           int parts;
82           char *cp;
83
84           /* Try reading the number using `sysctl' first.  */
85           if (__sysctl ((int *) sysctl_args,
86                         sizeof (sysctl_args) / sizeof (sysctl_args[0]),
87                         buf, &reslen, NULL, 0) < 0)
88             {
89               /* This was not successful.  Now try reading the /proc
90                  filesystem.  */
91               int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY);
92               if (fd == -1
93                   || (reslen = __read (fd, buf, sizeof (buf))) <= 0)
94                 /* This also didn't work.  We give up since we cannot
95                    make sure the library can actually work.  */
96                 __libc_fatal ("FATAL: cannot determine library version\n");
97
98               __close (fd);
99             }
100           buf[MIN (reslen, sizeof (buf) - 1)] = '\0';
101
102           /* Now convert it into a number.  The string consists of at most
103              three parts.  */
104           version = 0;
105           parts = 0;
106           cp = buf;
107           while ((*cp >= '0') && (*cp <= '9'))
108             {
109               unsigned int here = *cp++ - '0';
110
111               while ((*cp >= '0') && (*cp <= '9'))
112                 {
113                   here *= 10;
114                   here += *cp++ - '0';
115                 }
116
117               ++parts;
118               version <<= 8;
119               version |= here;
120
121               if (*cp++ != '.')
122                 /* Another part following?  */
123                 break;
124             }
125
126           if (parts < 3)
127             version <<= 8 * (3 - parts);
128
129           /* Now we can test with the required version.  */
130           if (version < __LINUX_KERNEL_VERSION)
131             /* Not sufficent.  */
132             __libc_fatal ("FATAL: kernel too old\n");
133         }
134
135       /* Set the FPU control word to the proper default value if the
136          kernel would use a different value.  (In a static program we
137          don't have this information.)  */
138 #ifdef SHARED
139       if (__fpu_control != _dl_fpu_control)
140 #endif
141         __setfpucw (__fpu_control);
142     }
143
144   /* Save the command-line arguments.  */
145   __libc_argc = argc;
146   __libc_argv = argv;
147   __environ = envp;
148
149 #ifndef SHARED
150   __libc_init_secure ();
151 #endif
152
153   __libc_init (argc, argv, envp);
154
155   /* This is a hack to make the special getopt in GNU libc working.  */
156   __getopt_clean_environment (envp);
157
158 #ifdef SHARED
159   __libc_global_ctors ();
160 #endif
161 }
162
163 #ifdef SHARED
164
165 strong_alias (init, _init);
166
167 void
168 __libc_init_first (void)
169 {
170 }
171
172 #else
173 void
174 __libc_init_first (int argc, char **argv, char **envp)
175 {
176   init (argc, argv, envp);
177 }
178 #endif
179
180
181 /* This function is defined here so that if this file ever gets into
182    ld.so we will get a link error.  Having this file silently included
183    in ld.so causes disaster, because the _init definition above will
184    cause ld.so to gain an init function, which is not a cool thing. */
185
186 void
187 _dl_start (void)
188 {
189   abort ();
190 }