Tag Archives: Shell

Shutdown/restart & mounting drives without display manager

Quite a long time ago I became unable to shutdown or restart my system from the Xfce logout dialog. I also couldn’t mount USB flash drives. Recently I tackled this issue which seems to be related to systemd + PolicyKit + Consolekit and found a solution. As written there I have created two files:

/etc/polkit-1/localauthority/50-local.d/consolekit.pkla:

[restart]
Identity=unix-user:<username>
Action=org.freedesktop.consolekit.system.restart
ResultAny=yes

[stop]
Identity=unix-user:<username>
Action=org.freedesktop.consolekit.system.stop
ResultAny=yes

/etc/polkit-1/localauthority/50-local.d/udisks.pkla:

[udisks]
Identity=unix-user:<username>
Action=org.freedesktop.udisks.*
ResultAny=yes

This finally gave me back full control over my system even though I didn’t bother digging deeper into the involved concepts.

After a recent update I once again lost these capabilities again though and had to give it another spin. Once again I found a solution and adapted my snippet for automatically launching the X server:

# Autostart X if not running
if [[ -z "$DISPLAY" ]] && [[ $(tty) = /dev/tty1 ]]; then
  startx -- vt1
fi

Getty hangs after upgrade to systemd 215

After an upgrade to systemd 215 I was not able to boot anymore and got messages like these for all of my virtual terminals:

[ TIME ] Timed out waiting for device dev-tty1.device.
[DEPEND] Dependency failed for Getty on tty1.

Turned out that I had an old copy of /etc/systemd/system/[email protected], booting into recovery mode and replacing it with a symlink to /lib/systemd/system/[email protected] solved the issue.

Herunterfahren/Neustarten & Laufwerke einhängen ohne Display Manager

Notice: this entry is also available in English.

Vor längerer Zeit verlor ich die Möglichkeit, als regulärer Nutzer über den Xfce-Abmeldedialog mein System herunterzufahren oder neuzustarten. Auch USB-Sticks konnte ich nicht mehr einhängen. Kürzlich befasste ich mich endlich ein wenig mit diesem Problem, was offenbar mit systemd + PolicyKit + ConsoleKit zusammenhängt und stieß auf eine Lösung. Wie dort beschrieben habe ich zwei neue Dateien angelegt:

/etc/polkit-1/localauthority/50-local.d/consolekit.pkla:

[restart]
Identity=unix-user:<username>
Action=org.freedesktop.consolekit.system.restart
ResultAny=yes

[stop]
Identity=unix-user:<username>
Action=org.freedesktop.consolekit.system.stop
ResultAny=yes

/etc/polkit-1/localauthority/50-local.d/udisks.pkla:

[udisks]
Identity=unix-user:<username>
Action=org.freedesktop.udisks.*
ResultAny=yes

Damit konnte ich nun endlich wieder mein System ganz normal benutzen, auch wenn ich weder Zeit noch Lust hatte, mich eingehender mit dem zugrundeliegenden System zu befassen.

Bei einem kürzlichen Update verlor ich aber wiederum diese Fähigkeiten und musste mich erneut auf die Suche begeben. Glücklicherweise wurde ich wieder fündig und passte meinen Codeschnipsel für den automatischen Start des X-Servers an:

# Autostart X if not running
if [[ -z "$DISPLAY" ]] && [[ $(tty) = /dev/tty1 ]]; then
  startx -- vt1
fi

Mal sehen, wie lange diese Konstellation nun funktionstüchtig bleibt.

Initscript mit Tiny Tiny RSS 1.5.10

Mit der Veröffentlichung der Version 1.5.10 des webbasierten Feed-Aggregators Tiny Tiny RSS fiel mir auf, dass das sich das optional beziehbare Initscript nicht mehr zum Starten des Update-Daemons nutzen lies. Beim Ausführen des Startkommandos geschah schlichtweg gar nichts.

Erste Versuche, das betreffende PHP-Script händisch zu starten schlugen weitestgehend fehl. Das Daemon-Script fror ständig ein, nachdem ich die SSH-Verbindung trennte, mit der ich meinen Server administriere. Folgende Fehlermeldung wies mich darauf hin:

Der Aktualisierungs Daemon braucht zu lange um eine Aktualisierung durchzuführen. Dies könnte auf ein Problem wie einen Absturz oder eine Blockierung hinweisen. Bitte überprüfen Sie den Prozess des Daemons oder benachrichtigen Sie den Besitzer des Instanz.

Und tatsächlich konnte das Update durch Töten des Prozesses und Löschen der lock-Dateien zeitweise wiederbeleben. Eine dauerhafte Lösung konnte dies aber nicht sein.

Also befasste ich mich erneut mit dem Initscript, welches das Hilfsprogramm start-stop-daemon zum Starten des Update-Daemons nutzt. Nach genauer Betrachtung fiel mir auf, dass nirgends ein Wechsel zu einem unprivilegierten Nutzer stattfand, der Daemon lief daher bisher immer mit Superuser-Rechten. Dass aus dies aus Sicherheitsgründen eine schlechte Idee ist dürfte ersichtlich sein.

Jedenfalls wurde diesem Verfahren mit der neuesten Version von Tiny Tiny RSS ein Riegel vorgeschoben, der im Änderungsprotokoll nicht aufgeführt aber durchaus im Versionierungsprotokoll durch diese Änderung ersichtlich ist. Der Versuch wird nun entsprechend quittiert:

[sanity_check] Please don’t run this script as root.

Mit diesem Wissen erweiterte ich das Initscript und seine Datei für Standardeinstellungen um eine neue Variable, welcher ein Nutzername oder eine -ID zugewiesen werden kann. Der Update-Daemon wird nun mit diesem Nutzer (www-data hier) ausgeführt und verfügt nicht mehr über systemweite Rechte. Es folgen die aktualisierten Dateien.

Die Einstellungsdatei /etc/default/tt-rss

## Defaults for Tiny Tiny RSS update daemon init.d script
 
# Set DISABLED to 1 to prevent the daemon from starting.
DISABLED=0
 
# Emplacement of your Tiny Tiny RSS installation.
TTRSS_PATH="/var/www/feeds"
 
# Set FORKING to 1 to use the forking daemon (update_daemon2.php) in stead of
# the standard one.
# This option is only available for Tiny Tiny RSS 1.2.20 and over.
FORKING=1
 
# Set USER to the user/uid to run the daemon as
USER=www-data

Das Initscript /etc/init.d/tt-rss

#! /bin/sh
### BEGIN INIT INFO
# Provides:          ttrss-DOMAIN
# Required-Start:    $local_fs $remote_fs networking
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Tiny Tiny RSS update daemon for DOMAIN
# Description:       Update the Tiny Tiny RSS subscribed syndication feeds.
### END INIT INFO
 
# Author: Pierre-Yves Landuré 
 
# Do NOT "set -e"
 
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Tiny Tiny RSS update daemon"
NAME=$(command basename "${0}")
DISABLED=0
FORKING=0
USER=$(id --user)
 
# Read configuration variable file if it is present
[ -r "/etc/default/${NAME}" ] && . "/etc/default/${NAME}"
 
DAEMON_SCRIPT="update.php --daemon"
 
if [ "$FORKING" != "0" ]; then
  DAEMON_SCRIPT="update_daemon2.php"
fi
 
DAEMON=/usr/bin/php
DAEMON_ARGS="${TTRSS_PATH}/${DAEMON_SCRIPT}"
DAEMON_DIR="${TTRSS_PATH}"
PIDFILE="/var/run/${NAME}.pid"
SCRIPTNAME="/etc/init.d/${NAME}"
 
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
 
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
 
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
 
if [ "$DISABLED" != "0" -a "$1" != "stop" ]; then
  log_warning_msg "Not starting $DESC - edit /etc/default/tt-rss-DOMAIN and change DISABLED to be 0.";
  exit 0;
fi
 
#
# Function that starts the daemon/service
#
do_start()
{
  # Return
  #   0 if daemon has been started
  #   1 if daemon was already running
  #   2 if daemon could not be started
  start-stop-daemon --start --make-pidfile --background --quiet --chdir "$DAEMON_DIR" --pidfile "$PIDFILE" --chuid "$USER" --exec "$DAEMON" --test > /dev/null \
    || return 1
 
  start-stop-daemon --start --make-pidfile --background --quiet --chdir "$DAEMON_DIR" --pidfile "$PIDFILE" --chuid "$USER" --exec "$DAEMON" -- \
    $DAEMON_ARGS \
    || return 2
  # Add code here, if necessary, that waits for the process to be ready
  # to handle requests from services started subsequently which depend
  # on this one.  As a last resort, sleep for some time.
}
 
#
# Function that stops the daemon/service
#
do_stop()
{
  # Return
  #   0 if daemon has been stopped
  #   1 if daemon was already stopped
  #   2 if daemon could not be stopped
  #   other if a failure occurred
  start-stop-daemon --stop --make-pidfile --quiet --retry=TERM/1/KILL/5 --pidfile $PIDFILE --name $NAME
  RETVAL="$?"
  [ "$RETVAL" = 2 ] && return 2
  # Wait for children to finish too if this is a daemon that forks
  # and if the daemon is only ever run from this initscript.
  # If the above conditions are not satisfied then add some other code
  # that waits for the process to drop all resources that could be
  # needed by services started subsequently.  A last resort is to
  # sleep for some time.
  start-stop-daemon --stop --quiet --oknodo --retry=0/1/KILL/5 --exec $DAEMON
  [ "$?" = 2 ] && return 2
  # Many daemons don't delete their pidfiles when they exit.
  rm -f $PIDFILE
  return "$RETVAL"
}
 
case "$1" in
  start)
  [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
  do_start
  case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
  esac
  ;;
  stop)
  [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
  do_stop
  case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
  esac
  ;;
  restart|force-reload)
  #
  # If the "reload" option is implemented then remove the
  # 'force-reload' alias
  #
  log_daemon_msg "Restarting $DESC" "$NAME"
  do_stop
  case "$?" in
    0|1)
    do_start
    case "$?" in
      0) log_end_msg 0 ;;
      1) log_end_msg 1 ;; # Old process is still running
      *) log_end_msg 1 ;; # Failed to start
    esac
    ;;
    *)
      # Failed to stop
    log_end_msg 1
    ;;
  esac
  ;;
  *)
  echo "Usage: ${SCRIPTNAME} {start|stop|restart|force-reload}" >&2
  exit 3
  ;;
esac
 
:

Mingetty und systemd

Das von systemd standardmäßig für das Öffnen virtueller Terminals genutzte agetty verfügt verglichen mit mingetty nur über einen sehr beschränkten Funktionsumfang. So ist gerade die Option --autologin von mingetty interessant, wenn man beim Start des Systems automatisch einen Nutzer ohne manuelle Eingaben anmelden möchte. Unter SysVinit ist hierfür folgender Eintrag in der /etc/inittab erforderlich:

1:2345:respawn:/sbin/mingetty --autologin USER tty1

Die Konfiguration unter systemd gestaltet sich dagegen komplett anders, ermöglicht aber eine nicht minder flexible Anpassung:

  1. Einen Symlink mit Verweis auf /lib/systemd/system/[email protected] in /etc/systemd/system anlegen
  2. Eine Datei /etc/systemd/system/[email protected]/autologin.conf wie folgt anlegen:
    [Service]
    ExecStart=
    ExecStart=-/sbin/mingetty --autologin USER %I

Hiernach kann der Dienst neu gestartet werden. Eine laufende X-Sitzung wird damit allerings auch beendet:

systemctl restart getty@tty1.service

Ab diesem Zeitpunkt wird bei jedem Systemstart der per USER spezifierte Nutzer automatisch angemeldet. Als kleiner Bonus noch eine mögliche Vorgehensweise, um dabei auch automatisch den X-Server zu starten:

if [ -z "$DISPLAY" -a $(tty) = /dev/tty1 ]; then
  startx
fi

Hier wird geprüft, ob noch kein X-Server gestartet wurde (die Umgebungsvariable $DISPLAY ist andernfalls gesetzt) und ob wir uns gerade auf tty1 befinden, von wo aus üblicherweise der erste X-Server gestartet wird. Einzutragen ist das ganze in die ~/.bash_profile, nicht in die ~/.bashrc.

Update: Die nötigen Schritte haben sich deutlich vereinfacht.

Shell-Autovervollständigung

Um den Umgang mit der Shell zu vereinfachen, habe ich schon seit geraumer Zeit die sofortige Anzeige aller Optionen bei einer mehrdeutigen Autovervollständigung aktiviert. Hierzu genügt folgender Eintrag in der ~/.inputrc:

# If you have this in your /etc/inputrc or ~/.inputrc, you will no longer
# have to hit the <Tab> key twice to produce a list of all possible
# completions.
# A single <Tab>  will suffice.
set show-all-if-ambiguous on

Dazu gesellte sich auch immer gleich die Festlegung der Autovervollständigung auf die Tab-Taste:

TAB:menu-complete

Nun bin ich auch endlich auf einen Hinweis gestoßen, wie man das Gegenstück, das rückwärtige Durchlaufen der Optionen, mittels Shift-Tab erreichen kann:

"\e[Z":menu-complete-backward

Die geliebten Einzeiler präsentieren sich wieder einmal in ganzer Pracht.

Aktueller Befehl im Terminaltitel

Ein schönes Feature worauf ich nicht mehr verzichten möchte ist die automatische Anzeige des aktuell ausgeführten Befehls im Titel des Terminals bzw. des Tabs. Dadurch wird die Arbeit mit multiplen Fenstern bzw. Tabs ungemein einfacher. Hier die Umsetzung, einzutragen in die ~/.bashrc:

function reset_prompt_and_title() {
  # Gewünschten Standard-Prompt hier angeben
  PS1='\[\033[0;32m\]\u\[\033[00m\] \[\033[0;33m\]\w\[\033[00m\] \$ '
 
  echo -ne "\e]0;${USER}@${HOSTNAME}: ${PWD}\a"
  # Variante: Die überflüssige Angabe des Home-Verzeichnisses
  #           durch die übliche Tilde ersetzen
  #echo -ne "\e]0;${USER}@${HOSTNAME}: ${PWD/#${HOME}/~}\a"
}
 
# Nur für grafische Terminals gedacht
case "$TERM" in
  xterm*|rxvt*)
    # Eventuelle weitere Kommandos für $PROMPT_COMMAND unbedingt erst
    # nach dieser Zeile anhängen
    PROMPT_COMMAND=reset_prompt_and_title
 
    # Aktuell ausgeführten Befehl in den Terminaltitel schreiben
    trap 'echo -ne "\e]0;$BASH_COMMAND\a"' DEBUG
    ;;
esac