source: trunk/src/win32k/ldr/myldrOpen.cpp

Last change on this file was 6009, checked in by bird, 24 years ago

Close file on error.

File size: 43.1 KB
RevLine 
[6009]1/* $Id: myldrOpen.cpp,v 1.16 2001-06-14 12:19:41 bird Exp $
[847]2 *
[2501]3 * myldrOpen - ldrOpen.
[847]4 *
[5119]5 * Copyright (c) 1998-2001 knut st. osmundsen <knut.stange.osmundsen@mynd.no>
[847]6 *
[1678]7 * Project Odin Software License can be found in LICENSE.TXT
8 *
[847]9 */
10
11
12/*******************************************************************************
13* Defined Constants And Macros *
14*******************************************************************************/
15#define INCL_DOSERRORS
16#define INCL_NOPMAPI
17
[2827]18#define INCL_OS2KRNL_IO
[4164]19#define INCL_OS2KRNL_TCB
20#define INCL_OS2KRNL_SEM
21#define INCL_OS2KRNL_SEC
[5086]22#define INCL_OS2KRNL_LDR
[2827]23
[847]24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <os2.h>
28
[4164]29#include "devSegDf.h" /* Win32k segment definitions. */
[2827]30#include "rmalloc.h"
[1273]31#include "malloc.h"
32#include <memory.h>
33#include <stdlib.h>
[2827]34#include <string.h>
[4164]35#include <stdarg.h>
[847]36
[1273]37#include "log.h"
[4164]38#include "avl.h"
39#include "options.h"
[1273]40#include <peexe.h>
41#include <exe386.h>
[4164]42#include "elf.h"
[847]43#include "OS2Krnl.h"
[2827]44#include "dev32.h"
[4164]45#include "ldr.h"
[1678]46#include "ModuleBase.h"
[1273]47#include "pe2lx.h"
[2827]48#include "myExecPgm.h"
[4164]49#include "env.h"
50#include "vprintf.h" /* Make 100% sure we have va_start. */
[847]51
52
[4164]53
[2827]54/*******************************************************************************
55* Internal Functions *
56*******************************************************************************/
[4164]57/* static */ APIRET AddArgsToFront(int cArgs, ...);
58/* static */ APIRET SetExecName(const char *pszExeName);
59/* static */ APIRET OpenPATH(PSFN phFile, char *pszFilename, PULONG pfl);
[2827]60
61
[847]62/**
[2501]63 * ldrOpen override.
[847]64 * @returns Return code.
65 * @param phFile Pointer to file handler. Holds filehandle on output.
66 * @param pszFilename Pointer to filename.
[4164]67 * @parma pfl Pointer to some flags.
[847]68 */
[4164]69ULONG LDRCALL myldrOpen(PSFN phFile, PSZ pszFilename, PULONG pfl)
[847]70{
[4164]71 static int cNesting = 0; /* This is an variable which hold the nesting */
72 /* level of this function. This is useful */
73 /* when we call it recurcively. */
74 /* The maximum nesting level is currently 3. */
75 /* When the maximum depth has been reached */
76 /* we'll not intercept loading any longer! */
[4778]77 ULONG rc; /* Return value. */
[847]78
[4164]79 /** @sketch
[4778]80 * Try open the file (that's why this function is called)
81 * Apply Extention fix if this is requested.
[2827]82 */
[4778]83 if (fldrOpenExtentionFix)
84 {
85 int cchFilename = strlen(pszFilename);
86 pszFilename[cchFilename - 4] = '\0';
87 rc = ldrOpen(phFile, pszFilename, pfl);
88 if (rc != NO_ERROR)
89 {
90 pszFilename[cchFilename - 4] = '.';
91 rc = ldrOpen(phFile, pszFilename, pfl);
92 }
93 }
94 else
95 rc = ldrOpen(phFile, pszFilename, pfl);
96
[847]97 if (rc == NO_ERROR)
[4164]98 kprintf(("myldrOpen-%d: phFile=%#.4x, flags=%#.8x, pszFn=%s\n", cNesting, *phFile, pfl, pszFilename));
[847]99
[4164]100
101 /** @sketch
[2827]102 * Are we to intercept the loading?
[4164]103 * - If open were successful.
104 * - And Not too deep nesting.
105 * - And that this isn't an unsupported load.
106 * - And one of the loaders are enabled.
[2827]107 */
[4164]108 if (rc == NO_ERROR
109 && cNesting < 3
110 && !isLdrStateLoadingUnsupported()
111 && isAnyLoaderEnabled()
112 )
[847]113 {
[4164]114 union _u_ReadBufferPointers /* Read buffer pointer(s). */
115 {
116 char *pach; /* Pointer to the buffer as char. */
117 unsigned long *pul; /* Pointer to the buffer as unsigned long. */
118 PIMAGE_DOS_HEADER pMzHdr; /* Use the buffer as a dosheader. */
119 PIMAGE_NT_HEADERS pNtHdrs; /* Use the buffer as a NT header. */
120 } u1;
121 unsigned cbFile; /* Filesize (0xffffffff if call to SftFileSize failed - should _never_ happen though) */
122 unsigned cbRead; /* Amount of the buffer which contains valid data. */
123 char * psz; /* Multipurpose string pointer no.1. */
124 char * psz2; /* Multipurpose string pointer no.2. */
125 char * psz3; /* Multipurpose string pointer no.3. */
[1273]126
[4164]127 /** @sketch
128 * Allocate read buffer from resident heap.
129 * IF this fails THEN we'll simply return NO_ERROR.
[2827]130 */
[4164]131 u1.pach = (char*)rmalloc(640);
132 if (u1.pach == NULL)
[2827]133 {
[4164]134 kprintf(("myldrOpen-%d: rmalloc(640) failed\n", cNesting));
135 goto ret;
[2827]136 }
137
[4164]138
139 /** @sketch
140 * Increment nesting level.
[2827]141 */
[4164]142 cNesting++;
143
144
145 /** @sketch
146 * Get the filesize. On failure filesize is set to ~0.
147 */
[2827]148 rc = SftFileSize(*phFile, (PULONG)SSToDS(&cbFile));
149 if (rc != NO_ERROR)
150 {
[4164]151 kprintf(("myldrOpen-%d: SftFileSize failed with rc=%d\n", cNesting, rc));
[2827]152 cbFile = (unsigned)~0;
[2838]153 }
[2827]154
[4164]155
156 /** @sketch
157 * Read the size of a DOS (ie. MZ) header.
158 * IF successful and more stuff in file THEN
159 * See if this is an recognizable module binary format:
[1273]160 */
[4164]161 cbRead = min(sizeof(IMAGE_DOS_HEADER), cbFile);
162 rc = ldrRead(*phFile, 0UL, u1.pMzHdr, 0UL, cbRead, NULL);
163 if (rc == NO_ERROR && cbRead < cbFile)
[847]164 {
[4164]165 /** @sketch
166 * If LX header just give up at once.
[2827]167 */
[4164]168 if (u1.pMzHdr->e_magic == E32MAGIC)
169 goto cleanup;
170
171 /** @sketch
172 * IF PE or MZ header THEN
173 */
174 if (u1.pMzHdr->e_magic == IMAGE_DOS_SIGNATURE
175 || u1.pNtHdrs->Signature == IMAGE_NT_SIGNATURE)
176 {
177 ULONG offPe; /* Offset to PE header. */
178
179 /** @sketch
180 * ---
181 * We now known that this is file has a MZ or a PE header. If it's
182 * a MZ header, we might end up with no "New" header or the "New"
183 * header might turn out to be a NE, LE, or LX header. I any of
184 * these non PE headers occur OS/2 will take care of it, we'll do nothing.
185 * ---
186 * IF PE loading is disable or MZ header and e_lfanew is invalid THEN
187 * return (successfully) to the caller.
188 * ENDIF
189 * (Find the offset of the PE header while testing (offPe).)
[2827]190 */
[4164]191 if (isPELoaderDisabled())
192 goto cleanup;
193 if (u1.pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
[2827]194 {
[4164]195 offPe = u1.pMzHdr->e_lfanew;
196 if (offPe < sizeof(IMAGE_DOS_HEADER) || offPe > 0x04000000UL)
197 goto cleanup;
[2827]198 }
[4164]199 else
200 offPe = 0;
[1535]201
[4164]202
203 /** @sketch
204 * Read the PE header.
205 * If the read failes or not PE signature, there isn't anything for us to do.
[2827]206 */
[4164]207 rc = ldrRead(*phFile, offPe, u1.pach, 0UL, sizeof(IMAGE_NT_HEADERS), NULL);
208 if (rc != NO_ERROR || u1.pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
209 goto cleanup_noerror;
[1535]210
[4164]211
212 /** @sketch
213 * PE signature found!
[2827]214 */
[4164]215 kprintf(("myldrOpen-%d: PE executable...\n", cNesting));
[2827]216
[4164]217
218 /** @sketch
219 * Use Pe2Lx?
220 * - When Pe2Lx flag is set
221 * - When the MIXED flag is set and the image isn't an executable
222 * above the first 64MB private limit without relocations
223 */
224 if (isPe2LxLoaderEnabled()
225 || (isMixedPeLoaderEnabled()
226 && ((u1.pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)
227 || !(u1.pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
228 || u1.pNtHdrs->OptionalHeader.ImageBase < 0x04000000UL /* 64MB */
[1535]229 )
230 )
[4164]231 )
232 { /** @sketch
233 * Pe2Lx (Ring0 of course)
234 * - Create a Pe2Lx class,
235 * - initiate it
236 * - Add the module to the module tree so we may find it later...
237 * - Set the (file)handle state to 'our'.
238 * - Set pExeModule to module pointer and loaderstate to our exe.
239 */
240 Pe2Lx * pPe2Lx = new Pe2Lx(*phFile);
241 if (pPe2Lx != NULL)
242 {
243 rc = pPe2Lx->init(pszFilename);
244 if (rc == NO_ERROR)
[1273]245 {
[4164]246 kprintf(("myldrOpen-%d: Successfully init of Pe2Lx object.\n", cNesting));
247 rc = addModule(*phFile, NULL, MOD_TYPE_PE2LX, pPe2Lx);
[1467]248 if (rc == NO_ERROR)
[1273]249 {
[4164]250 #pragma info(notrd)
251 SetState(*phFile, HSTATE_OUR);
252 #pragma info(restore)
253 if (pPe2Lx->isExe())
254 {
255 setLdrStateLoadingOurEXE();
256 pExeModule = getModuleBySFN(*phFile);
257 #ifdef DEBUG
258 if (pExeModule == NULL)
259 kprintf(("myldrOpen-%d: getModuleBySFN failed when setting pExeModule! FATAL!\n", cNesting));
260 #endif
261 }
[1273]262 }
263 else
[4164]264 kprintf(("myldrOpen-%d: Failed to add the module. rc=%d\n", cNesting));
[1273]265 }
266 else
[4164]267 kprintf(("myldrOpen-%d: Failed to init Pe2Lx object. rc=%d\n", cNesting));
268 if (rc != NO_ERROR)
269 delete pPe2Lx;
[1273]270 }
271 else
[2827]272 {
[4164]273 kprintf(("myldrOpen-%d: Failed to allocate Pe2Lx object.\n", cNesting));
274 rc = ERROR_NOT_ENOUGH_MEMORY;
275 }
276
277 goto cleanup;
278 }
279
280
281 /** @sketch
282 * Using PE.EXE to start EXE?
283 * - When the file is an EXE file and PE.EXE is enabled.
284 */
285 if ((u1.pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0UL
286 && (options.fPE == FLAGS_PE_PE || options.fPE == FLAGS_PE_MIXED)
287 && (isLdrStateExecPgm() || isLdrStateQAppType())
288 )
289 {
290 /** @sketch
291 * PE.EXE:
292 * Find pe.exe - look in current directory and thru the PATH.
293 * Note! We use the read buffer (u1.p*) as a storage for the
294 * pe.exe filename and path.
295 */
296 kprintf(("myldrOpen-%d: pe.exe - opening\n", cNesting));
297 ldrClose(*phFile);
[6009]298 *phFile = 0xFFFF;
[4164]299 strcpy(u1.pach, "PE.EXE");
300 rc = ldrOpen(phFile, u1.pach, pfl); /* This isn't recusive! */
301 if (rc != NO_ERROR)
302 rc = OpenPATH(phFile, u1.pach, pfl);
303 if (rc == NO_ERROR)
304 {
305 /** @sketch
306 * If we're in tkExecPgm state we'll have to shuffle the parameters
307 * and executable filename tkExecPgm were called with.
308 * If not tkExecPgm we can't do anything about parameters (and there is
309 * probably nothing to do either).
[4239]310 * We'll always enclose the PE executable name in quotes.
[2827]311 */
[4164]312 kprintf(("myldrOpen-%d: pe.exe - %s\n", cNesting, u1.pach));
313 if (isLdrStateExecPgm() && fTkExecPgm)
314 {
[4239]315 u1.pach[0] = '"';
316 strcpy(&u1.pach[1], achTkExecPgmFilename);
317 u1.pach[strlen(u1.pach)] = '\0';
318 rc = AddArgsToFront(2, ldrpFileNameBuf, u1.pach);
[4164]319 if (rc == NO_ERROR)
320 {
321 rc = SetExecName(ldrpFileNameBuf);
322 if (rc != NO_ERROR)
323 kprintf(("myldrOpen-%d: pe.exe - failed to set pe.exe as execname. rc=%d\n", cNesting));
324 }
325 else
326 kprintf(("myldrOpen-%d: pe.exe - failed to add programname as argument. rc=%d\n", cNesting, rc));
327 goto cleanup_noerror;
[1535]328 }
[2827]329 }
[4164]330 else
331 kprintf(("myldrOpen-%d: pe.exe - couldn't find/open pe.exe\n", cNesting));
[1273]332 }
[4164]333 goto cleanup;
[847]334 }
[4164]335 /** @sketch End of PE Loading. */
336
337
338 /** @sketch
339 * ELF image?
340 */
341 if (*u1.pul == ELFMAGICLSB)
[847]342 {
[4164]343 if (isELFDisabled())
344 goto cleanup_noerror;
345
[2827]346 /*
[4164]347 * ELF signature found.
[2827]348 */
[4164]349 kprintf(("myldrOpen-%d: ELF image! - not implemented yet!\n", cNesting));
350
351 /*
352 * Do nothing more yet. NEED AN ELF LOADER!!!
353 */
354 goto cleanup;
355 }
356
357
358 /** @sketch
359 * Java image?
360 */
361 if (*u1.pul == 0xBEBAFECAUL) //CAh FEh BAh BEh
362 {
363 char *pszName = NULL;
364 int cchName;
365
366 if (isJAVADisabled())
367 goto cleanup_noerror;
368
369 /** @sketch
370 * Java signature found.
371 * Copy the name to a temporary buffer. (only if necessary)
372 * Remove the extention (.class) and insert a space between the name and the path.
373 * (This is the needed processing of the class filename to make it a classpath
374 * entry (path) and a class name (filename).)
375 * Try find the java executor in current dir or PATH: java.exe
376 */
377 kprintf(("myldrOpen-%d: Jave image!\n", cNesting));
378
379 if (isLdrStateExecPgm() && fTkExecPgm)
[1273]380 {
[4164]381 /* Ooops we had to get the file name from the MFT. ldrpFileNameBuf is allways uppercased... */
382 /* MFT seems to hold uppercased filenames! ARG! But (by pure luck?) achTkExecPgmArguments is
383 * not uppercased (yet). Nothing could be simpler!
[2827]384 */
[4164]385 #if 1
386 psz3 = achTkExecPgmArguments;
387 #elif 0
388 psz3 = SecPathFromSFN(*phFile);
389 if (psz3 == NULL)
390 psz3 = ldrpFileNameBuf;
391 #else
392 psz3 = ldrpFileNameBuf;
393 #endif
394 cchName = strlen(psz3);
395 pszName = (char*)rmalloc(cchName + 2);
396 if (pszName == NULL)
397 {
398 rc = ERROR_NOT_ENOUGH_MEMORY;
399 goto cleanup;
400 }
401 memcpy(pszName, psz3, cchName+1);
[2827]402
[4164]403 psz = pszName + strlen(pszName) - 1;
404 while (psz > pszName && *psz != '.' && *psz != '\\' && *psz != '/')
405 psz--;
406 if (*psz == '.')
407 {
408 cchName = psz - pszName;
409 *psz-- = '\0';
410 while (psz > pszName && *psz != '\\' && *psz != '/')
411 psz--;
412
413 /* check for root and evt. make room for an extra slash. */
414 if (psz - pszName == 2)
415 {
416 memmove(psz + 1, psz, cchName - 1);
417 *psz++ = '\\';
418 }
419 }
420 /* check if no path */
421 if (psz == pszName)
422 memmove(pszName + 1, pszName, cchName + 1);
423 *psz = ' ';
424 }
425
426 ldrClose(*phFile);
[6009]427 *phFile = 0xFFFF;
[4164]428 rc = ldrOpen(phFile, ".\\JAVA.EXE", pfl);
429 if (rc != NO_ERROR)
430 rc = OpenPATH(phFile, "JAVA.EXE", pfl);
431 if (rc == NO_ERROR)
432 {
433 kprintf(("myldrOpen-%d: java - %s\n", cNesting, ldrpFileNameBuf));
434
435 /** @sketch
436 * To be able to execute any given class name we'll have to pass in the
437 * directory as -classpath. But -classpath seems to override the default
438 * and environmental CLASSPATHs. So, we'll have to pass in the value of
439 * the CLASSPATH env.var. or generate the default class path (what ever that is).
440 *
[4239]441 * TODO: spaces in class path.
[2827]442 */
[4164]443 if (isLdrStateExecPgm() && fTkExecPgm)
444 {
445 psz = u1.pach;
446
447 /*
448 * Get classpath and add it as a parameter
449 */
450 strcpy(u1.pach, "-classpath ");
451 psz = u1.pach + strlen(u1.pach);
452
453 psz3 = (char*)ScanEnv(GetEnv(TRUE), "CLASSPATH");
454 if (psz3 != NULL)
455 { /* environment variable set */
456 if (strlen(psz3) > 640 - 11 - 1 - cchName) //check for overflow
457 { // TODO? should reallocate...
458 memcpy(psz, psz3, 640 - 11 - 1 - cchName);
459 psz[640 - 11 - 1 - cchName] = '\0';
460 }
461 else
462 strcpy(psz, psz3);
463 psz += strlen(psz);
464 }
465 else
466 {
467 /* Make default classpath by taking the java.exe path + '..\lib\classes.zip' */
468 strcpy(psz, ldrpFileNameBuf);
469 psz3 = psz + strlen(psz) - 1;
470 while (psz3 > psz && *psz3 != '\\' && *psz3 != '/')
471 psz3--;
472 strcpy(++psz3, "..\\lib\\classes.zip");
473 psz = psz3 + strlen(psz3);
474 }
475
476 /*
477 * Add the class directory (as the last classpath entry) and the class name.
478 * (Note. I may happen that there is no directory, but that don't matter
479 * a space is allways preceding the class name.)
480 */
481 *psz++ = ';';
482 strcpy(psz, pszName);
483 if (pszName != NULL)
484 rfree(pszName);
485
486 /*
487 * Setup JAVA.EXE as executable with the parameters we've build.
488 */
489 rc = AddArgsToFront(2, ldrpFileNameBuf, u1.pach);
490 kprintf(("myldrOpen-%d: java - Exe: %s Args: %s\n", cNesting, ldrpFileNameBuf, u1.pach));
491 if (rc == NO_ERROR)
492 {
493 rc = SetExecName(ldrpFileNameBuf);
494 if (rc != NO_ERROR)
495 kprintf(("myldrOpen-%d: java - failed to set java.exe as execname. rc=%d\n", cNesting, rc));
496 }
497 else
498 kprintf(("myldrOpen-%d: java - failed to setup the parameters. rc=%d\n", cNesting, rc));
499
500 goto cleanup_noerror;
501 }
[1273]502 }
[4164]503 else
504 kprintf(("myldrOpen-%d: java - couldn't find/open java.exe\n", cNesting));
505
506
507 /** @sketch
508 * End of Java loading. (return)
509 */
510 if (pszName != NULL)
511 rfree(pszName);
512 goto cleanup;
[2827]513 }
[4164]514
[2838]515 }
[4164]516 else
517 {
518 /** @sketch
519 * ELSE - the reading size of a DOS header failed or file is smaller than the dos header.
520 * IF read failed or filesize is less than 4 bytes THEN
521 * return no_error to the caller.
522 * ENDIF
523 */
524 #ifdef DEBUG
525 if (rc != NO_ERROR)
526 {
527 kprintf(("myldrOpen-%d: ldrRead failed cbRead=%d, cbFile=%d, rc=%d\n", cNesting, cbRead, cbFile, rc));
528 goto cleanup_noerror;
529 }
530 if (cbRead < 4)
531 {
532 kprintf(("myldrOpen-%d: File too small! cbFile=%d\n", cNesting, cbFile));
533 goto cleanup_noerror;
534 }
535 #else
536 if (rc != NO_ERROR || cbRead < 4) //just forget files less than 4 bytes!
537 goto cleanup_noerror;
538 #endif
539 }
540 /** @sketch ENDIF (dos header read) */
[2827]541
[4164]542
543
[2838]544 /*
[4164]545 * Only unreconized files passes this point!
[2838]546 *
547 * * Fileformats with lower priority should reside here. *
548 *
549 */
[2827]550
[4164]551 /** @sketch
552 * UNIX styled script?
553 * - Starts with a hash (#)
554 * - And we're loading an EXE
555 * - And we're either in QAppType or ExecPgm state.
556 * - And that a bang (!) is the first char after the hash (ignoring blanks).
[4239]557 *
558 * FIXME: spaces script name.
[2838]559 */
[4164]560 if (*u1.pach == '#'
561 && isLdrStateLoadingEXE()
562 && (isLdrStateQAppType() || isLdrStateExecPgm())
563 )
[2838]564 {
[4164]565 if (isUNIXScriptDisabled())
566 goto cleanup_noerror;
[2827]567 /*
[4164]568 * Look for a bang (!). Tabs and spaces are skipped, anything else result in error.
[2827]569 */
[4164]570 psz = u1.pach + 1;
571 while ((*psz == ' ' || *psz == '\t') && psz - u1.pach < cbRead)
572 psz++;
573 if (*psz == '!')
[2827]574 {
[4164]575 /** @sketch Found UNIX styled script! */
[2827]576
[4164]577 /** @sketch
578 * Read more of the script if necessary. (max is 256 chars (- Linux max is 127))
579 * Terminate the string read from the file to make sure with stop somewhere!
[2827]580 */
[4164]581 if (cbRead < cbFile /*&& cbRead != 256*/)
582 {
583 cbRead = min(256, cbFile);
584 rc = ldrRead(*phFile, 0UL, u1.pach, 0UL, cbRead, NULL);
585 }
586 u1.pach[cbRead] = '\0';
[2827]587
[4164]588 if (rc == NO_ERROR)
[2827]589 {
[4164]590 /** @sketch
591 * Parse out filename and optional arguments (if any).
592 * The result of the parsing is that:
593 * psz will point at the executable name.
594 * psz2 will point at the arguments.
595 * Both strings are trimmed.
[2827]596 */
[4164]597 psz++; /* psz points to the bang, skip it. */
598 while (*psz == ' ' || *psz == '\t') /* skip blanks after bang */
599 psz++;
600 if (*psz == '\r' || *psz == '\n' || *psz == '\0') /* End-of-line? */
[1535]601 {
[4164]602 kprintf(("myldrOpen-%d: script no executable name.\n", cNesting));
603 goto cleanup_noerror; /* other error code? */
[2838]604 }
[4164]605 psz2 = psz + 1; /* Not end-of-line, so add 1 before searching for args. */
606 while (*psz2 != '\0' && *psz2 != '\n' && *psz2 != '\r' /* skip executable name. */
607 && *psz2 != ' ' && *psz2 != '\t')
608 psz2++;
609 while (*psz2 == ' ' || *psz2 == '\t') /* skip blanks after executable - pad them with '\0'! */
610 *psz2++ = '\0';
[2838]611
[4164]612 psz3 = psz2;
613 while (*psz3 != '\n' && *psz3 != '\r' && *psz3 != '\0') /* find end of parameters and terminate the string. */
614 psz3++;
615 *psz3 = '\0';
616 while (psz3 >= psz2 && (*psz3 == '\0' || *psz3 == ' ' || *psz3 == '\t')) /* trim args */
617 *psz3-- = '\0';
618
619
620 /** @sketch
621 * IF tkExecPgm THEN
622 * Correct parameters - ie. add exec name (as argv[0]),
623 * arguments (psz2) as argv[1+], old exec name, and finally
624 * the existing parameters (current argv[1+]).
625 * Set the executable name.
626 * ENDIF
627 * Open the new executable file recursively. (psz)
[2838]628 */
[4164]629 if (isLdrStateExecPgm())
[2838]630 {
[4164]631 if (*psz2)
632 rc = AddArgsToFront(3, psz, psz2, achTkExecPgmFilename);
633 else
634 rc = AddArgsToFront(2, psz, achTkExecPgmFilename);
635 if (rc != NO_ERROR)
636 {
637 kprintf(("myldrOpen-%d: AddArgsToFront failed with rc=%d\n", cNesting));
638 goto cleanup_noerror;
639 }
640 rc = SetExecName(psz);
641 if (rc != NO_ERROR)
642 kprintf(("myldrOpen-%d: SetExecName failed with rc=%d\n", cNesting));
[2838]643 }
[4164]644 ldrClose(*phFile);
[6009]645 *phFile = 0xFFFF;
[4164]646 rc = myldrOpen(phFile, psz, pfl);
647 if (rc != NO_ERROR)
[2838]648 {
[4164]649 psz2 = psz + strlen(psz);
650 if (psz + 4 >= psz2 || strcmp(psz2 - 4, ".EXE") != 0)
[2827]651 {
[4164]652 strcpy(psz2, ".EXE");
653 rc = myldrOpen(phFile, psz, pfl);
654 *psz2 = '\0';
[1535]655 }
656 else
[4164]657 psz2 = NULL;
658
659 //should we search the PATH??? For a starting, we'll do it.
660 if (rc != NO_ERROR
661 && (rc = OpenPATH(phFile, psz, pfl)) != NO_ERROR
662 && psz2 != NULL)
[2827]663 {
[4164]664 *psz2 = '.';
665 rc = OpenPATH(phFile, psz, pfl);
[2827]666 }
[1535]667 }
[2827]668 }
669 else
670 {
[4164]671 kprintf(("myldrOpen-%d: script - failed to read more of the script!, rc=%d cbRead=%d cbFile=%d.\n",
672 cNesting, rc, cbRead, cbFile));
[2827]673 }
[4164]674
675 goto cleanup;
[2838]676 }
677 else
678 {
[4164]679 kprintf(("myldrOpen-%d: script - hash found but no bang (!).\n", cNesting));
[2838]680 }
[4164]681 } /**@sketch ENDIF - UNIX styled script. */
682
683
684
685 /** @sketch
686 * REXX script?
687 * - Starts with a REXX start comment ('/','*')
688 * - And we're loading an EXE
689 * - And we're either in QAppType or ExecPgm state.
690 * - Extention:
691 * .RX and .REX are known to be pure REXX scripts.
692 * While .CMD has to invoked used the commandline OS2_SHELL or COMSPEC variable.
[4239]693 *
694 * FIXME: spaces script name.
[4164]695 */
696 psz2 = pszFilename + strlen(pszFilename) - 1;
697 while (psz2 > pszFilename && *psz2 != '.')
698 psz2--;
699 if (*psz2 == '.'
700 && *u1.pach == '/' && u1.pach[1] == '*'
701 && isLdrStateLoadingEXE()
702 && (isLdrStateQAppType() || isLdrStateExecPgm())
703 && (stricmp(psz2, ".RX") == 0 || stricmp(psz2, ".REX") == 0)
704 )
705 {
706 if (isREXXScriptDisabled())
707 goto cleanup_noerror;
708
709 /** @sketch
710 * Found REXX styled script!
711 * Find the REXX interpreter. We'll use kRx.exe to execute the REXX scripts.
712 * (This interpreter could be embedded as a child of ModuleBase as it turned out
713 * to be quite small about 700 bytes.)
714 */
715 kprintf(("myldrOpen-%d: Found REXX script\n", cNesting));
716 ldrClose(*phFile);
[6009]717 *phFile = 0xFFFF;
[4164]718 psz = "KRX.EXE";
719 rc = ldrOpen(phFile, psz, pfl);
720 if (rc != NO_ERROR)
721 rc = OpenPATH(phFile, psz, pfl);
722
723 /** @sketch
724 * IF tkExecPgm THEN
725 * Correct parameters - ie. add exec name (as argv[0]), old exec name,
726 * and finally the existing parameters (current argv[1+]).
727 * Set the executable name.
728 * ENDIF
729 */
730 if (rc == NO_ERROR && isLdrStateExecPgm())
731 {
732 rc = AddArgsToFront(2, ldrpFileNameBuf, achTkExecPgmFilename);
733 if (rc != NO_ERROR)
734 {
735 kprintf(("myldrOpen-%d: AddArgsToFront failed with rc=%d\n", cNesting));
736 goto cleanup_noerror;
737 }
738 rc = SetExecName(ldrpFileNameBuf);
739 if (rc != NO_ERROR)
740 kprintf(("myldrOpen-%d: SetExecName failed with rc=%d\n", cNesting));
741
742 goto cleanup_noerror;
743 }
744 goto cleanup;
745 } /**@sketch ENDIF - REXX styled script. */
746
747
748 /*
749 * Cleanup with rc set to NO_ERROR.
750 */
751 cleanup_noerror:
752 rc = NO_ERROR;
753
754 /*
755 * Cleanup without having rc set to NO_ERROR.
756 * Decrement the nesting count.
757 */
758 cleanup:
[6009]759 if (rc && *phFile != 0xFFFF)
760 {
761 ldrClose(*phFile);
762 *phFile = 0xFFFF;
763 }
[4164]764 rfree(u1.pach);
765 cNesting--;
[847]766 }
[4164]767 #ifdef DEBUG
768 else if (cNesting >= 3)
769 kprintf(("myldrOpen-%d: cNesting = %d, which is too deep!\n", cNesting, cNesting));
770 #endif
771
772ret:
773 /** @sketch
[5119]774 * If successful and force preload enabled and media flag pointer valid Then
775 * Set removable media.
[4164]776 * Return rc.
777 */
[5119]778 if (rc == NO_ERROR && isForcePreloadEnabled() && pfl)
779 *pfl &= ~0x1000UL; /* 0x1000 is the fixed media flag. */
780
[847]781 return rc;
782}
[2827]783
784
785/**
[4164]786 * Adds new arguments to the front of the startup arguments for the program about to be
787 * executed.
788 *
789 * @returns OS/2 return code.
790 * @param cArgs Count of arguments to add. At least 1!!!
791 * @param ... Pointers to the arguments to add.
792 * The first argument have to be the executable name. This have to the
793 * the only argument in the first string.
794 * The other arguements are space separated, so you could add a bunch
795 * of arguments in a single string!
796 * The last argument should be the old first parameter if this is to be
797 * preserved. The old first parameter is overwritten since it's
798 * normally the executable name.
799 *
800 * @status completly implemented.
[4778]801 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
[4164]802 * @remark Implementation note:
803 * The arguments convention is as follows:
804 * First argument, which should be the executable name, is terminated with a '\0'.
805 * It starts at offset 0 into the argument buffer, of course.
806 * All other arguemnts are separated by a space and follows the immediately after the
807 * first argument.
808 * The arguments are terminated by a double nulltermination: '\0\0'.
[2827]809 */
[4164]810APIRET AddArgsToFront(int cArgs, ...)
[2827]811{
[4164]812 va_list vaarg; /* Variable length argument list. */
813 int cchOldArgs; /* Length of the old arguments (including the first argument). */
814 /* cchOldArgs = 1 means no arguments. It don't include the very last '\0' */
815 /* (remember argumets are terminated with two '\0's). */
816 int iSecondArg; /* Index of the second argument. (Used to skip the first argument.) */
817 /* Used first on the original arguments and them when adding the first */
818 /* new argument. */
819 int cchNewArgs; /* Length of the new arguments to be inserted. */
820 int i; /* Loop variable. Current function argument. */
821 char * psz; /* General string pointer. */
[2827]822
[4164]823
824 /** @sketch
825 * Assert that we're in the right state.
826 * Calc the length of the existing parameters.
827 * Calc the length of the new arguments to determin.
828 * Assert that the new arguments have length > 0.
829 */
830 #ifdef DEBUG
831 if (!isLdrStateExecPgm())
832 {
833 kprintf(("AddArgsToFront: not in tkExecPgm state.\n"));
834 return ERROR_INVALID_PARAMETER;
835 }
836 #endif
837 if (!fTkExecPgm)
838 {
839 kprintf(("AddArgsToFront: called when not in tkExecPgm data is invalid!\n"));
840 return ERROR_INVALID_PARAMETER;
841 }
842
843 iSecondArg = strlen(&achTkExecPgmArguments[0]) + 1;
844 psz = &achTkExecPgmArguments[iSecondArg];
[2827]845 while (*psz != '\0')
[4164]846 psz += strlen(psz) + 1;
847 cchOldArgs = psz - &achTkExecPgmArguments[iSecondArg];
848
849 va_start(vaarg, cArgs);
850 for (cchNewArgs = i = 0; i < cArgs; i++)
851 cchNewArgs += strlen(va_arg(vaarg, char *)) + 1; /* 1 is for space or '\0'. */
852 va_end(vaarg);
853 #ifdef DEBUG
854 if (cchNewArgs == 0)
[2827]855 {
[4164]856 kprintf(("AddArgsToFront: the size of the arguments to add is zero!\n"));
857 return ERROR_INVALID_PARAMETER;
[2827]858 }
[4164]859 #endif
[2827]860
[4164]861
862 /** @sketch
863 * Check if we have enough room for the new arguments. Fail if not enough.
864 * Move the existing arguments to make room for the new ones.
865 * !IMPORTANT! The first existing arguments (executable name) is skipped !IMPORTANT!
866 * !IMPORTANT! in this move as this have to be re-added in this call! !IMPORTANT!
867 */
868 if (cchOldArgs + cchNewArgs + 1 > CCHARGUMENTS)
869 {
870 kprintf(("AddArgsToFront: argument buffer is too small to hold the arguments to add, cchOldArgs=%d, cchNewArgs=%d\n",
871 cchOldArgs, cchNewArgs));
872 return ERROR_BAD_ARGUMENTS;
873 }
874
875 if (cchOldArgs > 0)
876 {
877 memmove(&achTkExecPgmArguments[cchNewArgs], &achTkExecPgmArguments[iSecondArg],
878 cchOldArgs + 1);
879 }
880 else
881 achTkExecPgmArguments[cchNewArgs] = '\0';
882
883
884 /** @sketch
885 * Copy new arguments.
886 * Since the first argument is special case we'll do it separately. (Uses '\0' as separator.)
887 * We assume that the entire first argument passed into this function should be the first argument!
888 * (This don't have to be true for the other arguments since these are space separated. You could
889 * pass in more than argument in a single string.)
890 * Loop thru the rest of the new arguments and add them with space as separator.
891 */
892 va_start(vaarg, cArgs);
893 psz = va_arg(vaarg, char *);
894 memcpy(&achTkExecPgmArguments[0], psz, (i = strlen(psz) + 1));
895 psz = &achTkExecPgmArguments[i];
896
897 for (i = 1; i < cArgs; i++)
898 {
899 if (i > 1) *psz++ = ' '; //Add space if not second argument.
900 strcpy(psz, va_arg(vaarg, char *));
901 psz += strlen(psz);
902 }
903 va_end(vaarg);
904 if (cchOldArgs > 0) *psz++ = ' '; //Add space if old arguments
905
906 #ifdef DEBUG /* assertion */
907 if (psz != &achTkExecPgmArguments[cchNewArgs])
908 {
909 kprintf(("AddArgsToFront: !Assertion failed! psz didn't end up where it should! (psz -> %d should be %d)\n",
910 psz - &achTkExecPgmArguments[0], cchNewArgs));
911 if (cchOldArgs <= 1)
912 psz[0] = psz[1] = '\0';
913 }
914 #endif
915
916 return NO_ERROR;
[2827]917}
[4164]918
919
920/**
921 * Sets the executable name of the module.
922 * This function is normally invoked after a different executable than the one requested was
923 * opened. It does _NOT_ set the new executable name as the first argument, since it is more
924 * convenient to this while calling AddArgsToFront to add other arguments.
925 *
926 * @returns OS/2 return code.
927 * @param pszExecName Pointer to new executable name.
928 * @status completly implemented.
[4778]929 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
[4164]930 * @remark .
931 */
932APIRET SetExecName(const char *pszExecName)
933{
934 #ifdef DEBUG
935 int cch;
936 cch = strlen(pszExecName);
937 if (cch > CCHMAXPATH)
938 {
939 kprintf(("ChangeExecName: filename is too long! cch=%d. name=%s\n", cch, pszExecName));
940 return ERROR_FILENAME_EXCED_RANGE;
941 }
942 if (!isLdrStateExecPgm())
943 {
944 kprintf(("ChangeExecName: called when not in tkExecPgm state!!! FATAL ERROR!\n"));
945 return ERROR_INVALID_PARAMETER;
946 }
947 #endif
948 if (!fTkExecPgm)
949 {
950 kprintf(("ChangeExecName: called when not in tkExecPgm data is invalid!!! FATAL ERROR!\n"));
951 return ERROR_INVALID_PARAMETER;
952 }
953
954 strcpy(achTkExecPgmFilename, pszExecName);
955
956 return 0;
957}
958
959
960/**
961 * Opens a file using the PATH environment variable of the current process.
962 * @returns OS2 return code.
963 * @param phFile Pointer to filehandle. The filehandle is set to the SFN for the opened
964 * file on successful return.
965 * The filehandle is 0 on failure.
966 * @param pszFilename Pointer to filename buffer. This will hold the filename on input.
967 * On successful return it holds the filepath found.
968 * On failiure it's undefined.
969 * @param pfl Some flags set by ldrOpen.
970 * @sketch stub
[4778]971 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
[4164]972 * @remark
973 */
974APIRET OpenPATH(PSFN phFile, char *pszFilename, PULONG pfl)
975{
976 APIRET rc;
977 USHORT TCBFailErr_save;
978 int cchFile; /* Filename length + 1. */
979 const char *pszFile; /* Pointer to filename portion. */
980 const char *pszPath = ScanEnv(GetEnv(FALSE), "PATH"); /* Current Process environment? */
981
982 /**@sketch
983 * No PATH environment.
984 */
985 if (pszPath == NULL)
986 return ERROR_FILE_NOT_FOUND;
987
988 /**@sketch
989 * Skip any paths in the filename.
990 */
991 pszFile = pszFilename + (cchFile = strlen(pszFilename));
992 while (pszFile >= pszFilename && *pszFile != '\\' && *pszFile != '/')
993 pszFile--;
994 cchFile -= pszFile - pszFilename;
995 pszFile++;
996
997 /**@sketch
998 * We'll have to save the TCBFailErr since we don't want to cause
999 * Hard Errors while searching invalid paths, etc. (ldrOpenPath does this!)
1000 */
1001 TCBFailErr_save = tcbGetTCBFailErr(tcbGetCur());
1002
1003 /**@ sketch
1004 * Loop thru the PATH trying to open the specified file in each
1005 * directory.
1006 */
1007 while (*pszPath != '\0')
1008 {
1009 const char * pszNext;
1010 int cchPath;
1011 char chEnd;
1012 register char ch;
1013
1014 /*
1015 * Find end of this path.
1016 */
1017 while (*pszPath == ' ') pszPath++; //skip leading spaces.
1018 if (*pszPath == '"')
1019 {
1020 chEnd = '"';
1021 pszPath++;
1022 }
1023 else
1024 chEnd = ';';
1025 pszNext = pszPath;
1026 while ((ch = *pszNext) != chEnd && ch != '\0')
1027 pszNext++;
1028
1029 cchPath = pszNext - pszPath;
1030 if (chEnd == '"')
1031 {
1032 /* Skip anything between the " and the ; or string end. */
1033 while ((ch = *pszNext) != ';' && ch != '\0')
1034 pszNext++;
1035 }
1036 else
1037 {
1038 /* Trim the string. */
1039 while (cchPath > 0 && pszPath[cchPath-1] == ' ') //??
1040 cchPath--;
1041 }
1042
1043 /*
1044 * No length? No Path! Or path'\'filename too long? => Next
1045 */
1046 if (cchPath > 0 && cchPath + cchFile + 1 < CCHMAXPATH)
1047 {
1048 static char achFilename[CCHMAXPATH];
1049 /*
1050 * Build filename
1051 */
1052 memcpy(achFilename, pszPath, cchPath);
1053 if ((ch = achFilename[cchPath - 1]) == '\\' || ch == '/')
1054 cchPath--;
1055 else
1056 achFilename[cchPath] = '\\';
1057 memcpy(&achFilename[cchPath + 1], pszFile, cchFile); /* cchFile = length + 1; hence we copy the terminator too. */
1058
1059 /*
1060 * Try open the file.
1061 */
1062 rc = myldrOpen(phFile, achFilename, pfl);
1063 switch (rc)
1064 {
1065 case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_ACCESS_DENIED: case ERROR_INVALID_ACCESS:
1066 case ERROR_INVALID_DRIVE: case ERROR_NOT_DOS_DISK: case ERROR_REM_NOT_LIST: case ERROR_BAD_NETPATH:
1067 case ERROR_NETWORK_BUSY: case ERROR_DEV_NOT_EXIST: case ERROR_TOO_MANY_CMDS: case ERROR_ADAP_HDW_ERR:
1068 case ERROR_UNEXP_NET_ERR: case ERROR_BAD_REM_ADAP: case ERROR_NETNAME_DELETED: case ERROR_BAD_DEV_TYPE:
1069 case ERROR_NETWORK_ACCESS_DENIED: case ERROR_BAD_NET_NAME: case ERROR_TOO_MANY_SESS: case ERROR_REQ_NOT_ACCEP:
1070 case ERROR_INVALID_PASSWORD: case ERROR_OPEN_FAILED: case ERROR_INVALID_NAME: case ERROR_FILENAME_EXCED_RANGE:
1071 case ERROR_VC_DISCONNECTED:
1072 break;
1073
1074 case NO_ERROR:
1075 strcpy(pszFilename, achFilename);
1076 default:
1077 tcbSetTCBFailErr(tcbGetCur(), TCBFailErr_save);
1078 return rc;
1079 }
1080 }
1081 #ifdef DEBUG
1082 else if (cchPath > 0) kprintf(("OpenPATH: Path component is too long\n"));
1083 #endif
1084
1085 /*
1086 * Next
1087 */
1088 if (*pszNext == '\0')
1089 break;
1090 pszPath = pszNext + 1;
1091 }
1092
1093
1094 /*
1095 * File is not found.
1096 */
1097 *phFile = 0;
1098 tcbSetTCBFailErr(tcbGetCur(), TCBFailErr_save);
1099 return ERROR_FILE_NOT_FOUND;
1100}
Note: See TracBrowser for help on using the repository browser.