blob: c5d3a7ccfa57e43e5c86d2d9a673d34dd3fe37b6 [file] [log] [blame] [raw]
/* reboot - toolbox
Copyright 2015-2023 Rivoreo
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#ifdef _WIN32
#define RB_AUTOBOOT 0x01234567
#define RB_HALT_SYSTEM 0xcdef0123
#include <errno.h>
#include <windows.h>
#ifdef _WIN32_WCE
#ifdef _USE_KIOCTL
#if 0
#include <pkfuncs.h>
#else
#include <winioctl.h>
#define IOCTL_HAL_REBOOT CTL_CODE(FILE_DEVICE_HAL, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
extern int WINAPI KernelIoControl(unsigned long int, void *, unsigned long int, void *, unsigned long int, unsigned long int *);
#endif
#else
#include <pm.h>
#endif
#else
#ifdef _WINDOWSNT_NATIVE
#include <nt.h>
#else
#ifndef SE_SHUTDOWN_PRIVILEGE
#define SE_SHUTDOWN_PRIVILEGE (19)
#endif
//#ifndef _WIN32_WCE
// Custom errno mapping for reboot
static int __set_errno_from_oserror() {
switch(GetLastError()) {
case ERROR_INVALID_FUNCTION:
return errno = ENOSYS;
case ERROR_ACCESS_DENIED:
return errno = EPERM;
default:
return errno = EINVAL;
}
}
//#endif
#endif
static int enable_shutdown_privilege() {
void *token;
TOKEN_PRIVILEGES privilege;
memset(&privilege, 0, sizeof privilege);
privilege.PrivilegeCount = 1;
privilege.Privileges[0].Luid.LowPart = SE_SHUTDOWN_PRIVILEGE;
privilege.Privileges[0].Luid.HighPart = 0;
privilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
#ifdef _WINDOWSNT_NATIVE
long int status = NtOpenProcessToken((void *)-1, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
status = NtAdjustPrivilegesToken(token, 0, &privilege, sizeof privilege, NULL, NULL);
NtClose(token);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
return 0;
#else
//LUID id;
//memset(&id, 0, sizeof id);
if(!OpenProcessToken((void *)-1, TOKEN_ADJUST_PRIVILEGES, &token)) {
__set_errno_from_oserror();
return -1;
}
//if(!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &id)) return -1;
int ok = AdjustTokenPrivileges(token, 0, &privilege, sizeof privilege, NULL, NULL);
if(!ok) __set_errno_from_oserror();
CloseHandle(token);
return ok ? 0 : -1;
#endif
}
#endif /* _WIN32_WCE */
static int reboot(int flags) {
#ifdef _WIN32_WCE
if(flags != RB_AUTOBOOT) {
errno = EINVAL;
return -1;
}
#ifdef _USE_KIOCTL
if(!KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL)) return -1;
#else
unsigned long int e = SetSystemPowerState(NULL, POWER_STATE_RESET, 0);
if(e) {
SetLastError(e);
return -1;
}
#endif
#else
if(enable_shutdown_privilege() < 0) return -1;
#ifdef _WINDOWSNT_NATIVE
SHUTDOWN_ACTION action;
switch(flags) {
case RB_AUTOBOOT:
action = ShutdownReboot;
break;
case RB_HALT_SYSTEM:
action = ShutdownNoReboot;
break;
default:
errno = EINVAL;
return -1;
}
long int status = NtShutdownSystem(action);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
#else
#ifdef _USE_EWX
unsigned int wflags = EWX_FORCE;
switch(flags) {
case RB_AUTOBOOT:
flags |= EWX_REBOOT;
break;
case RB_HALT_SYSTEM:
flags |= EWX_SHUTDOWN;
break;
default:
errno = EINVAL;
return -1;
}
if(!ExitWindowsEx(wflags, 0)) {
__set_errno_from_oserror();
return -1;
}
#else
if(!InitiateSystemShutdownW(NULL, NULL, 0, 1, flags & EWX_REBOOT)) {
__set_errno_from_oserror();
return -1;
}
#endif
#endif /* _WINDOWSNT_NATIVE */
#endif /* _WIN32_WCE */
while(1) sleep(10000);
}
#else
#include <sys/reboot.h>
#ifdef __sun
#define reboot(_howto) reboot(_howto,NULL)
#endif
#endif
static void print_usage(const char *name) {
fprintf(stderr, "Usage: %s [-n]\n", name);
}
int reboot_main(int argc, char **argv) {
int flags = RB_AUTOBOOT;
#ifndef RB_NOSYNC
int no_sync = 0;
#endif
int i = 1;
int end_of_options = 0;
while(i < argc && !end_of_options) {
if(argv[i][0] == '-' && argv[i][1]) {
const char *o = argv[i] + 1;
while(*o) switch(*o++) {
case 'f':
break;
case 'n':
#ifdef RB_NOSYNC
flags |= RB_NOSYNC;
#else
no_sync = 1;
#endif
break;
case 'q':
break;
case 'h':
print_usage(argv[0]);
return 0;
case '-':
if(*o) {
fprintf(stderr, "%s: Invalid option '%s'\n", argv[0], argv[i]);
return -1;
} else end_of_options = 1;
break;
default:
fprintf(stderr, "%s: Invalid option '-%c'\n", argv[0], o[-1]);
print_usage(argv[0]);
return -1;
}
}
i++;
}
#ifndef RB_NOSYNC
if(!no_sync) sync();
#endif
if(reboot(flags) < 0) {
perror("reboot");
return 1;
}
// Never reached?
return 0;
}