]>
Commit | Line | Data |
---|---|---|
99b306dc RM |
1 | /* Operating system support for run-time dynamic linker. Hurd version. |
2 | Copyright (C) 1995 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 | |
17 | not, write to the Free Software Foundation, Inc., 675 Mass Ave, | |
18 | Cambridge, MA 02139, 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 <sys/wait.h> | |
27 | #include <assert.h> | |
28 | #include <sysdep.h> | |
29 | #include <mach/mig_support.h> | |
30 | #include "hurdstartup.h" | |
31 | #include <mach/host_info.h> | |
ec967c06 | 32 | #include "../stdio-common/_itoa.h" |
99b306dc RM |
33 | #include <hurd/auth.h> |
34 | #include <hurd/term.h> | |
35 | #include <stdarg.h> | |
36 | ||
37 | #include "dl-machine.h" | |
38 | ||
a1a9d215 RM |
39 | extern void __mach_init (void); |
40 | ||
99b306dc RM |
41 | extern int _dl_argc; |
42 | extern char **_dl_argv; | |
43 | extern char **_environ; | |
44 | ||
45 | struct hurd_startup_data *_dl_hurd_data; | |
46 | ||
5bf62f2d RM |
47 | unsigned int __hurd_threadvar_max = _HURD_THREADVAR_MAX; |
48 | static unsigned long int threadvars[_HURD_THREADVAR_MAX]; | |
49 | unsigned long int __hurd_threadvar_stack_offset | |
50 | = (unsigned long int) &threadvars; | |
51 | ||
52 | ||
53 | /* XXX loser kludge for vm_map kernel bug */ | |
54 | static vm_address_t fmha; | |
55 | static vm_size_t fmhs; | |
56 | static void unfmh(){ | |
57 | __vm_deallocate(__mach_task_self(),fmha,fmhs);} | |
58 | static void fmh() { | |
59 | error_t err;int x;mach_port_t p; | |
60 | vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS; | |
61 | while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){ | |
62 | __mach_port_deallocate(__mach_task_self(),p); | |
63 | if (a+fmhs>=0x80000000U){ | |
d819080c | 64 | max=a; break;} |
5bf62f2d RM |
65 | fmha=a+=fmhs;} |
66 | if (err) assert(err==KERN_NO_SPACE); | |
d819080c | 67 | if (!fmha)fmhs=0;else{ |
5bf62f2d RM |
68 | fmhs=max-fmha; |
69 | err = __vm_map (__mach_task_self (), | |
70 | &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1, | |
71 | VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY); | |
d819080c | 72 | assert_perror(err);} |
5bf62f2d RM |
73 | } |
74 | /* XXX loser kludge for vm_map kernel bug */ | |
75 | ||
76 | ||
77 | ||
99b306dc RM |
78 | Elf32_Addr |
79 | _dl_sysdep_start (void **start_argptr, | |
80 | void (*dl_main) (const Elf32_Phdr *phdr, Elf32_Word phent, | |
81 | Elf32_Addr *user_entry)) | |
82 | { | |
879bf2e6 RM |
83 | extern void _start (); |
84 | ||
99b306dc RM |
85 | void go (int *argdata) |
86 | { | |
879bf2e6 | 87 | extern unsigned int _dl_skip_args; /* rtld.c */ |
99b306dc RM |
88 | char **p; |
89 | ||
90 | /* Cache the information in various global variables. */ | |
a1a9d215 | 91 | _dl_argc = *argdata; |
879bf2e6 | 92 | _dl_argv = 1 + (char **) argdata; |
99b306dc | 93 | _environ = &_dl_argv[_dl_argc + 1]; |
879bf2e6 RM |
94 | for (p = _environ; *p++;); /* Skip environ pointers and terminator. */ |
95 | ||
96 | if ((void *) p == _dl_argv[0]) | |
97 | { | |
98 | static struct hurd_startup_data nodata; | |
99 | _dl_hurd_data = &nodata; | |
100 | nodata.user_entry = (vm_address_t) &_start; | |
101 | } | |
102 | else | |
103 | _dl_hurd_data = (void *) p; | |
99b306dc RM |
104 | |
105 | _dl_secure = _dl_hurd_data->flags & EXEC_SECURE; | |
106 | ||
ec967c06 RM |
107 | if (_dl_hurd_data->flags & EXEC_STACK_ARGS && |
108 | _dl_hurd_data->user_entry == 0) | |
109 | _dl_hurd_data->user_entry = (vm_address_t) &_start; | |
110 | ||
5bf62f2d | 111 | unfmh(); /* XXX */ |
879bf2e6 RM |
112 | |
113 | if (_dl_hurd_data->user_entry == (vm_address_t) &_start) | |
114 | /* We were invoked as a command, not as the program interpreter. | |
115 | The generic ld.so code supports this: it will parse the args | |
116 | as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we | |
117 | support an additional special syntax: | |
118 | ld.so [-LIBS...] PROGRAM [ARGS...] | |
119 | Each LIBS word consists of "FILENAME=MEMOBJ"; | |
120 | for example "-/lib/libc.so=123" says that the contents of | |
121 | /lib/libc.so are found in a memory object whose port name | |
122 | in our task is 123. */ | |
6a76c115 | 123 | while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-') |
879bf2e6 RM |
124 | { |
125 | char *lastslash, *memobjname, *p; | |
126 | struct link_map *l; | |
127 | mach_port_t memobj; | |
128 | error_t err; | |
129 | ||
130 | ++_dl_skip_args; | |
131 | --_dl_argc; | |
132 | p = _dl_argv++[1] + 1; | |
133 | ||
134 | memobjname = strchr (p, '='); | |
135 | if (! memobjname) | |
136 | _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL); | |
137 | *memobjname++ = '\0'; | |
138 | memobj = (mach_port_t) atoi (memobjname); | |
ec967c06 | 139 | |
879bf2e6 RM |
140 | /* Add a user reference on the memory object port, so we will |
141 | still have one after _dl_map_object_from_fd calls our | |
142 | `close'. */ | |
143 | err = __mach_port_mod_refs (__mach_task_self (), memobj, | |
144 | MACH_PORT_RIGHT_SEND, +1); | |
145 | assert_perror (err); | |
ec967c06 | 146 | |
879bf2e6 RM |
147 | lastslash = strrchr (p, '/'); |
148 | l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p, | |
149 | memobj, strdup (p)); | |
150 | ||
151 | /* Squirrel away the memory object port where it | |
152 | can be retrieved by the program later. */ | |
153 | l->l_info[DT_NULL] = (void *) memobj; | |
154 | } | |
155 | ||
99b306dc RM |
156 | /* Call elf/rtld.c's main program. It will set everything |
157 | up and leave us to transfer control to USER_ENTRY. */ | |
158 | (*dl_main) ((const Elf32_Phdr *) _dl_hurd_data->phdr, | |
159 | _dl_hurd_data->phdrsz / sizeof (Elf32_Phdr), | |
160 | &_dl_hurd_data->user_entry); | |
161 | ||
879bf2e6 RM |
162 | if (_dl_skip_args && _dl_argv[-_dl_skip_args] == (char *) p) |
163 | { | |
164 | /* We are ignoring the first few arguments, but we have no Hurd | |
165 | startup data. It is magical convention that ARGV[0] == P in | |
166 | this case. The startup code in init-first.c will get confused | |
167 | if this is not the case, so we must rearrange things to make | |
168 | it so. Overwrite the original ARGV[0] at P with | |
169 | ARGV[_dl_skip_args]. */ | |
170 | assert ((char *) p < _dl_argv[0]); | |
171 | _dl_argv[0] = strcpy ((char *) p, _dl_argv[0]); | |
172 | } | |
173 | ||
99b306dc RM |
174 | { |
175 | extern void _dl_start_user (void); | |
176 | /* Unwind the stack to ARGDATA and simulate a return from _dl_start | |
177 | to the RTLD_START code which will run the user's entry point. */ | |
178 | RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry); | |
179 | } | |
180 | } | |
181 | ||
a1a9d215 RM |
182 | /* Set up so we can do RPCs. */ |
183 | __mach_init (); | |
184 | ||
5bf62f2d RM |
185 | fmh(); /* XXX */ |
186 | ||
99b306dc RM |
187 | /* See hurd/hurdstartup.c; this deals with getting information |
188 | from the exec server and slicing up the arguments. | |
189 | Then it will call `go', above. */ | |
190 | _hurd_startup (start_argptr, &go); | |
191 | ||
192 | LOSE; | |
54da5be3 | 193 | abort (); |
99b306dc | 194 | } |
4cb20290 RM |
195 | |
196 | void | |
197 | _dl_sysdep_start_cleanup (void) | |
198 | { | |
199 | /* Deallocate the reply port and task port rights acquired by | |
200 | __mach_init. We are done with them now, and the user will | |
201 | reacquire them for himself when he wants them. */ | |
202 | __mig_dealloc_reply_port (MACH_PORT_NULL); | |
203 | __mach_port_deallocate (__mach_task_self (), __mach_task_self_); | |
204 | } | |
99b306dc RM |
205 | \f |
206 | int | |
207 | _dl_sysdep_open_zero_fill (void) | |
208 | { | |
209 | return (int) MACH_PORT_NULL; | |
210 | } | |
211 | ||
212 | ||
213 | void | |
214 | _dl_sysdep_fatal (const char *msg, ...) | |
215 | { | |
99b306dc RM |
216 | va_list ap; |
217 | ||
218 | va_start (ap, msg); | |
219 | do | |
220 | { | |
221 | size_t len = strlen (msg); | |
222 | mach_msg_type_number_t nwrote; | |
223 | do | |
224 | { | |
54da5be3 | 225 | if (__io_write (_hurd_init_dtable[2], msg, len, -1, &nwrote)) |
99b306dc RM |
226 | break; |
227 | len -= nwrote; | |
228 | msg += nwrote; | |
229 | } while (nwrote > 0); | |
230 | msg = va_arg (ap, const char *); | |
231 | } while (msg); | |
232 | va_end (ap); | |
233 | ||
234 | _exit (127); | |
235 | } | |
236 | ||
237 | ||
6a76c115 RM |
238 | void |
239 | _dl_sysdep_message (const char *msg, ...) | |
240 | { | |
241 | va_list ap; | |
242 | ||
243 | va_start (ap, msg); | |
244 | do | |
245 | { | |
246 | size_t len = strlen (msg); | |
247 | mach_msg_type_number_t nwrote; | |
248 | do | |
249 | { | |
250 | if (__io_write (_hurd_init_dtable[1], msg, len, -1, &nwrote)) | |
251 | break; | |
252 | len -= nwrote; | |
253 | msg += nwrote; | |
254 | } while (nwrote > 0); | |
255 | msg = va_arg (ap, const char *); | |
256 | } while (msg); | |
257 | va_end (ap); | |
258 | } | |
259 | \f | |
99b306dc RM |
260 | /* Minimal open/close/mmap implementation sufficient for initial loading of |
261 | shared libraries. These are weak definitions so that when the | |
262 | dynamic linker re-relocates itself to be user-visible (for -ldl), | |
263 | it will get the user's definition (i.e. usually libc's). */ | |
264 | ||
265 | int | |
266 | open (const char *file_name, int mode, ...) | |
267 | { | |
99b306dc RM |
268 | enum retry_type doretry; |
269 | char retryname[1024]; /* XXX string_t LOSES! */ | |
270 | file_t startdir, newpt, fileport; | |
271 | int dealloc_dir; | |
272 | int nloops; | |
b122c703 | 273 | error_t err; |
99b306dc RM |
274 | |
275 | assert (mode == O_RDONLY); | |
276 | ||
99b306dc RM |
277 | startdir = _dl_hurd_data->portarray[file_name[0] == '/' ? |
278 | INIT_PORT_CRDIR : INIT_PORT_CWDIR]; | |
279 | ||
280 | while (file_name[0] == '/') | |
281 | file_name++; | |
282 | ||
b122c703 RM |
283 | if (err = __dir_lookup (startdir, file_name, mode, 0, |
284 | &doretry, retryname, &fileport)) | |
285 | return __hurd_fail (err); | |
99b306dc RM |
286 | |
287 | dealloc_dir = 0; | |
288 | nloops = 0; | |
ec967c06 | 289 | |
99b306dc RM |
290 | while (1) |
291 | { | |
292 | if (dealloc_dir) | |
293 | __mach_port_deallocate (__mach_task_self (), startdir); | |
b122c703 RM |
294 | if (err) |
295 | return __hurd_fail (err); | |
99b306dc RM |
296 | |
297 | switch (doretry) | |
298 | { | |
299 | case FS_RETRY_REAUTH: | |
300 | { | |
301 | mach_port_t ref = __mach_reply_port (); | |
b122c703 RM |
302 | err = __io_reauthenticate (fileport, ref, MACH_MSG_TYPE_MAKE_SEND); |
303 | if (! err) | |
304 | err = __auth_user_authenticate | |
99b306dc RM |
305 | (_dl_hurd_data->portarray[INIT_PORT_AUTH], |
306 | fileport, | |
307 | ref, MACH_MSG_TYPE_MAKE_SEND, | |
308 | &newpt); | |
309 | __mach_port_destroy (__mach_task_self (), ref); | |
310 | } | |
311 | __mach_port_deallocate (__mach_task_self (), fileport); | |
b122c703 RM |
312 | if (err) |
313 | return __hurd_fail (err); | |
99b306dc RM |
314 | fileport = newpt; |
315 | /* Fall through. */ | |
316 | ||
317 | case FS_RETRY_NORMAL: | |
318 | #ifdef SYMLOOP_MAX | |
319 | if (nloops++ >= SYMLOOP_MAX) | |
b122c703 | 320 | return __hurd_fail (ELOOP); |
99b306dc RM |
321 | #endif |
322 | ||
323 | /* An empty RETRYNAME indicates we have the final port. */ | |
324 | if (retryname[0] == '\0') | |
325 | { | |
326 | mach_port_t memobj_rd, memobj_wr; | |
99b306dc RM |
327 | |
328 | dealloc_dir = 1; | |
329 | ||
330 | opened: | |
331 | /* We have the file open. Now map it. */ | |
b122c703 | 332 | err = __io_map (fileport, &memobj_rd, &memobj_wr); |
99b306dc RM |
333 | if (dealloc_dir) |
334 | __mach_port_deallocate (__mach_task_self (), fileport); | |
b122c703 RM |
335 | if (err) |
336 | return __hurd_fail (err); | |
99b306dc RM |
337 | if (memobj_wr != MACH_PORT_NULL) |
338 | __mach_port_deallocate (__mach_task_self (), memobj_wr); | |
339 | ||
340 | return (int) memobj_rd; | |
341 | } | |
342 | ||
343 | startdir = fileport; | |
344 | dealloc_dir = 1; | |
345 | file_name = retryname; | |
346 | break; | |
347 | ||
348 | case FS_RETRY_MAGICAL: | |
349 | switch (retryname[0]) | |
350 | { | |
351 | case '/': | |
352 | startdir = _dl_hurd_data->portarray[INIT_PORT_CRDIR]; | |
353 | dealloc_dir = 0; | |
354 | if (fileport != MACH_PORT_NULL) | |
355 | __mach_port_deallocate (__mach_task_self (), fileport); | |
356 | file_name = &retryname[1]; | |
357 | break; | |
358 | ||
359 | case 'f': | |
360 | if (retryname[1] == 'd' && retryname[2] == '/') | |
361 | { | |
362 | int fd; | |
363 | char *end; | |
b122c703 | 364 | err = 0; |
99b306dc | 365 | fd = (int) strtol (retryname, &end, 10); |
b122c703 | 366 | if (end == NULL || err || /* Malformed number. */ |
99b306dc RM |
367 | /* Check for excess text after the number. A slash |
368 | is valid; it ends the component. Anything else | |
369 | does not name a numeric file descriptor. */ | |
370 | (*end != '/' && *end != '\0')) | |
b122c703 | 371 | return __hurd_fail (ENOENT); |
99b306dc RM |
372 | if (fd < 0 || fd >= _dl_hurd_data->dtablesize || |
373 | _dl_hurd_data->dtable[fd] == MACH_PORT_NULL) | |
b122c703 RM |
374 | /* If the name was a proper number, but the file |
375 | descriptor does not exist, we return EBADF instead | |
376 | of ENOENT. */ | |
377 | return __hurd_fail (EBADF); | |
99b306dc RM |
378 | fileport = _dl_hurd_data->dtable[fd]; |
379 | if (*end == '\0') | |
380 | { | |
381 | /* This descriptor is the file port we want. */ | |
382 | dealloc_dir = 0; | |
383 | goto opened; | |
384 | } | |
385 | else | |
386 | { | |
387 | /* Do a normal retry on the remaining components. */ | |
388 | startdir = fileport; | |
389 | dealloc_dir = 1; | |
390 | file_name = end + 1; /* Skip the slash. */ | |
391 | break; | |
392 | } | |
393 | } | |
394 | else | |
395 | goto bad_magic; | |
396 | break; | |
397 | ||
398 | case 'm': | |
399 | if (retryname[1] == 'a' && retryname[2] == 'c' && | |
400 | retryname[3] == 'h' && retryname[4] == 't' && | |
401 | retryname[5] == 'y' && retryname[6] == 'p' && | |
402 | retryname[7] == 'e') | |
403 | { | |
404 | error_t err; | |
405 | struct host_basic_info hostinfo; | |
406 | mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT; | |
407 | char *p; | |
408 | if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO, | |
409 | (natural_t *) &hostinfo, | |
410 | &hostinfocnt)) | |
411 | return err; | |
412 | if (hostinfocnt != HOST_BASIC_INFO_COUNT) | |
413 | return EGRATUITOUS; | |
414 | p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0); | |
415 | *--p = '/'; | |
416 | p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0); | |
417 | if (p < retryname) | |
418 | abort (); /* XXX write this right if this ever happens */ | |
419 | if (p > retryname) | |
420 | strcpy (retryname, p); | |
421 | startdir = fileport; | |
422 | dealloc_dir = 1; | |
423 | } | |
424 | else | |
425 | goto bad_magic; | |
426 | break; | |
427 | ||
428 | case 't': | |
429 | if (retryname[1] == 't' && retryname[2] == 'y') | |
430 | switch (retryname[3]) | |
431 | { | |
432 | error_t opentty (file_t *result) | |
433 | { | |
434 | error_t err; | |
435 | file_t unauth; | |
436 | err = __termctty_open_terminal | |
437 | (_dl_hurd_data->portarray[INIT_PORT_CTTYID], | |
438 | mode, &unauth); | |
439 | if (! err) | |
440 | { | |
441 | mach_port_t ref = __mach_reply_port (); | |
54da5be3 | 442 | err = __io_reauthenticate |
99b306dc RM |
443 | (unauth, ref, MACH_MSG_TYPE_MAKE_SEND); |
444 | if (! err) | |
445 | err = __auth_user_authenticate | |
446 | (_dl_hurd_data->portarray[INIT_PORT_AUTH], | |
447 | unauth, | |
448 | ref, MACH_MSG_TYPE_MAKE_SEND, | |
449 | result); | |
450 | __mach_port_deallocate (__mach_task_self (), | |
451 | unauth); | |
452 | __mach_port_destroy (__mach_task_self (), ref); | |
453 | } | |
454 | return err; | |
455 | } | |
456 | ||
457 | case '\0': | |
b122c703 RM |
458 | if (err = opentty (&fileport)) |
459 | return __hurd_fail (err); | |
99b306dc RM |
460 | dealloc_dir = 1; |
461 | goto opened; | |
462 | case '/': | |
b122c703 RM |
463 | if (err = opentty (&startdir)) |
464 | return __hurd_fail (err); | |
99b306dc RM |
465 | dealloc_dir = 1; |
466 | strcpy (retryname, &retryname[4]); | |
467 | break; | |
468 | default: | |
469 | goto bad_magic; | |
470 | } | |
471 | else | |
472 | goto bad_magic; | |
473 | break; | |
474 | ||
475 | default: | |
476 | bad_magic: | |
b122c703 | 477 | return __hurd_fail (EGRATUITOUS); |
99b306dc | 478 | } |
ec967c06 | 479 | break; |
99b306dc RM |
480 | |
481 | default: | |
b122c703 | 482 | return __hurd_fail (EGRATUITOUS); |
99b306dc RM |
483 | } |
484 | ||
b122c703 RM |
485 | err = __dir_lookup (startdir, file_name, mode, 0, |
486 | &doretry, retryname, &fileport); | |
99b306dc RM |
487 | } |
488 | } | |
489 | ||
490 | int | |
491 | close (int fd) | |
492 | { | |
493 | if (fd != (int) MACH_PORT_NULL) | |
494 | __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd); | |
495 | return 0; | |
496 | } | |
497 | ||
498 | caddr_t | |
499 | mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset) | |
500 | { | |
b122c703 | 501 | error_t err; |
99b306dc RM |
502 | vm_prot_t vmprot; |
503 | vm_address_t mapaddr; | |
504 | ||
505 | vmprot = VM_PROT_NONE; | |
506 | if (prot & PROT_READ) | |
507 | vmprot |= VM_PROT_READ; | |
508 | if (prot & PROT_WRITE) | |
509 | vmprot |= VM_PROT_WRITE; | |
510 | if (prot & PROT_EXEC) | |
511 | vmprot |= VM_PROT_EXECUTE; | |
512 | ||
513 | mapaddr = (vm_address_t) addr; | |
b122c703 RM |
514 | err = __vm_map (__mach_task_self (), |
515 | &mapaddr, (vm_size_t) len, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/, | |
516 | !(flags & MAP_FIXED), | |
517 | (mach_port_t) fd, (vm_offset_t) offset, | |
518 | flags & (MAP_COPY|MAP_PRIVATE), | |
519 | vmprot, VM_PROT_ALL, | |
755f55b0 | 520 | (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY); |
b122c703 | 521 | return err ? (caddr_t) __hurd_fail (err) : (caddr_t) mapaddr; |
99b306dc RM |
522 | } |
523 | ||
524 | void | |
525 | _exit (int status) | |
526 | { | |
54da5be3 RM |
527 | __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC], |
528 | W_EXITCODE (status, 0)); | |
99b306dc RM |
529 | while (__task_terminate (__mach_task_self ())) |
530 | __mach_task_self_ = (__mach_task_self) (); | |
531 | } | |
532 | ||
533 | weak_symbol (_exit) | |
534 | weak_symbol (open) | |
535 | weak_symbol (close) | |
536 | weak_symbol (mmap) | |
537 | \f | |
99b306dc | 538 | |
54da5be3 RM |
539 | /* This function is called by interruptible RPC stubs. For initial |
540 | dynamic linking, just use the normal mach_msg. Since this defn is | |
99b306dc RM |
541 | weak, the real defn in libc.so will override it if we are linked into |
542 | the user program (-ldl). */ | |
54da5be3 RM |
543 | |
544 | error_t | |
545 | _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, | |
546 | mach_msg_option_t option, | |
547 | mach_msg_size_t send_size, | |
548 | mach_msg_size_t rcv_size, | |
549 | mach_port_t rcv_name, | |
550 | mach_msg_timeout_t timeout, | |
551 | mach_port_t notify) | |
552 | { | |
553 | return __mach_msg (msg, option, send_size, rcv_size, rcv_name, | |
554 | timeout, notify); | |
555 | } | |
556 | weak_symbol (_hurd_intr_rpc_mach_msg) |