blob: bc973a8bb2ae0bf7182a27702b456b87f466c177 [file] [log] [blame]
jseward2886b0e2004-01-04 03:46:11 +00001
nethercotebb1c9912004-01-04 16:43:23 +00002/*--------------------------------------------------------------------*/
nethercote107e1c02004-10-13 17:55:31 +00003/*--- User-mode execve(), and other stuff shared between stage1 ---*/
4/*--- and stage2. ume.c ---*/
nethercotebb1c9912004-01-04 16:43:23 +00005/*--------------------------------------------------------------------*/
6
jseward2886b0e2004-01-04 03:46:11 +00007/*
8 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
10
11 Copyright (C) 2000-2004 Julian Seward
12 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
fitzhardinge7e343cd2003-12-16 02:14:00 +000032
33#define _GNU_SOURCE
34#define _FILE_OFFSET_BITS 64
35
nethercotef1e5e152004-09-01 23:58:16 +000036#include "core.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000037
fitzhardinge7e343cd2003-12-16 02:14:00 +000038#include <sys/mman.h>
39#include <fcntl.h>
40#include <errno.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000041#include <stdio.h>
42#include <string.h>
43#include <stdlib.h>
44#include <unistd.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000045#include <assert.h>
46
47#include "ume.h"
48
nethercote1fe54502004-07-26 15:28:33 +000049struct elfinfo
50{
51 ESZ(Ehdr) e;
52 ESZ(Phdr) *p;
53 int fd;
54};
55
nethercote30d37842004-07-26 10:05:55 +000056static void check_mmap(void* res, void* base, int len)
nethercotebfed1c82004-07-17 12:57:44 +000057{
58 if ((void*)-1 == res) {
nethercote969ecf12004-10-13 17:29:01 +000059 fprintf(stderr, "valgrind: mmap(%p, %d) failed in UME.\n", base, len);
nethercotebfed1c82004-07-17 12:57:44 +000060 exit(1);
61 }
62}
63
nethercote31779c72004-07-30 21:50:15 +000064// 'extra' allows the caller to pass in extra args to 'fn', like free
65// variables to a closure.
66void foreach_map(int (*fn)(char *start, char *end,
fitzhardinge7e343cd2003-12-16 02:14:00 +000067 const char *perm, off_t offset,
nethercote31779c72004-07-30 21:50:15 +000068 int maj, int min, int ino, void* extra),
69 void* extra)
fitzhardinge7e343cd2003-12-16 02:14:00 +000070{
71 static char buf[10240];
72 char *bufptr = buf;
73 int ret, fd;
74
75 fd = open("/proc/self/maps", O_RDONLY);
76
77 if (fd == -1) {
78 perror("open /proc/self/maps");
79 return;
80 }
81
82 ret = read(fd, buf, sizeof(buf));
83
84 if (ret == -1) {
85 perror("read /proc/self/maps");
86 close(fd);
87 return;
88 }
89 close(fd);
90
91 if (ret == sizeof(buf)) {
92 fprintf(stderr, "buf too small\n");
93 return;
94 }
95
96 while(bufptr && bufptr < buf+ret) {
97 char perm[5];
98 off_t offset;
99 int maj, min;
100 int ino;
101 void *segstart, *segend;
102
nethercote545fe672004-11-01 16:52:43 +0000103 sscanf(bufptr, "%p-%p %s %llx %x:%x %d",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000104 &segstart, &segend, perm, &offset, &maj, &min, &ino);
105 bufptr = strchr(bufptr, '\n');
106 if (bufptr != NULL)
107 bufptr++; /* skip \n */
108
nethercote31779c72004-07-30 21:50:15 +0000109 if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
fitzhardinge7e343cd2003-12-16 02:14:00 +0000110 break;
111 }
112}
113
nethercote31779c72004-07-30 21:50:15 +0000114/*------------------------------------------------------------*/
115/*--- Finding auxv on the stack ---*/
116/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000117
118struct ume_auxv *find_auxv(int *esp)
119{
120 esp++; /* skip argc */
121
122 while(*esp != 0) /* skip argv */
123 esp++;
124 esp++;
125
126 while(*esp != 0) /* skip env */
127 esp++;
128 esp++;
129
130 return (struct ume_auxv *)esp;
131}
132
nethercote31779c72004-07-30 21:50:15 +0000133/*------------------------------------------------------------*/
134/*--- Loading ELF files ---*/
135/*------------------------------------------------------------*/
fitzhardinge7e343cd2003-12-16 02:14:00 +0000136
137struct elfinfo *readelf(int fd, const char *filename)
138{
139 struct elfinfo *e = malloc(sizeof(*e));
140 int phsz;
141
nethercote7c018f42004-07-17 16:40:50 +0000142 assert(e);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000143 e->fd = fd;
144
145 if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
nethercote08eaff32004-07-22 12:41:12 +0000146 fprintf(stderr, "valgrind: %s: can't read elf header: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000147 filename, strerror(errno));
148 return NULL;
149 }
150
151 if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
nethercote08eaff32004-07-22 12:41:12 +0000152 fprintf(stderr, "valgrind: %s: bad ELF magic\n", filename);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000153 return NULL;
154 }
nethercotebdaa89f2004-10-09 19:08:08 +0000155 if (e->e.e_ident[EI_CLASS] != VG_ELF_CLASS) {
156 fprintf(stderr, "valgrind: wrong executable class (eg. 32-bit instead\n"
157 "valgrind: of 64-bit)\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000158 return NULL;
159 }
nethercotebdaa89f2004-10-09 19:08:08 +0000160 if (e->e.e_ident[EI_DATA] != VG_ELF_ENDIANNESS) {
161 fprintf(stderr, "valgrind: wrong endian-ness\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000162 return NULL;
163 }
164 if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
nethercote08eaff32004-07-22 12:41:12 +0000165 fprintf(stderr, "valgrind: need executable\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000166 return NULL;
167 }
168
nethercotebdaa89f2004-10-09 19:08:08 +0000169 if (e->e.e_machine != VG_ELF_MACHINE) {
170 fprintf(stderr, "valgrind: wrong architecture\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000171 return NULL;
172 }
173
174 if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
nethercote08eaff32004-07-22 12:41:12 +0000175 fprintf(stderr, "valgrind: sizeof Phdr wrong\n");
fitzhardinge7e343cd2003-12-16 02:14:00 +0000176 return NULL;
177 }
178
179 phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
180 e->p = malloc(phsz);
nethercote7c018f42004-07-17 16:40:50 +0000181 assert(e->p);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000182
183 if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
nethercote08eaff32004-07-22 12:41:12 +0000184 fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000185 return NULL;
186 }
187
188 return e;
189}
190
fitzhardinge7e343cd2003-12-16 02:14:00 +0000191/* Map an ELF file. Returns the brk address. */
fitzhardingeb50068f2004-02-24 23:42:55 +0000192ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000193{
194 int i;
nethercotebfed1c82004-07-17 12:57:44 +0000195 void* res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000196 ESZ(Addr) elfbrk = 0;
197
198 for(i = 0; i < e->e.e_phnum; i++) {
199 ESZ(Phdr) *ph = &e->p[i];
200 ESZ(Addr) addr, brkaddr;
201 ESZ(Word) memsz;
202
203 if (ph->p_type != PT_LOAD)
204 continue;
205
nethercote6c3cf412004-10-26 13:32:11 +0000206 addr = ph->p_vaddr+base;
207 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000208 brkaddr = addr+memsz;
209
210 if (brkaddr > elfbrk)
211 elfbrk = brkaddr;
212 }
213
fitzhardinge7e343cd2003-12-16 02:14:00 +0000214 for(i = 0; i < e->e.e_phnum; i++) {
215 ESZ(Phdr) *ph = &e->p[i];
216 ESZ(Addr) addr, bss, brkaddr;
217 ESZ(Off) off;
218 ESZ(Word) filesz;
219 ESZ(Word) memsz;
220 ESZ(Word) align;
221 unsigned prot = 0;
222
223 if (ph->p_type != PT_LOAD)
224 continue;
225
nethercote6c3cf412004-10-26 13:32:11 +0000226 if (ph->p_flags & PF_X) prot |= PROT_EXEC;
227 if (ph->p_flags & PF_W) prot |= PROT_WRITE;
228 if (ph->p_flags & PF_R) prot |= PROT_READ;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000229
nethercote6c3cf412004-10-26 13:32:11 +0000230 align = ph->p_align;
231 addr = ph->p_vaddr+base;
232 off = ph->p_offset;
233 filesz = ph->p_filesz;
234 bss = addr+filesz;
235 memsz = ph->p_memsz;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000236 brkaddr = addr+memsz;
237
nethercotebfed1c82004-07-17 12:57:44 +0000238 res = mmap((char *)ROUNDDN(addr, align),
239 ROUNDUP(bss, align)-ROUNDDN(addr, align),
240 prot, MAP_FIXED|MAP_PRIVATE, e->fd, ROUNDDN(off, align));
241 check_mmap(res, (char*)ROUNDDN(addr,align),
242 ROUNDUP(bss, align)-ROUNDDN(addr, align));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000243
244 /* if memsz > filesz, then we need to fill the remainder with zeroed pages */
245 if (memsz > filesz) {
246 UInt bytes;
247
248 bytes = ROUNDUP(brkaddr, align)-ROUNDUP(bss, align);
nethercotebfed1c82004-07-17 12:57:44 +0000249 if (bytes > 0) {
250 res = mmap((char *)ROUNDUP(bss, align), bytes,
251 prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
252 check_mmap(res, (char*)ROUNDUP(bss,align), bytes);
253 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000254
nethercote73b526f2004-10-31 18:48:21 +0000255 bytes = bss & (VKI_PAGE_SIZE - 1);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000256 if (bytes > 0) {
nethercote73b526f2004-10-31 18:48:21 +0000257 bytes = VKI_PAGE_SIZE - bytes;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000258 memset((char *)bss, 0, bytes);
259 }
260 }
261 }
262
263 return elfbrk;
264}
265
nethercote31779c72004-07-30 21:50:15 +0000266// Forward declaration.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000267static int do_exec_inner(const char *exe, struct exeinfo *info);
268
fitzhardinge7e343cd2003-12-16 02:14:00 +0000269static int match_ELF(const char *hdr, int len)
270{
271 ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
272 return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
273}
274
nethercote31779c72004-07-30 21:50:15 +0000275static int load_ELF(char *hdr, int len, int fd, const char *name,
276 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277{
278 struct elfinfo *e;
279 struct elfinfo *interp = NULL;
fitzhardingeca9bd9c2004-09-08 20:05:02 +0000280 ESZ(Addr) minaddr = ~0; /* lowest mapped address */
281 ESZ(Addr) maxaddr = 0; /* highest mapped address */
282 ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
283 ESZ(Word) interp_size = 0; /* interpreter size */
nethercote73b526f2004-10-31 18:48:21 +0000284 ESZ(Word) interp_align = VKI_PAGE_SIZE;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000285 int i;
286 void *entry;
nethercote7f390022004-10-25 17:18:24 +0000287 ESZ(Addr) ebase = 0;
288
289#ifdef HAVE_PIE
290 ebase = info->exe_base;
291#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000292
293 e = readelf(fd, name);
294
295 if (e == NULL)
296 return ENOEXEC;
297
298 info->phnum = e->e.e_phnum;
nethercote7f390022004-10-25 17:18:24 +0000299 info->entry = e->e.e_entry + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300
301 for(i = 0; i < e->e.e_phnum; i++) {
302 ESZ(Phdr) *ph = &e->p[i];
303
304 switch(ph->p_type) {
305 case PT_PHDR:
nethercote7f390022004-10-25 17:18:24 +0000306 info->phdr = ph->p_vaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000307 break;
308
309 case PT_LOAD:
310 if (ph->p_vaddr < minaddr)
311 minaddr = ph->p_vaddr;
312 if (ph->p_vaddr+ph->p_memsz > maxaddr)
313 maxaddr = ph->p_vaddr+ph->p_memsz;
314 break;
315
316 case PT_INTERP: {
317 char *buf = malloc(ph->p_filesz+1);
318 int j;
319 int intfd;
320 int baseaddr_set;
321
nethercote7c018f42004-07-17 16:40:50 +0000322 assert(buf);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000323 pread(fd, buf, ph->p_filesz, ph->p_offset);
324 buf[ph->p_filesz] = '\0';
325
326 intfd = open(buf, O_RDONLY);
327 if (intfd == -1) {
328 perror("open interp");
329 exit(1);
330 }
331
332 interp = readelf(intfd, buf);
333 if (interp == NULL) {
334 fprintf(stderr, "Can't read interpreter\n");
335 return 1;
336 }
337 free(buf);
338
339 baseaddr_set = 0;
340 for(j = 0; j < interp->e.e_phnum; j++) {
341 ESZ(Phdr) *iph = &interp->p[j];
342 ESZ(Addr) end;
343
344 if (iph->p_type != PT_LOAD)
345 continue;
346
347 if (!baseaddr_set) {
nethercote7f390022004-10-25 17:18:24 +0000348 interp_addr = iph->p_vaddr;
349 interp_align = iph->p_align;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000350 baseaddr_set = 1;
351 }
352
353 /* assumes that all segments in the interp are close */
354 end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
355
356 if (end > interp_size)
357 interp_size = end;
358 }
359 break;
nethercoteb24cbc82004-09-03 23:25:33 +0000360
361 default:
362 // do nothing
363 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000364 }
365 }
366 }
367
368 if (info->exe_base != info->exe_end) {
369 if (minaddr >= maxaddr ||
nethercote7f390022004-10-25 17:18:24 +0000370 (minaddr + ebase < info->exe_base ||
371 maxaddr + ebase > info->exe_end)) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000372 fprintf(stderr, "Executable range %p-%p is outside the\n"
373 "acceptable range %p-%p\n",
nethercote7f390022004-10-25 17:18:24 +0000374 (void *)minaddr + ebase, (void *)maxaddr + ebase,
375 (void *)info->exe_base, (void *)info->exe_end);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000376 return ENOMEM;
377 }
378 }
379
nethercote7f390022004-10-25 17:18:24 +0000380 info->brkbase = mapelf(e, ebase); /* map the executable */
fitzhardinge7e343cd2003-12-16 02:14:00 +0000381
fitzhardinge92360792003-12-24 10:11:11 +0000382 if (info->brkbase == 0)
383 return ENOMEM;
384
fitzhardinge7e343cd2003-12-16 02:14:00 +0000385 if (interp != NULL) {
386 /* reserve a chunk of address space for interpreter */
nethercotebfed1c82004-07-17 12:57:44 +0000387 void* res;
388 char* base = (char *)info->exe_base;
389 char* baseoff;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000390 int flags = MAP_PRIVATE|MAP_ANONYMOUS;
391
392 if (info->map_base != 0) {
nethercote7f390022004-10-25 17:18:24 +0000393 base = (char *)ROUNDUP(info->map_base, interp_align);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000394 flags |= MAP_FIXED;
395 }
396
nethercotebfed1c82004-07-17 12:57:44 +0000397 res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
398 check_mmap(res, base, interp_size);
399 base = res;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000400
401 baseoff = base - interp_addr;
402
fitzhardingeb50068f2004-02-24 23:42:55 +0000403 mapelf(interp, (ESZ(Addr))baseoff);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000404
405 close(interp->fd);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000406
407 entry = baseoff + interp->e.e_entry;
408 info->interp_base = (ESZ(Addr))base;
thughes54d08592004-09-26 14:42:47 +0000409
410 free(interp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000411 } else
nethercote7f390022004-10-25 17:18:24 +0000412 entry = (void *)e->e.e_entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000413
nethercote7f390022004-10-25 17:18:24 +0000414 info->exe_base = minaddr + ebase;
415 info->exe_end = maxaddr + ebase;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000416
417 info->init_eip = (addr_t)entry;
418
419 free(e);
420
421 return 0;
422}
423
424
425static int match_script(const char *hdr, Int len)
426{
427 return (len > 2) && memcmp(hdr, "#!", 2) == 0;
428}
429
nethercote31779c72004-07-30 21:50:15 +0000430static int load_script(char *hdr, int len, int fd, const char *name,
431 struct exeinfo *info)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000432{
433 char *interp;
434 char *const end = hdr+len;
435 char *cp;
436 char *arg = NULL;
437 int eol;
438
439 interp = hdr + 2;
440 while(interp < end && (*interp == ' ' || *interp == '\t'))
441 interp++;
442
443 if (*interp != '/')
444 return ENOEXEC; /* absolute path only for interpreter */
445
446 /* skip over interpreter name */
447 for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
448 ;
449
450 eol = (*cp == '\n');
451
452 *cp++ = '\0';
453
454 if (!eol && cp < end) {
455 /* skip space before arg */
456 while (cp < end && (*cp == '\t' || *cp == ' '))
457 cp++;
458
459 /* arg is from here to eol */
460 arg = cp;
461 while (cp < end && *cp != '\n')
462 cp++;
463 *cp = '\0';
464 }
465
nethercoted6a56872004-07-26 15:32:47 +0000466 info->interp_name = strdup(interp);
467 assert(NULL != info->interp_name);
nethercote71980f02004-01-24 18:18:54 +0000468 if (arg != NULL && *arg != '\0') {
nethercoted6a56872004-07-26 15:32:47 +0000469 info->interp_args = strdup(arg);
470 assert(NULL != info->interp_args);
nethercote71980f02004-01-24 18:18:54 +0000471 }
fitzhardinge7e343cd2003-12-16 02:14:00 +0000472
473 if (info->argv && info->argv[0] != NULL)
474 info->argv[0] = (char *)name;
475
476 if (0)
nethercoted6a56872004-07-26 15:32:47 +0000477 printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
478 info->interp_name, info->interp_args);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000479
480 return do_exec_inner(interp, info);
481}
482
fitzhardingefd7da3a2004-09-08 20:05:29 +0000483/*
484 Emulate the normal Unix permissions checking algorithm.
485
486 If owner matches, then use the owner permissions, else
487 if group matches, then use the group permissions, else
488 use other permissions.
489
490 Note that we can't deal with SUID/SGID, so we refuse to run them
491 (otherwise the executable may misbehave if it doesn't have the
492 permissions it thinks it does).
493*/
494static int check_perms(int fd)
495{
496 struct stat st;
497
498 if (fstat(fd, &st) == -1)
499 return errno;
500
501 if (st.st_mode & (S_ISUID | S_ISGID)) {
502 //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
503 return EACCES;
504 }
505
506 if (geteuid() == st.st_uid) {
507 if (!(st.st_mode & S_IXUSR))
508 return EACCES;
509 } else {
510 int grpmatch = 0;
511
512 if (getegid() == st.st_gid)
513 grpmatch = 1;
514 else {
515 gid_t groups[32];
516 int ngrp = getgroups(32, groups);
517 int i;
518
519 for(i = 0; i < ngrp; i++)
520 if (groups[i] == st.st_gid) {
521 grpmatch = 1;
522 break;
523 }
524 }
525
526 if (grpmatch) {
527 if (!(st.st_mode & S_IXGRP))
528 return EACCES;
529 } else if (!(st.st_mode & S_IXOTH))
530 return EACCES;
531 }
532
533 return 0;
534}
535
fitzhardinge7e343cd2003-12-16 02:14:00 +0000536static int do_exec_inner(const char *exe, struct exeinfo *info)
537{
538 int fd;
fitzhardinged2e37112004-09-09 08:10:42 +0000539 int err;
nethercote73b526f2004-10-31 18:48:21 +0000540 char buf[VKI_PAGE_SIZE];
fitzhardinge7e343cd2003-12-16 02:14:00 +0000541 int bufsz;
542 int i;
543 int ret;
nethercote31779c72004-07-30 21:50:15 +0000544 static const struct {
545 int (*match)(const char *hdr, int len);
546 int (*load) ( char *hdr, int len, int fd2, const char *name,
547 struct exeinfo *);
548 } formats[] = {
549 { match_ELF, load_ELF },
550 { match_script, load_script },
551 };
fitzhardinge7e343cd2003-12-16 02:14:00 +0000552
553 fd = open(exe, O_RDONLY);
554 if (fd == -1) {
555 if (0)
556 fprintf(stderr, "Can't open executable %s: %s\n",
557 exe, strerror(errno));
558 return errno;
559 }
560
fitzhardinged2e37112004-09-09 08:10:42 +0000561 err = check_perms(fd);
fitzhardingefd7da3a2004-09-08 20:05:29 +0000562 if (err != 0) {
563 close(fd);
564 return err;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000565 }
566
567 bufsz = pread(fd, buf, sizeof(buf), 0);
568 if (bufsz < 0) {
569 fprintf(stderr, "Can't read executable header: %s\n",
570 strerror(errno));
571 close(fd);
572 return errno;
573 }
574
575 ret = ENOEXEC;
576 for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
577 if ((formats[i].match)(buf, bufsz)) {
578 ret = (formats[i].load)(buf, bufsz, fd, exe, info);
579 break;
580 }
581 }
582
583 close(fd);
584
585 return ret;
586}
587
nethercoteea147e72004-07-26 15:43:57 +0000588// See ume.h for an indication of which entries of 'info' are inputs, which
589// are outputs, and which are both.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000590int do_exec(const char *exe, struct exeinfo *info)
591{
nethercoted6a56872004-07-26 15:32:47 +0000592 info->interp_name = NULL;
593 info->interp_args = NULL;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000594
595 return do_exec_inner(exe, info);
596}
nethercotebb1c9912004-01-04 16:43:23 +0000597
598/*--------------------------------------------------------------------*/
599/*--- end ume.c ---*/
600/*--------------------------------------------------------------------*/