1 /* This file handles the EXEC system call. It performs the work as follows:
2 * - see if the permissions allow the file to be executed
3 * - read the header and extract the sizes
4 * - fetch the initial args and environment from the user space
5 * - allocate the memory for the new process
6 * - copy the initial stack from PM to the process
7 * - read in the text and data segments and copy to the process
8 * - take care of setuid and setgid bits
9 * - fix up 'mproc' table
10 * - tell kernel about EXEC
11 * - save offset to initial argc (for ps)
13 * The entry points into this file are:
14 * pm_exec: perform the EXEC system call
20 #include <minix/callnr.h>
21 #include <minix/endpoint.h>
22 #include <minix/com.h>
23 #include <minix/u64.h>
27 #include <sys/dirent.h>
29 #include <sys/param.h>
33 #include <minix/vfsif.h>
34 #include <machine/vmparam.h>
38 #define _KERNEL /* for ELF_AUX_ENTRIES */
41 /* fields only used by elf and in VFS */
42 struct vfs_exec_info
{
43 struct exec_info args
; /* libexec exec args */
44 struct vnode
*vp
; /* Exec file's vnode */
45 struct vmnt
*vmp
; /* Exec file's vmnt */
46 struct stat sb
; /* Exec file's stat structure */
47 int userflags
; /* exec() flags from userland */
48 int is_dyn
; /* Dynamically linked executable */
49 int elf_main_fd
; /* Dyn: FD of main program execuatble */
50 char execname
[PATH_MAX
]; /* Full executable invocation */
55 static int patch_stack(struct vnode
*vp
, char stack
[ARG_MAX
],
56 size_t *stk_bytes
, char path
[PATH_MAX
], vir_bytes
*vsp
);
57 static int is_script(struct vfs_exec_info
*execi
);
58 static int insert_arg(char stack
[ARG_MAX
], size_t *stk_bytes
, char *arg
,
59 vir_bytes
*vsp
, char replace
);
60 static void clo_exec(struct fproc
*rfp
);
61 static int stack_prepare_elf(struct vfs_exec_info
*execi
,
62 char *curstack
, size_t *frame_len
, vir_bytes
*vsp
);
63 static int map_header(struct vfs_exec_info
*execi
);
64 static int read_seg(struct exec_info
*execi
, off_t off
, vir_bytes seg_addr
, size_t seg_bytes
);
66 #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */
68 /* Array of loaders for different object file formats */
69 typedef int (*exechook_t
)(struct vfs_exec_info
*execpackage
);
70 typedef int (*stackhook_t
)(struct vfs_exec_info
*execi
, char *curstack
,
71 size_t *frame_len
, vir_bytes
*vsp
);
73 libexec_exec_loadfunc_t load_object
; /* load executable into memory */
74 stackhook_t setup_stack
; /* prepare stack before argc and argv push */
77 static const struct exec_loaders exec_loaders
[] = {
78 { libexec_load_elf
, stack_prepare_elf
},
82 #define lock_exec() lock_proc(fproc_addr(VM_PROC_NR))
83 #define unlock_exec() unlock_proc(fproc_addr(VM_PROC_NR))
85 /*===========================================================================*
87 *===========================================================================*/
88 static int get_read_vp(struct vfs_exec_info
*execi
,
89 char *fullpath
, int copyprogname
, int sugid
, struct lookup
*resolve
, struct fproc
*fp
)
91 /* Make the executable that we want to exec() into the binary pointed
92 * to by 'fullpath.' This function fills in necessary details in the execi
93 * structure, such as opened vnode. It unlocks and releases the vnode if
94 * it was already there. This makes it easy to change the executable
95 * during the exec(), which is often necessary, by calling this function
96 * more than once. This is specifically necessary when we discover the
97 * executable is actually a script or a dynamically linked executable.
101 /* Caller wants to switch vp to the file in 'fullpath.'
102 * unlock and put it first if there is any there.
105 unlock_vnode(execi
->vp
);
106 put_vnode(execi
->vp
);
110 /* Remember/overwrite the executable name if requested. */
112 char *cp
= strrchr(fullpath
, '/');
115 strlcpy(execi
->args
.progname
, cp
, sizeof(execi
->args
.progname
));
116 execi
->args
.progname
[sizeof(execi
->args
.progname
)-1] = '\0';
119 /* Open executable */
120 if ((execi
->vp
= eat_path(resolve
, fp
)) == NULL
)
123 unlock_vmnt(execi
->vmp
);
125 if (!S_ISREG(execi
->vp
->v_mode
))
127 else if ((r
= forbidden(fp
, execi
->vp
, X_BIT
)) != OK
)
130 r
= req_stat(execi
->vp
->v_fs_e
, execi
->vp
->v_inode_nr
,
131 VFS_PROC_NR
, (vir_bytes
) &(execi
->sb
));
133 if (r
!= OK
) return r
;
135 /* If caller wants us to, honour suid/guid mode bits. */
137 /* Deal with setuid/setgid executables */
138 if (execi
->vp
->v_mode
& I_SET_UID_BIT
) {
139 execi
->args
.new_uid
= execi
->vp
->v_uid
;
140 execi
->args
.allow_setuid
= 1;
142 if (execi
->vp
->v_mode
& I_SET_GID_BIT
) {
143 execi
->args
.new_gid
= execi
->vp
->v_gid
;
144 execi
->args
.allow_setuid
= 1;
148 /* Read in first chunk of file. */
149 if((r
=map_header(execi
)) != OK
)
155 #define FAILCHECK(expr) if((r=(expr)) != OK) { goto pm_execfinal; } while(0)
156 #define Get_read_vp(e,f,p,s,rs,fp) do { \
157 r=get_read_vp(&e,f,p,s,rs,fp); if(r != OK) { FAILCHECK(r); } \
160 static int vfs_memmap(struct exec_info
*execi
,
161 vir_bytes vaddr
, vir_bytes len
, vir_bytes foffset
, u16_t clearend
,
164 struct vfs_exec_info
*vi
= (struct vfs_exec_info
*) execi
->opaque
;
165 struct vnode
*vp
= ((struct vfs_exec_info
*) execi
->opaque
)->vp
;
169 if(protflags
& PROT_WRITE
)
170 flags
|= MVM_WRITABLE
;
172 r
= minix_vfs_mmap(execi
->proc_e
, foffset
, len
,
173 vp
->v_dev
, vp
->v_inode_nr
, vi
->vmfd
, vaddr
, clearend
, flags
);
181 /*===========================================================================*
183 *===========================================================================*/
184 int pm_exec(vir_bytes path
, size_t path_len
, vir_bytes frame
, size_t frame_len
,
185 vir_bytes
*pc
, vir_bytes
*newsp
, vir_bytes
*UNUSED(ps_str
))
187 /* Perform the execve(name, argv, envp) call. The user library builds a
188 * complete stack image, including pointers, args, environ, etc. The stack
189 * is copied to a buffer inside VFS, and then to the new core image.
191 * ps_str is not currently used, but may be if the ps_strings structure has to
192 * be moved to another location.
196 static char mbuf
[ARG_MAX
]; /* buffer for stack and zeroes */
197 struct vfs_exec_info execi
;
199 static char fullpath
[PATH_MAX
],
200 elf_interpreter
[PATH_MAX
],
203 struct lookup resolve
;
204 struct fproc
*vmfp
= fproc_addr(VM_PROC_NR
);
205 stackhook_t makestack
= NULL
;
206 struct filp
*newfilp
= NULL
;
210 /* unset execi values are 0. */
211 memset(&execi
, 0, sizeof(execi
));
214 /* passed from exec() libc code */
216 execi
.args
.stack_high
= kinfo
.user_sp
;
217 execi
.args
.stack_size
= DEFAULT_STACK_LIMIT
;
222 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &execi
.vmp
, &execi
.vp
);
224 resolve
.l_vmnt_lock
= VMNT_READ
;
225 resolve
.l_vnode_lock
= VNODE_READ
;
227 /* Fetch the stack from the user before destroying the old core image. */
228 if (frame_len
> ARG_MAX
)
229 FAILCHECK(ENOMEM
); /* stack too big */
231 r
= sys_datacopy_wrapper(fp
->fp_endpoint
, (vir_bytes
) frame
, SELF
, (vir_bytes
) mbuf
,
233 if (r
!= OK
) { /* can't fetch stack (e.g. bad virtual addr) */
234 printf("VFS: pm_exec: sys_datacopy failed\n");
238 /* Compute the current virtual stack pointer, has to be done before calling
239 * patch_stack, which needs it, and will adapt as required. */
240 vsp
= execi
.args
.stack_high
- frame_len
;
242 /* The default is to keep the original user and group IDs */
243 execi
.args
.new_uid
= fp
->fp_effuid
;
244 execi
.args
.new_gid
= fp
->fp_effgid
;
246 /* Get the exec file name. */
247 FAILCHECK(fetch_name(path
, path_len
, fullpath
));
248 strlcpy(finalexec
, fullpath
, PATH_MAX
);
249 strlcpy(firstexec
, fullpath
, PATH_MAX
);
251 /* Get_read_vp will return an opened vn in execi.
252 * if necessary it releases the existing vp so we can
253 * switch after we find out what's inside the file.
254 * It reads the start of the file.
256 Get_read_vp(execi
, fullpath
, 1, 1, &resolve
, fp
);
258 /* If this is a script (i.e. has a #!/interpreter line),
259 * retrieve the name of the interpreter and open that
260 * executable instead.
262 if(is_script(&execi
)) {
263 /* patch_stack will add interpreter name and
264 * args to stack and retrieve the new binary
265 * name into fullpath.
267 FAILCHECK(fetch_name(path
, path_len
, fullpath
));
268 FAILCHECK(patch_stack(execi
.vp
, mbuf
, &frame_len
, fullpath
, &vsp
));
270 strlcpy(finalexec
, fullpath
, PATH_MAX
);
271 strlcpy(firstexec
, fullpath
, PATH_MAX
);
272 Get_read_vp(execi
, fullpath
, 1, 0, &resolve
, fp
);
275 /* If this is a dynamically linked executable, retrieve
276 * the name of that interpreter in elf_interpreter and open that
277 * executable instead. But open the current executable in an
278 * fd for the current process.
280 if(elf_has_interpreter(execi
.args
.hdr
, execi
.args
.hdr_len
,
281 elf_interpreter
, sizeof(elf_interpreter
))) {
282 /* Switch the executable vnode to the interpreter */
285 /* The interpreter (loader) needs an fd to the main program,
286 * which is currently in finalexec
288 if((r
= execi
.elf_main_fd
= common_open(finalexec
, O_RDONLY
, 0)) < 0) {
289 printf("VFS: exec: dynamic: open main exec failed %s (%d)\n",
294 /* ld.so is linked at 0, but it can relocate itself; we
295 * want it higher to trap NULL pointer dereferences.
296 * Let's put it below the stack, and reserve 10MB for ld.so.
298 execi
.args
.load_offset
=
299 execi
.args
.stack_high
- execi
.args
.stack_size
- 0xa00000;
302 strlcpy(execi
.execname
, finalexec
, PATH_MAX
);
304 /* The executable we need to execute first (loader)
305 * is in elf_interpreter, and has to be in fullpath to
308 strlcpy(fullpath
, elf_interpreter
, PATH_MAX
);
309 strlcpy(firstexec
, elf_interpreter
, PATH_MAX
);
310 Get_read_vp(execi
, fullpath
, 0, 0, &resolve
, fp
);
313 /* We also want an FD for VM to mmap() the process in if possible. */
315 struct vnode
*vp
= execi
.vp
;
317 if ((vp
->v_vmnt
->m_fs_flags
& RES_HASPEEK
) &&
318 major(vp
->v_dev
) != MEMORY_MAJOR
) {
320 if(get_fd(vmfp
, 0, R_BIT
, &newfd
, &newfilp
) == OK
) {
321 assert(newfd
>= 0 && newfd
< OPEN_MAX
);
322 assert(!vmfp
->fp_filp
[newfd
]);
323 newfilp
->filp_count
= 1;
324 newfilp
->filp_vno
= vp
;
325 newfilp
->filp_flags
= O_RDONLY
;
326 vmfp
->fp_filp
[newfd
] = newfilp
;
329 execi
.args
.memmap
= vfs_memmap
;
334 /* callback functions and data */
335 execi
.args
.copymem
= read_seg
;
336 execi
.args
.clearproc
= libexec_clearproc_vm_procctl
;
337 execi
.args
.clearmem
= libexec_clear_sys_memset
;
338 execi
.args
.allocmem_prealloc_cleared
= libexec_alloc_mmap_prealloc_cleared
;
339 execi
.args
.allocmem_prealloc_junk
= libexec_alloc_mmap_prealloc_junk
;
340 execi
.args
.allocmem_ondemand
= libexec_alloc_mmap_ondemand
;
341 execi
.args
.opaque
= &execi
;
343 execi
.args
.proc_e
= fp
->fp_endpoint
;
344 execi
.args
.frame_len
= frame_len
;
345 execi
.args
.filesize
= execi
.vp
->v_size
;
347 for (i
= 0; exec_loaders
[i
].load_object
!= NULL
; i
++) {
348 r
= (*exec_loaders
[i
].load_object
)(&execi
.args
);
349 /* Loaded successfully, so no need to try other loaders */
350 if (r
== OK
) { makestack
= exec_loaders
[i
].setup_stack
; break; }
356 FAILCHECK(libexec_pm_newexec(fp
->fp_endpoint
, &execi
.args
));
361 /* call a stack-setup function if this executable type wants it */
362 if(makestack
) FAILCHECK(makestack(&execi
, mbuf
, &frame_len
, &vsp
));
364 /* Copy the stack from VFS to new core image. */
365 FAILCHECK(sys_datacopy_wrapper(SELF
, (vir_bytes
) mbuf
, fp
->fp_endpoint
,
366 (vir_bytes
) vsp
, (phys_bytes
)frame_len
));
368 /* Return new stack pointer to caller */
373 if (execi
.args
.allow_setuid
) {
374 /* If after loading the image we're still allowed to run with
375 * setuid or setgid, change credentials now */
376 fp
->fp_effuid
= execi
.args
.new_uid
;
377 fp
->fp_effgid
= execi
.args
.new_gid
;
380 /* Remember the new name of the process */
381 strlcpy(fp
->fp_name
, execi
.args
.progname
, PROC_NAME_LEN
);
382 fp
->text_size
= execi
.args
.text_size
;
383 fp
->data_size
= execi
.args
.data_size
;
386 if(newfilp
) unlock_filp(newfilp
);
387 else if (execi
.vp
!= NULL
) {
388 unlock_vnode(execi
.vp
);
392 if(execi
.vmfd
>= 0 && !execi
.vmfd_used
) {
393 if(OK
!= close_fd(vmfp
, execi
.vmfd
)) {
394 printf("VFS: unexpected close fail of vm fd\n");
403 /* This is a copy-paste of the same macro in minix/lib/libc/sys/stack_utils.c.
404 * Keep it synchronized. */
405 #define STACK_MIN_SZ \
407 sizeof(int) + sizeof(void *) * 2 + \
408 sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
409 sizeof(struct ps_strings) \
412 static int stack_prepare_elf(struct vfs_exec_info
*execi
, char *frame
, size_t *frame_size
,
415 AuxInfo
*aux_vec
, *aux_vec_end
;
416 vir_bytes vap
; /* Address in proc space of the first AuxVec. */
417 Elf_Ehdr
const * const elf_header
= (Elf_Ehdr
*) execi
->args
.hdr
;
418 struct ps_strings
const * const psp
= (struct ps_strings
*)
419 (frame
+ (*frame_size
- sizeof(struct ps_strings
)));
421 size_t const execname_len
= strlen(execi
->execname
);
426 if (execi
->args
.hdr_len
< sizeof(*elf_header
)) {
427 printf("VFS: malformed ELF headers for exec\n");
431 if (*frame_size
< STACK_MIN_SZ
) {
432 printf("VFS: malformed stack for exec(), smaller than minimum"
433 " possible size.\n");
437 /* Find first Aux vector in the stack frame. */
438 vap
= (vir_bytes
)(psp
->ps_envstr
+ (psp
->ps_nenvstr
+ 1));
439 aux_vec
= (AuxInfo
*) (frame
+ (vap
- *vsp
));
440 aux_vec_end
= aux_vec
+ PMEF_AUXVECTORS
;
442 if (((char *)aux_vec
< frame
) ||
443 ((char *)aux_vec
> (frame
+ *frame_size
))) {
444 printf("VFS: malformed stack for exec(), first AuxVector is"
445 " not on the stack.\n");
449 if (((char *)aux_vec_end
< frame
) ||
450 ((char *)aux_vec_end
> (frame
+ *frame_size
))) {
451 printf("VFS: malformed stack for exec(), last AuxVector is"
452 " not on the stack.\n");
456 /* Userland provides a fully filled stack frame, with argc, argv, envp
457 * and then all the argv and envp strings; consistent with ELF ABI,
458 * except for a list of Aux vectors that should be between envp points
459 * and the start of the strings.
461 * It would take some very unpleasant hackery to insert the aux vectors
462 * before the strings, and correct all the pointers, so the exec code
463 * in libc makes space for us.
466 #define AUXINFO(a, type, value) \
468 if (a < aux_vec_end) { \
473 printf("VFS: No more room for ELF AuxVec type %d, skipping it for %s\n", type, execi->execname); \
474 (aux_vec_end - 1)->a_type = AT_NULL; \
475 (aux_vec_end - 1)->a_v = 0; \
479 AUXINFO(aux_vec
, AT_BASE
, execi
->args
.load_base
);
480 AUXINFO(aux_vec
, AT_ENTRY
, execi
->args
.pc
);
481 AUXINFO(aux_vec
, AT_EXECFD
, execi
->elf_main_fd
);
483 AUXINFO(aux_vec
, AT_PHDR
, XXX
); /* should be &phdr[0] */
484 AUXINFO(aux_vec
, AT_PHENT
, elf_header
->e_phentsize
);
485 AUXINFO(aux_vec
, AT_PHNUM
, elf_header
->e_phnum
);
487 AUXINFO(aux_vec
, AT_RUID
, XXX
);
488 AUXINFO(aux_vec
, AT_RGID
, XXX
);
490 AUXINFO(aux_vec
, AT_EUID
, execi
->args
.new_uid
);
491 AUXINFO(aux_vec
, AT_EGID
, execi
->args
.new_gid
);
492 AUXINFO(aux_vec
, AT_PAGESZ
, PAGE_SIZE
);
494 if(execname_len
< PMEF_EXECNAMELEN1
) {
498 /* Empty space starts after aux_vec table; we can put the name
500 spacestart
= (char *) aux_vec
+ 2 * sizeof(AuxInfo
);
501 strlcpy(spacestart
, execi
->execname
, PMEF_EXECNAMELEN1
);
502 memset(spacestart
+ execname_len
, '\0',
503 PMEF_EXECNAMELEN1
- execname_len
);
505 /* What will the address of the string for the user be */
506 userp
= *vsp
+ (spacestart
- frame
);
508 /* Move back to where the AT_NULL is */
509 AUXINFO(aux_vec
, AT_SUN_EXECNAME
, userp
);
512 /* Always terminate with AT_NULL */
513 AUXINFO(aux_vec
, AT_NULL
, 0);
518 /*===========================================================================*
520 *===========================================================================*/
521 static int is_script(struct vfs_exec_info
*execi
)
523 /* Is Interpreted script? */
524 assert(execi
->args
.hdr
!= NULL
);
526 return(execi
->args
.hdr
[0] == '#' && execi
->args
.hdr
[1] == '!'
527 && execi
->args
.hdr_len
>= 2);
530 /*===========================================================================*
532 *===========================================================================*/
533 static int patch_stack(vp
, stack
, stk_bytes
, path
, vsp
)
534 struct vnode
*vp
; /* pointer for open script file */
535 char stack
[ARG_MAX
]; /* pointer to stack image within VFS */
536 size_t *stk_bytes
; /* size of initial stack */
537 char path
[PATH_MAX
]; /* path to script file */
540 /* Patch the argument vector to include the path name of the script to be
541 * interpreted, and all strings on the #! line. Returns the path name of
544 enum { INSERT
=FALSE
, REPLACE
=TRUE
};
547 char *sp
, *interp
= NULL
;
551 /* Make 'path' the new argv[0]. */
552 if (!insert_arg(stack
, stk_bytes
, path
, vsp
, REPLACE
)) return(ENOMEM
);
554 pos
= 0; /* Read from the start of the file */
557 r
= req_readwrite(vp
->v_fs_e
, vp
->v_inode_nr
, pos
, READING
, VFS_PROC_NR
,
558 (vir_bytes
) buf
, sizeof(buf
), &new_pos
, &cum_io
);
560 if (r
!= OK
) return(r
);
565 if (n
< 2) return ENOEXEC
;
567 sp
= &(buf
[2]); /* just behind the #! */
569 if (n
> PATH_MAX
) n
= PATH_MAX
;
571 /* Use the 'path' variable for temporary storage */
574 if ((sp
= memchr(path
, '\n', n
)) == NULL
) /* must be a proper line */
577 /* Move sp backwards through script[], prepending each string to stack. */
579 /* skip spaces behind argument. */
580 while (sp
> path
&& (*--sp
== ' ' || *sp
== '\t')) {}
581 if (sp
== path
) break;
584 /* Move to the start of the argument. */
585 while (sp
> path
&& sp
[-1] != ' ' && sp
[-1] != '\t') --sp
;
588 if (!insert_arg(stack
, stk_bytes
, sp
, vsp
, INSERT
)) {
589 printf("VFS: patch_stack: insert_arg failed\n");
598 memmove(path
, interp
, strlen(interp
)+1);
603 /*===========================================================================*
605 *===========================================================================*/
606 static int insert_arg(char stack
[ARG_MAX
], size_t *stk_bytes
, char *arg
,
607 vir_bytes
*vsp
, char replace
)
609 /* Patch the stack so that arg will become argv[0]. Be careful, the
610 * stack may be filled with garbage, although it normally looks like
612 * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL
613 * followed by the strings "pointed" to by the argv[i] and the envp[i].
614 * The * pointers are in the new process address space.
616 * Return true iff the operation succeeded.
618 struct ps_strings
*psp
;
620 size_t old_bytes
= *stk_bytes
;
622 int const arg_len
= strlen(arg
) + 1;
624 /* Offset to argv[0][0] in the stack frame. */
625 int const a0
= (int)(((char **)stack
)[1] - *vsp
);
627 /* Check that argv[0] points within the stack frame. */
628 if ((a0
< 0) || (a0
>= old_bytes
)) {
629 printf("vfs:: argv[0][] not within stack range!! %i\n", a0
);
634 /* Prepending arg adds one pointer, one string and a zero byte. */
635 offset
= arg_len
+ PTRSIZE
;
637 /* replacing argv[0] with arg adds the difference in length of
638 * the two strings. Make sure we don't go beyond the stack size
639 * when computing the length of the current argv[0]. */
640 offset
= arg_len
- strnlen(stack
+ a0
, ARG_MAX
- a0
- 1);
643 /* As ps_strings follows the strings, ensure the offset is word aligned. */
644 offset
= offset
+ (PTRSIZE
- ((PTRSIZE
+ offset
) % PTRSIZE
));
646 /* The stack will grow (or shrink) by offset bytes. */
647 if ((*stk_bytes
+= offset
) > ARG_MAX
) {
648 printf("vfs:: offset too big!! %d (max %d)\n", *stk_bytes
,
653 /* Reposition the strings by offset bytes */
654 memmove(stack
+ a0
+ offset
, stack
+ a0
, old_bytes
- a0
);
656 /* Put arg in the new space, leaving padding in front of it. */
657 strlcpy(stack
+ a0
+ offset
- arg_len
, arg
, arg_len
);
660 /* Make space for a new argv[0]. */
661 memmove(stack
+ 2 * PTRSIZE
,
662 stack
+ 1 * PTRSIZE
, a0
- 2 * PTRSIZE
);
664 ((char **) stack
)[0]++; /* nargs++; */
667 /* set argv[0] correctly */
668 ((char **) stack
)[1] = (char *) a0
- arg_len
+ *vsp
;
670 /* Update stack pointer in the process address space. */
673 /* Update argv and envp in ps_strings */
674 psp
= (struct ps_strings
*) (stack
+ *stk_bytes
- sizeof(struct ps_strings
));
675 psp
->ps_argvstr
-= (offset
/ PTRSIZE
);
679 psp
->ps_envstr
= psp
->ps_argvstr
+ psp
->ps_nargvstr
+ 1;
684 /*===========================================================================*
686 *===========================================================================*/
687 static int read_seg(struct exec_info
*execi
, off_t off
, vir_bytes seg_addr
, size_t seg_bytes
)
690 * The byte count on read is usually smaller than the segment count, because
691 * a segment is padded out to a click multiple, and the data segment is only
692 * partially initialized.
697 struct vnode
*vp
= ((struct vfs_exec_info
*) execi
->opaque
)->vp
;
699 /* Make sure that the file is big enough */
700 if (off
+ seg_bytes
> LONG_MAX
) return(EIO
);
701 if ((unsigned long) vp
->v_size
< off
+seg_bytes
) return(EIO
);
703 if ((r
= req_readwrite(vp
->v_fs_e
, vp
->v_inode_nr
, off
, READING
,
704 execi
->proc_e
, (vir_bytes
) seg_addr
, seg_bytes
,
705 &new_pos
, &cum_io
)) != OK
) {
706 printf("VFS: read_seg: req_readwrite failed (data)\n");
710 if (r
== OK
&& cum_io
!= seg_bytes
)
711 printf("VFS: read_seg segment has not been read properly\n");
717 /*===========================================================================*
719 *===========================================================================*/
720 static void clo_exec(struct fproc
*rfp
)
722 /* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec).
726 /* Check the file desriptors one by one for presence of FD_CLOEXEC. */
727 for (i
= 0; i
< OPEN_MAX
; i
++)
728 if ( FD_ISSET(i
, &rfp
->fp_cloexec_set
))
729 (void) close_fd(rfp
, i
);
732 /*===========================================================================*
734 *===========================================================================*/
735 static int map_header(struct vfs_exec_info
*execi
)
740 static char hdr
[PAGE_SIZE
]; /* Assume that header is not larger than a page */
742 pos
= 0; /* Read from the start of the file */
744 /* How much is sensible to read */
745 execi
->args
.hdr_len
= MIN(execi
->vp
->v_size
, sizeof(hdr
));
746 execi
->args
.hdr
= hdr
;
748 r
= req_readwrite(execi
->vp
->v_fs_e
, execi
->vp
->v_inode_nr
,
749 pos
, READING
, VFS_PROC_NR
, (vir_bytes
) hdr
,
750 execi
->args
.hdr_len
, &new_pos
, &cum_io
);
752 printf("VFS: exec: map_header: req_readwrite failed\n");