make vfs & filesystems use failable copying
[minix3.git] / servers / rs / exec.c
blob09e0b9a0b39aaf36aff3a235ef35e1acb09e0eb2
1 #include "inc.h"
2 #include <assert.h>
3 #include <sys/exec.h>
4 #include <libexec.h>
5 #include <minix/param.h>
6 #include <machine/vmparam.h>
8 static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
9 char *frame, int frame_len, vir_bytes ps_str);
10 static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str);
11 static int read_seg(struct exec_info *execi, off_t off,
12 vir_bytes seg_addr, size_t seg_bytes);
14 /* Array of loaders for different object formats */
15 static struct exec_loaders {
16 libexec_exec_loadfunc_t load_object;
17 } const exec_loaders[] = {
18 { libexec_load_elf },
19 { NULL }
22 int srv_execve(int proc_e, char *exec, size_t exec_len, char **argv,
23 char **envp)
25 size_t frame_size = 0; /* Size of the new initial stack. */
26 int argc = 0; /* Argument count. */
27 int envc = 0; /* Environment count */
28 char overflow = 0; /* No overflow yet. */
29 char *frame;
30 struct ps_strings *psp;
31 int vsp = 0; /* (virtual) Stack pointer in new address space. */
33 char *progname;
34 int r;
36 minix_stack_params(argv[0], argv, envp, &frame_size, &overflow,
37 &argc, &envc);
39 /* The party is off if there is an overflow. */
40 if (overflow) {
41 errno = E2BIG;
42 return -1;
45 /* Allocate space for the stack frame. */
46 if ((frame = (char *) sbrk(frame_size)) == (char *) -1) {
47 errno = E2BIG;
48 return -1;
51 minix_stack_fill(argv[0], argc, argv, envc, envp, frame_size, frame,
52 &vsp, &psp);
54 (progname=strrchr(argv[0], '/')) ? progname++ : (progname=argv[0]);
56 r = do_exec(proc_e, exec, exec_len, progname, frame, frame_size,
57 vsp + ((char *)psp - frame));
59 /* Failure, return the memory used for the frame and exit. */
60 (void) sbrk(-frame_size);
62 return r;
66 static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
67 char *frame, int frame_len, vir_bytes ps_str)
69 int r;
70 vir_bytes vsp;
71 struct exec_info execi;
72 int i;
74 memset(&execi, 0, sizeof(execi));
76 execi.stack_high = kinfo.user_sp;
77 execi.stack_size = DEFAULT_STACK_LIMIT;
78 execi.proc_e = proc_e;
79 execi.hdr = exec;
80 execi.filesize = execi.hdr_len = exec_len;
81 strncpy(execi.progname, progname, PROC_NAME_LEN-1);
82 execi.progname[PROC_NAME_LEN-1] = '\0';
83 execi.frame_len = frame_len;
85 /* callback functions and data */
86 execi.copymem = read_seg;
87 execi.clearproc = libexec_clearproc_vm_procctl;
88 execi.clearmem = libexec_clear_sys_memset;
89 execi.allocmem_prealloc_cleared = libexec_alloc_mmap_prealloc_cleared;
90 execi.allocmem_prealloc_junk = libexec_alloc_mmap_prealloc_junk;
91 execi.allocmem_ondemand = libexec_alloc_mmap_ondemand;
93 for(i = 0; exec_loaders[i].load_object != NULL; i++) {
94 r = (*exec_loaders[i].load_object)(&execi);
95 /* Loaded successfully, so no need to try other loaders */
96 if (r == OK) break;
99 /* No exec loader could load the object */
100 if (r != OK) {
101 printf("RS: do_exec: loading error %d\n", r);
102 return r;
105 /* Inform PM */
106 if((r = libexec_pm_newexec(execi.proc_e, &execi)) != OK)
107 return r;
109 /* Patch up stack and copy it from RS to new core image. */
110 vsp = execi.stack_high - frame_len;
111 r = sys_datacopy(SELF, (vir_bytes) frame,
112 proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
113 if (r != OK) {
114 printf("do_exec: copying out new stack failed: %d\n", r);
115 exec_restart(proc_e, r, execi.pc, ps_str);
116 return r;
119 return exec_restart(proc_e, OK, execi.pc, ps_str);
122 /*===========================================================================*
123 * exec_restart *
124 *===========================================================================*/
125 static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str)
127 int r;
128 message m;
130 memset(&m, 0, sizeof(m));
131 m.m_type = PM_EXEC_RESTART;
132 m.PM_EXEC_RESTART_ENDPT = proc_e;
133 m.PM_EXEC_RESTART_RESULT = result;
134 m.PM_EXEC_RESTART_PC = (void *)pc;
135 m.PM_EXEC_RESTART_PS_STR = (void *)ps_str;
137 r = ipc_sendrec(PM_PROC_NR, &m);
138 if (r != OK)
139 return r;
141 return m.m_type;
144 /*===========================================================================*
145 * read_seg *
146 *===========================================================================*/
147 static int read_seg(
148 struct exec_info *execi, /* various data needed for exec */
149 off_t off, /* offset in file */
150 vir_bytes seg_addr, /* address to load segment */
151 size_t seg_bytes /* how much is to be transferred? */
155 * The byte count on read is usually smaller than the segment count, because
156 * a segment is padded out to a click multiple, and the data segment is only
157 * partially initialized.
160 int r;
162 if (off+seg_bytes > execi->hdr_len) return ENOEXEC;
163 if((r= sys_datacopy(SELF, ((vir_bytes)execi->hdr)+off,
164 execi->proc_e, seg_addr, seg_bytes)) != OK) {
165 printf("RS: exec read_seg: copy 0x%x bytes into %i at 0x%08lx failed: %i\n",
166 seg_bytes, execi->proc_e, seg_addr, r);
168 return r;