ReactOS  0.4.12-dev-51-ge94618b
shutdown.c
Go to the documentation of this file.
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
20 {
21  int index;
22 
23  if (!pOpts)
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 */
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 (index+1 >= argc)
60  return ERROR_INVALID_DATA;
61  if (!argv[index+1] || wcslen(argv[index+1]) <= 512)
62  {
63  pOpts->message = argv[index+1];
64  index++;
65  }
66  else
67  {
69  return ERROR_BAD_LENGTH;
70  }
71  break;
72 
73  case L'd': /* Reason code [p|u:]xx:yy */
74  if (index+1 >= argc)
75  return ERROR_INVALID_DATA;
76  pOpts->reason = ParseReasonCode(argv[index+1]);
77  index++;
78  break;
79 
80  case L'e': /* Documents reason for shutdown */
81  /* TODO: Determine what this flag does exactly. */
82  pOpts->document_reason = TRUE;
83  break;
84 
85  case L'f': /* Force shutdown without warning */
86  pOpts->force = TRUE;
87  break;
88 
89  case L'h': /* Hibernate the local computer */
90  pOpts->hibernate = TRUE;
91  break;
92 
93  case L'i': /* Shows GUI version of the tool */
94  pOpts->show_gui = TRUE;
95  break;
96 
97  case L'l': /* Logoff the current user */
98  pOpts->logoff = TRUE;
99  break;
100 
101  case L'm': /* Target remote systems (UNC name/IP address) */
102  if (index+1 >= argc)
103  return ERROR_INVALID_DATA;
104  pOpts->remote_system = argv[index+1];
105  index++;
106  break;
107 
108  case L'p': /* Turn off local computer with no warning/time-out */
109  pOpts->force = TRUE;
110  pOpts->shutdown_delay = 0;
111  break;
112 
113  case L'r': /* Restart computer */
114  pOpts->restart = TRUE;
115  break;
116 
117  case L's': /* Shutdown */
118  pOpts->shutdown = TRUE;
119  break;
120 
121  case L't': /* Shutdown delay */
122  if (index+1 >= argc)
123  return ERROR_INVALID_DATA;
124  pOpts->shutdown_delay = _wtoi(argv[index+1]);
125  if (pOpts->shutdown_delay > 0)
126  pOpts->force = TRUE;
127  index++;
128  break;
129 
130  default:
131  /* Unknown arguments will exit the program. */
133  return ERROR_SUCCESS;
134  }
135  }
136  }
137 
138  return ERROR_SUCCESS;
139 }
140 
141 static DWORD
142 EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege)
143 {
144  DWORD dwRet = ERROR_SUCCESS;
145  HANDLE hToken = NULL;
146 
149  &hToken))
150  {
152 
153  tp.PrivilegeCount = 1;
154  tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0);
155 
157  lpszPrivilegeName,
158  &tp.Privileges[0].Luid))
159  {
160  if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
161  {
163  dwRet = ERROR_NOT_ALL_ASSIGNED;
164  }
165  else
166  {
167  dwRet = GetLastError();
168  }
169  }
170  else
171  {
172  dwRet = GetLastError();
173  }
174 
175  CloseHandle(hToken);
176  }
177  else
178  {
179  dwRet = GetLastError();
180  }
181 
182  /* Display the error description if any */
183  if (dwRet != ERROR_SUCCESS) DisplayError(dwRet);
184 
185  return dwRet;
186 }
187 
188 /* Main entry for program */
189 int wmain(int argc, WCHAR *argv[])
190 {
192  struct CommandLineOptions opts;
193 
194  /* Initialize the Console Standard Streams */
196 
197  if (argc == 1) /* i.e. no commandline arguments given */
198  {
200  return EXIT_SUCCESS;
201  }
202 
203  error = ParseArguments(&opts, argc, argv);
204  if (error != ERROR_SUCCESS)
205  {
206  DisplayError(error);
207  return EXIT_FAILURE;
208  }
209 
210  /* If the user wants to abort a shutdown */
211  if (opts.abort)
212  {
213  /* First, the program has to determine if the shutdown/restart is local
214  or remote. This is done since each one requires separate privileges. */
215  if (opts.remote_system == NULL)
217  else
219 
220  /* Abort the delayed system shutdown specified. */
222  {
225  return EXIT_FAILURE;
226  }
227  else
228  {
229  return EXIT_SUCCESS;
230  }
231  }
232 
233  /*
234  * If the user wants to hibernate the computer. Assume
235  * that the user wants to wake the computer up from
236  * hibernation and it should not force it on the system.
237  */
238  if (opts.hibernate)
239  {
240  if (IsPwrHibernateAllowed())
241  {
243 
244  /* The shutdown utility cannot hibernate remote systems */
245  if (opts.remote_system != NULL)
246  {
247  return EXIT_FAILURE;
248  }
249 
251  {
254  return EXIT_FAILURE;
255  }
256  else
257  {
259  return EXIT_SUCCESS;
260  }
261  }
262  else
263  {
264  return EXIT_FAILURE;
265  }
266  }
267 
268  /* Both shutdown and restart flags cannot both be true */
269  if (opts.shutdown && opts.restart)
270  {
272  return EXIT_FAILURE;
273  }
274 
275  /* Ensure that the timeout amount is not too high or a negative number */
277  {
279  return EXIT_FAILURE;
280  }
281 
282  /* If the user wants a GUI environment */
283  if (opts.show_gui)
284  {
285  if (ShutdownGuiMain(opts))
286  return EXIT_SUCCESS;
287  else
288  return EXIT_FAILURE;
289  }
290 
291  if (opts.logoff && (opts.remote_system == NULL))
292  {
293  /*
294  * NOTE: Sometimes, shutdown and logoff are used together. If the logoff
295  * flag is used by itself, then simply logoff. But if used with shutdown,
296  * then skip logging off of the computer and eventually go to the action
297  * for shutdown.
298  */
299  if (!opts.shutdown && !opts.restart)
300  {
302 
303  if (ExitWindowsEx(EWX_LOGOFF, opts.reason))
304  {
305  return EXIT_SUCCESS;
306  }
307  else
308  {
311  return EXIT_FAILURE;
312  }
313  }
314  }
315 
316  /*
317  * Since both shutting down the system and restarting calls the exact same
318  * function, all we need to know is if we wanted to restart or shutdown.
319  */
320  if (opts.shutdown || opts.restart)
321  {
322  /*
323  * First, the program has to determine if the shutdown/restart is local
324  * or remote. This is done since each one requires separate privileges.
325  */
326  if (opts.remote_system == NULL)
327  {
329  }
330  else
331  {
332  /* TODO: Remote shutdown is not supported yet */
333  // EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME, TRUE);
334  return EXIT_SUCCESS;
335  }
336 
337  /* Initiate the shutdown */
339  opts.message,
340  opts.shutdown_delay,
341  opts.force,
342  opts.restart,
343  opts.reason))
344  {
345  /*
346  * If there is an error, give the proper output depending
347  * on whether the user wanted to shutdown or restart.
348  */
349  if (opts.restart)
351  else
353 
355  return EXIT_FAILURE;
356  }
357  else
358  {
359  return EXIT_SUCCESS;
360  }
361  }
362 
363  return EXIT_SUCCESS;
364 }
365 
366 /* EOF */
BOOLEAN WINAPI SetSuspendState(BOOLEAN Hibernate, BOOLEAN ForceCritical, BOOLEAN DisableWakeEvent)
Definition: powrprof.c:681
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
static int argc
Definition: ServiceArgs.c:12
BOOL WINAPI AbortSystemShutdownW(LPCWSTR lpMachineName)
Definition: shutdown.c:48
#define IDS_ERROR_TIMEOUT
Definition: resource.h:7
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
BOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpPrivilegeName, PLUID lpLuid)
Definition: misc.c:782
#define ERROR_SUCCESS
Definition: deptool.c:10
#define error(str)
Definition: mkdosfs.c:1605
#define ERROR_BAD_LENGTH
Definition: winerror.h:127
__wchar_t WCHAR
Definition: xmlstorage.h:180
BOOL WINAPI InitiateSystemShutdownExW(LPWSTR lpMachineName, LPWSTR lpMessage, DWORD dwTimeout, BOOL bForceAppsClosed, BOOL bRebootAfterShutdown, DWORD dwReason)
Definition: shutdown.c:254
_Check_return_ _CRTIMP int __cdecl _wtoi(_In_z_ const wchar_t *_Str)
#define IDS_ERROR_RESTART
Definition: resource.h:10
$ULONG PrivilegeCount
Definition: setypes.h:969
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define IDS_USAGE
Definition: resource.h:3
_In_ UINT64 _In_ UINT64 _In_ UINT64 _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2630
#define IDS_ERROR_SHUTDOWN_REBOOT
Definition: resource.h:6
static char ** argv
Definition: ServiceArgs.c:11
#define EWX_LOGOFF
Definition: winuser.h:631
#define IDS_ERROR_LOGOFF
Definition: resource.h:9
#define EXIT_SUCCESS
Definition: rdjpgcom.c:55
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63
#define ConInitStdStreams()
Definition: stream.h:122
#define IDS_ERROR_SHUTDOWN
Definition: resource.h:11
static DWORD ParseArguments(struct CommandLineOptions *pOpts, int argc, WCHAR *argv[])
Definition: shutdown.c:19
#define IDS_ERROR_HIBERNATE
Definition: resource.h:13
smooth NULL
Definition: ftsmooth.c:416
#define IDS_ERROR_ABORT
Definition: resource.h:8
INT __cdecl ConResPrintf(IN PCON_STREAM Stream, IN UINT uID,...)
Definition: outstream.c:781
unsigned int BOOL
Definition: ntddk_ex.h:94
HANDLE WINAPI GetCurrentProcess(VOID)
Definition: proc.c:1168
BOOL ShutdownGuiMain(struct CommandLineOptions opts)
Definition: gui.c:45
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD shutdown_delay
Definition: precomp.h:43
#define EXIT_FAILURE
Definition: jerror.c:33
LPWSTR message
Definition: precomp.h:45
#define StdErr
Definition: stream.h:77
INT ConResPuts(IN PCON_STREAM Stream, IN UINT uID)
Definition: outstream.c:610
#define index(s, c)
Definition: various.h:29
DWORD ParseReasonCode(LPCWSTR code)
Definition: misc.c:55
static const WCHAR L[]
Definition: oid.c:1087
BOOL WINAPI ExitWindowsEx(_In_ UINT, _In_ DWORD)
BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength)
Definition: security.c:372
#define SE_REMOTE_SHUTDOWN_NAME
Definition: winnt_old.h:388
#define ERROR_INVALID_DATA
Definition: winerror.h:116
VOID DisplayError(DWORD dwError)
Definition: logoff.c:33
BOOL document_reason
Definition: precomp.h:41
#define IDS_ERROR_HIBERNATE_ENABLED
Definition: resource.h:15
static DWORD EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege)
Definition: shutdown.c:142
BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle)
Definition: security.c:292
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]
Definition: setypes.h:970
#define ERROR_NOT_ALL_ASSIGNED
Definition: winerror.h:782
#define StdOut
Definition: stream.h:76
int wmain(int argc, WCHAR *argv[])
Definition: shutdown.c:189
#define SE_SHUTDOWN_NAME
Definition: winnt_old.h:383
#define IDS_ERROR_MAX_COMMENT_LENGTH
Definition: resource.h:12
#define towlower(c)
Definition: wctype.h:97
BOOLEAN WINAPI IsPwrHibernateAllowed(VOID)
Definition: powrprof.c:450
#define TOKEN_ADJUST_PRIVILEGES
Definition: setypes.h:876
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define MAX_SHUTDOWN_TIMEOUT
Definition: winreg.h:53
LPWSTR remote_system
Definition: precomp.h:44