tar: use utime() to restore timestamps
[minix.git] / servers / rs / exec.c
blob7dd908de1aebd7004f28a6bea9ba32b25e87bc8f
1 #include "inc.h"
2 #include <a.out.h>
3 #include <assert.h>
4 #include <libexec.h>
5 #include <machine/vmparam.h>
7 static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
8 char *frame, int frame_len);
9 static int exec_restart(int proc_e, int result, vir_bytes pc);
10 static int read_seg(struct exec_info *execi, off_t off,
11 off_t seg_addr, size_t seg_bytes);
12 static int exec_restart(int proc_e, int result, vir_bytes pc);
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 **UNUSED(Xenvp))
25 char * const *ap;
26 char * const *ep;
27 char *frame;
28 char **vp;
29 char *sp, *progname;
30 size_t argc;
31 size_t frame_size;
32 size_t string_off;
33 size_t n;
34 int ov;
35 int r;
37 /* Assumptions: size_t and char *, it's all the same thing. */
39 /* Create a stack image that only needs to be patched up slightly
40 * by the kernel to be used for the process to be executed.
43 ov= 0; /* No overflow yet. */
44 frame_size= 0; /* Size of the new initial stack. */
45 string_off= 0; /* Offset to start of the strings. */
46 argc= 0; /* Argument count. */
48 for (ap= argv; *ap != NULL; ap++) {
49 n = sizeof(*ap) + strlen(*ap) + 1;
50 frame_size+= n;
51 if (frame_size < n) ov= 1;
52 string_off+= sizeof(*ap);
53 argc++;
56 /* Add an argument count and two terminating nulls. */
57 frame_size+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
58 string_off+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
60 /* Align. */
61 frame_size= (frame_size + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
63 /* The party is off if there is an overflow. */
64 if (ov || frame_size < 3 * sizeof(char *)) {
65 errno= E2BIG;
66 return -1;
69 /* Allocate space for the stack frame. */
70 frame = (char *) malloc(frame_size);
71 if (!frame) {
72 errno = E2BIG;
73 return -1;
76 /* Set arg count, init pointers to vector and string tables. */
77 * (size_t *) frame = argc;
78 vp = (char **) (frame + sizeof(argc));
79 sp = frame + string_off;
81 /* Load the argument vector and strings. */
82 for (ap= argv; *ap != NULL; ap++) {
83 *vp++= (char *) (sp - frame);
84 n= strlen(*ap) + 1;
85 memcpy(sp, *ap, n);
86 sp+= n;
88 *vp++= NULL;
90 #if 0
91 /* Load the environment vector and strings. */
92 for (ep= envp; *ep != NULL; ep++) {
93 *vp++= (char *) (sp - frame);
94 n= strlen(*ep) + 1;
95 memcpy(sp, *ep, n);
96 sp+= n;
98 #endif
99 *vp++= NULL;
101 /* Padding. */
102 while (sp < frame + frame_size) *sp++= 0;
104 (progname=strrchr(argv[0], '/')) ? progname++ : (progname=argv[0]);
105 r = do_exec(proc_e, exec, exec_len, progname, frame, frame_size);
107 /* Return the memory used for the frame and exit. */
108 free(frame);
109 return r;
113 static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
114 char *frame, int frame_len)
116 int r;
117 vir_bytes vsp;
118 struct exec_info execi;
119 int i;
121 memset(&execi, 0, sizeof(execi));
123 execi.stack_high = kinfo.user_sp;
124 execi.stack_size = DEFAULT_STACK_LIMIT;
125 execi.proc_e = proc_e;
126 execi.hdr = exec;
127 execi.hdr_len = exec_len;
128 strncpy(execi.progname, progname, PROC_NAME_LEN-1);
129 execi.progname[PROC_NAME_LEN-1] = '\0';
130 execi.frame_len = frame_len;
132 /* callback functions and data */
133 execi.copymem = read_seg;
134 execi.clearproc = libexec_clearproc_vm_procctl;
135 execi.clearmem = libexec_clear_sys_memset;
136 execi.allocmem_prealloc = libexec_alloc_mmap_prealloc;
137 execi.allocmem_ondemand = libexec_alloc_mmap_ondemand;
139 for(i = 0; exec_loaders[i].load_object != NULL; i++) {
140 r = (*exec_loaders[i].load_object)(&execi);
141 /* Loaded successfully, so no need to try other loaders */
142 if (r == OK) break;
145 /* No exec loader could load the object */
146 if (r != OK) {
147 printf("RS: do_exec: loading error %d\n", r);
148 return r;
151 /* Inform PM */
152 if((r = libexec_pm_newexec(execi.proc_e, &execi)) != OK)
153 return r;
155 /* Patch up stack and copy it from RS to new core image. */
156 vsp = execi.stack_high;
157 vsp -= frame_len;
158 libexec_patch_ptr(frame, vsp);
159 r = sys_datacopy(SELF, (vir_bytes) frame,
160 proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
161 if (r != OK) {
162 printf("do_exec: copying out new stack failed: %d\n", r);
163 exec_restart(proc_e, r, execi.pc);
164 return r;
167 return exec_restart(proc_e, OK, execi.pc);
170 /*===========================================================================*
171 * exec_restart *
172 *===========================================================================*/
173 static int exec_restart(int proc_e, int result, vir_bytes pc)
175 int r;
176 message m;
178 m.m_type= EXEC_RESTART;
179 m.EXC_RS_PROC= proc_e;
180 m.EXC_RS_RESULT= result;
181 m.EXC_RS_PC= (void*)pc;
182 r= sendrec(PM_PROC_NR, &m);
183 if (r != OK)
184 return r;
185 return m.m_type;
188 /*===========================================================================*
189 * read_seg *
190 *===========================================================================*/
191 static int read_seg(
192 struct exec_info *execi, /* various data needed for exec */
193 off_t off, /* offset in file */
194 off_t seg_addr, /* address to load segment */
195 size_t seg_bytes /* how much is to be transferred? */
199 * The byte count on read is usually smaller than the segment count, because
200 * a segment is padded out to a click multiple, and the data segment is only
201 * partially initialized.
204 int r;
206 if (off+seg_bytes > execi->hdr_len) return ENOEXEC;
207 if((r= sys_vircopy(SELF, ((vir_bytes)execi->hdr)+off,
208 execi->proc_e, seg_addr, seg_bytes)) != OK) {
209 printf("RS: exec read_seg: copy 0x%x bytes into %i at 0x%08x failed: %i\n",
210 seg_bytes, execi->proc_e, seg_addr, r);
212 return r;