SM: simplify and fix client (subsystem servers) management.
[reactos.git] / reactos / subsys / smss / smapiexec.c
1 /* $Id$
2 *
3 * smapiexec.c - SM_API_EXECUTE_PROGRAM
4 *
5 * Reactos Session Manager
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
22 * MA 02139, USA.
23 *
24 * --------------------------------------------------------------------
25 */
26 #include "smss.h"
27
28 #define NDEBUG
29 #include <debug.h>
30
31 /**********************************************************************
32 * SmCreateUserProcess/5
33 *
34 * DESCRIPTION
35 *
36 * ARGUMENTS
37 * ImagePath: absolute path of the image to run;
38 * CommandLine: arguments and options for ImagePath;
39 * WaitForIt: TRUE for boot time processes and FALSE for
40 * subsystems bootstrapping;
41 * Timeout: optional: used if WaitForIt==TRUE;
42 * ProcessHandle: optional: a duplicated handle for
43 the child process (storage provided by the caller).
44 *
45 * RETURN VALUE
46 * NTSTATUS:
47 *
48 */
49 NTSTATUS STDCALL
50 SmCreateUserProcess (LPWSTR ImagePath,
51 LPWSTR CommandLine,
52 BOOLEAN WaitForIt,
53 PLARGE_INTEGER Timeout OPTIONAL,
54 PRTL_USER_PROCESS_INFORMATION UserProcessInfo OPTIONAL)
55 {
56 UNICODE_STRING ImagePathString = {0};
57 UNICODE_STRING CommandLineString = {0};
58 PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
59 RTL_USER_PROCESS_INFORMATION ProcessInfo = {0};
60 PRTL_USER_PROCESS_INFORMATION pProcessInfo = & ProcessInfo;
61 NTSTATUS Status = STATUS_SUCCESS;
62
63 DPRINT("SM: %s called\n", __FUNCTION__);
64
65 if (NULL != UserProcessInfo)
66 {
67 pProcessInfo = UserProcessInfo;
68 }
69
70 RtlInitUnicodeString (& ImagePathString, ImagePath);
71 RtlInitUnicodeString (& CommandLineString, CommandLine);
72
73 RtlCreateProcessParameters(& ProcessParameters,
74 & ImagePathString,
75 NULL,
76 NULL,
77 & CommandLineString,
78 SmSystemEnvironment,
79 NULL,
80 NULL,
81 NULL,
82 NULL);
83
84 Status = RtlCreateUserProcess (& ImagePathString,
85 OBJ_CASE_INSENSITIVE,
86 ProcessParameters,
87 NULL,
88 NULL,
89 NULL,
90 FALSE,
91 NULL,
92 NULL,
93 pProcessInfo);
94
95 RtlDestroyProcessParameters (ProcessParameters);
96
97 if (!NT_SUCCESS(Status))
98 {
99 DPRINT1("SM: %s: Running \"%S\" failed (Status=0x%08lx)\n",
100 __FUNCTION__, ImagePathString.Buffer, Status);
101 return Status;
102 }
103 /*
104 * It the caller is *not* interested in the child info,
105 * resume it immediately.
106 */
107 if (NULL == UserProcessInfo)
108 {
109 Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL);
110 if(!NT_SUCCESS(Status))
111 {
112 DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n",
113 __FUNCTION__, Status);
114 }
115 }
116
117 /* Wait for process termination */
118 if (WaitForIt)
119 {
120 Status = NtWaitForSingleObject (pProcessInfo->ProcessHandle,
121 FALSE,
122 Timeout);
123 if (!NT_SUCCESS(Status))
124 {
125 DPRINT1("SM: %s: NtWaitForSingleObject failed with Status=0x%08lx\n",
126 __FUNCTION__, Status);
127 }
128
129 }
130 if (NULL == UserProcessInfo)
131 {
132 NtClose(pProcessInfo->ProcessHandle);
133 NtClose(pProcessInfo->ThreadHandle);
134 }
135 return Status;
136 }
137
138
139 /**********************************************************************
140 * SmExecPgm/1 API
141 */
142 SMAPI(SmExecPgm)
143 {
144 PSM_PORT_MESSAGE_EXECPGM ExecPgm = NULL;
145 WCHAR Name [SM_EXEXPGM_MAX_LENGTH + 1];
146 NTSTATUS Status = STATUS_SUCCESS;
147
148 DPRINT("SM: %s called\n",__FUNCTION__);
149
150 if(NULL == Request)
151 {
152 DPRINT1("SM: %s: Request == NULL!\n", __FUNCTION__);
153 return STATUS_INVALID_PARAMETER;
154 }
155 DPRINT("SM: %s called from CID(%lx|%lx)\n",
156 __FUNCTION__, Request->Header.ClientId.UniqueProcess,
157 Request->Header.ClientId.UniqueThread);
158 ExecPgm = & Request->Request.ExecPgm;
159 /* Check if the name lenght is valid */
160 if((ExecPgm->NameLength > 0) &&
161 (ExecPgm->NameLength <= SM_EXEXPGM_MAX_LENGTH) &&
162 TRUE /* TODO: check LPC payload size */)
163 {
164 WCHAR Data [MAX_PATH + 1] = {0};
165 ULONG DataLength = sizeof Data;
166 ULONG DataType = REG_EXPAND_SZ;
167
168
169 RtlZeroMemory (Name, sizeof Name);
170 RtlCopyMemory (Name,
171 ExecPgm->Name,
172 (sizeof ExecPgm->Name[0] * ExecPgm->NameLength));
173 DPRINT("SM: %s: Name='%S'\n", __FUNCTION__, Name);
174 /* Lookup Name in the registry */
175 Status = SmLookupSubsystem (Name,
176 Data,
177 & DataLength,
178 & DataType,
179 SmSystemEnvironment /* expand */);
180 if(NT_SUCCESS(Status))
181 {
182 /* Is the subsystem definition non-empty? */
183 if (DataLength > sizeof Data[0])
184 {
185 WCHAR ImagePath [MAX_PATH + 1] = {0};
186 PWCHAR CommandLine = ImagePath;
187 RTL_USER_PROCESS_INFORMATION ProcessInfo = {0};
188
189 wcscpy (ImagePath, L"\\??\\");
190 wcscat (ImagePath, Data);
191 /*
192 * Look for the beginning of the command line.
193 */
194 for (; (*CommandLine != L'\0') && (*CommandLine != L' ');
195 CommandLine ++);
196 for (; *CommandLine == L' '; CommandLine ++)
197 {
198 *CommandLine = L'\0';
199 }
200 /*
201 * Create a native process (suspended).
202 */
203 ProcessInfo.Size = sizeof ProcessInfo;
204 Request->SmHeader.Status =
205 SmCreateUserProcess(ImagePath,
206 CommandLine,
207 FALSE, /* wait */
208 NULL, /* timeout */
209 & ProcessInfo);
210 if (NT_SUCCESS(Request->SmHeader.Status))
211 {
212 Status = SmCreateClient (& ProcessInfo, Name);
213 if (NT_SUCCESS(Status))
214 {
215 Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL);
216 if (!NT_SUCCESS(Status))
217 {
218 DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n",
219 __FUNCTION__, Status);
220 //Status = SmDestroyClient TODO
221 }
222 } else {
223 DPRINT1("SM: %s: SmCreateClient failed (Status=0x%08lx)\n",
224 __FUNCTION__, Status);
225 }
226 }
227 }
228 else
229 {
230 /*
231 * OK, the definition is empty, but check
232 * if it is the name of an embedded subsystem.
233 */
234 if(0 == _wcsicmp(L"DEBUG", Name))
235 {
236 /*
237 * Initialize the embedded DBGSS.
238 */
239 Request->SmHeader.Status = SmInitializeDbgSs();
240 }
241 else
242 {
243 /*
244 * Badly defined subsystem. Check the registry!
245 */
246 Request->SmHeader.Status = STATUS_NOT_FOUND;
247 }
248 }
249 } else {
250 /* It couldn't lookup the Name! */
251 Request->SmHeader.Status = Status;
252 }
253 }
254 return Status;
255 }
256
257 /* EOF */