[TASKMGR]
[reactos.git] / base / applications / shutdown / shutdown.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS shutdown/logoff utility
4 * FILE: base/application/shutdown/shutdown.c
5 * PURPOSE: Initiate logoff, shutdown or reboot of the system
6 */
7
8 #include "precomp.h"
9
10 // Print information about which commandline arguments the program accepts.
11 static void PrintUsage() {
12 LPTSTR lpUsage = NULL;
13 DWORD errLength; // error message length
14 LPTSTR resMsg; // for error message in OEM symbols
15
16 if( AllocAndLoadString( &lpUsage,
17 GetModuleHandle(NULL),
18 IDS_USAGE ) )
19 {
20 errLength = strlen(lpUsage) + 1;
21 resMsg = (LPTSTR)LocalAlloc(LPTR, errLength * sizeof(TCHAR));
22 CharToOemBuff(lpUsage, resMsg, errLength);
23
24 _putts( resMsg );
25
26 LocalFree(lpUsage);
27 LocalFree(resMsg);
28 }
29 }
30
31 struct CommandLineOptions {
32 BOOL abort; // Not used yet
33 BOOL force;
34 BOOL logoff;
35 BOOL restart;
36 BOOL shutdown;
37 };
38
39 struct ExitOptions {
40 // This flag is used to distinguish between a user-initiated LOGOFF (which has value 0)
41 // and an underdetermined situation because user didn't give an argument to start Exit.
42 BOOL shouldExit;
43 // flags is the type of shutdown to do - EWX_LOGOFF, EWX_REBOOT, EWX_POWEROFF, etc..
44 UINT flags;
45 // reason is the System Shutdown Reason code. F.instance SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED.
46 DWORD reason;
47 };
48
49 // Takes the commandline arguments, and creates a struct which matches the arguments supplied.
50 static struct CommandLineOptions ParseArguments(int argc, TCHAR *argv[])
51 {
52 struct CommandLineOptions opts;
53 int i;
54
55 // Reset all flags in struct
56 opts.abort = FALSE;
57 opts.force = FALSE;
58 opts.logoff = FALSE;
59 opts.restart = FALSE;
60 opts.shutdown = FALSE;
61
62 for (i = 1; i < argc; i++)
63 {
64 if (argv[i][0] == '-' || argv[i][0] == '/')
65 {
66 switch(argv[i][1]) {
67 case '?':
68 PrintUsage();
69 exit(0);
70 case 'f':
71 case 'F':
72 opts.force = TRUE;
73 break;
74 case 'l':
75 case 'L':
76 opts.logoff = TRUE;
77 break;
78 case 'r':
79 case 'R':
80 opts.restart = TRUE;
81 break;
82 case 's':
83 case 'S':
84 opts.shutdown = TRUE;
85 break;
86 default:
87 // Unknown arguments will exit program.
88 PrintUsage();
89 exit(0);
90 break;
91 }
92 }
93 }
94
95 return opts;
96 }
97
98 // Converts the commandline arguments to flags used to shutdown computer
99 static struct ExitOptions ParseCommandLineOptionsToExitOptions(struct CommandLineOptions opts)
100 {
101 struct ExitOptions exitOpts;
102 exitOpts.shouldExit = TRUE;
103
104 // Sets ONE of the exit type flags
105 if (opts.logoff)
106 exitOpts.flags = EWX_LOGOFF;
107 else if (opts.restart)
108 exitOpts.flags = EWX_REBOOT;
109 else if(opts.shutdown)
110 exitOpts.flags = EWX_POWEROFF;
111 else
112 {
113 exitOpts.flags = 0;
114 exitOpts.shouldExit = FALSE;
115 }
116
117 // Sets additional flags
118 if (opts.force)
119 {
120 exitOpts.flags = exitOpts.flags | EWX_FORCE;
121
122 // This makes sure that we log off, also if there is only the "-f" option specified.
123 // The Windows shutdown utility does it the same way.
124 exitOpts.shouldExit = TRUE;
125 }
126
127 // Reason for shutdown
128 // Hardcoded to "Other (Planned)"
129 exitOpts.reason = SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED;
130
131 return exitOpts;
132 }
133
134 // Writes the last error as both text and error code to the console.
135 void DisplayLastError()
136 {
137 int errorCode = GetLastError();
138 LPTSTR lpMsgBuf = NULL;
139 DWORD errLength; // error message length
140 LPTSTR resMsg; // for error message in OEM symbols
141
142 // Display the error message to the user
143 errLength = FormatMessage(
144 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
145 NULL,
146 errorCode,
147 LANG_USER_DEFAULT,
148 (LPTSTR) &lpMsgBuf,
149 0,
150 NULL) + 1;
151
152 resMsg = (LPTSTR)LocalAlloc(LPTR, errLength * sizeof(TCHAR));
153 CharToOemBuff(lpMsgBuf, resMsg, errLength);
154
155 _ftprintf(stderr, resMsg);
156 _ftprintf(stderr, _T("Error code: %d\n"), errorCode);
157
158 LocalFree(lpMsgBuf);
159 LocalFree(resMsg);
160 }
161
162 void EnableShutdownPrivileges()
163 {
164 HANDLE token;
165 TOKEN_PRIVILEGES privs;
166
167 // Check to see if the choosen action is allowed by the user. Everyone can call LogOff, but only privilieged users can shutdown/restart etc.
168 if (! OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
169 {
170 DisplayLastError();
171 exit(1);
172 }
173
174 // Get LUID (Locally Unique Identifier) for the privilege we need
175 if (!LookupPrivilegeValue(
176 NULL, // system - NULL is localsystem
177 SE_SHUTDOWN_NAME, // name of the privilege
178 &privs.Privileges[0].Luid) // output
179 )
180 {
181 DisplayLastError();
182 exit(1);
183 }
184 // and give our current process (i.e. shutdown.exe) the privilege to shutdown the machine.
185 privs.PrivilegeCount = 1;
186 privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
187 if (AdjustTokenPrivileges(
188 token,
189 FALSE,
190 &privs,
191 0,
192 (PTOKEN_PRIVILEGES)NULL, // previous state. Set to NULL, we don't care about previous state.
193 NULL
194 ) == 0) // return value 0 means failure
195 {
196 DisplayLastError();
197 exit(1);
198 }
199 }
200
201 // Main entry for program
202 int _tmain(int argc, TCHAR *argv[])
203 {
204 struct CommandLineOptions opts;
205 struct ExitOptions exitOpts;
206
207 if (argc == 1) // i.e. no commandline arguments given
208 {
209 PrintUsage();
210 exit(0);
211 }
212
213 opts = ParseArguments(argc, argv);
214 exitOpts = ParseCommandLineOptionsToExitOptions(opts);
215
216 // Perform the shutdown/restart etc. action
217 if (exitOpts.shouldExit)
218 {
219 EnableShutdownPrivileges();
220
221 if (!ExitWindowsEx(exitOpts.flags, exitOpts.reason))
222 {
223 DisplayLastError();
224 exit(1);
225 }
226 }
227 return 0;
228 }
229
230 // EOF