xref: /reactos/sdk/lib/crt/process/_system.c (revision 0b366ea1)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS system libraries
4  * FILE:        lib/sdk/crt/process/_system.c
5  * PURPOSE:     Excutes a shell command
6  * PROGRAMER:   Ariadne
7  *              Katayama Hirofumi MZ
8  * UPDATE HISTORY:
9  *              04/03/99: Created
10  */
11 
12 #include <precomp.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <process.h>
16 
17 /*
18  * @implemented
19  */
20 int system(const char *command)
21 {
22   char *szCmdLine = NULL;
23   char *szComSpec = NULL;
24   PROCESS_INFORMATION ProcessInformation;
25   STARTUPINFOA StartupInfo;
26   BOOL result;
27   int exit_code;
28   char cmd_exe[MAX_PATH];
29 
30   szComSpec = getenv("COMSPEC");
31 
32 // system should return 0 if command is null and the shell is found
33 
34   if (command == NULL) {
35     return (szComSpec == NULL) ? 0 : 1;
36   }
37 
38   if (!szComSpec || GetFileAttributesA(szComSpec) == INVALID_FILE_ATTRIBUTES)
39   {
40     GetSystemDirectoryA(cmd_exe, _countof(cmd_exe));
41     strcat(cmd_exe, "\\cmd.exe");
42     szComSpec = cmd_exe;
43   }
44 
45   szCmdLine = malloc(1 + strlen(szComSpec) + 5 + strlen(command) + 1);
46   if (szCmdLine == NULL)
47   {
48     _set_errno(ENOMEM);
49     return -1;
50   }
51 
52   strcpy(szCmdLine, "\"");
53   strcat(szCmdLine, szComSpec);
54   strcat(szCmdLine, "\" /C ");
55   strcat(szCmdLine, command);
56 
57 //command file has invalid format ENOEXEC
58 
59   memset(&StartupInfo, 0, sizeof(StartupInfo));
60   StartupInfo.cb = sizeof(StartupInfo);
61   StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
62   StartupInfo.wShowWindow = SW_SHOWDEFAULT;
63 
64 // In order to disable Ctrl+C, the process is created with CREATE_NEW_PROCESS_GROUP.
65 // Thus, SetConsoleCtrlHandler(NULL, TRUE) is made on behalf of the new process.
66 
67 //SIGCHILD should be blocked as well
68 
69   result = CreateProcessA(szComSpec,
70 	                  szCmdLine,
71 			  NULL,
72 			  NULL,
73 			  TRUE,
74 			  CREATE_NEW_PROCESS_GROUP,
75 			  NULL,
76 			  NULL,
77 			  &StartupInfo,
78 			  &ProcessInformation);
79   free(szCmdLine);
80 
81   if (result == FALSE)
82   {
83 	_dosmaperr(GetLastError());
84      return -1;
85   }
86 
87   CloseHandle(ProcessInformation.hThread);
88 
89   /* Wait for the process to exit */
90   _cwait(&exit_code, (intptr_t)ProcessInformation.hProcess, 0);
91 
92   CloseHandle(ProcessInformation.hProcess);
93 
94   _set_errno(0);
95   return exit_code;
96 }
97 
98 int CDECL _wsystem(const wchar_t *cmd)
99 {
100     wchar_t *cmdline = NULL;
101     wchar_t *comspec = NULL;
102     PROCESS_INFORMATION process_info;
103     STARTUPINFOW startup_info;
104     BOOL result;
105     int exit_code;
106     wchar_t cmd_exe[MAX_PATH];
107 
108     comspec = _wgetenv(L"COMSPEC");
109 
110     /* _wsystem should return 0 if cmd is null and the shell is found */
111     if (cmd == NULL)
112     {
113         return (comspec == NULL) ? 0 : 1;
114     }
115 
116     if (comspec == NULL || GetFileAttributesW(comspec) == INVALID_FILE_ATTRIBUTES)
117     {
118         GetSystemDirectoryW(cmd_exe, _countof(cmd_exe));
119         wcscat(cmd_exe, L"\\cmd.exe");
120         comspec = cmd_exe;
121     }
122 
123     cmdline = malloc((1 + wcslen(comspec) + 5 + wcslen(cmd) + 1) * sizeof(wchar_t));
124     if (cmdline == NULL)
125     {
126         _set_errno(ENOMEM);
127         return -1;
128     }
129 
130     wcscpy(cmdline, L"\"");
131     wcscat(cmdline, comspec);
132     wcscat(cmdline, L"\" /C ");
133     wcscat(cmdline, cmd);
134 
135     /* command file has invalid format ENOEXEC */
136 
137     memset(&startup_info, 0, sizeof(startup_info));
138     startup_info.cb = sizeof(startup_info);
139     startup_info.dwFlags = STARTF_USESHOWWINDOW;
140     startup_info.wShowWindow = SW_SHOWDEFAULT;
141 
142     /* In order to disable Ctrl+C, the process is created with CREATE_NEW_PROCESS_GROUP.
143        Thus, SetConsoleCtrlHandler(NULL, TRUE) is made on behalf of the new process. */
144 
145     /* SIGCHILD should be blocked as well */
146 
147     /* Create the process to execute the command */
148     result = CreateProcessW(comspec,
149                             cmdline,
150                             NULL,
151                             NULL,
152                             TRUE,
153                             CREATE_NEW_PROCESS_GROUP,
154                             NULL,
155                             NULL,
156                             &startup_info,
157                             &process_info);
158     free(cmdline);
159 
160     if (!result)
161     {
162         _dosmaperr(GetLastError());
163         return -1;
164     }
165 
166     CloseHandle(process_info.hThread);
167 
168     /* Wait for the process to exit */
169     _cwait(&exit_code, (intptr_t)process_info.hProcess, 0);
170 
171     CloseHandle(process_info.hProcess);
172 
173     _set_errno(0);
174     return exit_code;
175 }
176