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
15 * Takes the commandline arguments, and creates a
16 * struct which matches the arguments supplied.
19 ParseArguments(struct CommandLineOptions
* pOpts
, int argc
, WCHAR
*argv
[])
24 return ERROR_INVALID_PARAMETER
;
26 /* Reset all flags in struct */
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
;
41 * Determine which flags the user has specified
42 * to the program so we can use them later.
44 for (index
= 1; index
< argc
; index
++)
46 if (argv
[index
][0] == L
'-' || argv
[index
][0] == L
'/')
48 switch (towlower(argv
[index
][1]))
51 ConResPuts(StdOut
, IDS_USAGE
);
54 case L
'a': /* Cancel delayed shutdown */
58 case L
'c': /* Comment on reason for shutdown */
59 if(CheckCommentLength(argv
[index
+1]))
62 pOpts
->message
= argv
[index
+1];
64 return ERROR_INVALID_DATA
;
69 ConResPuts(StdErr
, IDS_ERROR_MAX_COMMENT_LENGTH
);
70 return ERROR_BAD_LENGTH
;
74 case L
'd': /* Reason code [p|u:]xx:yy */
76 pOpts
->reason
= ParseReasonCode(argv
[index
+1]);
78 return ERROR_INVALID_DATA
;
82 case L
'e': /* Documents reason for shutdown */
83 /* TODO: Determine what this flag does exactly. */
84 pOpts
->document_reason
= TRUE
;
87 case L
'f': /* Force shutdown without warning */
91 case L
'h': /* Hibernate the local computer */
92 pOpts
->hibernate
= TRUE
;
95 case L
'i': /* Shows GUI version of the tool */
96 pOpts
->show_gui
= TRUE
;
99 case L
'l': /* Logoff the current user */
100 pOpts
->logoff
= TRUE
;
103 case L
'm': /* Target remote systems (UNC name/IP address) */
104 pOpts
->remote_system
= argv
[index
+1];
107 case L
'p': /* Turn off local computer with no warning/time-out */
109 pOpts
->shutdown_delay
= 0;
112 case L
'r': /* Restart computer */
113 pOpts
->restart
= TRUE
;
116 case L
's': /* Shutdown */
117 pOpts
->shutdown
= TRUE
;
120 case L
't': /* Shutdown delay */
121 pOpts
->shutdown_delay
= _wtoi(argv
[index
+1]);
122 if (pOpts
->shutdown_delay
> 0)
127 /* Unknown arguments will exit the program. */
128 ConResPuts(StdOut
, IDS_USAGE
);
129 return ERROR_SUCCESS
;
134 return ERROR_SUCCESS
;
138 EnablePrivilege(LPCWSTR lpszPrivilegeName
, BOOL bEnablePrivilege
)
140 DWORD dwRet
= ERROR_SUCCESS
;
141 HANDLE hToken
= NULL
;
143 if (OpenProcessToken(GetCurrentProcess(),
144 TOKEN_ADJUST_PRIVILEGES
,
149 tp
.PrivilegeCount
= 1;
150 tp
.Privileges
[0].Attributes
= (bEnablePrivilege
? SE_PRIVILEGE_ENABLED
: 0);
152 if (LookupPrivilegeValueW(NULL
,
154 &tp
.Privileges
[0].Luid
))
156 if (AdjustTokenPrivileges(hToken
, FALSE
, &tp
, 0, NULL
, NULL
))
158 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED
)
159 dwRet
= ERROR_NOT_ALL_ASSIGNED
;
163 dwRet
= GetLastError();
168 dwRet
= GetLastError();
175 dwRet
= GetLastError();
178 /* Display the error description if any */
179 if (dwRet
!= ERROR_SUCCESS
) DisplayError(dwRet
);
184 /* Main entry for program */
185 int wmain(int argc
, WCHAR
*argv
[])
187 DWORD error
= ERROR_SUCCESS
;
188 struct CommandLineOptions opts
;
190 /* Initialize the Console Standard Streams */
193 if (argc
== 1) /* i.e. no commandline arguments given */
195 ConResPuts(StdOut
, IDS_USAGE
);
199 error
= ParseArguments(&opts
, argc
, argv
);
200 if (error
!= ERROR_SUCCESS
)
206 /* If the user wants to abort a shutdown */
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
);
214 EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME
, TRUE
);
216 /* Abort the delayed system shutdown specified. */
217 if (!AbortSystemShutdownW(opts
.remote_system
))
219 ConResPuts(StdErr
, IDS_ERROR_ABORT
);
220 DisplayError(GetLastError());
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.
236 if (IsPwrHibernateAllowed())
238 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
240 /* The shutdown utility cannot hibernate remote systems */
241 if (opts
.remote_system
!= NULL
)
246 if (!SetSuspendState(TRUE
, FALSE
, FALSE
))
248 ConResPuts(StdErr
, IDS_ERROR_HIBERNATE
);
249 DisplayError(GetLastError());
254 ConResPuts(StdOut
, IDS_ERROR_HIBERNATE_ENABLED
);
264 /* Both shutdown and restart flags cannot both be true */
265 if (opts
.shutdown
&& opts
.restart
)
267 ConResPuts(StdErr
, IDS_ERROR_SHUTDOWN_REBOOT
);
271 /* Ensure that the timout amount is not too high or a negative number */
272 if (opts
.shutdown_delay
> MAX_SHUTDOWN_TIMEOUT
)
274 ConResPrintf(StdErr
, IDS_ERROR_TIMEOUT
, opts
.shutdown_delay
);
278 /* If the user wants a GUI environment */
281 if (ShutdownGuiMain(opts
))
287 if (opts
.logoff
&& (opts
.remote_system
== NULL
))
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
295 if (!opts
.shutdown
&& !opts
.restart
)
297 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
299 if (ExitWindowsEx(EWX_LOGOFF
, opts
.reason
))
305 ConResPuts(StdErr
, IDS_ERROR_LOGOFF
);
306 DisplayError(GetLastError());
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.
316 if (opts
.shutdown
|| opts
.restart
)
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.
322 if (opts
.remote_system
== NULL
)
324 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
328 /* TODO: Remote shutdown is not supported yet */
329 // EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME, TRUE);
333 /* Initiate the shutdown */
334 if (!InitiateSystemShutdownExW(opts
.remote_system
,
342 * If there is an error, give the proper output depending
343 * on whether the user wanted to shutdown or restart.
346 ConResPuts(StdErr
, IDS_ERROR_RESTART
);
348 ConResPuts(StdErr
, IDS_ERROR_SHUTDOWN
);
350 DisplayError(GetLastError());