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 * This takes strings from a resource stringtable
16 * and outputs it to the console.
18 VOID
PrintResourceString(INT resID
, ...)
20 WCHAR tmpBuffer
[MAX_BUFFER_SIZE
];
23 va_start(arg_ptr
, resID
);
24 LoadStringW(GetModuleHandle(NULL
), resID
, tmpBuffer
, MAX_BUFFER_SIZE
);
25 vfwprintf(stdout
, tmpBuffer
, arg_ptr
);
30 * Takes the commandline arguments, and creates a
31 * struct which matches the arguments supplied.
34 ParseArguments(struct CommandLineOptions
* pOpts
, int argc
, WCHAR
*argv
[])
39 return ERROR_INVALID_PARAMETER
;
41 /* Reset all flags in struct */
44 pOpts
->logoff
= FALSE
;
45 pOpts
->restart
= FALSE
;
46 pOpts
->shutdown
= FALSE
;
47 pOpts
->document_reason
= FALSE
;
48 pOpts
->hibernate
= FALSE
;
49 pOpts
->shutdown_delay
= 30;
50 pOpts
->remote_system
= NULL
;
51 pOpts
->reason
= ParseReasonCode(NULL
); /* NOTE: NEVER use 0 here since it can delay the shutdown. */
52 pOpts
->message
= NULL
;
53 pOpts
->show_gui
= FALSE
;
56 * Determine which flags the user has specified
57 * to the program so we can use them later.
59 for (index
= 1; index
< argc
; index
++)
61 if (argv
[index
][0] == L
'-' || argv
[index
][0] == L
'/')
63 switch (towlower(argv
[index
][1]))
66 PrintResourceString(IDS_USAGE
);
69 case L
'a': /* Cancel delayed shutdown */
73 case L
'c': /* Comment on reason for shutdown */
74 if(CheckCommentLength(argv
[index
+1]))
77 pOpts
->message
= argv
[index
+1];
79 return ERROR_INVALID_DATA
;
84 PrintResourceString(IDS_ERROR_MAX_COMMENT_LENGTH
);
85 return ERROR_BAD_LENGTH
;
89 case L
'd': /* Reason code [p|u:]xx:yy */
91 pOpts
->reason
= ParseReasonCode(argv
[index
+1]);
93 return ERROR_INVALID_DATA
;
97 case L
'e': /* Documents reason for shutdown */
98 /* TODO: Determine what this flag does exactly. */
99 pOpts
->document_reason
= TRUE
;
102 case L
'f': /* Force shutdown without warning */
106 case L
'h': /* Hibernate the local computer */
107 pOpts
->hibernate
= TRUE
;
110 case L
'i': /* Shows GUI version of the tool */
111 pOpts
->show_gui
= TRUE
;
114 case L
'l': /* Logoff the current user */
115 pOpts
->logoff
= TRUE
;
118 case L
'm': /* Target remote systems (UNC name/IP address) */
119 pOpts
->remote_system
= argv
[index
+1];
122 case L
'p': /* Turn off local computer with no warning/time-out */
124 pOpts
->shutdown_delay
= 0;
127 case L
'r': /* Restart computer */
128 pOpts
->restart
= TRUE
;
131 case L
's': /* Shutdown */
132 pOpts
->shutdown
= TRUE
;
135 case L
't': /* Shutdown delay */
136 pOpts
->shutdown_delay
= _wtoi(argv
[index
+1]);
137 if (pOpts
->shutdown_delay
> 0)
142 /* Unknown arguments will exit the program. */
143 PrintResourceString(IDS_USAGE
);
144 return ERROR_SUCCESS
;
149 return ERROR_SUCCESS
;
153 EnablePrivilege(LPCWSTR lpszPrivilegeName
, BOOL bEnablePrivilege
)
155 DWORD dwRet
= ERROR_SUCCESS
;
156 HANDLE hToken
= NULL
;
158 if (OpenProcessToken(GetCurrentProcess(),
159 TOKEN_ADJUST_PRIVILEGES
,
164 tp
.PrivilegeCount
= 1;
165 tp
.Privileges
[0].Attributes
= (bEnablePrivilege
? SE_PRIVILEGE_ENABLED
: 0);
167 if (LookupPrivilegeValueW(NULL
,
169 &tp
.Privileges
[0].Luid
))
171 if (AdjustTokenPrivileges(hToken
, FALSE
, &tp
, 0, NULL
, NULL
))
173 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED
)
174 dwRet
= ERROR_NOT_ALL_ASSIGNED
;
178 dwRet
= GetLastError();
183 dwRet
= GetLastError();
190 dwRet
= GetLastError();
193 /* Display the error description if any */
194 if (dwRet
!= ERROR_SUCCESS
) DisplayError(dwRet
);
199 /* Main entry for program */
200 int wmain(int argc
, WCHAR
*argv
[])
202 DWORD error
= ERROR_SUCCESS
;
203 struct CommandLineOptions opts
;
205 if (argc
== 1) /* i.e. no commandline arguments given */
207 PrintResourceString(IDS_USAGE
);
211 error
= ParseArguments(&opts
, argc
, argv
);
212 if (error
!= ERROR_SUCCESS
)
218 /* If the user wants to abort a shutdown */
221 /* First, the program has to determine if the shutdown/restart is local
222 or remote. This is done since each one requires separate privileges. */
223 if (opts
.remote_system
== NULL
)
224 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
226 EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME
, TRUE
);
228 /* Abort the delayed system shutdown specified. */
229 if (!AbortSystemShutdownW(opts
.remote_system
))
231 PrintResourceString(IDS_ERROR_ABORT
);
232 DisplayError(GetLastError());
242 * If the user wants to hibernate the computer. Assume
243 * that the user wants to wake the computer up from
244 * hibernation and it should not force it on the system.
248 if (IsPwrHibernateAllowed())
250 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
252 /* The shutdown utility cannot hibernate remote systems */
253 if (opts
.remote_system
!= NULL
)
258 if (!SetSuspendState(TRUE
, FALSE
, FALSE
))
260 PrintResourceString(IDS_ERROR_HIBERNATE
);
261 DisplayError(GetLastError());
266 PrintResourceString(IDS_ERROR_HIBERNATE_ENABLED
);
276 /* Both shutdown and restart flags cannot both be true */
277 if (opts
.shutdown
&& opts
.restart
)
279 PrintResourceString(IDS_ERROR_SHUTDOWN_REBOOT
);
283 /* Ensure that the timout amount is not too high or a negative number */
284 if (opts
.shutdown_delay
> MAX_SHUTDOWN_TIMEOUT
)
286 PrintResourceString(IDS_ERROR_TIMEOUT
, opts
.shutdown_delay
);
290 /* If the user wants a GUI environment */
293 if (ShutdownGuiMain(opts
))
299 if (opts
.logoff
&& (opts
.remote_system
== NULL
))
302 * NOTE: Sometimes, shutdown and logoff are used together. If the logoff
303 * flag is used by itself, then simply logoff. But if used with shutdown,
304 * then skip logging off of the computer and eventually go to the action
307 if (!opts
.shutdown
&& !opts
.restart
)
309 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
311 if (ExitWindowsEx(EWX_LOGOFF
, opts
.reason
))
317 PrintResourceString(IDS_ERROR_LOGOFF
);
318 DisplayError(GetLastError());
325 * Since both shutting down the system and restarting calls the exact same
326 * function, all we need to know is if we wanted to restart or shutdown.
328 if (opts
.shutdown
|| opts
.restart
)
331 * First, the program has to determine if the shutdown/restart is local
332 * or remote. This is done since each one requires separate privileges.
334 if (opts
.remote_system
== NULL
)
336 EnablePrivilege(SE_SHUTDOWN_NAME
, TRUE
);
340 /* TODO: Remote shutdown is not supported yet */
341 // EnablePrivilege(SE_REMOTE_SHUTDOWN_NAME, TRUE);
345 /* Initiate the shutdown */
346 if (!InitiateSystemShutdownExW(opts
.remote_system
,
354 * If there is an error, give the proper output depending
355 * on whether the user wanted to shutdown or restart.
358 PrintResourceString(IDS_ERROR_RESTART
);
360 PrintResourceString(IDS_ERROR_SHUTDOWN
);
362 DisplayError(GetLastError());