sigwait.3: Add missing '.'
[dragonfly.git] / usr.bin / doscmd / exe.c
blobf94521522fdbc486f7106d9ca23f032da17ce0db
1 /*
2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Berkeley Software
16 * Design, Inc.
18 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
30 * BSDI exe.c,v 2.2 1996/04/08 19:32:34 bostic Exp
32 * $FreeBSD: src/usr.bin/doscmd/exe.c,v 1.2.2.1 2002/04/25 11:04:51 tg Exp $
33 * $DragonFly: src/usr.bin/doscmd/exe.c,v 1.2 2003/06/17 04:29:26 dillon Exp $
36 #include <sys/types.h>
37 #include <sys/uio.h>
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
43 #include "doscmd.h"
45 /* exports */
46 int pspseg;
47 int curpsp = 0;
49 /* locals */
50 static int psp_s[10] = { 0 };
51 static int env_s[10];
52 static regcontext_t frames[10];
54 static int
55 make_environment(char *cmd_name, char **env)
57 int i;
58 int total;
59 int len;
60 int envseg;
61 char *p;
62 char *env_block;
64 total = 0;
65 for (i = 0; env[i]; i++) {
66 debug (D_EXEC,"env: %s\n", env[i]);
67 len = strlen(env[i]);
68 if (total + len >= 32 * 1024)
69 break;
70 total += len + 1;
73 total++; /* terminating null */
74 total += 2; /* word count */
75 total += strlen(cmd_name) + 1;
76 total += 4; /* some more zeros, just in case */
78 if ((envseg = mem_alloc(total/16 + 1, 1, NULL)) == 0)
79 fatal("out of memory for env\n");
81 env_block = (char *)MAKEPTR(envseg, 0);
82 memset (env_block, 0, total);
84 p = env_block;
85 total = 0;
86 for (i = 0; env[i]; i++) {
87 len = strlen(env[i]);
88 if (total + len >= 32 * 1024)
89 break;
90 total += len + 1;
91 strcpy (p, env[i]);
92 p += strlen(p) + 1;
94 *p++ = 0;
95 *(short *)p = strlen(cmd_name);
96 p += 2;
97 strcpy (p, cmd_name);
98 while(*p) {
99 if (*p == '/')
100 *p = '\\';
101 else if (islower(*p))
102 *p = toupper(*p);
103 p++;
105 *p = '\0';
106 return(envseg);
109 static void
110 load_com(int fd, int start_segment)
112 char *start_addr;
113 int i;
115 start_addr = (char *)MAKEPTR(start_segment, 0);
117 lseek (fd, 0, 0);
118 i = read (fd, start_addr, 0xff00);
120 debug(D_EXEC, "Read %05x into %04x\n",
121 i, start_segment);
124 static void
125 load_exe(int fd, int start_segment, int reloc_segment __unused, struct exehdr *hdr, int text_size)
127 char *start_addr;
128 int reloc_size;
129 struct reloc_entry *reloc_tbl, *rp;
130 u_short *segp;
131 int i;
133 start_addr = (char *)MAKEPTR(start_segment, 0);
135 lseek (fd, hdr->hdr_size * 16, 0);
136 if (read (fd, start_addr, text_size) != text_size)
137 fatal ("error reading program text\n");
138 debug(D_EXEC, "Read %05x into %04x\n",
139 text_size, start_segment);
141 if (hdr->nreloc) {
142 reloc_size = hdr->nreloc * sizeof (struct reloc_entry);
144 if ((reloc_tbl = (struct reloc_entry *)malloc (reloc_size)) == NULL)
145 fatal ("out of memory for program\n");
147 lseek (fd, hdr->reloc_offset, 0);
148 if (read (fd, reloc_tbl, reloc_size) != reloc_size)
149 fatal ("error reading reloc table\n");
151 for (i = 0, rp = reloc_tbl; i < hdr->nreloc; i++, rp++) {
152 segp = (u_short *)MAKEPTR(start_segment + rp->seg, rp->off);
153 *segp += start_segment;
155 free((char *)reloc_tbl);
159 void
160 load_command(regcontext_t *REGS, int run, int fd, char *cmd_name,
161 u_short *param, char **argv, char **envs)
163 struct exehdr hdr;
164 int min_memory, max_memory;
165 int biggest;
166 int envseg;
167 char *psp;
168 int text_size = 0;
169 int i;
170 int start_segment;
171 int exe_file;
172 char *p;
173 int used, n;
174 char *fcb;
175 int newpsp;
176 u_short init_cs, init_ip, init_ss, init_sp, init_ds, init_es;
178 if (envs)
179 envseg = make_environment(cmd_name, envs);
180 else
181 envseg = env_s[curpsp];
183 /* read exe header */
184 if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
185 fatal ("can't read header\n");
187 /* proper header ? */
188 if (hdr.magic == 0x5a4d) {
189 exe_file = 1;
190 text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
191 - hdr.hdr_size * 16;
192 min_memory = hdr.min_memory + (text_size + 15)/16;
193 max_memory = hdr.max_memory + (text_size + 15)/16;
194 } else {
195 exe_file = 0;
196 min_memory = 64 * (1024/16);
197 max_memory = 0xffff;
200 /* alloc mem block */
201 pspseg = mem_alloc(max_memory, 1, &biggest);
202 if (pspseg == 0) {
203 if (biggest < min_memory ||
204 (pspseg = mem_alloc(biggest, 1, NULL)) == 0)
205 fatal("not enough memory: needed %d have %d\n",
206 min_memory, biggest);
208 max_memory = biggest;
211 mem_change_owner(pspseg, pspseg);
212 mem_change_owner(envseg, pspseg);
214 /* create psp */
215 newpsp = curpsp + 1;
216 psp_s[newpsp] = pspseg;
217 env_s[newpsp] = envseg;
219 psp = (char *)MAKEPTR(pspseg, 0);
220 memset(psp, 0, 256);
222 psp[0] = 0xcd;
223 psp[1] = 0x20;
225 *(u_short *)&psp[2] = pspseg + max_memory;
228 * this is supposed to be a long call to dos ... try to fake it
230 psp[5] = 0xcd;
231 psp[6] = 0x99;
232 psp[7] = 0xc3;
234 *(u_short *)&psp[0x16] = psp_s[curpsp];
235 psp[0x18] = 1;
236 psp[0x19] = 1;
237 psp[0x1a] = 1;
238 psp[0x1b] = 0;
239 psp[0x1c] = 2;
240 memset(psp + 0x1d, 0xff, 15);
242 *(u_short *)&psp[0x2c] = envseg;
244 *(u_short *)&psp[0x32] = 20;
245 *(u_long *)&psp[0x34] = MAKEVEC(pspseg, 0x18);
246 *(u_long *)&psp[0x38] = 0xffffffff;
248 psp[0x50] = 0xcd;
249 psp[0x51] = 0x98;
250 psp[0x52] = 0xc3;
252 p = psp + 0x81;
253 *p = 0;
254 used = 0;
255 for (i = 0; argv[i]; i++) {
256 n = strlen(argv[i]);
257 if (used + 1 + n > 0x7d)
258 break;
259 *p++ = ' ';
260 memcpy(p, argv[i], n);
261 p += n;
262 used += n;
265 psp[0x80] = strlen(psp + 0x81);
266 psp[0x81 + psp[0x80]] = 0x0d;
267 psp[0x82 + psp[0x80]] = 0;
269 p = psp + 0x81;
270 parse_filename(0x00, p, psp + 0x5c, &n);
271 p += n;
272 parse_filename(0x00, p, psp + 0x6c, &n);
274 if (param[4]) {
275 fcb = (char *)MAKEPTR(param[4], param[3]);
276 memcpy(psp + 0x5c, fcb, 16);
278 if (param[6]) {
279 fcb = (char *)MAKEPTR(param[6], param[5]);
280 memcpy(psp + 0x6c, fcb, 16);
283 #if 0
284 printf("005c:");
285 for (n = 0; n < 16; n++)
286 printf(" %02x", psp[0x5c + n]);
287 printf("\n");
288 printf("006c:");
289 for (n = 0; n < 16; n++)
290 printf(" %02x", psp[0x6c + n]);
291 printf("\n");
292 #endif
294 disk_transfer_addr = MAKEVEC(pspseg, 0x80);
296 start_segment = pspseg + 0x10;
298 if (!exe_file) {
299 load_com(fd, start_segment);
301 init_cs = pspseg;
302 init_ip = 0x100;
303 init_ss = init_cs;
304 init_sp = 0xfffe;
305 init_ds = init_cs;
306 init_es = init_cs;
307 } else {
308 load_exe(fd, start_segment, start_segment, &hdr, text_size);
310 init_cs = hdr.init_cs + start_segment;
311 init_ip = hdr.init_ip;
312 init_ss = hdr.init_ss + start_segment;
313 init_sp = hdr.init_sp;
314 init_ds = pspseg;
315 init_es = init_ds;
318 debug(D_EXEC, "cs:ip = %04x:%04x, ss:sp = %04x:%04x, "
319 "ds = %04x, es = %04x\n",
320 init_cs, init_ip, init_ss, init_sp, init_ds, init_es);
322 if (run) {
323 frames[newpsp] = *REGS;
324 curpsp = newpsp;
326 R_EFLAGS = 0x20202;
327 R_CS = init_cs;
328 R_IP = init_ip;
329 R_SS = init_ss;
330 R_SP = init_sp;
331 R_DS = init_ds;
332 R_ES = init_es;
334 R_AX = R_BX = R_CX = R_DX = R_SI = R_DI = R_BP = 0;
336 } else {
337 param[7] = init_sp;
338 param[8] = init_ss;
339 param[9] = init_ip;
340 param[10] = init_cs;
344 void
345 load_overlay(int fd, int start_segment, int reloc_segment)
347 struct exehdr hdr;
348 int text_size;
349 int exe_file;
351 /* read exe header */
352 if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
353 fatal ("can't read header\n");
355 /* proper header ? */
356 if (hdr.magic == 0x5a4d) {
357 exe_file = 1;
358 text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
359 - hdr.hdr_size * 16;
360 } else {
361 exe_file = 0;
364 if (!exe_file)
365 load_com(fd, start_segment);
366 else
367 load_exe(fd, start_segment, reloc_segment, &hdr, text_size);
371 get_env(void)
373 return(env_s[curpsp]);
376 void
377 exec_command(regcontext_t *REGS, int run,
378 int fd, char *cmd_name, u_short *param)
380 char *arg;
381 char *env;
382 char *argv[2];
383 char *envs[100];
385 env = (char *)MAKEPTR(param[0], 0);
386 arg = (char *)MAKEPTR(param[2], param[1]);
388 if (arg) {
389 int nbytes = *arg++;
390 arg[nbytes] = 0;
391 if (!*arg)
392 arg = NULL;
394 argv[0] = arg;
395 argv[1] = NULL;
397 debug (D_EXEC, "exec_command: cmd_name = %s\n"
398 "env = 0x0%x, arg = %04x:%04x(%s)\n",
399 cmd_name, param[0], param[2], param[1], arg);
401 if (env) {
402 int i;
403 for ( i=0; i < 99 && *env; ++i ) {
404 envs[i] = env;
405 env += strlen(env)+1;
407 envs[i] = NULL;
408 load_command(REGS, run, fd, cmd_name, param, argv, envs);
409 } else
410 load_command(REGS, run, fd, cmd_name, param, argv, NULL);
413 void
414 exec_return(regcontext_t *REGS, int code)
416 debug(D_EXEC, "Returning from exec\n");
417 mem_free_owner(psp_s[curpsp]);
418 *REGS = frames[curpsp--];
419 R_AX = code;
420 R_FLAGS &= ~PSL_C; /* It must have worked */