aoakley.com

How to start GNU Screen automatically without login

Ever wanted to start GNU Screen automatically at boot time, without logging in? This is a Linux challenge that seems obvious, but actually isn't. The usual place to start things automatically at boot is /etc/rc.local , but that doesn't work with screen because it gets confused over who is the user that it's starting for. Even if you so a sudo -u or sudo su it still gets confused.

Examples of when you might want to do this, include running a script using .screenrc and a stuff command. For instance, I have a Raspberry Pi which I use as a webcam, with the following ~/.screenrc :

screen -t "Webcam"
stuff "cd ~/webcam ; sudo python webcam.py\015"

The solution to starting screen at boot is simple but not always obvious. You start it from an ordinary user's crontab using the @reboot directive. From an ordinary user account, do crontab -e and add a @reboot line at the end of the file:

#m hh dd mm dow command
07 03  *  * SUN /usr/local/bin/my-sunday-backup-script
@reboot /usr/bin/screen -dm

(where my-sunday-backup-script is an unrelated example of what might already be in your crontab)

However, that's not necessarily the full solution, which is where it starts getting complicated. This will start the GNU screen session for the correct user and that user's correct ~/.screenrc , but it will not run the user's .bashrc , .profile or .bash_profile . The most obvious symptom of not running those scripts, is that sessions won't have their command-line prompt prefix set, nor any of your usual aliases or, in my case, preferred colour settings (I'm heavily colour blind so I have my sessions set to VT100 no colour, and a bunch of aliases which add --nocolor or somesuch as a default parameter). Instead, you'll just get a plain $ dollar-prompt.

To force those login scripts to run too, you need a bit of sudo trickery. First you will need to make sure that your user can run sudo su - back to your own account, without needing to enter a password. If you can't already do this, you can go into sudo visudo and then add:

aoakley ALL=(ALL) NOPASSWD: su - aoakley
...where aoakley is the user account in question

Now do crontab -e and change your @reboot line as follows:

@reboot sudo su - aoakley -c '/usr/bin/screen -dm'

This forces the session to run your full login scripts, before then starting GNU Screen.

But what if your login scripts already start GNU Screen? That'll produce what IBM technical manuals used to call "unpredictable results", i.e. a mess; most likely it will create multiple screen sessions (each running multiple individual instances of the script you fired off from ~/.screenrc - I managed six at one point before I realised what was happening!), but it depends on what parameters you supply to screen in your login scripts.

To solve this, I've created a script that I've named goscreen, which can be passed a parameter -n which attaches to a screen session only if one already exists, but otherwise does not create a new session. So you can safely add goscreen -n to your ~/.bash_profile whilst also having a normal screen command start GNU Screen from your crontab @reboot line.

#!/bin/bash
# goscreen by Andrew Oakley www.aoakley.com 2010 public domain

# Help text
if [[ "$1" == "--help" ]]; then
  echo "goscreen by Andrew Oakley www.aoakley.com 2010 public domain"
  echo "Usage: goscreen [ --help | [ -v ] [-n] ]"
  echo "Get into GNU Screen unless root or already inside"
  echo "-v      Verbose (quiet by default)"
  echo "-n      Do not create session  (i.e. do nothing if no existing session)"
  echo "--help  This help text"
  exit
fi

VERBOSE=""
if [[ "$1" == "-v" ]]; then
  VERBOSE="TRUE"
  shift
fi

# Join screen session unless root or already inside
if [[ "$(id -u)" != 0 ]]; then
  if [[ -z $STY ]]; then
    if [[ -z `screen -list | grep "No Sockets"` ]] ; then
      if [[ $VERBOSE ]]; then
        echo "Reattaching to existing session..."
      fi
      screen -Ax
    else
      if [[ "$1" != "-n" ]]; then
        if [[ $VERBOSE ]]; then
          echo "No existing session - creating..."
        fi
        screen
      else
        if [[ $VERBOSE ]]; then
          echo "Ignored - no existing session and -n flag supplied"
        fi
      fi
    fi
  else
    if [[ $VERBOSE ]]; then
      echo "Ignored - you're already inside screen"
    fi
  fi
else
  if [[ $VERBOSE ]]; then
    echo "Ignored - you are root"
  fi
fi

I put this script in /usr/local/bin/goscreen so all users can use it, but you may prefer it to run from your home directory or from ~/bin/ .

You could condense this down to simply one line in your .bash_profile if you prefer:

if [[ -z `screen -list | grep "No Sockets"` ]] ; then screen -Ax; fi

The above tips have been tested on a few Debian-based Linux distributions including Ubuntu and Raspbian. However if it doesn't work on Fedora or Red Hat, I won't be at all surprised, but do give it a try - feel free to email me andrew@aoakley.com with updates for other distros.

Before anyone starts, yes, I am aware of tmux but it doesn't support serial connections, which matters on a headless Raspberry Pi when you're trying to use the UART serial console. Users who want to find out more about the otherwise superior terminal multiplexer can do so at the tmux SourceForge page. Please don't ask me about tmux ; it doesn't support what I want to do, so I don't use it and don't know anything else about it beyond "experts who don't use serial connections tend to prefer tmux over GNU Screen".

Public Domain - Andrew Oakley - 2014-09-09

Top - More Computing Articles - Article Index - aoakley.com