729 "get a shell and shell arguments for command execution" |
729 "get a shell and shell arguments for command execution" |
730 |
730 |
731 self subclassResponsibility |
731 self subclassResponsibility |
732 ! |
732 ! |
733 |
733 |
734 exec:aCommandPath withArguments:argArray |
|
735 "execute the OS command specified by the argument, aCommandPath, with |
|
736 arguments in argArray (no arguments, if nil). |
|
737 If successful, this method does NOT return and smalltalk is gone. |
|
738 If not successful, it does return. |
|
739 Can be used on UNIX with fork or on other systems to chain to another program." |
|
740 |
|
741 ^ self |
|
742 exec:aCommandPath |
|
743 withArguments:argArray |
|
744 environment:nil |
|
745 fileDescriptors:#(0 1 2) |
|
746 fork:false |
|
747 newPgrp:false |
|
748 inDirectory:nil |
|
749 |
|
750 "/ never reached ... |
|
751 |
|
752 "Modified: / 12.11.1998 / 14:44:26 / cg" |
|
753 ! |
|
754 |
|
755 exec:aCommandPath withArguments:argArray environment:env fileDescriptors:fds fork:doFork newPgrp:newGrp inDirectory:aDirectory |
|
756 "execute an OS command" |
|
757 |
|
758 ^ self subclassResponsibility |
|
759 |
|
760 "Created: / 12.11.1998 / 14:46:15 / cg" |
|
761 ! |
|
762 |
|
763 exec:aCommandPath withArguments:argArray fileDescriptors:fileDescriptors fork:doFork newPgrp:newPgrp inDirectory:aDirectory |
|
764 ^ self |
|
765 exec:aCommandPath |
|
766 withArguments:argArray |
|
767 environment:nil |
|
768 fileDescriptors:fileDescriptors |
|
769 fork:doFork |
|
770 newPgrp:newPgrp |
|
771 inDirectory:aDirectory |
|
772 ! |
|
773 |
|
774 exec:aCommandPath withArguments:argArray fork:doFork |
|
775 "execute an OS command without I/O redirection. |
|
776 The command reads its input and writes its output |
|
777 from/to whatever terminal device ST/X was started |
|
778 (typically, the terminal window)" |
|
779 |
|
780 ^ self |
|
781 exec:aCommandPath |
|
782 withArguments:argArray |
|
783 environment:nil |
|
784 fileDescriptors:#(0 1 2) |
|
785 fork:doFork |
|
786 newPgrp:false |
|
787 inDirectory:nil |
|
788 |
|
789 " |
|
790 |id| |
|
791 |
|
792 id := OperatingSystem fork. |
|
793 id == 0 ifTrue:[ |
|
794 'I am the child'. |
|
795 OperatingSystem |
|
796 exec:'/bin/ls' |
|
797 withArguments:#('ls' '/tmp') |
|
798 fork:false. |
|
799 'not reached'. |
|
800 ] |
|
801 " |
|
802 |
|
803 " |
|
804 |id| |
|
805 |
|
806 id := OperatingSystem fork. |
|
807 id == 0 ifTrue:[ |
|
808 'I am the child'. |
|
809 OperatingSystem |
|
810 exec:'/bin/sh' |
|
811 withArguments:#('sh' '-c' 'sleep 2;echo 1;sleep 2;echo 2') |
|
812 fork:false. |
|
813 'not reached'. |
|
814 ]. |
|
815 id printNL. |
|
816 (Delay forSeconds:3.5) wait. |
|
817 'killing ...' printNL. |
|
818 OperatingSystem sendSignal:(OperatingSystem sigTERM) to:id. |
|
819 OperatingSystem sendSignal:(OperatingSystem sigKILL) to:id |
|
820 " |
|
821 |
|
822 "Modified: / 15.7.1997 / 15:54:32 / stefan" |
|
823 "Modified: / 12.11.1998 / 14:44:46 / cg" |
|
824 ! |
|
825 |
|
826 exec:aCommandPath withArguments:argArray fork:doFork inDirectory:aDirectory |
|
827 "execute an OS command without I/O redirection. |
|
828 The command reads its input and writes its output |
|
829 from/to whatever terminal device ST/X was started |
|
830 (typically, the terminal window)" |
|
831 |
|
832 ^ self |
|
833 exec:aCommandPath |
|
834 withArguments:argArray |
|
835 environment:nil |
|
836 fileDescriptors:#(0 1 2) |
|
837 fork:doFork |
|
838 newPgrp:false |
|
839 inDirectory:aDirectory |
|
840 |
|
841 " |
|
842 |id| |
|
843 |
|
844 id := OperatingSystem fork. |
|
845 id == 0 ifTrue:[ |
|
846 'I am the child'. |
|
847 OperatingSystem |
|
848 exec:'/bin/ls' |
|
849 withArguments:#('ls' '/tmp') |
|
850 fork:false. |
|
851 'not reached'. |
|
852 ] |
|
853 " |
|
854 |
|
855 " |
|
856 |id| |
|
857 |
|
858 id := OperatingSystem fork. |
|
859 id == 0 ifTrue:[ |
|
860 'I am the child'. |
|
861 OperatingSystem |
|
862 exec:'/bin/sh' |
|
863 withArguments:#('sh' '-c' 'sleep 2;echo 1;sleep 2;echo 2') |
|
864 fork:false. |
|
865 'not reached'. |
|
866 ]. |
|
867 id printNL. |
|
868 (Delay forSeconds:3.5) wait. |
|
869 'killing ...' printNL. |
|
870 OperatingSystem sendSignal:(OperatingSystem sigTERM) to:id. |
|
871 OperatingSystem sendSignal:(OperatingSystem sigKILL) to:id |
|
872 " |
|
873 |
|
874 "Created: / 28.1.1998 / 14:14:03 / md" |
|
875 "Modified: / 28.1.1998 / 14:14:45 / md" |
|
876 "Modified: / 12.11.1998 / 14:45:06 / cg" |
|
877 ! |
|
878 |
|
879 executableFileExtensions |
734 executableFileExtensions |
880 "return a collection of extensions for executable program files. |
735 "return a collection of extensions for executable program files. |
881 Only req'd for msdos & vms like systems ..." |
736 Only req'd for msdos & vms like systems ..." |
882 |
737 |
883 ^ #('') |
738 ^ #('') |
1182 onError:[:exitStatus | false]. |
1041 onError:[:exitStatus | false]. |
1183 outStream contents |
1042 outStream contents |
1184 " |
1043 " |
1185 ! |
1044 ! |
1186 |
1045 |
|
1046 executeCommand:aCommandString inputFrom:anInStream outputTo:anOutStream errorTo:anErrStream auxFrom:anAuxStream inDirectory:dirOrNil lineWise:lineWise onError:aBlock |
|
1047 "execute the unix command specified by the argument, aCommandString. |
|
1048 The commandString is passed to a shell for execution - see the description of |
|
1049 'sh -c' in your UNIX manual. |
|
1050 Return true if successful, or the value of aBlock if not. |
|
1051 If not successfull, aBlock is called with an OsProcessStatus |
|
1052 (containing the exit status) as argument. |
|
1053 The given in, out and err streams may be arbitrary (Smalltalk-) streams; |
|
1054 if any is not an external stream (which is required by the command), |
|
1055 extra pipes and shuffler processes are created, which stuff the data into |
|
1056 those internal stream(s). |
|
1057 Nil stream args will execute the command connected to ST/X's standard input, output or |
|
1058 error resp. - i.e. usually, i/o will be from/to the terminal" |
|
1059 |
|
1060 |pid exitStatus sema pIn pOut pErr pAux externalInStream externalOutStream externalErrStream externalAuxStream |
|
1061 shuffledInStream shuffledOutStream shuffledErrStream shuffledAuxStream |
|
1062 inputShufflerProcess outputShufflerProcess errorShufflerProcess auxShufflerProcess stopShufflers |
|
1063 inStreamToClose outStreamToClose errStreamToClose auxStreamToClose terminateLock| |
|
1064 |
|
1065 terminateLock := Semaphore forMutualExclusion. |
|
1066 ((externalInStream := anInStream) notNil |
|
1067 and:[externalInStream isExternalStream not]) ifTrue:[ |
|
1068 pIn := ExternalStream makePipe. |
|
1069 inStreamToClose := externalInStream := pIn at:1. |
|
1070 shuffledInStream := pIn at:2. |
|
1071 lineWise ifTrue:[shuffledInStream buffered:false]. |
|
1072 |
|
1073 "/ start a reader process, shuffling data from the given |
|
1074 "/ inStream to the pipe (which is connected to the commands input) |
|
1075 inputShufflerProcess := [ |
|
1076 [ |
|
1077 [anInStream atEnd] whileFalse:[ |
|
1078 self shuffleFrom:anInStream to:shuffledInStream lineWise:lineWise. |
|
1079 shuffledInStream flush |
|
1080 ] |
|
1081 ] ensure:[ |
|
1082 shuffledInStream close |
|
1083 ] |
|
1084 ] forkNamed:'cmd input shuffler'. |
|
1085 ]. |
|
1086 ((externalOutStream := anOutStream) notNil |
|
1087 and:[externalOutStream isExternalStream not]) ifTrue:[ |
|
1088 pOut := ExternalStream makePipe. |
|
1089 shuffledOutStream := (pOut at:1). |
|
1090 outStreamToClose := externalOutStream := pOut at:2. |
|
1091 lineWise ifTrue:[shuffledOutStream buffered:false]. |
|
1092 outputShufflerProcess := |
|
1093 [ |
|
1094 self shuffleAllFrom:shuffledOutStream to:anOutStream lineWise:lineWise lockWith:terminateLock. |
|
1095 ] forkNamed:'cmd output shuffler'. |
|
1096 ]. |
|
1097 (externalErrStream := anErrStream) notNil ifTrue:[ |
|
1098 anErrStream == anOutStream ifTrue:[ |
|
1099 externalErrStream := externalOutStream |
|
1100 ] ifFalse:[ |
|
1101 anErrStream isExternalStream ifFalse:[ |
|
1102 pErr := ExternalStream makePipe. |
|
1103 shuffledErrStream := (pErr at:1). |
|
1104 errStreamToClose := externalErrStream := pErr at:2. |
|
1105 |
|
1106 lineWise ifTrue:[shuffledErrStream buffered:false]. |
|
1107 errorShufflerProcess := |
|
1108 [ |
|
1109 self shuffleAllFrom:shuffledErrStream to:anErrStream lineWise:lineWise lockWith:terminateLock. |
|
1110 ] forkNamed:'cmd err-output shuffler'. |
|
1111 ] |
|
1112 ] |
|
1113 ]. |
|
1114 ((externalAuxStream := anAuxStream) notNil |
|
1115 and:[externalAuxStream isExternalStream not]) ifTrue:[ |
|
1116 pAux := ExternalStream makePipe. |
|
1117 auxStreamToClose := externalAuxStream := pAux at:1. |
|
1118 shuffledAuxStream := pAux at:2. |
|
1119 |
|
1120 "/ start a reader process, shuffling data from the given |
|
1121 "/ auxStream to the pipe (which is connected to the commands aux) |
|
1122 auxShufflerProcess := [ |
|
1123 [ |
|
1124 [anAuxStream atEnd] whileFalse:[ |
|
1125 self shuffleFrom:anAuxStream to:shuffledAuxStream lineWise:false. |
|
1126 shuffledAuxStream flush |
|
1127 ] |
|
1128 ] ensure:[ |
|
1129 shuffledAuxStream close |
|
1130 ] |
|
1131 ] forkNamed:'cmd aux shuffler'. |
|
1132 ]. |
|
1133 |
|
1134 sema := Semaphore new name:'OS command wait'. |
|
1135 pid := Processor |
|
1136 monitor:[ |
|
1137 self |
|
1138 startProcess:aCommandString |
|
1139 inputFrom:externalInStream |
|
1140 outputTo:externalOutStream |
|
1141 errorTo:externalErrStream |
|
1142 auxFrom:externalAuxStream |
|
1143 inDirectory:dirOrNil |
|
1144 ] |
|
1145 action:[:status | |
|
1146 status stillAlive ifFalse:[ |
|
1147 exitStatus := status. |
|
1148 sema signal. |
|
1149 self closePid:pid |
|
1150 ] |
|
1151 ]. |
|
1152 |
|
1153 inStreamToClose notNil ifTrue:[ |
|
1154 inStreamToClose close |
|
1155 ]. |
|
1156 errStreamToClose notNil ifTrue:[ |
|
1157 errStreamToClose close |
|
1158 ]. |
|
1159 outStreamToClose notNil ifTrue:[ |
|
1160 outStreamToClose close |
|
1161 ]. |
|
1162 auxStreamToClose notNil ifTrue:[ |
|
1163 auxStreamToClose close |
|
1164 ]. |
|
1165 |
|
1166 stopShufflers := [ |
|
1167 inputShufflerProcess notNil ifTrue:[ |
|
1168 terminateLock critical:[inputShufflerProcess terminate]. |
|
1169 inputShufflerProcess waitUntilTerminated |
|
1170 ]. |
|
1171 auxShufflerProcess notNil ifTrue:[ |
|
1172 terminateLock critical:[auxShufflerProcess terminate]. |
|
1173 auxShufflerProcess waitUntilTerminated |
|
1174 ]. |
|
1175 outputShufflerProcess notNil ifTrue:[ |
|
1176 terminateLock critical:[outputShufflerProcess terminate]. |
|
1177 outputShufflerProcess waitUntilTerminated. |
|
1178 self shuffleRestFrom:shuffledOutStream to:anOutStream lineWise:lineWise. |
|
1179 shuffledOutStream close. |
|
1180 ]. |
|
1181 errorShufflerProcess notNil ifTrue:[ |
|
1182 terminateLock critical:[errorShufflerProcess terminate]. |
|
1183 errorShufflerProcess waitUntilTerminated. |
|
1184 self shuffleRestFrom:shuffledErrStream to:anErrStream lineWise:lineWise. |
|
1185 shuffledErrStream close. |
|
1186 ]. |
|
1187 ]. |
|
1188 |
|
1189 pid notNil ifTrue:[ |
|
1190 [ |
|
1191 sema wait. |
|
1192 ] ifCurtailed:[ |
|
1193 "/ terminate the os-command (and all of its forked commands) |
|
1194 self terminateProcessGroup:pid. |
|
1195 self terminateProcess:pid. |
|
1196 self closePid:pid. |
|
1197 stopShufflers value. |
|
1198 ] |
|
1199 ] ifFalse:[ |
|
1200 exitStatus := self osProcessStatusClass processCreationFailure |
|
1201 ]. |
|
1202 stopShufflers value. |
|
1203 exitStatus success ifFalse:[ |
|
1204 ^ aBlock value:exitStatus |
|
1205 ]. |
|
1206 ^ true |
|
1207 |
|
1208 " |
|
1209 |outStream errStream| |
|
1210 |
|
1211 outStream := '' writeStream. |
|
1212 |
|
1213 OperatingSystem executeCommand:'ls -l' |
|
1214 inputFrom:'abc' readStream |
|
1215 outputTo:outStream |
|
1216 errorTo:nil |
|
1217 inDirectory:nil |
|
1218 lineWise:true |
|
1219 onError:[:exitStatus | ^ false]. |
|
1220 outStream contents |
|
1221 " |
|
1222 |
|
1223 " |
|
1224 |outStream errStream| |
|
1225 |
|
1226 outStream := '' writeStream. |
|
1227 |
|
1228 OperatingSystem executeCommand:'gpg -s --batch --no-tty --passphrase-fd 0 /tmp/passwd' |
|
1229 inputFrom:'bla' readStream |
|
1230 outputTo:outStream |
|
1231 errorTo:nil |
|
1232 inDirectory:nil |
|
1233 lineWise:true |
|
1234 onError:[:exitStatus | false]. |
|
1235 outStream contents |
|
1236 " |
|
1237 ! |
|
1238 |
1187 executeCommand:aCommandString inputFrom:anInStream outputTo:anOutStream errorTo:anErrStream inDirectory:dirOrNil lineWise:lineWise onError:aBlock |
1239 executeCommand:aCommandString inputFrom:anInStream outputTo:anOutStream errorTo:anErrStream inDirectory:dirOrNil lineWise:lineWise onError:aBlock |
1188 "execute the unix command specified by the argument, aCommandString. |
1240 "execute the unix command specified by the argument, aCommandString. |
1189 The commandString is passed to a shell for execution - see the description of |
1241 The commandString is passed to a shell for execution - see the description of |
1190 'sh -c' in your UNIX manual. |
1242 'sh -c' in your UNIX manual. |
1191 Return true if successful, the value from aBlock if not. |
1243 Return true if successful, the value from aBlock if not. |
1614 ^ self pathOfCommand:(self nameOfSTXExecutable) |
1639 ^ self pathOfCommand:(self nameOfSTXExecutable) |
1615 |
1640 |
1616 " |
1641 " |
1617 OperatingSystem pathOfSTXExecutable |
1642 OperatingSystem pathOfSTXExecutable |
1618 " |
1643 " |
1619 ! |
1644 ! ! |
|
1645 |
|
1646 !AbstractOperatingSystem class methodsFor:'executing OS commands - low level'! |
|
1647 |
|
1648 exec:aCommandPath withArguments:argArray |
|
1649 "execute the OS command specified by the argument, aCommandPath, with |
|
1650 arguments in argArray (no arguments, if nil). |
|
1651 If successful, this method does NOT return and smalltalk is gone. |
|
1652 If not successful, it does return. |
|
1653 Can be used on UNIX with fork or on other systems to chain to another program." |
|
1654 |
|
1655 ^ self |
|
1656 exec:aCommandPath |
|
1657 withArguments:argArray |
|
1658 environment:nil |
|
1659 fileDescriptors:#(0 1 2) |
|
1660 fork:false |
|
1661 newPgrp:false |
|
1662 inDirectory:nil |
|
1663 |
|
1664 "/ never reached ... |
|
1665 |
|
1666 "Modified: / 12.11.1998 / 14:44:26 / cg" |
|
1667 ! |
|
1668 |
|
1669 exec:aCommandPath withArguments:argArray environment:env fileDescriptors:fds fork:doFork newPgrp:newGrp inDirectory:aDirectory |
|
1670 "execute an OS command" |
|
1671 |
|
1672 ^ self subclassResponsibility |
|
1673 |
|
1674 "Created: / 12.11.1998 / 14:46:15 / cg" |
|
1675 ! |
|
1676 |
|
1677 exec:aCommandPath withArguments:argArray fileDescriptors:fileDescriptors fork:doFork newPgrp:newPgrp inDirectory:aDirectory |
|
1678 ^ self |
|
1679 exec:aCommandPath |
|
1680 withArguments:argArray |
|
1681 environment:nil |
|
1682 fileDescriptors:fileDescriptors |
|
1683 fork:doFork |
|
1684 newPgrp:newPgrp |
|
1685 inDirectory:aDirectory |
|
1686 ! |
|
1687 |
|
1688 exec:aCommandPath withArguments:argArray fork:doFork |
|
1689 "execute an OS command without I/O redirection. |
|
1690 The command reads its input and writes its output |
|
1691 from/to whatever terminal device ST/X was started |
|
1692 (typically, the terminal window)" |
|
1693 |
|
1694 ^ self |
|
1695 exec:aCommandPath |
|
1696 withArguments:argArray |
|
1697 environment:nil |
|
1698 fileDescriptors:#(0 1 2) |
|
1699 fork:doFork |
|
1700 newPgrp:false |
|
1701 inDirectory:nil |
|
1702 |
|
1703 " |
|
1704 |id| |
|
1705 |
|
1706 id := OperatingSystem fork. |
|
1707 id == 0 ifTrue:[ |
|
1708 'I am the child'. |
|
1709 OperatingSystem |
|
1710 exec:'/bin/ls' |
|
1711 withArguments:#('ls' '/tmp') |
|
1712 fork:false. |
|
1713 'not reached'. |
|
1714 ] |
|
1715 " |
|
1716 |
|
1717 " |
|
1718 |id| |
|
1719 |
|
1720 id := OperatingSystem fork. |
|
1721 id == 0 ifTrue:[ |
|
1722 'I am the child'. |
|
1723 OperatingSystem |
|
1724 exec:'/bin/sh' |
|
1725 withArguments:#('sh' '-c' 'sleep 2;echo 1;sleep 2;echo 2') |
|
1726 fork:false. |
|
1727 'not reached'. |
|
1728 ]. |
|
1729 id printNL. |
|
1730 (Delay forSeconds:3.5) wait. |
|
1731 'killing ...' printNL. |
|
1732 OperatingSystem sendSignal:(OperatingSystem sigTERM) to:id. |
|
1733 OperatingSystem sendSignal:(OperatingSystem sigKILL) to:id |
|
1734 " |
|
1735 |
|
1736 "Modified: / 15.7.1997 / 15:54:32 / stefan" |
|
1737 "Modified: / 12.11.1998 / 14:44:46 / cg" |
|
1738 ! |
|
1739 |
|
1740 exec:aCommandPath withArguments:argArray fork:doFork inDirectory:aDirectory |
|
1741 "execute an OS command without I/O redirection. |
|
1742 The command reads its input and writes its output |
|
1743 from/to whatever terminal device ST/X was started |
|
1744 (typically, the terminal window)" |
|
1745 |
|
1746 ^ self |
|
1747 exec:aCommandPath |
|
1748 withArguments:argArray |
|
1749 environment:nil |
|
1750 fileDescriptors:#(0 1 2) |
|
1751 fork:doFork |
|
1752 newPgrp:false |
|
1753 inDirectory:aDirectory |
|
1754 |
|
1755 " |
|
1756 |id| |
|
1757 |
|
1758 id := OperatingSystem fork. |
|
1759 id == 0 ifTrue:[ |
|
1760 'I am the child'. |
|
1761 OperatingSystem |
|
1762 exec:'/bin/ls' |
|
1763 withArguments:#('ls' '/tmp') |
|
1764 fork:false. |
|
1765 'not reached'. |
|
1766 ] |
|
1767 " |
|
1768 |
|
1769 " |
|
1770 |id| |
|
1771 |
|
1772 id := OperatingSystem fork. |
|
1773 id == 0 ifTrue:[ |
|
1774 'I am the child'. |
|
1775 OperatingSystem |
|
1776 exec:'/bin/sh' |
|
1777 withArguments:#('sh' '-c' 'sleep 2;echo 1;sleep 2;echo 2') |
|
1778 fork:false. |
|
1779 'not reached'. |
|
1780 ]. |
|
1781 id printNL. |
|
1782 (Delay forSeconds:3.5) wait. |
|
1783 'killing ...' printNL. |
|
1784 OperatingSystem sendSignal:(OperatingSystem sigTERM) to:id. |
|
1785 OperatingSystem sendSignal:(OperatingSystem sigKILL) to:id |
|
1786 " |
|
1787 |
|
1788 "Created: / 28.1.1998 / 14:14:03 / md" |
|
1789 "Modified: / 28.1.1998 / 14:14:45 / md" |
|
1790 "Modified: / 12.11.1998 / 14:45:06 / cg" |
|
1791 ! |
|
1792 |
|
1793 fork |
|
1794 "fork a new (HEAVY-weight) unix process. |
|
1795 Not supported with MSDOS & VMS systems. |
|
1796 Dont confuse this with Block>>fork, which creates |
|
1797 lightweight smalltalk processes. This method will return |
|
1798 0 to the child process, and a non-zero number (which is the childs |
|
1799 unix-process-id) to the parent (original) process. |
|
1800 |
|
1801 In normal situations, you dont need to use this low level entry; see |
|
1802 #startProcess: and #executCommand: for higher level interfaces." |
|
1803 |
|
1804 "/ |
|
1805 "/ not supported by OS |
|
1806 "/ |
|
1807 |
|
1808 ^ UnsupportedOperationSignal raise |
|
1809 ! ! |
|
1810 |
|
1811 !AbstractOperatingSystem class methodsFor:'executing OS commands - private'! |
1620 |
1812 |
1621 startProcess:aCommandString |
1813 startProcess:aCommandString |
1622 "start executing the OS command as specified by the argument, aCommandString |
1814 "start executing the OS command as specified by the argument, aCommandString |
1623 as a separate process; do not wait for the command to finish. |
1815 as a separate process; do not wait for the command to finish. |
1624 The commandString is passed to a shell for execution - see the description of |
1816 The commandString is passed to a shell for execution - see the description of |