2394 |
2394 |
2395 "Modified: / 20.1.1998 / 16:57:19 / md" |
2395 "Modified: / 20.1.1998 / 16:57:19 / md" |
2396 "Modified: / 11.9.1998 / 19:03:55 / cg" |
2396 "Modified: / 11.9.1998 / 19:03:55 / cg" |
2397 ! |
2397 ! |
2398 |
2398 |
2399 exec:aCommandPath withArguments:argArray fileDescriptors:fdArray closeDescriptors:closeFdArray fork:doFork newPgrp:newPgrp |
2399 exec:aCommandPath withArguments:argArray fileDescriptors:fdArray closeDescriptors:closeFdArray fork:doFork newPgrp:newPgrp inDirectory:aDirectory |
2400 "Internal lowLevel entry for combined fork & exec; |
2400 "Internal lowLevel entry for combined fork & exec for WIN32 |
|
2401 |
2401 If fork is false (chain a command): |
2402 If fork is false (chain a command): |
2402 execute the OS command specified by the argument, aCommandPath, with |
2403 execute the OS command specified by the argument, aCommandPath, with |
2403 arguments in argArray (no arguments, if nil). |
2404 arguments in argArray (no arguments, if nil). |
2404 If successful, this method does not return and smalltalk is gone. |
2405 If successful, this method does not return and smalltalk is gone. |
2405 If not successful, it does return. |
2406 If not successful, it does return. |
2406 Normal use is with forkForCommand. |
2407 Normal use is with forkForCommand. |
2407 |
2408 |
2408 If fork is true (subprocess command execution): |
2409 If fork is true (subprocess command execution): |
2409 fork a child to do the above. |
2410 fork a child to do the above. |
2410 The process id of the child process is returned; nil if the fork failed. |
2411 The process id of the child process is returned; nil if the fork failed. |
2411 |
2412 |
2412 fdArray contains the filedescriptors, to be used for the child (if fork is true). |
2413 fdArray contains the filedescriptors, to be used for the child (if fork is true). |
2413 fdArray[1] = 15 -> use fd 15 as stdin. |
2414 fdArray[1] = 15 -> use fd 15 as stdin. |
2414 If an element of the array is set to nil, the corresponding filedescriptor |
2415 If an element of the array is set to nil, the corresponding filedescriptor |
2415 will be closed for the child. |
2416 will be closed for the child. |
2416 fdArray[0] == StdIn for child |
2417 fdArray[0] == StdIn for child |
2417 fdArray[1] == StdOut for child |
2418 fdArray[1] == StdOut for child |
2418 fdArray[2] == StdErr for child |
2419 fdArray[2] == StdErr for child |
2419 on VMS, these must be channels as returned by createMailBox. |
2420 on VMS, these must be channels as returned by createMailBox. |
2420 |
2421 |
2421 closeFdArray contains descriptors that will be closed in the subprocess. |
2422 closeFdArray contains descriptors that will be closed in the subprocess. |
2422 closeDescriptors are ignored in the WIN32 & VMS versions. |
2423 closeDescriptors are ignored in the WIN32 & VMS versions. |
2423 |
2424 |
2424 NOTE that in WIN32 the fds are HANDLES!! |
2425 NOTE that in WIN32 the fds are HANDLES!! |
2425 |
2426 |
2426 If newPgrp is true, the subprocess will be established in a new process group. |
2427 If newPgrp is true, the subprocess will be established in a new process group. |
2427 The processgroup will be equal to id. |
2428 The processgroup will be equal to id. |
2428 newPgrp is not used on WIN32 and VMS systems. |
2429 newPgrp is not used on WIN32 and VMS systems." |
2429 |
2430 |
2430 Notice: this used to be two separate ST-methods; however, in order to use |
2431 |path| |
2431 vfork on some machines, it had to be merged into one, to avoid write |
2432 |
2432 accesses to ST/X memory from the vforked-child. |
2433 aDirectory notNil ifTrue:[ |
2433 The code below only does read accesses." |
2434 path := aDirectory asFilename asAbsoluteFilename osNameForDirectory. |
|
2435 (path endsWith:':') ifTrue:[ |
|
2436 path := path , '\'. |
|
2437 ]. |
|
2438 ]. |
2434 |
2439 |
2435 ^ self |
2440 ^ self |
2436 exec:aCommandPath |
2441 primExec:aCommandPath |
2437 withArguments:argArray |
2442 withArguments:argArray |
2438 fileDescriptors:fdArray |
2443 fileDescriptors:fdArray |
2439 closeDescriptors:closeFdArray |
2444 closeDescriptors:closeFdArray |
2440 fork:doFork |
2445 fork:doFork |
2441 newPgrp:newPgrp |
2446 newPgrp:newPgrp |
2442 inDirectory:nil. |
2447 inPath:path |
2443 ! |
2448 |
2444 |
2449 "Modified: / 31.1.1998 / 10:54:24 / md" |
2445 exec:aCommandPath withArguments:argArray fileDescriptors:fdArray closeDescriptors:closeFdArray fork:doFork newPgrp:newPgrp inDirectory:aDirectory |
2450 "Modified: / 10.11.1998 / 20:44:24 / cg" |
2446 "Internal lowLevel entry for combined fork & exec for WIN32" |
|
2447 |
|
2448 |path| |
|
2449 aDirectory isNil ifTrue:[ |
|
2450 path := nil. |
|
2451 ] ifFalse:[ |
|
2452 path := aDirectory asFilename pathName asFilename osNameForDirectory. |
|
2453 (path endsWith:':') ifTrue:[ |
|
2454 path := path , '\'. |
|
2455 ]. |
|
2456 ]. |
|
2457 ^ self |
|
2458 primExec:aCommandPath |
|
2459 withArguments:argArray |
|
2460 fileDescriptors:fdArray |
|
2461 closeDescriptors:closeFdArray |
|
2462 fork:doFork |
|
2463 newPgrp:newPgrp |
|
2464 inPath:path |
|
2465 |
|
2466 "Modified: 31.1.1998 / 10:54:24 / md" |
|
2467 ! |
|
2468 |
|
2469 executeCommand:aCommandString inDirectory:aDirectory |
|
2470 "much like #executeCommand:, but changes the current directory |
|
2471 for the command. Since this is OS specific, use this instead of |
|
2472 hardwiring any 'cd ..' command strings into your applictions." |
|
2473 |
|
2474 ^ self |
|
2475 executeCommand:aCommandString |
|
2476 onError:[:status| false] |
|
2477 inDirectory:aDirectory |
|
2478 |
|
2479 " |
|
2480 OperatingSystem executeCommand:'tdump date.obj' inDirectory:'c:\winstx\stx\libbasic\objbc'. |
|
2481 OperatingSystem executeCommand:'xxdir date.obj' inDirectory:'c:\winstx\stx\libbasic\objbc'. |
|
2482 " |
|
2483 |
|
2484 "Modified: / 20.1.1998 / 17:03:03 / md" |
|
2485 "Modified: / 11.9.1998 / 18:52:36 / cg" |
|
2486 ! |
|
2487 |
|
2488 executeCommand:aCommandString inputFrom:anExternalInStream outputTo:anExternalOutStream errorTo:anExternalErrStream onError:aBlock |
|
2489 "execute the unix command specified by the argument, aCommandString. |
|
2490 The commandString is passed to a shell for execution - see the description of |
|
2491 'sh -c' in your UNIX manual. |
|
2492 Return true if successful. |
|
2493 If not successfull, aBlock is called with an OsProcessStatus |
|
2494 (containing the exit status) as argument." |
|
2495 |
|
2496 |pid exitStatus sema| |
|
2497 |
|
2498 sema := Semaphore new name:'Unix command wait'. |
|
2499 |
|
2500 pid := Processor |
|
2501 monitor:[ |
|
2502 self |
|
2503 startProcess:aCommandString |
|
2504 inputFrom:anExternalInStream |
|
2505 outputTo:anExternalOutStream |
|
2506 errorTo:anExternalErrStream. |
|
2507 ] |
|
2508 action:[:status | |
|
2509 status stillAlive ifFalse:[ |
|
2510 exitStatus := status. |
|
2511 self closePid:pid. |
|
2512 sema signal |
|
2513 ]. |
|
2514 ]. |
|
2515 pid notNil ifTrue:[ |
|
2516 sema wait. |
|
2517 ] ifFalse:[ |
|
2518 exitStatus := OSProcessStatus processCreationFailure. |
|
2519 ]. |
|
2520 |
|
2521 exitStatus success ifFalse:[ |
|
2522 ^ aBlock value:exitStatus |
|
2523 ]. |
|
2524 ^ true. |
|
2525 |
|
2526 "Modified: 25.3.1997 / 11:02:02 / stefan" |
|
2527 "Modified: 19.4.1997 / 18:15:04 / cg" |
|
2528 "Modified: 28.1.1998 / 14:46:36 / md" |
|
2529 ! |
|
2530 |
|
2531 executeCommand:aCommandString onError:aBlock |
|
2532 "execute the unix command specified by the argument, aCommandString. |
|
2533 The commandString is passed to a shell for execution - see the description of |
|
2534 'sh -c' in your UNIX manual. |
|
2535 Return true if successful. |
|
2536 If not successfull, aBlock is called with an OsProcessStatus |
|
2537 (containing the exit status) as argument." |
|
2538 |
|
2539 |pid exitStatus sema| |
|
2540 |
|
2541 sema := Semaphore new name:'OS command wait'. |
|
2542 |
|
2543 pid := Processor |
|
2544 monitor:[self startProcess:aCommandString] |
|
2545 action:[:status | |
|
2546 status stillAlive ifFalse:[ |
|
2547 exitStatus := status. |
|
2548 self closePid:pid. |
|
2549 sema signal |
|
2550 ]. |
|
2551 ]. |
|
2552 pid notNil ifTrue:[ |
|
2553 sema wait. |
|
2554 ] ifFalse:[ |
|
2555 exitStatus := OSProcessStatus processCreationFailure. |
|
2556 ]. |
|
2557 |
|
2558 exitStatus success ifFalse:[ |
|
2559 ^ aBlock value:exitStatus |
|
2560 ]. |
|
2561 ^ true. |
|
2562 |
|
2563 |
|
2564 " |
|
2565 OperatingSystem executeCommand:'sleep 30' onError:[]. |
|
2566 OperatingSystem executeCommand:'pwd' onError:[:status|status inspect]. |
|
2567 OperatingSystem executeCommand:'ls -l' onError:[]. |
|
2568 OperatingSystem executeCommand:'invalidCommand' onError:[:status| status inspect]. |
|
2569 OperatingSystem executeCommand:'rm /tmp/foofoofoofoo'onError:[:status | status inspect]. |
|
2570 " |
|
2571 |
|
2572 "Created: 22.12.1995 / 14:49:59 / stefan" |
|
2573 "Modified: 25.3.1997 / 11:06:43 / stefan" |
|
2574 "Modified: 19.4.1997 / 18:14:41 / cg" |
|
2575 "Modified: 28.1.1998 / 14:46:56 / md" |
|
2576 ! |
|
2577 |
|
2578 executeCommand:aCommandString onError:aBlock inDirectory:aDirectory |
|
2579 "execute the unix command specified by the argument, aCommandString. |
|
2580 The commandString is passed to a shell for execution - see the description of |
|
2581 'sh -c' in your UNIX manual. |
|
2582 Return true if successful. |
|
2583 If not successfull, aBlock is called with an OsProcessStatus |
|
2584 (containing the exit status) as argument." |
|
2585 |
|
2586 |pid exitStatus sema| |
|
2587 |
|
2588 sema := Semaphore new name:'OS command wait'. |
|
2589 |
|
2590 pid := Processor |
|
2591 monitor:[self startProcess:aCommandString inDirectory:aDirectory] |
|
2592 action:[:status | |
|
2593 status stillAlive ifFalse:[ |
|
2594 exitStatus := status. |
|
2595 self closePid:pid. |
|
2596 sema signal |
|
2597 ]. |
|
2598 ]. |
|
2599 pid notNil ifTrue:[ |
|
2600 sema wait. |
|
2601 ] ifFalse:[ |
|
2602 exitStatus := OSProcessStatus processCreationFailure. |
|
2603 ]. |
|
2604 |
|
2605 exitStatus success ifFalse:[ |
|
2606 ^ aBlock value:exitStatus |
|
2607 ]. |
|
2608 ^ true. |
|
2609 |
|
2610 |
|
2611 " |
|
2612 OperatingSystem executeCommand:'sleep 30' onError:[]. |
|
2613 OperatingSystem executeCommand:'pwd' onError:[:status|status inspect]. |
|
2614 OperatingSystem executeCommand:'ls -l' onError:[]. |
|
2615 OperatingSystem executeCommand:'invalidCommand' onError:[:status| status inspect]. |
|
2616 OperatingSystem executeCommand:'rm /tmp/foofoofoofoo'onError:[:status | status inspect]. |
|
2617 " |
|
2618 |
|
2619 "Created: 28.1.1998 / 14:12:15 / md" |
|
2620 ! |
2451 ! |
2621 |
2452 |
2622 getStatusOfProcess:aProcessId |
2453 getStatusOfProcess:aProcessId |
2623 "wait for a process to terminate and fetch its exit status. |
2454 "wait for a process to terminate and fetch its exit status. |
2624 This is required to avoid zombie processes." |
2455 This is required to avoid zombie processes." |
2882 or #killProcess: to stop it." |
2713 or #killProcess: to stop it." |
2883 |
2714 |
2884 |in out err shellAndArgs| |
2715 |in out err shellAndArgs| |
2885 |
2716 |
2886 anExternalInStream notNil ifTrue:[ |
2717 anExternalInStream notNil ifTrue:[ |
2887 in := anExternalInStream fileDescriptor. |
2718 in := anExternalInStream fileDescriptor. |
2888 ]. |
2719 ]. |
2889 anExternalOutStream notNil ifTrue:[ |
2720 anExternalOutStream notNil ifTrue:[ |
2890 out := anExternalOutStream fileDescriptor. |
2721 out := anExternalOutStream fileDescriptor. |
2891 ]. |
2722 ]. |
2892 anExternalErrStream notNil ifTrue:[ |
2723 anExternalErrStream notNil ifTrue:[ |
2893 err := anExternalErrStream fileDescriptor. |
2724 err := anExternalErrStream fileDescriptor. |
2894 ]. |
2725 ]. |
2895 |
2726 |
2896 shellAndArgs := self commandAndArgsForOSCommand:aCommandString. |
2727 shellAndArgs := self commandAndArgsForOSCommand:aCommandString. |
2897 ^ self |
2728 ^ self |
2898 exec:(shellAndArgs at:1) |
2729 exec:(shellAndArgs at:1) |
2899 withArguments:(shellAndArgs at:2) |
2730 withArguments:(shellAndArgs at:2) |
2900 fileDescriptors:(Array with:in with:out with:err) |
2731 fileDescriptors:(Array with:in with:out with:err) |
2901 closeDescriptors:nil |
2732 closeDescriptors:nil |
2902 fork:true |
2733 fork:true |
2903 newPgrp:false. |
2734 newPgrp:false |
2904 |
2735 inDirectory:dirOrNil |
2905 "blocking at current prio (i.e. only higher prio threads execute): |
2736 |
2906 |
2737 "Modified: / 10.11.1998 / 20:43:12 / cg" |
2907 OperatingSystem executeCommand:'dir'. |
2738 "Created: / 10.11.1998 / 20:48:35 / cg" |
2908 " |
|
2909 |
|
2910 "non-blocking (lower prio threads continue): |
|
2911 |
|
2912 |in out err pid sema| |
|
2913 |
|
2914 in := 'out' asFilename readStream. |
|
2915 out := 'out2' asFilename writeStream. |
|
2916 err := 'err' asFilename writeStream. |
|
2917 |
|
2918 sema := Semaphore new. |
|
2919 pid := OperatingSystem startProcess:'grep drw' inputFrom:in outputTo:out errorTo:err. |
|
2920 |
|
2921 The following will no longer work. monitorPid has disappeared |
|
2922 |
|
2923 pid notNil ifTrue:[ |
|
2924 Processor monitorPid:pid action:[:OSstatus | sema signal ]. |
|
2925 ]. |
|
2926 in close. |
|
2927 out close. |
|
2928 err close. |
|
2929 sema wait. |
|
2930 Transcript showCR:'finished' |
|
2931 " |
|
2932 |
|
2933 "Created: 29.2.1996 / 12:31:29 / cg" |
|
2934 "Modified: 21.3.1997 / 10:04:35 / dq" |
|
2935 "Modified: 2.5.1997 / 12:18:20 / cg" |
|
2936 "Modified: 15.7.1997 / 16:03:51 / stefan" |
|
2937 ! ! |
2739 ! ! |
2938 |
2740 |
2939 !Win32OperatingSystem class methodsFor:'file access'! |
2741 !Win32OperatingSystem class methodsFor:'file access'! |
2940 |
2742 |
2941 closeFd:anInteger |
2743 closeFd:anInteger |