2005-11-29 21:57:19 +00:00
|
|
|
/*
|
2004-07-07 22:29:37 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS shutdown/logoff utility
|
2007-07-15 11:15:27 +00:00
|
|
|
* FILE: base/application/shutdown/shutdown.c
|
2004-07-07 22:29:37 +00:00
|
|
|
* PURPOSE: Initiate logoff, shutdown or reboot of the system
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <tchar.h>
|
2007-07-15 11:15:27 +00:00
|
|
|
#include <reason.h> //shutdown codes
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
// Print information about which commandline arguments the program accepts.
|
|
|
|
static void PrintUsage() {
|
2007-07-15 13:53:28 +00:00
|
|
|
_tprintf(_T("Usage: shutdown [-?] [-l | -s | -r] [-f]\n"));
|
|
|
|
_tprintf(_T("\n No args or -?\t\tDisplay this message"));
|
|
|
|
_tprintf(_T("\n -l\t\t\tLog off"));
|
|
|
|
_tprintf(_T("\n -s\t\t\tShutdown the computer"));
|
|
|
|
_tprintf(_T("\n -r\t\t\tShutdown and restart the computer"));
|
|
|
|
_tprintf(_T("\n -f\t\t\tForces running applications to close without warnings"));
|
2007-07-16 21:50:50 +00:00
|
|
|
_tprintf(_T("\n \t\t\tIf you did not specify any other parameter, this option"));
|
|
|
|
_tprintf(_T("\n \t\t\twill also log off"));
|
2007-07-15 13:53:28 +00:00
|
|
|
_tprintf(_T("\n"));
|
2004-07-07 22:29:37 +00:00
|
|
|
}
|
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
struct CommandLineOptions {
|
|
|
|
BOOL abort; // Not used yet
|
|
|
|
BOOL force;
|
|
|
|
BOOL logoff;
|
|
|
|
BOOL restart;
|
|
|
|
BOOL shutdown;
|
|
|
|
};
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
struct ExitOptions {
|
|
|
|
// This flag is used to distinguish between a user-initiated LOGOFF (which has value 0)
|
|
|
|
// and an underdetermined situation because user didn't give an argument to start Exit.
|
|
|
|
BOOL shouldExit;
|
|
|
|
// flags is the type of shutdown to do - EWX_LOGOFF, EWX_REBOOT, EWX_POWEROFF, etc..
|
|
|
|
UINT flags;
|
|
|
|
// reason is the System Shutdown Reason code. F.instance SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED.
|
|
|
|
DWORD reason;
|
|
|
|
};
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
// Takes the commandline arguments, and creates a struct which matches the arguments supplied.
|
|
|
|
static struct CommandLineOptions ParseArguments(int argc, TCHAR *argv[])
|
|
|
|
{
|
|
|
|
struct CommandLineOptions opts;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Reset all flags in struct
|
|
|
|
opts.abort = FALSE;
|
|
|
|
opts.force = FALSE;
|
|
|
|
opts.logoff = FALSE;
|
|
|
|
opts.restart = FALSE;
|
|
|
|
opts.shutdown = FALSE;
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++)
|
|
|
|
{
|
|
|
|
if (argv[i][0] == '-' || argv[i][0] == '/')
|
|
|
|
{
|
|
|
|
switch(argv[i][1]) {
|
|
|
|
case '?': PrintUsage(); exit(0);
|
|
|
|
case 'f': opts.force = TRUE; break;
|
|
|
|
case 'l': opts.logoff = TRUE; break;
|
|
|
|
case 'r': opts.restart = TRUE; break;
|
|
|
|
case 's': opts.shutdown = TRUE; break;
|
|
|
|
default:
|
|
|
|
// Unknown arguments will exit program.
|
|
|
|
PrintUsage();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return opts;
|
|
|
|
}
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
// Converts the commandline arguments to flags used to shutdown computer
|
|
|
|
static struct ExitOptions ParseCommandLineOptionsToExitOptions(struct CommandLineOptions opts)
|
|
|
|
{
|
|
|
|
struct ExitOptions exitOpts;
|
|
|
|
exitOpts.shouldExit = TRUE;
|
|
|
|
|
|
|
|
// Sets ONE of the exit type flags
|
|
|
|
if (opts.logoff)
|
|
|
|
exitOpts.flags = EWX_LOGOFF;
|
|
|
|
else if (opts.restart)
|
|
|
|
exitOpts.flags = EWX_REBOOT;
|
|
|
|
else if(opts.shutdown)
|
|
|
|
exitOpts.flags = EWX_POWEROFF;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
exitOpts.flags = 0;
|
|
|
|
exitOpts.shouldExit = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets additional flags
|
|
|
|
if (opts.force)
|
2007-07-16 21:50:50 +00:00
|
|
|
{
|
2007-07-15 11:15:27 +00:00
|
|
|
exitOpts.flags = exitOpts.flags | EWX_FORCE;
|
2007-07-16 21:50:50 +00:00
|
|
|
|
|
|
|
// This makes sure that we log off, also if there is only the "-f" option specified.
|
|
|
|
// The Windows shutdown utility does it the same way.
|
|
|
|
exitOpts.shouldExit = TRUE;
|
|
|
|
}
|
2007-07-15 11:15:27 +00:00
|
|
|
|
|
|
|
// Reason for shutdown
|
|
|
|
// Hardcoded to "Other (Planned)"
|
|
|
|
exitOpts.reason = SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED;
|
|
|
|
|
|
|
|
return exitOpts;
|
|
|
|
}
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
// Writes the last error as both text and error code to the console.
|
|
|
|
void DisplayLastError()
|
|
|
|
{
|
|
|
|
int errorCode = GetLastError();
|
|
|
|
LPTSTR lpMsgBuf;
|
|
|
|
|
|
|
|
// Display the error message to the user
|
|
|
|
FormatMessage(
|
|
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
|
|
NULL,
|
|
|
|
errorCode,
|
|
|
|
LANG_USER_DEFAULT,
|
|
|
|
(LPTSTR) &lpMsgBuf,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
_ftprintf(stderr, lpMsgBuf);
|
|
|
|
_ftprintf(stderr, _T("Error code: %d\n"), errorCode);
|
|
|
|
}
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
void EnableShutdownPrivileges()
|
|
|
|
{
|
|
|
|
HANDLE token;
|
|
|
|
TOKEN_PRIVILEGES privs;
|
|
|
|
|
|
|
|
// Check to see if the choosen action is allowed by the user. Everyone can call LogOff, but only privilieged users can shutdown/restart etc.
|
|
|
|
if (! OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
|
|
|
|
{
|
|
|
|
DisplayLastError();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get LUID (Locally Unique Identifier) for the privilege we need
|
|
|
|
if (!LookupPrivilegeValue(
|
|
|
|
NULL, // system - NULL is localsystem
|
|
|
|
SE_SHUTDOWN_NAME, // name of the privilege
|
|
|
|
&privs.Privileges[0].Luid) // output
|
|
|
|
)
|
|
|
|
{
|
|
|
|
DisplayLastError();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
// and give our current process (i.e. shutdown.exe) the privilege to shutdown the machine.
|
|
|
|
privs.PrivilegeCount = 1;
|
|
|
|
privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
if (AdjustTokenPrivileges(
|
|
|
|
token,
|
|
|
|
FALSE,
|
|
|
|
&privs,
|
|
|
|
0,
|
|
|
|
(PTOKEN_PRIVILEGES)NULL, // previous state. Set to NULL, we don't care about previous state.
|
|
|
|
NULL
|
|
|
|
) == 0) // return value 0 means failure
|
|
|
|
{
|
|
|
|
DisplayLastError();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Main entry for program
|
|
|
|
int _tmain(int argc, TCHAR *argv[])
|
|
|
|
{
|
|
|
|
struct CommandLineOptions opts;
|
|
|
|
struct ExitOptions exitOpts;
|
|
|
|
|
|
|
|
if (argc == 1) // i.e. no commandline arguments given
|
|
|
|
{
|
|
|
|
PrintUsage();
|
|
|
|
exit(0);
|
|
|
|
}
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
opts = ParseArguments(argc, argv);
|
|
|
|
exitOpts = ParseCommandLineOptionsToExitOptions(opts);
|
2004-07-07 22:29:37 +00:00
|
|
|
|
2007-07-15 11:15:27 +00:00
|
|
|
// Perform the shutdown/restart etc. action
|
|
|
|
if (exitOpts.shouldExit)
|
|
|
|
{
|
|
|
|
EnableShutdownPrivileges();
|
|
|
|
|
|
|
|
if (!ExitWindowsEx(exitOpts.flags, exitOpts.reason))
|
|
|
|
{
|
|
|
|
DisplayLastError();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2004-07-07 22:29:37 +00:00
|
|
|
}
|
2007-07-15 11:15:27 +00:00
|
|
|
|
|
|
|
// EOF
|