/***************************************************************************** * FILE: sysdj.c * * * * DESC: * * - int 0x21, ah=0xff djgpp syscall handler * * * * Copyright (C) 1993,1994 * * Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld * * email: rainer@mathematik.uni-bielefeld.de * * * *****************************************************************************/ #include #include #include "DPMI.H" #include "RMLIB.H" #include "PRINTF.H" #include "TIMEDOS.H" #include "STATEMX.H" #include "PROCESS.H" #include "SIGNALS.H" #include "CDOSX32.H" #include "ADOSX32.H" #include "START32.H" #include "COPY32.H" #include "RSX.H" #include "DOSERRNO.H" #include "DJIO.H" /* ** For DJGPP programs 1.00 - 1.09 (not coff files) with big segments (4 MB) ** ** move stack,data,bss,heap ** |-CCCCC---------------------------------SSSS-DDDD-HHH-| ** 0 ^0x400000 ** ** to the end of text ** |-CCCCC-SSSS-DDDD-HHH-| */ void compress_memory(void) { DWORD movedmem, newhandle, newaddress; DWORD r_esp = ESP & ~4095L; /* check djgpp segment, and stack */ if (npz->data_start != 0x400000L || r_esp > npz->data_start) return; movedmem = npz->membytes - r_esp; /* memory to move */ if (r_esp - npz->stack_down < movedmem) /* enough space? */ return; cpy32_32(DS, r_esp, DS, npz->stack_down, movedmem); if (ResizeMem(npz->stack_down + movedmem, npz->memhandle, &newhandle, &newaddress)) { printf("error:resize memory block\n"); return; } if (npz->memaddress != newaddress) { npz->memaddress = newaddress; SetBaseAddress(npz->code32sel, npz->memaddress); SetBaseAddress(npz->data32sel, npz->memaddress); SetBaseAddress(npz->data32sel + sel_incr, npz->memaddress); } npz->p_flags |= PF_COMPRESS; } void uncompress_memory(void) { DWORD movedmem, newhandle, newaddress; DWORD r_esp = ESP & ~4095L; /* check djgpp segment, and stack */ if (npz->data_start != 0x400000L || !(npz->p_flags & PF_COMPRESS)) return; if (ResizeMem(npz->membytes, npz->memhandle, &newhandle, &newaddress)) { printf("Can't switch to parant process: ENOMEM\n"); shut_down(1); } if (npz->memaddress != newaddress) { npz->memaddress = newaddress; SetBaseAddress(npz->code32sel, npz->memaddress); SetBaseAddress(npz->data32sel, npz->memaddress); SetBaseAddress(npz->data32sel + sel_incr, npz->memaddress); } movedmem = npz->membytes - r_esp; /* memory to move */ cpy32_32(DS, npz->stack_down, DS, r_esp, movedmem); npz->p_flags &= ~PF_COMPRESS; } void def_extention(char *dst, const char *ext) { int dot, sep; dot = 0; sep = 1; while (*dst != 0) switch (*dst++) { case '.': dot = 1; sep = 0; break; case ':': case '/': case '\\': dot = 0; sep = 1; break; default: sep = 0; break; } if (!dot && !sep) { *dst++ = '.'; strcpy(dst, ext); } } char *search_path(char *file, char *path) { char *list, *end; int i; strcpy(path, file); if (rm_access(path, 4) == 0) return path; list = getenv("PATH"); if (list != NULL) for (;;) { while (*list == ' ' || *list == '\t') ++list; if (*list == 0) break; end = list; while (*end != 0 && *end != ';') ++end; i = end - list; while (i > 0 && (list[i - 1] == ' ' || list[i - 1] == '\t')) --i; if (i != 0) { memcpy(path, list, i); if (list[i - 1] != '/' && list[i - 1] != '\\' && list[i - 1] != ':') path[i++] = '\\'; strcpy(path + i, file); if (rm_access(path, 4) == 0) return path; } if (*end == 0) break; list = end + 1; } path[0] = 0; return (char *) 0; } struct time32 { DWORD secs, usecs; }; struct tz32 { DWORD offset, dst; }; struct stat32 { short st_dev, st_ino, st_mode, st_nlink, st_uid, st_gid, st_rdev, st_align_for_DWORD; long st_size, st_atime, st_mtime, st_ctime, st_blksize; }; static int set_systime(unsigned long *gmt_seconds) { struct tm tm; struct dos_time dt; gmt2tm(gmt_seconds, &tm); dt.dtime_hour = (char) tm.tm_hour; dt.dtime_minutes = (char) tm.tm_min; dt.dtime_seconds = (char) tm.tm_sec; dt.dtime_hsec = 0; rm_settime(&dt); return 0; } static int make_tokens(char *argmem, char **argp) { int i; int args=0; argp[args++] = argmem; for (i = 0; argmem[i] != '\0'; i++) if (argmem[i] == ' ') { argmem[i] = '\0'; if (argmem[i + 1] == ' ') continue; else if (argmem[i + 1] != '\0') argp[args++] = (argmem + i + 1); } argp[args] = 0; return args; } /* ** DJGPP 1.12 gcc compiler doesn't use this call ** ** RSX starts the new process instead of loading the extender + prg */ int sys_system(char *command, char **env) { char *argmem; char **argp; char exe[260]; int args, r, i; r = strlen(command); args = 0; for ( i = r; i > 0 ; i--) { if (command[i] == ' ') args++; } argmem = (char *) malloc(r+1); argp = (char **) malloc((args+3) * sizeof(char **)); if (argmem == NULL || argp == NULL) { if (argmem != NULL) free(argmem); if (argp != NULL) free(argp); errno = EMX_ENOMEM; return -1; } strcpy(argmem, command); /* make strings from command; build argv */ args = make_tokens(argmem, argp); /* check last argument, response file? */ if (args > 1 && argp[args - 1][0] == '@') { int f, bytes; char *s = &argmem[i + 2]; args--; f = rm_open(argp[args] + 1, RM_O_RDONLY | RM_O_DENYWR); bytes = rm_read(f, s, 900); s[bytes] = 0; rm_close(f); argp[args++] = s; for (i = 0; i < bytes; i++) if (*(s + i) == 13 && *(s + i + 1) == 10) { *(s + i) = 0; if (i + 4 > bytes) break; argp[args++] = (s + i + 2); } else if (*(s + i) == ' ' && *(s + i + 1) > ' ') { argp[args++] = (s + i + 2); } argp[args] = 0; } if (rm_access(argmem, 4)) { if (!search_path(argmem, exe)) { errno = EMX_ENOENT; free(argmem); free(argp); return -1; } else { argp[0] = exe; } } /* resize memory to the real used page */ compress_memory(); r = exec32(P_WAIT, argp[0], args, argp, org_envc, org_env); /* if error, try a real-mode prg */ if (r == EMX_ENOEXEC) r = realmode_prg(argp[0], &(argp[0]), org_env); uncompress_memory(); free(argmem); free(argp); return r; } /* ** DJGPP 1.11 exec/spawn ** uses TRANSLATION services by DPMI to simulate 0x21 ah=9x4b ** ** RSX starts the new process instead of loading the extender + prg */ int simulate_go32_exec(void) { TRANSLATION tr; DWORD offset; WORD *pblock; char **env; char *name; int z, args; char *cmd; static char cline[128]; cpy32_16(ES, EDI, & tr, sizeof(tr)); /* get pointer to program name */ tr.edx += (DWORD) tr.ds << 4; offset = tr.edx - ((DWORD)ds16real << 4); name = (char *)(UINT)offset; /* get pointer to exec block */ tr.ebx += (DWORD) tr.es << 4; offset = tr.ebx - ((DWORD)ds16real << 4); pblock = (WORD *)(UINT)offset; /* get args */ offset = ((DWORD) pblock[2] << 4) + (DWORD) pblock[1]; offset -= (DWORD) ds16real << 4; cmd = (char *) ((UINT) offset + 1); /* build comand line */ strcpy(cline, name); z = strlen(cline); for ( ; z < sizeof(cline) ; z++) { cline[z] = *cmd; if (cline[z] == 13) break; cmd++; } cline[z] = '\0'; /* environment */ if (pblock[0]) { offset = (DWORD) pblock[0] << 4; offset -= ((DWORD)ds16real << 4); env = (char **)(UINT)offset; } else env = org_env; /*** just like go32 ************** npz->regs.eax = 0x300; if (execute_dpmi_function()) r = -1; else r = (int) tr.eax & 0xFF; *********************************/ if (strstr(cline, "!proxy")) { /* go32 !proxy argc seg off seg off info */ char *param[12]; /* if more in future */ WORD *newargs; make_tokens(cline, param); args = hexstr2int(param[2]); offset = (DWORD) (UINT) hexstr2int(param[3]) << 4; offset -= ((DWORD)ds16real << 4); newargs = (WORD *) ((UINT) offset + (UINT) hexstr2int(param[4])); strcpy(iobuf, (char *) ((UINT)newargs[0] + (UINT)offset)); for ( z = 1; z < args; z++) { strcat(iobuf, " "); strcat(iobuf, (char *)((UINT)newargs[z] + (UINT)offset)); } cmd = iobuf; } else cmd = cline; /* but it's better to handle it self */ return sys_system(cmd, NULL); } static long my_daylight; static long my_timezone; int i_21_ff(void) { DWORD p1 = EBX, p2 = ECX; int r, i, handle; switch (AX & 0xff) { /* al=? */ case 1: handle = get_empty_proc_filp(); if (handle < 0) { EAX = EMX_EBADF; return CARRY_ON; } strcpy32_16(DS, p1, iobuf); /* p1 -> iobuf */ r = dj_creat(iobuf); if (r >= 0) { npz->filp[handle]->f_mode = FMODE_READ | FMODE_WRITE; npz->filp[handle]->f_doshandle = r; npz->filp[handle]->f_op = & msdos_fop; r = handle; } break; case 2: handle = get_empty_proc_filp(); if (handle < 0) { EAX = EMX_EBADF; return CARRY_ON; } strcpy32_16(DS, p1, iobuf); /* p1 -> iobuf */ i = (int) (UINT) p2; r = dj_open(iobuf, i); if (r >= 0) { npz->filp[handle]->f_mode = FMODE_READ | FMODE_WRITE; npz->filp[handle]->f_doshandle = r; npz->filp[handle]->f_op = & msdos_fop; r = handle; } break; case 3: /* fstat */ { struct stat32 statbuf32; struct stat statbuf; handle = get_dos_handle((WORD) p1); if (handle < 0) { EAX = EMX_EBADF; return CARRY_ON; } else p1 = handle; r = sys_fstat(handle, &statbuf); if (r == -1) { errno = doserror_to_errno(_doserrno); break; } statbuf32.st_dev = (short) statbuf.st_dev; statbuf32.st_ino = (short) statbuf.st_ino; statbuf32.st_mode = (short) statbuf.st_mode; statbuf32.st_nlink = (short) statbuf.st_nlink; statbuf32.st_uid = 42; statbuf32.st_gid = 42; statbuf32.st_rdev = (short) statbuf.st_rdev; statbuf32.st_size = statbuf.st_size; statbuf32.st_atime = statbuf.st_atime; statbuf32.st_mtime = statbuf.st_mtime; statbuf32.st_ctime = statbuf.st_ctime; statbuf32.st_blksize = 4096; /* stat -> p2 */ cpy16_32(DS, p2, &statbuf32, (DWORD) sizeof(statbuf32)); } break; case 4: /* get time & day */ { struct time32 time32; struct tz32 tz32; struct dos_date dd; struct dos_time dt; if (p2) { tz32.offset = my_timezone; tz32.dst = my_daylight; cpy16_32(DS, p2, &tz32, (DWORD) sizeof(tz32)); } if (p1) { unsigned long gmt; rm_getdate(&dd); rm_gettime(&dt); gmt = dos2gmt(&dd, &dt); time32.secs = gmt; time32.usecs = (DWORD) dt.dtime_hsec * 10; cpy16_32(DS, p1, &time32, (DWORD) sizeof(time32)); } r = 0; } break; case 5: /* set time & day */ { struct time32 time32; struct tz32 tz32; if (p2) { cpy32_16(DS, p2, &tz32, (DWORD) sizeof(tz32)); my_timezone = tz32.offset; my_daylight = (WORD) tz32.dst; } if (p1) { cpy32_16(DS, p1, &time32, (DWORD) sizeof(time32)); set_systime((unsigned long *) &(time32.secs)); } r = 0; } break; case 6: /* stat */ { struct stat32 statbuf32; struct stat statbuf; char fname[160]; memset(&statbuf, 0, sizeof(statbuf)); strcpy32_16(DS, p1, fname); r = sys_stat(fname, &statbuf); if (r == -1) { errno = doserror_to_errno(_doserrno); break; } statbuf32.st_dev = (short) statbuf.st_dev; statbuf32.st_ino = (short) statbuf.st_ino; statbuf32.st_mode = (short) statbuf.st_mode; statbuf32.st_nlink = (short) statbuf.st_nlink; statbuf32.st_uid = 42; statbuf32.st_gid = 42; statbuf32.st_rdev = (short) statbuf.st_rdev; statbuf32.st_size = statbuf.st_size; statbuf32.st_atime = statbuf.st_atime; statbuf32.st_mtime = statbuf.st_mtime; statbuf32.st_ctime = statbuf.st_ctime; statbuf32.st_blksize = 512; /* stat -> p2 */ cpy16_32(DS, p2, &statbuf32, (DWORD) sizeof(statbuf32)); } break; case 7: strcpy32_16(DS, p1, iobuf); r = sys_system(iobuf, NULL); if (r) { errno = r; r = -1; } break; case 8: handle = get_dos_handle((WORD) p1); if (handle < 0) { EAX = EMX_EBADF; return CARRY_ON; } else p1 = (long) handle; i = rm_ioctl_getattr(handle); if (p2 & 0x8000) /* O_BINARY */ i |= 0x20; else i &= ~0x20; rm_ioctl_setattr(handle, i); r = dj_setmode((int) p1, (int) p2); break; case 9: strcpy32_16(DS, p1, iobuf); /* p1 -> iobuf */ r = dj_chmod(iobuf, (int) p2); break; case 10: /* DOS 0x4B */ r = simulate_go32_exec(); break; default: r = -1; errno = EMX_EIO; break; } /* switch */ if (r == -1) { EAX = errno; return CARRY_ON; } else { EAX = (long) r; return CARRY_OFF; } } /* go32 debug functions */ #define EXTERNAL_DEBUGGER_EXECUTE 0 #define EXTERNAL_DEBUGGER_GETINFOPTR 1 typedef struct { WORD version; /* set to version number of interface */ WORD a_tss_ofs; /* pointer to TSS for debugged program */ WORD a_tss_seg; WORD filename_ofs; /* points to name of file being debugged */ WORD filename_seg; WORD filename_len; WORD areas_ofs; /* from paging.c */ WORD areas_seg; DWORD app_base; /* linear base address of application */ DWORD dr[8]; /* debug registers, set when a_tss runs */ DWORD ansi_mode; /* if set, OK to emit ansi control codes */ } ExternalDebuggerInfo; int i_21_fe(void) { puts("external debugger not supported"); do_exit4c(0); return 0; /* ext_debug_info.version = EXTERNAL_DEBUGGER_VERSION; ext_debug_info.a_tss_ofs = FP_OFF(&a_tss); ext_debug_info.a_tss_seg = ourDSsel; ext_debug_info.filename_ofs = FP_OFF(running_fname); ext_debug_info.filename_seg = ourDSsel; ext_debug_info.filename_len = strlen(running_fname); ext_debug_info.areas_ofs = FP_OFF(&areas); ext_debug_info.areas_seg = ourDSsel; ext_debug_info.app_base = ARENA; ext_debug_info.ansi_mode = use_ansi; memset(ext_debug_info.dr, 32, 0); */ }