| #!/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 unambiguously 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 between them. 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 issuing 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 |
| |