Add command line shutdown utility to build
[reactos.git] / reactos / apps / utils / shutdown / shutdown.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS shutdown/logoff utility
4 * FILE: apps/utils/shutdown/shutdown.c
5 * PURPOSE: Initiate logoff, shutdown or reboot of the system
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <windows.h>
11 #include <tchar.h>
12
13 static void
14 PrintUsage(LPCTSTR Cmd)
15 {
16 _ftprintf(stderr, _T("usage: %s [action] [flag]\n"), Cmd);
17 _ftprintf(stderr, _T(" action = \"logoff\", \"reboot\", \"shutdown\" or \"poweroff\"\n"));
18 _ftprintf(stderr, _T(" flag = \"force\"\n"));
19 }
20
21 int
22 _tmain(int argc, TCHAR *argv[])
23 {
24 static struct
25 {
26 TCHAR *Name;
27 UINT ExitType;
28 UINT ExitFlags;
29 }
30 Options[] =
31 {
32 { _T("logoff"), EWX_LOGOFF, 0 },
33 { _T("logout"), EWX_LOGOFF, 0 },
34 { _T("poweroff"), EWX_POWEROFF, 0 },
35 { _T("powerdown"), EWX_POWEROFF, 0 },
36 { _T("reboot"), EWX_REBOOT, 0 },
37 { _T("restart"), EWX_REBOOT, 0 },
38 { _T("shutdown"), EWX_SHUTDOWN, 0 },
39 { _T("force"), 0, EWX_FORCE },
40 { _T("forceifhung"), 0, EWX_FORCEIFHUNG },
41 { _T("ifhung"), 0, EWX_FORCEIFHUNG },
42 { _T("hung"), 0, EWX_FORCEIFHUNG },
43 };
44 UINT ExitType, ExitFlags;
45 HANDLE hToken;
46 TOKEN_PRIVILEGES npr;
47 TCHAR *Arg;
48 TCHAR BaseName[_MAX_FNAME];
49 unsigned i, j;
50 BOOL HaveType, Matched;
51
52 ExitType = 0;
53 ExitFlags = 0;
54 HaveType = FALSE;
55
56 _tsplitpath(argv[0], NULL, NULL, BaseName, NULL);
57
58 /* Process optional arguments */
59 for (i = 1; i < (unsigned) argc; i++)
60 {
61 /* Allow e.g. "/s" or "-l" for shutdown resp. logoff */
62 Arg = argv[i];
63 if (_T('/') == *Arg || _T('-') == *Arg)
64 {
65 Arg++;
66 }
67
68 /* Search known options */
69 Matched = FALSE;
70 for (j = 0; j < sizeof(Options) / sizeof(Options[0]) && ! Matched; j++)
71 {
72 /* Match if arg starts the same as the option name */
73 if (0 == _tcsnicmp(Options[j].Name, Arg, _tcslen(Arg)))
74 {
75 if (0 == Options[j].ExitFlags)
76 {
77 /* Can have only 1 type */
78 if (HaveType)
79 {
80 PrintUsage(BaseName);
81 exit(1);
82 }
83 ExitType = Options[j].ExitType;
84 HaveType = TRUE;
85 }
86 else
87 {
88 /* Can have only 1 flag */
89 if (0 != ExitFlags)
90 {
91 PrintUsage(BaseName);
92 exit(1);
93 }
94 ExitFlags |= Options[j].ExitFlags;
95 }
96 Matched = TRUE;
97 }
98 }
99
100 /* Was the argument processed? */
101 if (! Matched)
102 {
103 PrintUsage(BaseName);
104 exit(1);
105 }
106 }
107
108 /* Check command name if user didn't explicitly specify action */
109 if (! HaveType)
110 {
111 for (j = 0; j < sizeof(Options) / sizeof(Options[0]); j++)
112 {
113 if (0 == _tcsicmp(Options[j].Name, BaseName) && 0 == Options[j].ExitFlags)
114 {
115 ExitType = Options[j].ExitType;
116 HaveType = TRUE;
117 }
118 }
119 }
120
121 /* Still not sure what to do? */
122 if (! HaveType)
123 {
124 PrintUsage(BaseName);
125 exit(1);
126 }
127
128 /* Everyone can logoff, for the other actions you need the appropriate privilege */
129 if (EWX_LOGOFF != ExitType)
130 {
131 /* enable shutdown privilege for current process */
132 if (! OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
133 {
134 _ftprintf(stderr, _T("OpenProcessToken failed with error %d\n"), (int) GetLastError());
135 exit(1);
136 }
137 npr.PrivilegeCount = 1;
138 npr.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
139 if (! LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &npr.Privileges[0].Luid))
140 {
141 CloseHandle(hToken);
142 _ftprintf(stderr, _T("LookupPrivilegeValue failed with error %d\n"), (int) GetLastError());
143 exit(1);
144 }
145 if (! AdjustTokenPrivileges(hToken, FALSE, &npr, 0, 0, 0)
146 || ERROR_SUCCESS != GetLastError())
147 {
148 if (ERROR_NOT_ALL_ASSIGNED == GetLastError())
149 {
150 _ftprintf(stderr, _T("You are not authorized to shutdown the system\n"));
151 }
152 else
153 {
154 _ftprintf(stderr, _T("AdjustTokenPrivileges failed with error %d\n"), (int) GetLastError());
155 }
156 CloseHandle(hToken);
157 exit(1);
158 }
159 CloseHandle(hToken);
160 }
161
162 /* Finally do it */
163 if (! ExitWindowsEx(ExitType | ExitFlags, 0))
164 {
165 _ftprintf(stderr, _T("ExitWindowsEx failed with error %d\n"), (int) GetLastError());
166 exit(1);
167 }
168
169 return 0;
170 }