305 lines
7.8 KiB
Bash
305 lines
7.8 KiB
Bash
|
#!/bin/bash
|
||
|
#
|
||
|
# Demo of a shell frontend that communicates with a xorriso slave via
|
||
|
# two named pipes.
|
||
|
#
|
||
|
# This script creates two named pipes and starts xorriso with command
|
||
|
# -named_pipes_loop cleanup /tmp/xorriso_stdin_pipe_$$ xorriso_stdin_pipe_$$ -
|
||
|
# Its main loop prompts the user for commands, sends them to xorriso,
|
||
|
# receives the replies, and parses them by xorriso command
|
||
|
# -msg_op parse_silently. The resulting words are printed to stdout.
|
||
|
#
|
||
|
# xorriso removes the two pipes when it finishes execution of -named_pipes_loop
|
||
|
# regularly. (E.g. because of commands -end or -rollback_end or because of
|
||
|
# name loop control message "end_named_pipe_loop".)
|
||
|
# The vanishing of the pipe files tells this script that xorriso is gone.
|
||
|
#
|
||
|
#
|
||
|
# Copyright (C) 2013
|
||
|
# Thomas Schmitt <scdbackup@gmx.net>, libburnia-project.org
|
||
|
# Provided under BSD license: Use, modify, and distribute as you like.
|
||
|
#
|
||
|
|
||
|
# What xorriso program to use
|
||
|
xorriso=xorriso
|
||
|
if test o"$1" = o"-xorriso"
|
||
|
then
|
||
|
xorriso="$2"
|
||
|
fi
|
||
|
|
||
|
# Version of xorriso and minimum requirement by this script
|
||
|
export xorriso_version=
|
||
|
export xorriso_version_req=1.3.1
|
||
|
|
||
|
# Info about the xorriso slave process
|
||
|
export xorriso_is_running=0
|
||
|
export xorriso_pid=0
|
||
|
export xorriso_will_end=0
|
||
|
|
||
|
# Will be set to 1 before this script ends normally
|
||
|
export normal_end=0
|
||
|
|
||
|
|
||
|
# ---------------- An interpreter for quoted xorriso replies ----------------
|
||
|
|
||
|
# xorriso commands like -lsl wrap filenames into quotation marks in order
|
||
|
# to unambigously represent any character byte except the 0-byte.
|
||
|
# This piece of code parses input strings into words by letting xorriso
|
||
|
# command -msg_op "parse_silently" do the hard work.
|
||
|
# The input strings should be composed by concatenating input lines with
|
||
|
# newline characters inbetween. Begin by submitting a single line (without
|
||
|
# newline at its end) and retry with an appended further line, if
|
||
|
# xorriso_parse
|
||
|
# returns 1. See below xorriso_cmd_and_handle_result() for an example.
|
||
|
|
||
|
|
||
|
# The parsed reply words.
|
||
|
# Valid are reply_array[0] to reply_array[reply_count-1)]
|
||
|
export reply_array
|
||
|
export reply_count
|
||
|
|
||
|
|
||
|
# Interpret reply of -msg_op parse
|
||
|
xorriso_recv_parse_reply() {
|
||
|
reply_count=0
|
||
|
unset reply_array
|
||
|
export reply_array
|
||
|
ret=-1
|
||
|
read ret
|
||
|
if test "$ret" -lt 0 -o -z "$ret"
|
||
|
then
|
||
|
echo "Unexpected text as first reply line of -msg_op parse" >&2
|
||
|
xorriso_is_running=0
|
||
|
return 2
|
||
|
fi
|
||
|
test "$ret" = 0 && return "1"
|
||
|
read num_strings
|
||
|
string_count=0
|
||
|
while true
|
||
|
do
|
||
|
test "$string_count" -ge "$num_strings" && break
|
||
|
read num_lines
|
||
|
line_count=0
|
||
|
acc=
|
||
|
while true
|
||
|
do
|
||
|
test "$line_count" -ge "$num_lines" && break
|
||
|
read line
|
||
|
test "$line_count" -gt 0 && acc="$acc"$'\n'
|
||
|
acc="$acc""$line"
|
||
|
line_count=$(($line_count + 1))
|
||
|
done
|
||
|
reply_array["$string_count"]="$acc"
|
||
|
string_count=$(($string_count + 1))
|
||
|
done
|
||
|
reply_count="$num_strings"
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
|
||
|
# Parse a quoted multi-line string into words
|
||
|
xorriso_parse() {
|
||
|
# $1 : The string which shall be parsed
|
||
|
# $2 : The number of concatenated input lines (= number of newlines + 1)
|
||
|
# return: 0= array is valid , 1= line incomplete , 2= other error
|
||
|
|
||
|
test "$xorriso_is_running" = 0 && return 1
|
||
|
xorriso_send_cmd "msg_op parse_silently "'"'"'' '' 0 0 $2"'"'$'\n'"$1" || \
|
||
|
return 2
|
||
|
xorriso_recv_parse_reply <"$result_pipe" || xorriso_is_running=0
|
||
|
ret=$?
|
||
|
test "$xorriso_is_running" = 0 && ret=2
|
||
|
return "$ret"
|
||
|
}
|
||
|
|
||
|
|
||
|
# ------------- End of interpreter for quoted xorriso replies --------------
|
||
|
|
||
|
|
||
|
# Send one or more command lines to xorriso
|
||
|
xorriso_send_cmd() {
|
||
|
# $1 : the lines to send
|
||
|
|
||
|
# >>> is it possible to have a timeout on echo ?
|
||
|
|
||
|
if test -p "$cmd_pipe"
|
||
|
then
|
||
|
echo -E "$1" >"$cmd_pipe"
|
||
|
else
|
||
|
xorriso_is_running=0
|
||
|
return 1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
|
||
|
# Make filenames safe for transport by wrapping them in quotes and
|
||
|
# escaping quotes in their text
|
||
|
xorriso_esc() {
|
||
|
echo -n "'"
|
||
|
echo -n "$1" | sed -e "s/'/'"'"'"'"'"'"'/g"
|
||
|
echo -n "'"
|
||
|
}
|
||
|
|
||
|
|
||
|
# A handler function for xorriso_cmd_and_handle_result
|
||
|
xorriso_reply_to_stdout() {
|
||
|
echo "${reply_array[*]}"
|
||
|
}
|
||
|
|
||
|
|
||
|
# Let a handler inspect the result lines of a xorriso command line
|
||
|
xorriso_cmd_and_handle_result() {
|
||
|
# $1: handler command word and possibly argument words
|
||
|
# $2: command line for xorriso
|
||
|
|
||
|
if test "$xorriso_is_running" = 0
|
||
|
then
|
||
|
return 1
|
||
|
fi
|
||
|
|
||
|
handler="$1"
|
||
|
xorriso_send_cmd "$2" || return 1
|
||
|
res=$(cat "$result_pipe")
|
||
|
ret=$?
|
||
|
if test "$xorriso_will_end" = 1 -o "$xorriso_is_running" = 0 -o "$ret" -ne 0
|
||
|
then
|
||
|
test -n "$res" && echo -n "$res"
|
||
|
xorriso_is_running=0
|
||
|
test "$ret" = 0 || return 1
|
||
|
return 0
|
||
|
fi
|
||
|
test -z "$res" && return 0
|
||
|
echo "$res" | \
|
||
|
while read line
|
||
|
do
|
||
|
line_count=1
|
||
|
while true
|
||
|
do
|
||
|
xorriso_parse "$line" "$line_count"
|
||
|
ret=$?
|
||
|
test "$ret" = 0 && break
|
||
|
if test "$ret" = 2
|
||
|
then
|
||
|
return 1
|
||
|
fi
|
||
|
read addon
|
||
|
line="$line"$'\n'"$addon"
|
||
|
line_count=$(expr "$line_count" + 1)
|
||
|
done
|
||
|
# One can now make use of reply_array[0...(reply_count-1)]
|
||
|
$handler
|
||
|
done
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
|
||
|
# Execute -version and let xorriso_version_handler interpret reply
|
||
|
xorriso_check_version() {
|
||
|
lookfor='^xorriso version : '
|
||
|
xorriso_version=$("$xorriso" -version 2>/dev/null | grep "$lookfor" | \
|
||
|
sed -e "s/${lookfor}//")
|
||
|
ret=$?
|
||
|
if test "$ret" -ne 0 -o "$xorriso_version" = ""
|
||
|
then
|
||
|
echo "SORRY: Program run '${xorriso}' -version did not yield a result." >&2
|
||
|
echo >&2
|
||
|
exit 2
|
||
|
fi
|
||
|
smallest=$((echo "$xorriso_version_req" ; echo "$xorriso_version" ) | \
|
||
|
sort | head -1)
|
||
|
test "$smallest" = "$xorriso_version_req" && return 0
|
||
|
echo "SORRY: xorriso version too old: ${xorriso_version} . Need at least xorriso-${xorriso_version_req} ." >&2
|
||
|
echo >&2
|
||
|
exit 2
|
||
|
}
|
||
|
|
||
|
|
||
|
# To be executed on exit
|
||
|
xorriso_cleanup() {
|
||
|
|
||
|
send_end_cmd=0
|
||
|
if test -p "$cmd_pipe" -a "$xorriso_is_running" = 1
|
||
|
then
|
||
|
if test "$normal_end" = 0
|
||
|
then
|
||
|
echo "Checking whether xorriso is still running ..." >&2
|
||
|
set -x
|
||
|
# Give xorriso time to abort
|
||
|
sleep 1
|
||
|
if ps | grep '^'"$xorriso_pid" >/dev/null
|
||
|
then
|
||
|
|
||
|
# >>> try to further confirm xorriso identity
|
||
|
|
||
|
send_end_cmd=1
|
||
|
fi
|
||
|
else
|
||
|
send_end_cmd=1
|
||
|
fi
|
||
|
fi
|
||
|
test "$normal_end" = 0 && set -x
|
||
|
if test "$send_end_cmd" = 1
|
||
|
then
|
||
|
echo "Sending xorriso an -end command ..." >&2
|
||
|
xorriso_send_cmd "end" && \
|
||
|
test -p "$result_pipe" && cat "$result_pipe" >/dev/null
|
||
|
fi
|
||
|
test -p "$cmd_pipe" && rm "$cmd_pipe"
|
||
|
test -p "$result_pipe" && rm "$result_pipe"
|
||
|
}
|
||
|
|
||
|
|
||
|
# ---------------------------------- main ---------------------------------
|
||
|
|
||
|
# Choose pipe names
|
||
|
export cmd_pipe=/tmp/xorriso_stdin_pipe_$$
|
||
|
export result_pipe=/tmp/xorriso_stdout_pipe_$$
|
||
|
|
||
|
# Check the program whether it is modern enough
|
||
|
xorriso_check_version "$xorriso"
|
||
|
|
||
|
# Prepare for then end of this script
|
||
|
trap xorriso_cleanup EXIT
|
||
|
|
||
|
# Create the pipes and start xorriso
|
||
|
mknod "$cmd_pipe" p
|
||
|
mknod "$result_pipe" p
|
||
|
"$xorriso" -abort_on NEVER -for_backup \
|
||
|
-named_pipe_loop cleanup:buffered "$cmd_pipe" "$result_pipe" "-" &
|
||
|
xorriso_pid=$!
|
||
|
xorriso_is_running=1
|
||
|
|
||
|
# Get a sign of life from xorriso before issueing the loop prompt
|
||
|
xorriso_cmd_and_handle_result xorriso_reply_to_stdout \
|
||
|
"print_info 'xorriso process ${xorriso_pid} started by $0'"
|
||
|
echo >&2
|
||
|
|
||
|
|
||
|
# Now get commands from the user, send them to xorriso and display them
|
||
|
# via the simple handler xorriso_reply_to_stdout()
|
||
|
while test "$xorriso_is_running" = 1
|
||
|
do
|
||
|
if test -p "$cmd_pipe"
|
||
|
then
|
||
|
echo -n "xorriso> " >&2
|
||
|
else
|
||
|
echo "$0 : Lost contact to xorriso process $xorriso_pid" >&2
|
||
|
xorriso_is_running=0
|
||
|
break
|
||
|
fi
|
||
|
read line
|
||
|
if echo "$line" | grep '^-*end$' >/dev/null
|
||
|
then
|
||
|
break
|
||
|
fi
|
||
|
if echo "$line" | grep '^-*rollback_end$' >/dev/null
|
||
|
then
|
||
|
xorriso_will_end=1
|
||
|
fi
|
||
|
xorriso_cmd_and_handle_result xorriso_reply_to_stdout "$line"
|
||
|
done
|
||
|
|
||
|
# Prevent set -x in the exit handler
|
||
|
normal_end=1
|
||
|
|