aboutsummaryrefslogblamecommitdiff
path: root/doomsh.bash
blob: 13d0dc993d0985768cf6a71b3861b89d58bfd6bb (plain) (tree)
1
2
3
4
5
6
7
8
9
10
      
 







                                                                             
 


                                                                               
 



                                                                              



                                                    


                                                




                                                                               

                                 

                            
                                 






                           
                                           

                   
                            






                                                      

                


                                                      


                                         







                       
                                   
 





                                                                               


                                                        


                                                 



                                             





                                                    



                                                      






                                         











                                                   
                   
                                     
                
                                      
                
                                       
                 








                                                                           







                                                     



                                                             
                                               
#!bash
#
# Copyright (C) 2016, 2018, 2021 Tom Ryder <tom@sanctum.geek.nz>
#
# This file is part of doomsh.
#
# doomsh 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 3 of the License, or (at your option) any later
# version.
#
# doomsh 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.
#
# You should have received a copy of the GNU General Public License along with
# doomsh.  If not, see <https://www.gnu.org/licenses/>.

# doomsh: Play with low ulimits in Bash
self=doomsh

# Don't try to play doomsh if already playing doomsh
if [[ $DOOMSH ]] ; then
	printf '%s: Already playing doomsh!\n' \
		"$self" >&2
	exit 2
fi

# Show the coloured logo; thanks to Frans P. de Vries for the classic ASCII art
# <http://www.gamers.org/~fpv/doombann.html>
printf >&2 %s "$( {
	tput AF 3 || tput setaf 3
	tput md || tput bold
} 2>/dev/null )"
while IFS= read -r line ; do
	printf >&2 '%s\n' "$line"
done <<EOF
______ _____ _____ __   ___
| __  \  _  |  _  |  \ /  |
| | \ | | | | | | | . V . |
| | / | \_/ | \_/ | |\ /| |
| |/ / \   / \   /| | V | |
| ' /   \_/   \_/ \_|   | |
|__/					\_|
EOF
printf >&2 %s "$( {
	tput me || tput sgr0
} 2>/dev/null )"

# Need to figure out a skill level
declare -i skill

# If we have an argument, that must be the skill level
if (($#)) ; then
	skill=$1
	shift

# Otherwise, we'll give the user a menu to choose from
else
	while IFS= read -r line ; do
		printf >&2 '%s\n' "$line"
	done <<EOF

1. I'm too young to die
2. Hey, not too rough
3. Hurt me plenty
4. Ultra-Violence
5. Nightmare!

EOF
	read -er -p '[1-5]: ' skill

	# If the user chose "Nightmare!" mode, get them to confirm, in the true
	# spirit of things; otherwise, quit
	if ((skill == 5)) ; then
		while IFS= read -r line ; do
			printf '%s\n' "$line" >&2
		done <<EOF

Are you sure? This skill level isn't even remotely fair.
EOF
		read -er -p '[y/N]: ' confirm
		[[ $confirm == [Yy]* ]] || exit 1
	fi
fi

# Don't accept any other skill level settings
case $skill in
	1|2|3|4|5)
		;;
	*)
		printf '%s: Unknown skill level\n' \
			"$self" >&2
		exit 2
esac

# Form a red prompt (hopefully) using terminal escapes
ps1=$(printf '%sdoomsh[%u]\$%s ' \
	"$( {
		tput AF 1 || tput setaf 1
	} 2>/dev/null )" \
	"$skill" \
	"$( {
		tput me || tput sgr0
	} 2>/dev/null )"
)

# Set the limits based on the skill level
declare -i filesize files stack memory
filesize=$((1 << (8 - skill)))
files=$((11 - skill))
stack=$((1 << (11 - skill)))
memory=$((1 << (19 - skill)))

# Display the limits
printf >&2 '\n'
printf >&2 'File size writing limit: %u blocks\n' \
	"$filesize"
printf >&2 'Open files limit: %u\n' \
	"$files"
printf >&2 'Stack size: %u kbytes\n' \
	"$stack"
printf >&2 'Memory size: %u kbytes\n' \
	"$memory"
printf >&2 '\n'

# Record the current seconds since shell start, so we can tell how long the
# user lasts before giving up or segfaulting
declare -i start
start=$SECONDS

# Open a subshell so that the ulimit settings don't persist after the fork
(
	# We only proceed if the ulimit call succeeds
	ulimit \
		-f "$filesize" \
		-n "$files" \
		-s "$stack" \
		-v "$memory" \
		|| exit 2
	DOOMSH=$skill PS1=$ps1 bash --norc
)

# Give the user some statistics about their performance
printf >&2 '%s: You lasted %u seconds at skill level %u!\n' \
	"$self" "$((SECONDS - start))" "$skill"