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 */
60 return ERROR_INVALID_DATA
;
61 if (!argv
[index
+1] || wcslen(argv
[index
+1]) <= 512)
63 pOpts
->message
= argv
[index
+1];
68 ConResPuts(StdErr
, IDS_ERROR_MAX_COMMENT_LENGTH
);
69 return ERROR_BAD_LENGTH
;
73 case L
'd': /* Reason code [p|u:]xx:yy */
75 return ERROR_INVALID_DATA
;
76 pOpts
->reason
= ParseReasonCode(argv
[index
+1]);
80 case L
'e': /* Documents reason for shutdown */
81 /* TODO: Determine what this flag does exactly. */
82 pOpts
->document_reason
= TRUE
;
85 case L
'f': /* Force shutdown without warning */
89 case L
'h': /* Hibernate the local computer */
90 pOpts
->hibernate
= TRUE
;
93 case L
'i': /* Shows GUI version of the tool */
94 pOpts
->show_gui
= TRUE
;
97 case L
'l': /* Logoff the current user */
101 case L
'm': /* Target remote systems (UNC name/IP address) */
103 return ERROR_INVALID_DATA
;
104 pOpts
->remote_system
= argv
[index
+1];
108 case L
'p': /* Turn off local computer with no warning/time-out */
110 pOpts
->shutdown_delay
= 0;
113 case L
'r': /* Restart computer */
114 pOpts
->restart
= TRUE
;
117 case L
's': /* Shutdown */
118 pOpts
->shutdown
= TRUE
;
121 case L
't': /* Shutdown delay */
123 return ERROR_INVALID_DATA
;
124 pOpts
->shutdown_delay
= _wtoi(argv
[index
+1]);
125 if (pOpts
->shutdown_delay
> 0)
131 /* Unknown arguments will exit the program. */
132 ConResPuts(StdOut
, IDS_USAGE
);
133 return ERROR_SUCCESS
;
138 return ERROR_SUCCESS
;
142 EnablePrivilege(LPCWSTR lpszPrivilegeName
, BOOL bEnablePrivilege
)
144 DWORD dwRet
= ERROR_SUCCESS
;
145 HANDLE hToken
= NULL
;
147 if (OpenProcessToken(GetCurrentProcess(),
148 TOKEN_ADJUST_PRIVILEGES
,
153 tp
.PrivilegeCount
= 1;
154 tp
.Privileges
[0].Attributes
= (bEnablePrivilege
? SE_PRIVILEGE_ENABLED
: 0);
156 if (LookupPrivilegeValueW(NULL
,
158 &tp
.Privileges
[0].Luid
))
160 if (AdjustTokenPrivileges(hToken
, FALSE
, &tp
, 0, NULL
, NULL
))
162 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED
)
163 dwRet
= ERROR_NOT_ALL_ASSIGNED
;
167 dwRet
= GetLastError();
172 dwRet
= GetLastError();
179 dwRet
= GetLastError();
182 /* Display the error description if any */
183 if (dwRet
!= ERROR_SUCCESS
) DisplayError(dwRet
);
188 /* Main entry for program */
189 int wmain(int argc
, WCHAR
*argv
[])
191 DWORD error
= ERROR_SUCCESS
;
192 struct CommandLineOptions opts
;
194 /* Initialize the Console Standard Streams */
197 if (argc
== 1) /* i.e. no commandline arguments given */
199 ConResPuts(StdOut
, IDS_USAGE
);
203 error
= ParseArguments(&opts
, argc
, argv
);
204 if (error
!= ERROR_SUCCESS
)
210 /* If the user wants to abort a shutdown */
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
)
216 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
218 EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME
, TRUE
);
220 /* Abort the delayed system shutdown specified. */
221 if (!AbortSystemShutdownW(opts
.remote_system
))
223 ConResPuts(StdErr
, IDS_ERROR_ABORT
);
224 DisplayError(GetLastError());
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.
240 if (IsPwrHibernateAllowed())
242 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
244 /* The shutdown utility cannot hibernate remote systems */
245 if (opts
.remote_system
!= NULL
)
250 if (!SetSuspendState(TRUE
, FALSE
, FALSE
))
252 ConResPuts(StdErr
, IDS_ERROR_HIBERNATE
);
253 DisplayError(GetLastError());
258 ConResPuts(StdOut
, IDS_ERROR_HIBERNATE_ENABLED
);
268 /* Both shutdown and restart flags cannot both be true */
269 if (opts
.shutdown
&& opts
.restart
)
271 ConResPuts(StdErr
, IDS_ERROR_SHUTDOWN_REBOOT
);
275 /* Ensure that the timeout amount is not too high or a negative number */
276 if (opts
.shutdown_delay
> MAX_SHUTDOWN_TIMEOUT
)
278 ConResPrintf(StdErr
, IDS_ERROR_TIMEOUT
, opts
.shutdown_delay
);
282 /* If the user wants a GUI environment */
285 if (ShutdownGuiMain(opts
))
291 if (opts
.logoff
&& (opts
.remote_system
== NULL
))
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
299 if (!opts
.shutdown
&& !opts
.restart
)
301 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
303 if (ExitWindowsEx(EWX_LOGOFF
, opts
.reason
))
309 ConResPuts(StdErr
, IDS_ERROR_LOGOFF
);
310 DisplayError(GetLastError());
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.
320 if (opts
.shutdown
|| opts
.restart
)
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.
326 if (opts
.remote_system
== NULL
)
328 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
332 /* TODO: Remote shutdown is not supported yet */
333 // EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME, TRUE);
337 /* Initiate the shutdown */
338 if (!InitiateSystemShutdownExW(opts
.remote_system
,
346 * If there is an error, give the proper output depending
347 * on whether the user wanted to shutdown or restart.
350 ConResPuts(StdErr
, IDS_ERROR_RESTART
);
352 ConResPuts(StdErr
, IDS_ERROR_SHUTDOWN
);
354 DisplayError(GetLastError());