From bf61ca107069ea9ce5db2825558fa702be535049 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 3 Sep 2013 12:29:47 -0400 Subject: [PATCH] add guest support files for libvirt/unix schemes For systemd systems, the following files are used: - stapsh@.service.in: template file for a service which automatically respawns stapsh on a given virtio-serial port - 99-stapsh.rules: udev rules file that instantiates (or terminates) the stapsh service upon plugging in/out of virtio-serial ports For SYSV systems, the following files are used: - stapsh-daemon.in: libexec script file that automatically respawns stapsh on a given virtio-serial port - stapshd.in: init script to control stapsh-daemon instances - 99-stapsh-init.rules: udev rules file that forces a configuration reload upon plugging in/out of virtio-serial ports - virtio_console.modules: ensures that the virtio_console module is loaded at boot time if virtio-serial ports are detected. This is a workaround for RHEL5, in which the module is not auto-loaded, but does no harm in other systems such as RHEL6. --- configure.ac | 3 + staprun/guest/99-stapsh-init.rules | 10 ++ staprun/guest/99-stapsh.rules | 7 ++ staprun/guest/stapsh-daemon.in | 63 +++++++++++ staprun/guest/stapsh@.service.in | 16 +++ staprun/guest/stapshd.in | 161 +++++++++++++++++++++++++++ staprun/guest/virtio_console.modules | 19 ++++ 7 files changed, 279 insertions(+) create mode 100644 staprun/guest/99-stapsh-init.rules create mode 100644 staprun/guest/99-stapsh.rules create mode 100755 staprun/guest/stapsh-daemon.in create mode 100644 staprun/guest/stapsh@.service.in create mode 100755 staprun/guest/stapshd.in create mode 100755 staprun/guest/virtio_console.modules diff --git a/configure.ac b/configure.ac index aff480b0e..56c3b886c 100644 --- a/configure.ac +++ b/configure.ac @@ -692,6 +692,9 @@ AC_CONFIG_FILES(java/Makefile) AC_CONFIG_FILES([java/stapbm], [chmod +x java/stapbm]) AC_CONFIG_FILES(staprun/Makefile) AC_CONFIG_FILES([staprun/run-staprun], [chmod +x staprun/run-staprun]) +AC_CONFIG_FILES([staprun/guest/stapshd], [chmod +x staprun/guest/stapshd]) +AC_CONFIG_FILES([staprun/guest/stapsh-daemon], [chmod +x staprun/guest/stapsh-daemon]) +AC_CONFIG_FILES([staprun/guest/stapsh@.service]) # Setup "shadow" directory doc/beginners that has everything setup for # publican in one directory (through directory links if necessary). diff --git a/staprun/guest/99-stapsh-init.rules b/staprun/guest/99-stapsh-init.rules new file mode 100644 index 000000000..f1bc4be3c --- /dev/null +++ b/staprun/guest/99-stapsh-init.rules @@ -0,0 +1,10 @@ +# Used when systemd is not available. Runs 'service stapshd reload' when a port +# gets hotplugged/unplugged. This will create stapshd-daemon instances for new +# ports and kill stapshd-daemon instances for no longer existing ports. +# Should end up in /lib/udev/rules.d if it exists (RHEL6) or /etc/udev/rules.d +# otherwise (RHEL5) +# Docs: systemd.device(5), udev(7) + +SUBSYSTEM=="virtio-ports", ATTR{name}=="org.systemtap.stapsh.[0-9]*", \ + RUN+="/sbin/service stapshd reload" + diff --git a/staprun/guest/99-stapsh.rules b/staprun/guest/99-stapsh.rules new file mode 100644 index 000000000..d617089a8 --- /dev/null +++ b/staprun/guest/99-stapsh.rules @@ -0,0 +1,7 @@ +# Instantiates a stapsh systemd service for each detected port +# Should end up in /usr/lib/udev/rules.d +# Docs: systemd.device(5), udev(7) + +SUBSYSTEM=="virtio-ports", ATTR{name}=="org.systemtap.stapsh.[0-9]*", \ + TAG+="systemd" ENV{SYSTEMD_WANTS}="stapsh@$attr{name}.service" + diff --git a/staprun/guest/stapsh-daemon.in b/staprun/guest/stapsh-daemon.in new file mode 100755 index 000000000..e1cb75b77 --- /dev/null +++ b/staprun/guest/stapsh-daemon.in @@ -0,0 +1,63 @@ +#!/bin/bash +# Keeps respawning stapsh on the given port +# External programs used: basename, date, expr (all in coreutils) +# Must be in libexec dir + +STAPSH=@bindir@/stapsh + +# Make sure we were given a port +if [ ! -n "$1" ]; then + echo "Usage: `basename $0` " >&2 + exit 1 +fi + +STAPSH_PID=/var/run/stapsh.$(basename $1).pid +STAPSHD_PID=/var/run/stapshd.$(basename $1).pid + +# Make sure the port exists +if [ ! -c "$1" ]; then + echo "Argument $1 is not a character device" >&2 + if [ -f "$STAPSHD_PID" ]; then + rm "$STAPSHD_PID" + fi + exit 2 +fi + +# Returns the time in seconds +now() { + echo $(date "+%s") +} + +# Returns the time elapsed in seconds since arg +elapsed() { + echo $(expr $(now) - $1) +} + +# If stapsh is restarted more than 5 times in less than 1 second, we abort +last=$(now) +respawns=0 +while [ true ]; do + if [ "$(elapsed $last)" -gt 1 ]; then + last=$(now) + respawns=0 + elif [ "$respawns" -gt 5 ]; then + echo "Too many respawns... aborting" >&2 + rm "$STAPSH_PID" + if [ -f "$STAPSHD_PID" ]; then + rm "$STAPSHD_PID" + fi + exit 3 + elif [ ! -c "$1" ]; then + echo "Port no longer available" >&2 + if [ -f "$STAPSHD_PID" ]; then + rm "$STAPSHD_PID" + fi + exit 4 + fi + $STAPSH -l "$1" &>/dev/null & + pid=$! + echo $pid > $STAPSH_PID + wait $pid + respawns=$(expr $respawns + 1) +done + diff --git a/staprun/guest/stapsh@.service.in b/staprun/guest/stapsh@.service.in new file mode 100644 index 000000000..cfa46c77e --- /dev/null +++ b/staprun/guest/stapsh@.service.in @@ -0,0 +1,16 @@ +# To use this template service file, you would do something like +# systemctl start stapsh@org.systemtap.stapsh.0.service +# This file should end up in /usr/lib/systemd/system during installation +# Docs: http://0pointer.de/blog/projects/instances.html + +[Unit] +Description=SystemTap stapsh on %I +Documentation=man:stap man:stapsh +BindsTo=dev-virtio\x2dports-%i.device +After=dev-virtio\x2dports-%i.device + +[Service] +ExecStart=@bindir@/stapsh -l /dev/virtio-ports/%I +Restart=always +RestartSec=0 + diff --git a/staprun/guest/stapshd.in b/staprun/guest/stapshd.in new file mode 100755 index 000000000..f7983e381 --- /dev/null +++ b/staprun/guest/stapshd.in @@ -0,0 +1,161 @@ +#!/bin/bash +# +# chkconfig: - 90 10 +# description: Starts up stapshd instances for each SystemTap virtio-serial \ +# port discovered. +# +# Should end up in init dir + +if [ -f /etc/rc.d/init.d/functions ]; then + . /etc/rc.d/init.d/functions +fi + +STAPSHD=@libexecdir@/systemtap/stapsh-daemon +STAPSH=@bindir@/stapsh + +PORT_BASENAME="/dev/virtio-ports/org.systemtap.stapsh" + +# Prints paths to available SystemTap ports and returns the number of ports +ports() { + count=0 + for port in $PORT_BASENAME.*; do + if [[ $port =~ $PORT_BASENAME.[0-9]+ ]]; then + echo "$port" + count=$(expr $count + 1) + fi + done + return $count +} + +count_missing() { + missing=0 + for port in $(ports); do + if [ ! -f "/var/run/stapshd.$(basename $port).pid" ]; then + missing=$(expr $missing + 1) + fi + done + return $missing +} + +# Start stapshd instances +start() { + prts=$(ports) + if [ $? -eq 0 ]; then + echo "no ports detected" >&2 + # This shouldn't be an error + return 0 + fi + count_missing + if [ $? -eq 0 ]; then + echo "already running" >&2 + return 0 + fi + for port in $prts; do + pidfile="/var/run/stapshd.$(basename $port).pid" + if [ ! -f "$pidfile" ]; then + $STAPSHD "$port" &>/dev/null & + echo $! > $pidfile + fi + done + return 0 +} + +# First stops stapshd instances and then the stapsh instances +stop() { + for pidfile in /var/run/stapshd.$(basename $PORT_BASENAME).*.pid; do + if [ -f "$pidfile" ]; then + killproc -p $pidfile stapshd + fi + # Delete PID file if killproc didn't do it + if [ -f "$pidfile" ]; then + rm $pidfile + fi + done + for pidfile in /var/run/stapsh.$(basename $PORT_BASENAME).*.pid; do + if [ -f "$pidfile" ]; then + killproc -p $pidfile stapsh + fi + # Delete PID file if killproc didn't do it + if [ -f "$pidfile" ]; then + rm $pidfile + fi + done + return 0 +} + +# Only restart if we're running +condrestart() { + if [ -f "/var/run/stapshd.$(basename $PORT_BASENAME).*.pid" ]; then + stop + start + fi + return 0 +} + +# Check if there's a stapshd instance for each port +status() { + prts=$(ports) + if [ $? -eq 0 ]; then + echo "not running" >&2 + return 3 + fi + count_missing + if [ $? -eq 0 ]; then + echo "running" + return 0 + else + echo "missing $missing stapshd instances" + return 3 + fi +} + +# Stops any stapshd instances that are still running for a non-existent port +# and starts stapshd instances for any port that doesn't have one +reload() { + for pidfile in /var/run/stapshd.$(basename $PORT_BASENAME).*.pid; do + if [ -f "$pidfile" -a ! -c "/dev/virtio-ports/$(basename $PORT_BASENAME)" ]; then + killproc -p $pidfile stapshd + # Delete PID file if killproc didn't do it + if [ -f "$pidfile" ]; then + rm $pidfile + fi + fi + done + for pidfile in /var/run/stapsh.$(basename $PORT_BASENAME).*.pid; do + if [ -f "$pidfile" -a ! -c "/dev/virtio-ports/$(basename $PORT_BASENAME)" ]; then + killproc -p $pidfile stapsh + # Delete PID file if killproc didn't do it + if [ -f "$pidfile" ]; then + rm $pidfile + fi + fi + done + start +} + +# Main logic +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status + ;; + restart) + stop + start + ;; + condrestart|try-restart) + condrestart + ;; + reload) + reload + ;; + *) + echo "Usage: $0 {start|stop|restart|reload|condrestart|status}" + exit 1 +esac +exit $? diff --git a/staprun/guest/virtio_console.modules b/staprun/guest/virtio_console.modules new file mode 100755 index 000000000..30053dbfe --- /dev/null +++ b/staprun/guest/virtio_console.modules @@ -0,0 +1,19 @@ +#!/bin/sh +# +# Necessary for RHEL5. Ensures that the virtio_console module is loaded if +# virtio_serial ports are detected. Place in "/etc/sysconfig/modules/". + +function detect_virtio_console +{ + for modalias in /sys/bus/virtio/devices/virtio*/modalias; do + if [ "`cat $modalias`" == "virtio:d00000003v00001AF4" ]; then + return 0 + fi + done + return 1 +} + +if detect_virtio_console; then + /sbin/modprobe virtio_console >/dev/null 2>&1 +fi + -- 2.43.5