From the Terminal

Making Any Terminal Command Into a Background Service Daemon

This guide will show you to make a bash script that is self aware about it's location on the file system and therefore able to be used as a global terminal command from any current directory.

It will have the ability to take arguments as commands and have the ability to act on those commands with a set of basic daemon related functions such as start, stop, restart, status, version, and help.

The bash script will also have the ability to save a .pid file, read from the file, and use the file as necessary to send basic signals to the background running process. The script will collect any output from the running process to a log which you can monitor with tail.

First thing's first. Let's create our bash script. Use touch to create a new plaintext file.

user@machine:~# touch servicedaemon

Don't forget to give the file executable permission with this command.

user@machine:~# chmod +x servicedaemon

Now open the file in your favorite text editor and lets start putting our script together. It might be beneficial for you to leave a terminal open so you can play with your script as we go along.

#!/bin/bash

The script must contain this on the first line to tell bash what script interpreter to use. In this case we're using bash of course.

Next we setup a way to handle arguments for our command. In this case we want to show usage information when someone doesn't provide any arguments but also provide basic arguments that are known to most people like -h and -v for help and version information.

#!/bin/bash

# source: https://stackoverflow.com/questions/59895/getting-the-source-directory-of-a-bash-script-from-within
# this detects the real location of the script even if it's linked
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
cd $DIR

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")";

pidfile="$me.pid"

executable="myservice.sh"

function loadenv() {
    if [ -f ".env" ]
    then 
        envtype=$(cat .env)
        envfile="conf/$envtype"

        if [ -f $envfile ]
        then
            echo "Loading environment from $envfile"
            . $envfile
        else
            echo "$envfile not found."
        fi
    else
        echo 'Environment type definition not found. Attempting production.'
        if [ -f 'conf/production' ]
        then
            . conf/production
        else 
            echo 'Production environment definition not found.'
        fi
    fi
}

function status() {
    if [ -f $pidfile ]
    then 
        PID=`cat $pidfile`
        if ps -p $PID > /dev/null
        then
            echo "$me is running on $PID"
        else
            echo "$me is not running"
        fi
    else
        echo 'PID file not found.'
    fi
}

function start() {
    loadenv
    log=$DIR/$me.log

    if [ -f $pidfile ]; then 
        echo "PID file found: " && cat $pidfile && exit 0
    fi

    daemon() {
        echo "Starting $me"
        $executable >> $log 2>&1 &
        pid="$!"
        echo $pid > $pidfile
    }
    daemon
}

function stop() {
    echo 'Stopping $me'
    PID=`cat $pidfile`

    if ps -p $PID > /dev/null
    then
        kill `cat $pidfile`
    fi
    rm $pidfile
}

function version() {
    echo '0.0.1'
    exit
}



function usage() {
    echo "Usage: $me [status|start|reload|stop]" 1>&2;
    exit;
}

case $1 in
    status)
        status
        exit
    ;;
    start)
        start
        exit
    ;;
    reload)
        stop
        start
        exit
    ;;
    stop)
        stop
        exit 
    ;;
    -h|-\?|--help)
        usage
        exit
    ;;
    -v|--version)
        version
        exit
    ;;
    *)
        usage
        exit
    ;;
esac
shift

At this point you can run ./servicedaemon from terminal and see the usage information pop up.

user@machine:~$ ./servicedaemon 
Usage: servicedaemon [status|start|reload|stop]
user@machine:~$ ./servicedaemon status
PID file not found.
user@machine:~$ ./servicedaemon -v
0.0.1
user@machine:~$ ./servicedaemon -h
Usage: servicedaemon [status|start|reload|stop]

Now just replace executable on line 18 with what you want to run. A log of any output will be placed in the same folder with the name of the executable file with a log extension. You can tail it to see output. A PID file will be created in the same folder.

Login to SSH Faster and With Greater Security: The SSH Config File

If you're like me you need to login to multiple servers via SSH on a daily basis. For many years when I was younger I typed in the whole IP or hostname of a server everytime I wanted to login to that server. After learning how to use the ssh config file logging into your SSH machine can be cut down to just a few keystrokes.

The SSH config file is always in ~/.ssh/config

Here's a template you can use.

Host alias
	HostName example.com
	User user
	IdentityFile /Users/user/.ssh/mykey_rsa

You can create as many entrees in the file as you like.

  • Hostname can be a DNS resolved domain name or an IP address but that is what SSH will try to actually connect to.
  • Host is actually just the name of this entry in this case I used "alias".
  • User when you type in the SSH command in terminal you can specify a user like normal but if you don't it will use the option you put in
  • IdentityFile is an optional setting to specify your private key SSH key.

When I type in ssh alias in the terminal it will simply connect to example.com as user.

Here's an example

~/.ssh/config
Host henryparadiz.com hp
        Hostname henryparadiz.com
        User henry
        IdentityFile /Users/henry/.ssh/personal_rsa

Usage

henry@Coder-Laptop:~$ ssh hp
Enter passphrase for key '/Users/henry/.ssh/personal_rsa': 
Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-116-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

23 packages can be updated.
13 updates are security updates.


Last login: Mon Apr 16 05:26:15 2018 from 127.0.0.1

Notice how I use the second alias under the host option simply "hp" which allows me to shorten the entire command to just the above. Easy and simply way to speed up your development.

Port forwarding with SSH Tunneling

With OpenSSH, port forwarding is configured using the -L option.

You can initiate a port forwarding operation with this command:

ssh -L 80:example.com:80 technex.us

In this example we are telling OpenSSH to open port 80 on the current machine to example.com on port 80 from the server we are connecting to. In this case the server is technex.us.

Don't forget that anyone can connect to this port on your machine so you might want to limit connects to localhost by telling OpenSSH to listen on a specific IP. In this case you can specify 127.0.0.1 like so:

ssh -L 127.0.0.1:80:example.com:80 technex.us

Since this is OpenSSH you can actually use the alias you specified in your ~/.ssh/config file.

I talk more about the OpenSSH config file here.

Building on top of that guide if you want to maintain a port forward everytime you connect to a specific machine you can use this syntax:

Host alias
	HostName technex.us
	User user
	IdentityFile /Users/user/.ssh/mykey_rsa
	LocalForward 127.0.0.1:80 example.com:80

Now you can simply type in ssh alias in terminal and be connected with a port forward.

Enable Middle Mouse

In Firefox on linux middle mouse click pastes by default. To fix it set these things in about:config

middlemouse.paste: false
general.autoScroll: true

Age of Empires II: Definitive Edition on Linux

Get the Linux version of Steam and enable this in settings

 

This will unlock the ability to download and install any title even if they are Windows only titles.

Now you'll be able to enable a custom compatibility tool in the settings for the game.

I've been playing the game with Proton 5.8-GE-2-MF which you can get at https://github.com/GloriousEggroll/proton-ge-custom.

 

You will also need to delete these files to avoid lockups from playing wmv files in-game. Otherwise the game runs flawlessly.

rm -rf ~/.steam/steam/steamapps/common/AoE2DE/resources/_common/movies
rm -rf ~/.steam/steam/steamapps/common/AoE2DE/resources/en/campaign/movies

 

If you are having issues make sure you have the most recent version of DXVK, Proton, Wine and your video card's driver.

Solving Dependency Slot Conflicts in Gentoo Elegantly

Sometimes when you want to emerge something or upgrade something you will have dependency slot conflicts like this example.

 

To fix this problem you'd need to emerge all kde-frameworks/* packages you currently have installed to upgrade them all at once since it's all part of one framework.

The following commands let you do so with ease.

equery l kde-frameworks/* -F '$category/$name'

 

The output of which you can send right into emerge like so.

sudo emerge --ask -1 --verbose-conflicts $(equery l kde-frameworks/* -F '$category/$name')

 

Now you'll hopefully get a clean emerge.