* sysdeps/mach/hurd/xstat64.c: Conditionalize entire contents of the
[platform/upstream/glibc.git] / sysdeps / mach / hurd / dl-sysdep.c
1 /* Operating system support for run-time dynamic linker.  Hurd version.
2    Copyright (C) 1995,96,97,98,99,2000,01,02 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 <hurd.h>
21 #include <link.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <sys/mman.h>
26 #include <ldsodefs.h>
27 #include <sys/wait.h>
28 #include <assert.h>
29 #include <sysdep.h>
30 #include <mach/mig_support.h>
31 #include "hurdstartup.h"
32 #include <hurd/lookup.h>
33 #include <hurd/auth.h>
34 #include <hurd/term.h>
35 #include <stdarg.h>
36 #include <ctype.h>
37 #include <sys/stat.h>
38 #include <sys/uio.h>
39
40 #include <entry.h>
41 #include <dl-machine.h>
42 #include <dl-procinfo.h>
43
44 extern void __mach_init (void);
45
46 extern int _dl_argc;
47 extern char **_dl_argv;
48 extern char **_environ;
49
50 int __libc_enable_secure = 0;
51 INTVARDEF(__libc_enable_secure)
52 int __libc_multiple_libcs = 0;  /* Defining this here avoids the inclusion
53                                    of init-first.  */
54 /* This variable containts the lowest stack address ever used.  */
55 void *__libc_stack_end;
56
57
58 struct hurd_startup_data *_dl_hurd_data;
59
60 /* This is used only within ld.so, via dl-minimal.c's __errno_location.  */
61 #undef errno
62 int errno attribute_hidden;
63
64 /* Defining these variables here avoids the inclusion of hurdsig.c.  */
65 unsigned long int __hurd_sigthread_stack_base;
66 unsigned long int __hurd_sigthread_stack_end;
67 unsigned long int *__hurd_sigthread_variables;
68
69 /* Defining these variables here avoids the inclusion of init-first.c.
70    We need to provide temporary storage for the per-thread variables
71    of the main user thread here, since it is used for storing the
72    `errno' variable.  Note that this information is lost once we
73    relocate the dynamic linker.  */
74 static unsigned long int threadvars[_HURD_THREADVAR_MAX];
75 unsigned long int __hurd_threadvar_stack_offset
76   = (unsigned long int) &threadvars;
77 unsigned long int __hurd_threadvar_stack_mask;
78
79 #define FMH defined(__i386__)
80 #if ! FMH
81 # define fmh()          ((void)0)
82 # define unfmh()        ((void)0)
83 #else
84 /* XXX loser kludge for vm_map kernel bug */
85 #undef  ELF_MACHINE_USER_ADDRESS_MASK
86 #define ELF_MACHINE_USER_ADDRESS_MASK   0
87 static vm_address_t fmha;
88 static vm_size_t fmhs;
89 static void unfmh(void){
90 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
91 static void fmh(void) {
92     error_t err;int x;mach_port_t p;
93     vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
94     while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){
95       __mach_port_deallocate(__mach_task_self(),p);
96       if (a+fmhs>=0x80000000U){
97         max=a; break;}
98       fmha=a+=fmhs;}
99     if (err) assert(err==KERN_NO_SPACE);
100     if (!fmha)fmhs=0;else{
101     fmhs=max-fmha;
102     err = __vm_map (__mach_task_self (),
103                     &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
104                     VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
105     assert_perror(err);}
106   }
107 /* XXX loser kludge for vm_map kernel bug */
108 #endif
109
110
111 ElfW(Addr)
112 _dl_sysdep_start (void **start_argptr,
113                   void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
114                                    ElfW(Addr) *user_entry))
115 {
116   void go (int *argdata)
117     {
118       extern unsigned int _dl_skip_args; /* rtld.c */
119       char **p;
120
121       /* Cache the information in various global variables.  */
122       _dl_argc = *argdata;
123       _dl_argv = 1 + (char **) argdata;
124       _environ = &_dl_argv[_dl_argc + 1];
125       for (p = _environ; *p++;); /* Skip environ pointers and terminator.  */
126
127       if ((void *) p == _dl_argv[0])
128         {
129           static struct hurd_startup_data nodata;
130           _dl_hurd_data = &nodata;
131           nodata.user_entry = (vm_address_t) ENTRY_POINT;
132         }
133       else
134         _dl_hurd_data = (void *) p;
135
136       INTUSE(__libc_enable_secure) = _dl_hurd_data->flags & EXEC_SECURE;
137
138       if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
139           _dl_hurd_data->user_entry == 0)
140         _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
141
142 unfmh();                        /* XXX */
143
144 #if 0                           /* XXX make this work for real someday... */
145       if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
146         /* We were invoked as a command, not as the program interpreter.
147            The generic ld.so code supports this: it will parse the args
148            as "ld.so PROGRAM [ARGS...]".  For booting the Hurd, we
149            support an additional special syntax:
150              ld.so [-LIBS...] PROGRAM [ARGS...]
151            Each LIBS word consists of "FILENAME=MEMOBJ";
152            for example "-/lib/libc.so=123" says that the contents of
153            /lib/libc.so are found in a memory object whose port name
154            in our task is 123.  */
155         while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
156           {
157             char *lastslash, *memobjname, *p;
158             struct link_map *l;
159             mach_port_t memobj;
160             error_t err;
161
162             ++_dl_skip_args;
163             --_dl_argc;
164             p = _dl_argv++[1] + 1;
165
166             memobjname = strchr (p, '=');
167             if (! memobjname)
168               _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
169             *memobjname++ = '\0';
170             memobj = 0;
171             while (*memobjname != '\0')
172               memobj = (memobj * 10) + (*memobjname++ - '0');
173
174             /* Add a user reference on the memory object port, so we will
175                still have one after _dl_map_object_from_fd calls our
176                `close'.  */
177             err = __mach_port_mod_refs (__mach_task_self (), memobj,
178                                         MACH_PORT_RIGHT_SEND, +1);
179             assert_perror (err);
180
181             lastslash = strrchr (p, '/');
182             l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p,
183                                         memobj, strdup (p), 0);
184
185             /* Squirrel away the memory object port where it
186                can be retrieved by the program later.  */
187             l->l_info[DT_NULL] = (void *) memobj;
188           }
189 #endif
190
191       /* Call elf/rtld.c's main program.  It will set everything
192          up and leave us to transfer control to USER_ENTRY.  */
193       (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
194                   _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
195                   &_dl_hurd_data->user_entry);
196
197       /* The call above might screw a few things up.
198
199          First of all, if _dl_skip_args is nonzero, we are ignoring
200          the first few arguments.  However, if we have no Hurd startup
201          data, it is the magical convention that ARGV[0] == P.  The
202          startup code in init-first.c will get confused if this is not
203          the case, so we must rearrange things to make it so.  We'll
204          overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
205
206          Secondly, if we need to be secure, it removes some dangerous
207          environment variables.  If we have no Hurd startup date this
208          changes P (since that's the location after the terminating
209          NULL in the list of environment variables).  We do the same
210          thing as in the first case but make sure we recalculate P.
211          If we do have Hurd startup data, we have to move the data
212          such that it starts just after the terminating NULL in the
213          environment list.
214
215          We use memmove, since the locations might overlap.  */
216       if (INTUSE(__libc_enable_secure) || _dl_skip_args)
217         {
218           char **newp;
219
220           for (newp = _environ; *newp++;);
221
222           if (_dl_argv[-_dl_skip_args] == (char *) p)
223             {
224               if ((char *) newp != _dl_argv[0])
225                 {
226                   assert ((char *) newp < _dl_argv[0]);
227                   _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
228                                          strlen (_dl_argv[0]) + 1);
229                 }
230             }
231           else
232             {
233               if ((void *) newp != _dl_hurd_data)
234                 memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
235             }
236         }
237
238       {
239         extern void _dl_start_user (void);
240         /* Unwind the stack to ARGDATA and simulate a return from _dl_start
241            to the RTLD_START code which will run the user's entry point.  */
242         RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
243       }
244     }
245
246   /* Set up so we can do RPCs.  */
247   __mach_init ();
248
249   /* Initialize frequently used global variable.  */
250   GL(dl_pagesize) = __getpagesize ();
251
252 fmh();                          /* XXX */
253
254   /* See hurd/hurdstartup.c; this deals with getting information
255      from the exec server and slicing up the arguments.
256      Then it will call `go', above.  */
257   _hurd_startup (start_argptr, &go);
258
259   LOSE;
260   abort ();
261 }
262
263 void
264 internal_function
265 _dl_sysdep_start_cleanup (void)
266 {
267   /* Deallocate the reply port and task port rights acquired by
268      __mach_init.  We are done with them now, and the user will
269      reacquire them for himself when he wants them.  */
270   __mig_dealloc_reply_port (MACH_PORT_NULL);
271   __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
272 }
273 \f
274 /* Minimal open/close/mmap implementation sufficient for initial loading of
275    shared libraries.  These are weak definitions so that when the
276    dynamic linker re-relocates itself to be user-visible (for -ldl),
277    it will get the user's definition (i.e. usually libc's).  */
278
279 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
280    error.  If STAT is non-zero, stat the file into that stat buffer.  */
281 static error_t
282 open_file (const char *file_name, int flags,
283            mach_port_t *port, struct stat64 *stat)
284 {
285   enum retry_type doretry;
286   char retryname[1024];         /* XXX string_t LOSES! */
287   file_t startdir;
288   error_t err;
289
290   error_t use_init_port (int which, error_t (*operate) (file_t))
291     {
292       return (which < _dl_hurd_data->portarraysize
293               ? ((*operate) (_dl_hurd_data->portarray[which]))
294               : EGRATUITOUS);
295     }
296   file_t get_dtable_port (int fd)
297     {
298       if ((unsigned int) fd < _dl_hurd_data->dtablesize
299           && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
300         {
301           __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
302                                 MACH_PORT_RIGHT_SEND, +1);
303           return _dl_hurd_data->dtable[fd];
304         }
305       errno = EBADF;
306       return MACH_PORT_NULL;
307     }
308
309   assert (!(flags & ~O_READ));
310
311   startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
312                                       INIT_PORT_CRDIR : INIT_PORT_CWDIR];
313
314   while (file_name[0] == '/')
315     file_name++;
316
317   err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
318                       &doretry, retryname, port);
319
320   if (!err)
321     err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
322                                          __dir_lookup, doretry, retryname,
323                                          O_RDONLY, 0, port);
324   if (!err && stat)
325     {
326       err = __io_stat (*port, stat);
327       if (err)
328         __mach_port_deallocate (__mach_task_self (), *port);
329     }
330
331   return err;
332 }
333
334 int weak_function
335 __open (const char *file_name, int mode, ...)
336 {
337   mach_port_t port;
338   error_t err = open_file (file_name, mode, &port, 0);
339   if (err)
340     return __hurd_fail (err);
341   else
342     return (int)port;
343 }
344
345 int weak_function
346 __close (int fd)
347 {
348   if (fd != (int) MACH_PORT_NULL)
349     __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
350   return 0;
351 }
352
353 __ssize_t weak_function
354 __libc_read (int fd, void *buf, size_t nbytes)
355 {
356   error_t err;
357   char *data;
358   mach_msg_type_number_t nread;
359
360   data = buf;
361   err = __io_read ((mach_port_t) fd, &data, &nread, -1, nbytes);
362   if (err)
363     return __hurd_fail (err);
364
365   if (data != buf)
366     {
367       memcpy (buf, data, nread);
368       __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
369     }
370
371   return nread;
372 }
373
374 __ssize_t weak_function
375 __libc_write (int fd, const void *buf, size_t nbytes)
376 {
377   error_t err;
378   mach_msg_type_number_t nwrote;
379
380   assert (fd < _hurd_init_dtablesize);
381
382   err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
383   if (err)
384     return __hurd_fail (err);
385
386   return nwrote;
387 }
388
389 /* This is only used for printing messages (see dl-misc.c).  */
390 __ssize_t weak_function
391 __writev (int fd, const struct iovec *iov, int niov)
392 {
393   int i;
394   size_t total = 0;
395   for (i = 0; i < niov; ++i)
396     total += iov[i].iov_len;
397
398   assert (fd < _hurd_init_dtablesize);
399
400   if (total != 0)
401     {
402       char buf[total], *bufp = buf;
403       error_t err;
404       mach_msg_type_number_t nwrote;
405
406       for (i = 0; i < niov; ++i)
407         bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
408                 + iov[i].iov_len);
409
410       err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
411       if (err)
412         return __hurd_fail (err);
413
414       return nwrote;
415     }
416   return 0;
417 }
418
419
420 off64_t weak_function
421 __libc_lseek64 (int fd, off64_t offset, int whence)
422 {
423   error_t err;
424
425   err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
426   if (err)
427     return __hurd_fail (err);
428
429   return offset;
430 }
431
432 __ptr_t weak_function
433 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
434 {
435   error_t err;
436   vm_prot_t vmprot;
437   vm_address_t mapaddr;
438   mach_port_t memobj_rd, memobj_wr;
439
440   vmprot = VM_PROT_NONE;
441   if (prot & PROT_READ)
442     vmprot |= VM_PROT_READ;
443   if (prot & PROT_WRITE)
444     vmprot |= VM_PROT_WRITE;
445   if (prot & PROT_EXEC)
446     vmprot |= VM_PROT_EXECUTE;
447
448   if (flags & MAP_ANON)
449     memobj_rd = MACH_PORT_NULL;
450   else
451     {
452       assert (!(flags & MAP_SHARED));
453       err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
454       if (err)
455         return __hurd_fail (err), MAP_FAILED;
456       __mach_port_deallocate (__mach_task_self (), memobj_wr);
457     }
458
459   mapaddr = (vm_address_t) addr;
460   err = __vm_map (__mach_task_self (),
461                   &mapaddr, (vm_size_t) len, ELF_MACHINE_USER_ADDRESS_MASK,
462                   !(flags & MAP_FIXED),
463                   memobj_rd,
464                   (vm_offset_t) offset,
465                   flags & (MAP_COPY|MAP_PRIVATE),
466                   vmprot, VM_PROT_ALL,
467                   (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
468   if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
469     {
470       /* XXX this is not atomic as it is in unix! */
471       /* The region is already allocated; deallocate it first.  */
472       err = __vm_deallocate (__mach_task_self (), mapaddr, len);
473       if (! err)
474         err = __vm_map (__mach_task_self (),
475                         &mapaddr, (vm_size_t) len,
476                         ELF_MACHINE_USER_ADDRESS_MASK,
477                         !(flags & MAP_FIXED),
478                         memobj_rd, (vm_offset_t) offset,
479                         flags & (MAP_COPY|MAP_PRIVATE),
480                         vmprot, VM_PROT_ALL,
481                         (flags & MAP_SHARED)
482                         ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
483     }
484
485   if ((flags & MAP_ANON) == 0)
486     __mach_port_deallocate (__mach_task_self (), memobj_rd);
487
488   if (err)
489     return __hurd_fail (err), MAP_FAILED;
490   return (__ptr_t) mapaddr;
491 }
492
493 int weak_function
494 __fxstat64 (int vers, int fd, struct stat64 *buf)
495 {
496   error_t err;
497
498   assert (vers == _STAT_VER);
499
500   err = __io_stat ((mach_port_t) fd, buf);
501   if (err)
502     return __hurd_fail (err);
503
504   return 0;
505 }
506
507 int weak_function
508 __xstat64 (int vers, const char *file, struct stat64 *buf)
509 {
510   error_t err;
511   mach_port_t port;
512
513   assert (vers == _STAT_VER);
514
515   err = open_file (file, 0, &port, buf);
516   if (err)
517     return __hurd_fail (err);
518
519   __mach_port_deallocate (__mach_task_self (), port);
520
521   return 0;
522 }
523
524 /* This function is called by the dynamic linker (rtld.c) to check
525    whether debugging malloc is allowed even for SUID binaries.  This
526    stub will always fail, which means that malloc-debugging is always
527    disabled for SUID binaries.  */
528 int weak_function
529 __access (const char *file, int type)
530 {
531   errno = ENOSYS;
532   return -1;
533 }
534
535 pid_t weak_function
536 __getpid ()
537 {
538   pid_t pid, ppid;
539   int orphaned;
540
541   if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
542                       &pid, &ppid, &orphaned))
543     return -1;
544
545   return pid;
546 }
547
548 /* This is called only in some strange cases trying to guess a value
549    for $ORIGIN for the executable.  The dynamic linker copes with
550    getcwd failing (dl-object.c), and it's too much hassle to include
551    the functionality here.  (We could, it just requires duplicating or
552    reusing getcwd.c's code but using our special lookup function as in
553    `open', above.)  */
554 char *
555 weak_function
556 __getcwd (char *buf, size_t size)
557 {
558   errno = ENOSYS;
559   return NULL;
560 }
561
562 void weak_function
563 _exit (int status)
564 {
565   __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
566                     W_EXITCODE (status, 0), 0);
567   while (__task_terminate (__mach_task_self ()))
568     __mach_task_self_ = (__mach_task_self) ();
569 }
570
571 /* Try to get a machine dependent instruction which will make the
572    program crash.  This is used in case everything else fails.  */
573 #include <abort-instr.h>
574 #ifndef ABORT_INSTRUCTION
575 /* No such instruction is available.  */
576 # define ABORT_INSTRUCTION
577 #endif
578
579 void weak_function
580 abort (void)
581 {
582   /* Try to abort using the system specific command.  */
583   ABORT_INSTRUCTION;
584
585   /* If the abort instruction failed, exit.  */
586   _exit (127);
587
588   /* If even this fails, make sure we never return.  */
589   while (1)
590     /* Try for ever and ever.  */
591     ABORT_INSTRUCTION;
592 }
593 \f
594 /* This function is called by interruptible RPC stubs.  For initial
595    dynamic linking, just use the normal mach_msg.  Since this defn is
596    weak, the real defn in libc.so will override it if we are linked into
597    the user program (-ldl).  */
598
599 error_t weak_function
600 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
601                          mach_msg_option_t option,
602                          mach_msg_size_t send_size,
603                          mach_msg_size_t rcv_size,
604                          mach_port_t rcv_name,
605                          mach_msg_timeout_t timeout,
606                          mach_port_t notify)
607 {
608   return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
609                      timeout, notify);
610 }
611
612
613 void
614 internal_function
615 _dl_show_auxv (void)
616 {
617   /* There is nothing to print.  Hurd has no auxiliary vector.  */
618 }
619
620
621 /* Return an array of useful/necessary hardware capability names.  */
622 const struct r_strlenpair *
623 internal_function
624 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
625                       size_t *max_capstrlen)
626 {
627   struct r_strlenpair *result;
628
629   /* Return an empty array.  Hurd has no hardware capabilities.  */
630   result = (struct r_strlenpair *) malloc (sizeof (*result));
631   if (result == NULL)
632     _dl_signal_error (ENOMEM, NULL, NULL, "cannot create capability list");
633
634   result[0].str = (char *) result;      /* Does not really matter.  */
635   result[0].len = 0;
636
637   *sz = 1;
638   return result;
639 }
640
641 void weak_function
642 _dl_init_first (int argc, ...)
643 {
644   /* This no-op definition only gets used if libc is not linked in.  */
645 }