initial commit uwu
This commit is contained in:
commit
c3ddc9a664
5 changed files with 298 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
poweroff_guard
|
19
Makefile
Normal file
19
Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
POWEROFF_PATH ?= $(shell which poweroff)
|
||||
COUNTDOWN_SECS ?= 10
|
||||
|
||||
CFLAGS := -std=c99 -pedantic -Wall -Wextra \
|
||||
-DPOWEROFF_PATH="\"$(POWEROFF_PATH)\"" \
|
||||
-DCOUNTDOWN_SECS=$(COUNTDOWN_SECS)
|
||||
|
||||
poweroff_guard: poweroff_guard.c
|
||||
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o poweroff_guard poweroff_guard.c
|
||||
|
||||
install: poweroff_guard
|
||||
install poweroff_guard /usr/local/sbin/
|
||||
mkdir -p /usr/local/share/man/man8
|
||||
install poweroff_guard.8 /usr/local/share/man/man8/
|
||||
|
||||
clean:
|
||||
rm -f poweroff_guard
|
||||
|
||||
all: poweroff_guard
|
58
README.md
Normal file
58
README.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
# poweroff_guard
|
||||
|
||||
This utility is a proxy for `poweroff` to prevent you from accidentally shutting down
|
||||
the wrong system. It does this by printing a warning message and asking for confirmation
|
||||
followed by a countdown before executing the actual command.
|
||||
|
||||
## Important Consideration
|
||||
|
||||
If the standard output is not a tty, this behaves exactly like the regular `poweroff`.
|
||||
|
||||
## Build
|
||||
|
||||
Open a shell in this directory and type `make`.
|
||||
Optionally, you may want to append any of the following options:
|
||||
|
||||
- `POWEROFF_PATH=/path/to/poweroff`: Specify a custom (absolute) path for the
|
||||
the real `poweroff` command. The default is to use the one in your `$PATH`.
|
||||
- `COUNTDOWN_SECS=n`: Start the countdown timer at `n` seconds, the default is 10.
|
||||
- `EXTRA_CFLAGS=...`: Append extra flags to the C compiler.
|
||||
|
||||
For example:
|
||||
|
||||
```sh
|
||||
# build with default options
|
||||
make
|
||||
# build with all custom options
|
||||
make \
|
||||
POWEROFF_PATH=/bin/custom_poweroff \
|
||||
COUNTDOWN_SECS=5 \
|
||||
EXTRA_CFLAGS="-O2 -march=native"
|
||||
```
|
||||
|
||||
Watch out:
|
||||
If you want to recompile with different options, you MUST execute a `make clean` first.
|
||||
Make will erroneously think the binary is already up to date otherwise.
|
||||
|
||||
## Installation
|
||||
|
||||
Do the exact same as building, but append `install` at the end of the command.
|
||||
For example:
|
||||
|
||||
```sh
|
||||
# build and install with default options
|
||||
make install
|
||||
# build and install with all custom options
|
||||
make \
|
||||
POWEROFF_PATH=/sbin/custom_poweroff \
|
||||
COUNTDOWN_SECS=5 \
|
||||
EXTRA_CFLAGS="-O2 -march=native" \
|
||||
install
|
||||
```
|
||||
|
||||
## License and Copyright
|
||||
|
||||
Copyright © 2022 anna <owo AT fef.moe>.
|
||||
|
||||
This program is licensed under the 2-clause BSD license.
|
||||
The license text is at the end of the `poweroff_guard.c` file.
|
50
poweroff_guard.8
Normal file
50
poweroff_guard.8
Normal file
|
@ -0,0 +1,50 @@
|
|||
.\" Copyright (C) 2022 fef <owo@fef.moe>. All rights reserved.
|
||||
.\"
|
||||
.\" Any person obtaining a copy of this software and associated documentation
|
||||
.\" files (the ``Software'') is prohibited from using the Software under any
|
||||
.\" circumstances. However, it is strongly suggested that they partake in
|
||||
.\" homosexual conduct (``Be Gay'') and criminal activity (``Do Crime'').
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.Dd October 13, 2022
|
||||
.Dt POWEROFF_GUARD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm poweroff_guard
|
||||
.Nd prevent accidental system shutdowns
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility acts as a proxy for the
|
||||
.Xr poweroff 8
|
||||
command.
|
||||
If it finds the standard output to be a tty (using the
|
||||
.Xr isatty 3
|
||||
standard library routine), it prints a message to the standard output and
|
||||
prompts additional confirmation. Typing "YES" (in uppercase, but without
|
||||
the quotes) followed by RETURN will then initiate a countdown timer.
|
||||
Finally, upon counting to zero, the actual poweroff command is invoked.
|
||||
.Pp
|
||||
If the standard output is not a tty, this utility behaves exactly like the
|
||||
.Xr poweroff 8
|
||||
command.
|
||||
.Sh OPTIONS
|
||||
None.
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr halt 8
|
||||
.Sh BUGS
|
||||
None that I would be aware of.
|
170
poweroff_guard.c
Normal file
170
poweroff_guard.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* poweroff_guard - Simple yet effective guardian to prevent accidentally
|
||||
* powering off the wrong system because let's face it, you're stupid.
|
||||
*
|
||||
* Copyright (c) 2022 anna <owo@fef.moe>.
|
||||
* See the end of this file for license terms.
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef POWEROFF_PATH
|
||||
#define POWEROFF_PATH "/sbin/poweroff"
|
||||
#endif
|
||||
#ifndef COUNTDOWN_SECS
|
||||
#define COUNTDOWN_SECS 10
|
||||
#endif
|
||||
|
||||
#define red(s) "\x1b[1;91m" s "\x1b[0m" /* bright red */
|
||||
#define cyn(s) "\x1b[1;96m" s "\x1b[0m" /* bright cyan */
|
||||
#define wht(s) "\x1b[1;97m" s "\x1b[0m" /* bright white */
|
||||
|
||||
enum confirm_match {
|
||||
CONFIRM_MATCH_UPPERCASE, /* exact match ("YES") */
|
||||
CONFIRM_MATCH_LOWERCASE, /* case-insensitive match */
|
||||
CONFIRM_MATCH_NONE, /* no match */
|
||||
};
|
||||
|
||||
/* read and evaluate confirmation answer from stdin */
|
||||
static enum confirm_match get_confirmation(void);
|
||||
/* count down from COUNTDOWN_SECS and do the actual poweroff afterwards */
|
||||
static void poweroff_with_countdown(void);
|
||||
/* do the actual poweroff, without countdown */
|
||||
static void do_poweroff(void);
|
||||
/* call perror(message) and then exit(status) */
|
||||
static void perror_and_exit(int status, const char *message);
|
||||
|
||||
static char hostname[HOST_NAME_MAX];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* behave like regular poweroff if we're not running in a tty */
|
||||
if (!isatty(STDOUT_FILENO))
|
||||
do_poweroff();
|
||||
|
||||
int err = gethostname(hostname, sizeof(hostname));
|
||||
if (err) {
|
||||
perror("Could not determine hostname");
|
||||
strncpy(hostname, "this host", sizeof(hostname));
|
||||
}
|
||||
|
||||
puts(red("\n######## ATTENTION, DIPSHIT ########\n"));
|
||||
printf("You are about to shut down " cyn("%s") "!\n", hostname);
|
||||
puts("Are you really sure about this?");
|
||||
printf("Type " wht("yes") " in UPPERCASE and press enter to confirm: ");
|
||||
fflush(stdout);
|
||||
|
||||
int try = 0;
|
||||
again:
|
||||
switch (get_confirmation()) {
|
||||
case CONFIRM_MATCH_UPPERCASE:
|
||||
poweroff_with_countdown();
|
||||
break;
|
||||
case CONFIRM_MATCH_LOWERCASE:
|
||||
if (try++ == 0) {
|
||||
printf("I said " wht("UPPERCASE") " you idiot, try again: ");
|
||||
fflush(stdout);
|
||||
goto again; /* it's very important to piss off Dijkstra */
|
||||
} else {
|
||||
puts("Go fuck yourself");
|
||||
return 0;
|
||||
}
|
||||
case CONFIRM_MATCH_NONE:
|
||||
puts("That's what I thought.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char buf[5];
|
||||
|
||||
static enum confirm_match get_confirmation(void)
|
||||
{
|
||||
char *input = fgets(buf, sizeof(buf), stdin);
|
||||
if (!input) {
|
||||
if (feof(stdin)) {
|
||||
/* user probably pressed CTRL+D, print
|
||||
* a line break to make it look nicer */
|
||||
printf("\n");
|
||||
return CONFIRM_MATCH_NONE;
|
||||
} else {
|
||||
perror_and_exit(1, "Reading stdin failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* if, for some reason, the input came from a pipe rather than typing
|
||||
* on the keyboard (cat, echo, etc), the newline might be missing */
|
||||
char *newline = strchr(input, '\n');
|
||||
if (newline)
|
||||
*newline = '\0';
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
if (!strcmp(input, "YES"))
|
||||
return CONFIRM_MATCH_UPPERCASE;
|
||||
if (!strcasecmp(input, "yes"))
|
||||
return CONFIRM_MATCH_LOWERCASE;
|
||||
return CONFIRM_MATCH_NONE;
|
||||
}
|
||||
|
||||
static void poweroff_with_countdown(void)
|
||||
{
|
||||
#if COUNTDOWN_SECS > 0
|
||||
printf("Alright, shutting down in ");
|
||||
for (int i = COUNTDOWN_SECS; i > 0; i--) {
|
||||
printf(wht("%d") "\n", i);
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
#else
|
||||
puts("Alright, shutting down " wht("NOW"));
|
||||
#endif
|
||||
|
||||
do_poweroff();
|
||||
}
|
||||
|
||||
static void do_poweroff(void)
|
||||
{
|
||||
execl(POWEROFF_PATH, POWEROFF_PATH, NULL);
|
||||
perror_and_exit(2, "exec() failed");
|
||||
}
|
||||
|
||||
static void perror_and_exit(int status, const char *message)
|
||||
{
|
||||
if (!message)
|
||||
message = "poweroff_guard";
|
||||
perror(message);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* LICENSE TERMS
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
Loading…
Reference in a new issue