/* RSXOPT.C - patches options in the Win32 executable Copyright (C) 1995-1996 Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld email: rainer@mathematik.uni-bielefeld.de All rights reserved */ #include #include #include #include #include #include #include "ntbind.h" #include "port.h" struct layout { DWORD text_base; /* Base address of the text segment */ DWORD text_end; /* End address of the text segment */ DWORD data_base; /* Base address of initialized data */ DWORD data_end; /* End address of initialized data */ DWORD bss_base; /* Base address of uninitialized data */ DWORD bss_end; /* End address of uninitialized data */ DWORD heap_base; /* Base address of the heap */ DWORD heap_end; /* End address of the heap */ DWORD heap_brk; /* End address of the used heap space */ DWORD heap_off; /* Location of heap data in the executable */ DWORD os2_dll; /* Address of the import table for (I1) */ DWORD stack_base; /* Base address of the stack */ DWORD stack_end; /* End address of the stack */ DWORD flags; /* Flags (DLL) and interface number */ DWORD reserved[2]; /* Not yet used */ unsigned char options[64]; /* emx options to be used under OS/2 */ }; /* return first non-digit */ static char * asc2long(char *s, unsigned long *retv) { char *str = s; *retv = 0; while (*str != 0) { if ((*str < '0') || (*str > '9')) break; *retv *= 10; *retv += *str - '0'; str++; } return (str); } static char *scan_for_option(char *s) { unsigned long temp; switch (*s) { case 'c': /* core */ puts("- disable core dumps"); break; case 'e': /* redirect standard error */ puts("- redirect stderr to stdout"); break; case 'h': /* max handles */ ++s; if (!isdigit(*s)) return NULL; s = asc2long(s, &temp); printf("- limit of handles (win32s) = %ld\n", temp); return s; case 'q': /* quote all arguments to child */ puts("- quote all arguments to childs"); break; case 's': /* heap */ ++s; if (!isdigit(*s)) return NULL; s = asc2long(s, &temp); printf("- max. heap size = %ld KB\n", temp); return s; case 'r': /* default disk-drive */ if (!isalpha(*++s)) return NULL; printf("- prepend drive '%c'\n", *s); break; case 't': /* truncate filenames to 8.3 */ puts("- truncate files to 8.3 format"); break; case 'V': /* enables VT100/ANSI */ puts("- enables VT100/ANSI emulation"); break; default: return NULL; } /* switch (*s) */ return s; } static void display_options(char *s) { char *t; if (! *s) { puts("File has no options"); return; } printf("File contains options: '%s'\n", s); for (; *s != '\0'; ++s) { while (*s == ' ') ++s; if (*s == '-') { t = scan_for_option(++s); if (t == NULL) { printf("** error in rsxnt options : %s **\n", --s); return; } } else break; s = t; } } static int skip_exe_hdr(int filehandle, DWORD * headoff) { struct exe_hdr exehdr; read(filehandle, &exehdr, sizeof(struct exe_hdr)); if (exehdr.signatur == 0x5a4d) { /* falls exe-kopf */ DWORD new_off; lseek(filehandle, 0x3C, SEEK_SET); read(filehandle, &new_off, sizeof(long)); if (new_off) { DWORD pe_magic; lseek(filehandle, new_off, SEEK_SET); read(filehandle, &pe_magic, sizeof(pe_magic)); if (pe_magic == 0x4550) { *headoff = new_off + 4; return 0; } } } /* exe files */ *headoff = 0; return -1; } static int do_options(char * name, char option, char **argv) { FILEHDR file_hdr; NTOPTHDR ntopt_hdr; SCNHDR scn_hdr; struct layout layout; DWORD headoff; int mode, i; int pehandle; if (option == 'i') mode = O_BINARY | O_RDONLY; else mode = O_BINARY | O_RDWR; if ((pehandle = open(name, mode)) < 0) { perror("open"); return 1; } if (skip_exe_hdr(pehandle, &headoff) < 0) { puts("no a valid Win32 file"); return (1); } lseek(pehandle, headoff, SEEK_SET); read(pehandle, &file_hdr, sizeof(FILEHDR)); if (file_hdr.f_magic != 0x14C) { puts("no COFF header found"); return (1); } read(pehandle, &ntopt_hdr, sizeof(NTOPTHDR)); if (ntopt_hdr.Magic != 0x10b) { puts("no optional header found"); return (1); } for (i = 0; i < file_hdr.f_nscns; i++) { read(pehandle, &scn_hdr, sizeof(SCNHDR)); if (strcmp(scn_hdr.s_name, ".data") == 0) break; } lseek(pehandle, scn_hdr.s_scnptr, SEEK_SET); read(pehandle, &layout, sizeof (struct layout)); if (layout.text_end != layout.data_base && layout.data_end != layout.bss_base) { puts("This file is not created with GCC+RSXNT"); close(pehandle); return 1; } if (layout.options[0] != '-') layout.options[0] = 0; if (option == 'i') display_options(layout.options); else { int i; char *s = layout.options; if (option == 'a') { s += strlen(s); *s++ = ' '; } for (i = 3; argv[i]; i++) { strcpy(s, argv[i]); s += strlen(s); *s++ = ' '; } *--s = '\0'; lseek(pehandle, scn_hdr.s_scnptr, SEEK_SET); write(pehandle, &layout, sizeof (struct layout)); } close(pehandle); return 0; } static void usage(void ) { puts("usage: rsxntopt [-a -b -i] file.exe [options]"); puts("\t-a: append options"); puts("\t-b: build new options"); puts("\t-i: info about options"); puts("\t\noptions:"); puts("\t-c : disable core dumps"); puts("\t-e : redirect stderr to stdout"); puts("\t-h# : limit of handles (use for win32s, default 40)"); puts("\t-q : quote all arguments to childs"); puts("\t-s# : max. heap size of process"); puts("\t-r* : prepend drive * to path names"); puts("\t-t : truncate files to 8.3 format"); puts("\t-V : enables VT100/ANSI emulation"); } int main(int argc, char **argv) { puts("RSXNTOPT - bind options in exefile ; (c) Rainer Schnitker"); if (argc < 3) { usage(); return 1; } if ((strcmp(argv[1],"-i") != 0) && (strcmp(argv[1],"-a") != 0) && (strcmp(argv[1],"-b") != 0)) { usage(); return 1; } return do_options(argv[2], argv[1][1], argv); }