[CACLS][CLIP][COMP][EVENTCREATE][HELP][LOGOFF][SHUTDOWN][CHKDSK][FORMAT][SUBST]
[reactos.git] / reactos / base / applications / shutdown / shutdown.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS shutdown/logoff utility
4 * FILE: base/applications/shutdown/shutdown.c
5 * PURPOSE: Initiate logoff, shutdown or reboot of the system
6 */
7
8 #include "precomp.h"
9
10 #include <stdlib.h>
11 #include <tchar.h>
12 #include <powrprof.h>
13
14 /*
15 * Takes the commandline arguments, and creates a
16 * struct which matches the arguments supplied.
17 */
18 static DWORD
19 ParseArguments(struct CommandLineOptions* pOpts, int argc, WCHAR *argv[])
20 {
21 int index;
22
23 if (!pOpts)
24 return ERROR_INVALID_PARAMETER;
25
26 /* Reset all flags in struct */
27 pOpts->abort = FALSE;
28 pOpts->force = FALSE;
29 pOpts->logoff = FALSE;
30 pOpts->restart = FALSE;
31 pOpts->shutdown = FALSE;
32 pOpts->document_reason = FALSE;
33 pOpts->hibernate = FALSE;
34 pOpts->shutdown_delay = 30;
35 pOpts->remote_system = NULL;
36 pOpts->reason = ParseReasonCode(NULL); /* NOTE: NEVER use 0 here since it can delay the shutdown. */
37 pOpts->message = NULL;
38 pOpts->show_gui = FALSE;
39
40 /*
41 * Determine which flags the user has specified
42 * to the program so we can use them later.
43 */
44 for (index = 1; index < argc; index++)
45 {
46 if (argv[index][0] == L'-' || argv[index][0] == L'/')
47 {
48 switch (towlower(argv[index][1]))
49 {
50 case L'?': /* Help */
51 ConResPuts(StdOut, IDS_USAGE);
52 return ERROR_SUCCESS;
53
54 case L'a': /* Cancel delayed shutdown */
55 pOpts->abort = TRUE;
56 break;
57
58 case L'c': /* Comment on reason for shutdown */
59 if(CheckCommentLength(argv[index+1]))
60 {
61 if (index+1 <= argc)
62 pOpts->message = argv[index+1];
63 else
64 return ERROR_INVALID_DATA;
65 index++;
66 }
67 else
68 {
69 ConResPuts(StdErr, IDS_ERROR_MAX_COMMENT_LENGTH);
70 return ERROR_BAD_LENGTH;
71 }
72 break;
73
74 case L'd': /* Reason code [p|u:]xx:yy */
75 if (index+1 <= argc)
76 pOpts->reason = ParseReasonCode(argv[index+1]);
77 else
78 return ERROR_INVALID_DATA;
79 index++;
80 break;
81
82 case L'e': /* Documents reason for shutdown */
83 /* TODO: Determine what this flag does exactly. */
84 pOpts->document_reason = TRUE;
85 break;
86
87 case L'f': /* Force shutdown without warning */
88 pOpts->force = TRUE;
89 break;
90
91 case L'h': /* Hibernate the local computer */
92 pOpts->hibernate = TRUE;
93 break;
94
95 case L'i': /* Shows GUI version of the tool */
96 pOpts->show_gui = TRUE;
97 break;
98
99 case L'l': /* Logoff the current user */
100 pOpts->logoff = TRUE;
101 break;
102
103 case L'm': /* Target remote systems (UNC name/IP address) */
104 pOpts->remote_system = argv[index+1];
105 break;
106
107 case L'p': /* Turn off local computer with no warning/time-out */
108 pOpts->force = TRUE;
109 pOpts->shutdown_delay = 0;
110 break;
111
112 case L'r': /* Restart computer */
113 pOpts->restart = TRUE;
114 break;
115
116 case L's': /* Shutdown */
117 pOpts->shutdown = TRUE;
118 break;
119
120 case L't': /* Shutdown delay */
121 pOpts->shutdown_delay = _wtoi(argv[index+1]);
122 if (pOpts->shutdown_delay > 0)
123 pOpts->force = TRUE;
124 break;
125
126 default:
127 /* Unknown arguments will exit the program. */
128 ConResPuts(StdOut, IDS_USAGE);
129 return ERROR_SUCCESS;
130 }
131 }
132 }
133
134 return ERROR_SUCCESS;
135 }
136
137 static DWORD
138 EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege)
139 {
140 DWORD dwRet = ERROR_SUCCESS;
141 HANDLE hToken = NULL;
142
143 if (OpenProcessToken(GetCurrentProcess(),
144 TOKEN_ADJUST_PRIVILEGES,
145 &hToken))
146 {
147 TOKEN_PRIVILEGES tp;
148
149 tp.PrivilegeCount = 1;
150 tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0);
151
152 if (LookupPrivilegeValueW(NULL,
153 lpszPrivilegeName,
154 &tp.Privileges[0].Luid))
155 {
156 if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
157 {
158 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
159 dwRet = ERROR_NOT_ALL_ASSIGNED;
160 }
161 else
162 {
163 dwRet = GetLastError();
164 }
165 }
166 else
167 {
168 dwRet = GetLastError();
169 }
170
171 CloseHandle(hToken);
172 }
173 else
174 {
175 dwRet = GetLastError();
176 }
177
178 /* Display the error description if any */
179 if (dwRet != ERROR_SUCCESS) DisplayError(dwRet);
180
181 return dwRet;
182 }
183
184 /* Main entry for program */
185 int wmain(int argc, WCHAR *argv[])
186 {
187 DWORD error = ERROR_SUCCESS;
188 struct CommandLineOptions opts;
189
190 /* Initialize the Console Standard Streams */
191 ConInitStdStreams();
192
193 if (argc == 1) /* i.e. no commandline arguments given */
194 {
195 ConResPuts(StdOut, IDS_USAGE);
196 return EXIT_SUCCESS;
197 }
198
199 error = ParseArguments(&opts, argc, argv);
200 if (error != ERROR_SUCCESS)
201 {
202 DisplayError(error);
203 return EXIT_FAILURE;
204 }
205
206 /* If the user wants to abort a shutdown */
207 if (opts.abort)
208 {
209 /* First, the program has to determine if the shutdown/restart is local
210 or remote. This is done since each one requires separate privileges. */
211 if (opts.remote_system == NULL)
212 EnablePrivilege(SE_SHUTDOWN_NAME, TRUE);
213 else
214 EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME, TRUE);
215
216 /* Abort the delayed system shutdown specified. */
217 if (!AbortSystemShutdownW(opts.remote_system))
218 {
219 ConResPuts(StdErr, IDS_ERROR_ABORT);
220 DisplayError(GetLastError());
221 return EXIT_FAILURE;
222 }
223 else
224 {
225 return EXIT_SUCCESS;
226 }
227 }
228
229 /*
230 * If the user wants to hibernate the computer. Assume
231 * that the user wants to wake the computer up from
232 * hibernation and it should not force it on the system.
233 */
234 if (opts.hibernate)
235 {
236 if (IsPwrHibernateAllowed())
237 {
238 EnablePrivilege(SE_SHUTDOWN_NAME, TRUE);
239
240 /* The shutdown utility cannot hibernate remote systems */
241 if (opts.remote_system != NULL)
242 {
243 return EXIT_FAILURE;
244 }
245
246 if (!SetSuspendState(TRUE, FALSE, FALSE))
247 {
248 ConResPuts(StdErr, IDS_ERROR_HIBERNATE);
249 DisplayError(GetLastError());
250 return EXIT_FAILURE;
251 }
252 else
253 {
254 ConResPuts(StdOut, IDS_ERROR_HIBERNATE_ENABLED);
255 return EXIT_SUCCESS;
256 }
257 }
258 else
259 {
260 return EXIT_FAILURE;
261 }
262 }
263
264 /* Both shutdown and restart flags cannot both be true */
265 if (opts.shutdown && opts.restart)
266 {
267 ConResPuts(StdErr, IDS_ERROR_SHUTDOWN_REBOOT);
268 return EXIT_FAILURE;
269 }
270
271 /* Ensure that the timout amount is not too high or a negative number */
272 if (opts.shutdown_delay > MAX_SHUTDOWN_TIMEOUT)
273 {
274 ConResPrintf(StdErr, IDS_ERROR_TIMEOUT, opts.shutdown_delay);
275 return EXIT_FAILURE;
276 }
277
278 /* If the user wants a GUI environment */
279 if (opts.show_gui)
280 {
281 if (ShutdownGuiMain(opts))
282 return EXIT_SUCCESS;
283 else
284 return EXIT_FAILURE;
285 }
286
287 if (opts.logoff && (opts.remote_system == NULL))
288 {
289 /*
290 * NOTE: Sometimes, shutdown and logoff are used together. If the logoff
291 * flag is used by itself, then simply logoff. But if used with shutdown,
292 * then skip logging off of the computer and eventually go to the action
293 * for shutdown.
294 */
295 if (!opts.shutdown && !opts.restart)
296 {
297 EnablePrivilege(SE_SHUTDOWN_NAME, TRUE);
298
299 if (ExitWindowsEx(EWX_LOGOFF, opts.reason))
300 {
301 return EXIT_SUCCESS;
302 }
303 else
304 {
305 ConResPuts(StdErr, IDS_ERROR_LOGOFF);
306 DisplayError(GetLastError());
307 return EXIT_FAILURE;
308 }
309 }
310 }
311
312 /*
313 * Since both shutting down the system and restarting calls the exact same
314 * function, all we need to know is if we wanted to restart or shutdown.
315 */
316 if (opts.shutdown || opts.restart)
317 {
318 /*
319 * First, the program has to determine if the shutdown/restart is local
320 * or remote. This is done since each one requires separate privileges.
321 */
322 if (opts.remote_system == NULL)
323 {
324 EnablePrivilege(SE_SHUTDOWN_NAME, TRUE);
325 }
326 else
327 {
328 /* TODO: Remote shutdown is not supported yet */
329 // EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME, TRUE);
330 return EXIT_SUCCESS;
331 }
332
333 /* Initiate the shutdown */
334 if (!InitiateSystemShutdownExW(opts.remote_system,
335 opts.message,
336 opts.shutdown_delay,
337 opts.force,
338 opts.restart,
339 opts.reason))
340 {
341 /*
342 * If there is an error, give the proper output depending
343 * on whether the user wanted to shutdown or restart.
344 */
345 if (opts.restart)
346 ConResPuts(StdErr, IDS_ERROR_RESTART);
347 else
348 ConResPuts(StdErr, IDS_ERROR_SHUTDOWN);
349
350 DisplayError(GetLastError());
351 return EXIT_FAILURE;
352 }
353 else
354 {
355 return EXIT_SUCCESS;
356 }
357 }
358
359 return EXIT_SUCCESS;
360 }
361
362 /* EOF */