Include stdint.h.
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / dl-osinfo.h
1 /* Operating system specific code for generic dynamic loader functions.  Linux.
2    Copyright (C) 2000,2001,2002,2004,2005 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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <string.h>
21 #include <fcntl.h>
22 #include <sys/sysctl.h>
23 #include <sys/utsname.h>
24 #include "kernel-features.h"
25 #include <dl-sysdep.h>
26 #include <stdint.h>
27
28 #ifndef MIN
29 # define MIN(a,b) (((a)<(b))?(a):(b))
30 #endif
31
32 #ifdef SHARED
33 /* This is the function used in the dynamic linker to print the fatal error
34    message.  */
35 static inline void
36 __attribute__ ((__noreturn__))
37 dl_fatal (const char *str)
38 {
39   _dl_dprintf (2, str);
40   _exit (1);
41 }
42 #endif
43
44 static inline int __attribute__ ((always_inline))
45 _dl_discover_osversion (void)
46 {
47 #if (defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO) && defined SHARED
48   if (GLRO(dl_sysinfo_map) != NULL)
49     {
50       /* If the kernel-supplied DSO contains a note indicating the kernel's
51          version, we don't need to call uname or parse any strings.  */
52
53       static const struct
54       {
55         ElfW(Word) vendorlen;
56         ElfW(Word) datalen;
57         ElfW(Word) type;
58         char vendor[8];
59       } expected_note = { sizeof "Linux", sizeof (ElfW(Word)), 0, "Linux" };
60       const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr;
61       const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum;
62       for (uint_fast16_t i = 0; i < phnum; ++i)
63         if (phdr[i].p_type == PT_NOTE)
64           {
65             const ElfW(Addr) start = (phdr[i].p_vaddr
66                                       + GLRO(dl_sysinfo_map)->l_addr);
67             const struct
68             {
69               ElfW(Word) vendorlen;
70               ElfW(Word) datalen;
71               ElfW(Word) type;
72             } *note = (const void *) start;
73             while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
74               {
75                 if (!memcmp (note, &expected_note, sizeof expected_note))
76                   return *(const ElfW(Word) *) ((const void *) note
77                                                 + sizeof expected_note);
78 #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
79                 note = ((const void *) (note + 1)
80                         + ROUND (note->vendorlen) + ROUND (note->datalen));
81               }
82           }
83     }
84 #endif
85
86   char bufmem[64];
87   char *buf = bufmem;
88   unsigned int version;
89   int parts;
90   char *cp;
91   struct utsname uts;
92
93   /* Try the uname system call.  */
94   if (__uname (&uts))
95     {
96       /* This was not successful.  Now try reading the /proc filesystem.  */
97       int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY);
98       if (fd < 0)
99         return -1;
100       ssize_t reslen = __read (fd, bufmem, sizeof (bufmem));
101       __close (fd);
102       if (reslen <= 0)
103         /* This also didn't work.  We give up since we cannot
104            make sure the library can actually work.  */
105         return -1;
106       buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0';
107     }
108   else
109     buf = uts.release;
110
111   /* Now convert it into a number.  The string consists of at most
112      three parts.  */
113   version = 0;
114   parts = 0;
115   cp = buf;
116   while ((*cp >= '0') && (*cp <= '9'))
117     {
118       unsigned int here = *cp++ - '0';
119
120       while ((*cp >= '0') && (*cp <= '9'))
121         {
122           here *= 10;
123           here += *cp++ - '0';
124         }
125
126       ++parts;
127       version <<= 8;
128       version |= here;
129
130       if (*cp++ != '.')
131         /* Another part following?  */
132         break;
133     }
134
135   if (parts < 3)
136     version <<= 8 * (3 - parts);
137
138   return version;
139 }
140
141 #define DL_SYSDEP_OSCHECK(FATAL)                                              \
142   do {                                                                        \
143     /* Test whether the kernel is new enough.  This test is only performed    \
144        if the library is not compiled to run on all kernels.  */              \
145                                                                               \
146     int version = _dl_discover_osversion ();                                  \
147     if (__builtin_expect (version >= 0, 1))                                   \
148       {                                                                       \
149         if (__builtin_expect (GLRO(dl_osversion) == 0, 1)                     \
150             || GLRO(dl_osversion) > version)                                  \
151           GLRO(dl_osversion) = version;                                       \
152                                                                               \
153         /* Now we can test with the required version.  */                     \
154         if (__LINUX_KERNEL_VERSION > 0 && version < __LINUX_KERNEL_VERSION)   \
155           /* Not sufficent.  */                                               \
156           FATAL ("FATAL: kernel too old\n");                                  \
157       }                                                                       \
158     else if (__LINUX_KERNEL_VERSION > 0)                                      \
159       FATAL ("FATAL: cannot determine kernel version\n");                     \
160   } while (0)
161
162 static inline uintptr_t __attribute__ ((always_inline))
163 _dl_setup_stack_chk_guard (void)
164 {
165   uintptr_t ret;
166 #ifdef ENABLE_STACKGUARD_RANDOMIZE
167   int fd = __open ("/dev/urandom", O_RDONLY);
168   if (fd >= 0)
169     {
170       ssize_t reslen = __read (fd, &ret, sizeof (ret));
171       __close (fd);
172       if (reslen == (ssize_t) sizeof (ret))
173         return ret;
174     }
175 #endif
176   ret = 0;
177   unsigned char *p = (unsigned char *) &ret;
178   p[sizeof (ret) - 1] = 255;
179   p[sizeof (ret) - 2] = '\n';
180   return ret;
181 }