safe remote poweroff
If you run a root command shell on your linux machine and remotely administer another one, also via a root command shell, it's a matter of time before you power off the local one only to discover that, oops, no, you just shut down the remote instead by accident. At that point a remote physical presence is needed, to press the power button. Get in the car, or buy your plane ticket, or embarrass yourself with another phone call to somebody onsite asking them to again fix your mistake for you. Or, you could write some substitute prophylactic code under the same name(s) as the command(s) you habitually use for turning the machine off (probably shutdown, poweroff, or halt). Write it so it deflects (does not actually run) the poweroff attempt, instead printing a helpfully alarmist message reminding the adminstrator that OMG he appears to be trying to turn off the remote machine, telling him how to do so if it's what he actually intended, and exiting. Never again will he do it unawares.
Let's assume the command you always use to put your machines down is poweroff. There is probably more than one solution. But any of them will involve emplacing some code that goes by the name "poweroff" and gets called ahead of the usual code that actually turns out the lights, eclipsing it. The new code will not turn the machine off, but rather print a message saying so and giving the user an alternative direct command that will run the regular poweroff. Except, that's a bit of overkill if done unconditionally. You really want to take that step only in case of a remote connection. If "poweroff" is issued on a local one, you want to let it go through. It's OK, the protection is unneeded, because turning off the machine by accident is recoverable by just turning it right back on again. By contrast a remote user doesn't have that luxury; so the new code should be conditional on whether the user's connection is local or remote.
The assignment to perform:
Operate as root. Write a script to be run in whenever the root user types "poweroff" in place of the regular poweroff. The script logic is to be:
determine if the connection is on a regular
tty # (how? tty, ps, test, $-, $0 might help; see Advanced Bash
Scripting Guide sec
36.1)
if "tty"
print a message on screen saying in effect "You're local, I'm gonna
turn you off now"
pull the trigger by running the regular poweroff (machine
turns off)
else
print a warning message on screen declaring which machine this is by
hostname and
printing an alternative command formulation the user could
use
that would pull trigger by running the regular poweroff
exit with error (exit status value 1) (machine does not turn off)
endif
Put your code in a file named safe-remote-poweroff. Make it root-executable. Determine the directory where the poweroff executable file sits. Then determine a directory that will be placed in root's path, whether root connects locally or remotely, and that occurs within PATH earlier than poweroff's directory. You will have to determine this either analytically or empirically. If analytically, look into the bash startup files that run in the 2 possible cases (remote root, local root) and see what the PATH variable gets set to. If empirically (easier), just log in both ways and examine the results (i.e., the content of the PATH variables you get). Find a directory that shows up in both. Put your script file into it. Note that there is no need to use your script for non-root users. They need no protection from running the real poweroff, because it does its own checking and powers off only if being run as root.
Manually create an alias for your your script, under the name "poweroff". This gives it prior precedence over running the regular executable file by that name. That code turns off the machine; yours doesn't. (Another possibility would be to make a function out of your code, since functions too trump executable files.) Automate this step to make it persistent, by editing the appropriate bash startup script(s) that fires off whenever root logs in. You need to identify a startup script that runs both when connecting locally and remotely.
Connect all 4 ways-- local and remote root, local and remote non-root-- and make sure typing "poweroff" does what it's supposed to in each. Do this all on a local linux machine. Where you need a remote connection, simulate/achieve it by ssh'ing or telneting from your machine to itself. Make sure that in both root cases, your new code gets called. But also make sure that in those two cases the alternative code prescribed to the user to bring it down actually does do so. Make sure that in both local cases, "poweroff" does run the regular poweroff executable, and it prints its refusal, "poweroff: Need to be root". Any time the machine goes down but you need to continue this exercise, reboot it.
Here's what should happen when you are connected remotely and try to power off, as non-root and as root:

Perform this exercise at home. When you have it working please:
1 - drop a copy of it into your assignments subdirectory, and
2 - bring your file to
class and set your classroom machine up the same way, so that it works and can
be examined.
For reference:
This assignment calls on you to know
- the basics of execution precedence among
different types of code that have the same name
- which shell startup scripts
run under what scenarios
- how to construct an "if" conditional
- how to detect if you are local or remote
Below are a couple of summary slides and the man page section about bash invocation, for your reference.
![]() |
![]() |

INVOCATION
A login shell is one whose first character of argument zero is a -,
or one started with the --login option.
An interactive shell is one started without non-option arguments and
without the -c option whose standard input and error are both con-
nected to terminals (as determined by isatty(3)), or one started
with the -i option. PS1 is set and $- includes i if bash is inter-
active, allowing a shell script or a startup file to test this
state.
The following paragraphs describe how bash executes its startup
files. If any of the files exist but cannot be read, bash reports
an error. Tildes are expanded in file names as described below
under Tilde Expansion in the EXPANSION section.
When bash is invoked as an interactive login shell, or as a non-
interactive shell with the --login option, it first reads and exe-
cutes commands from the file /etc/profile, if that file exists.
After reading that file, it looks for ~/.bash_profile,
~/.bash_login, and ~/.profile, in that order, and reads and executes
commands from the first one that exists and is readable. The
--noprofile option may be used when the shell is started to inhibit
this behavior.
When a login shell exits, bash reads and executes commands from the
files ~/.bash_logout and /etc/bash.bash_logout, if the files exists.
When an interactive shell that is not a login shell is started, bash
reads and executes commands from ~/.bashrc, if that file exists.
This may be inhibited by using the --norc option. The --rcfile file
option will force bash to read and execute commands from file
instead of ~/.bashrc.
When bash is started non-interactively, to run a shell script, for
example, it looks for the variable BASH_ENV in the environment,
expands its value if it appears there, and uses the expanded value
as the name of a file to read and execute. Bash behaves as if the
following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the
file name.
If bash is invoked with the name sh, it tries to mimic the startup
behavior of historical versions of sh as closely as possible, while
conforming to the POSIX standard as well. When invoked as an inter-
active login shell, or a non-interactive shell with the --login
option, it first attempts to read and execute commands from
/etc/profile and ~/.profile, in that order. The --noprofile option
may be used to inhibit this behavior. When invoked as an interac-
tive shell with the name sh, bash looks for the variable ENV,
expands its value if it is defined, and uses the expanded value as
the name of a file to read and execute. Since a shell invoked as sh
does not attempt to read and execute commands from any other startup
files, the --rcfile option has no effect. A non-interactive shell
invoked with the name sh does not attempt to read any other startup
files. When invoked as sh, bash enters posix mode after the startup
files are read.
When bash is started in posix mode, as with the --posix command line
option, it follows the POSIX standard for startup files. In this
mode, interactive shells expand the ENV variable and commands are
read and executed from the file whose name is the expanded value.
No other startup files are read.
Bash attempts to determine when it is being run with its standard
input connected to a network connection, as when executed by the
remote shell daemon, usually rshd, or the secure shell daemon sshd.
If bash determines it is being run in this fashion, it reads and
executes commands from ~/.bashrc, if that file exists and is read-
able. It will not do this if invoked as sh. The --norc option may
be used to inhibit this behavior, and the --rcfile option may be
used to force another file to be read, but rshd does not generally
invoke the shell with those options or allow them to be specified.
If the shell is started with the effective user (group) id not equal
to the real user (group) id, and the -p option is not supplied, no
startup files are read, shell functions are not inherited from the
environment, the SHELLOPTS, BASHOPTS, CDPATH, and GLOBIGNORE vari-
ables, if they appear in the environment, are ignored, and the
effective user id is set to the real user id. If the -p option is
supplied at invocation, the startup behavior is the same, but the
effective user id is not reset.
-- bash man page