1#!/bin/bash 2# 3# Demo of a shell frontend that communicates with a xorriso slave via 4# two named pipes. 5# 6# This script creates two named pipes and starts xorriso with command 7# -named_pipes_loop cleanup /tmp/xorriso_stdin_pipe_$$ xorriso_stdin_pipe_$$ - 8# Its main loop prompts the user for commands, sends them to xorriso, 9# receives the replies, and parses them by xorriso command 10# -msg_op parse_silently. The resulting words are printed to stdout. 11# 12# xorriso removes the two pipes when it finishes execution of -named_pipes_loop 13# regularly. (E.g. because of commands -end or -rollback_end or because of 14# name loop control message "end_named_pipe_loop".) 15# The vanishing of the pipe files tells this script that xorriso is gone. 16# 17# 18# Copyright (C) 2013 19# Thomas Schmitt <scdbackup@gmx.net>, libburnia-project.org 20# Provided under BSD license: Use, modify, and distribute as you like. 21# 22 23# What xorriso program to use 24xorriso=xorriso 25if test o"$1" = o"-xorriso" 26then 27 xorriso="$2" 28fi 29 30# Version of xorriso and minimum requirement by this script 31export xorriso_version= 32export xorriso_version_req=1.3.1 33 34# Info about the xorriso slave process 35export xorriso_is_running=0 36export xorriso_pid=0 37export xorriso_will_end=0 38 39# Will be set to 1 before this script ends normally 40export normal_end=0 41 42 43# ---------------- An interpreter for quoted xorriso replies ---------------- 44 45# xorriso commands like -lsl wrap filenames into quotation marks in order 46# to unambigously represent any character byte except the 0-byte. 47# This piece of code parses input strings into words by letting xorriso 48# command -msg_op "parse_silently" do the hard work. 49# The input strings should be composed by concatenating input lines with 50# newline characters between them. Begin by submitting a single line (without 51# newline at its end) and retry with an appended further line, if 52# xorriso_parse 53# returns 1. See below xorriso_cmd_and_handle_result() for an example. 54 55 56# The parsed reply words. 57# Valid are reply_array[0] to reply_array[reply_count-1)] 58export reply_array 59export reply_count 60 61 62# Interpret reply of -msg_op parse 63xorriso_recv_parse_reply() { 64 reply_count=0 65 unset reply_array 66 export reply_array 67 ret=-1 68 read ret 69 if test "$ret" -lt 0 -o -z "$ret" 70 then 71 echo "Unexpected text as first reply line of -msg_op parse" >&2 72 xorriso_is_running=0 73 return 2 74 fi 75 test "$ret" = 0 && return "1" 76 read num_strings 77 string_count=0 78 while true 79 do 80 test "$string_count" -ge "$num_strings" && break 81 read num_lines 82 line_count=0 83 acc= 84 while true 85 do 86 test "$line_count" -ge "$num_lines" && break 87 read line 88 test "$line_count" -gt 0 && acc="$acc"$'\n' 89 acc="$acc""$line" 90 line_count=$(($line_count + 1)) 91 done 92 reply_array["$string_count"]="$acc" 93 string_count=$(($string_count + 1)) 94 done 95 reply_count="$num_strings" 96 return 0 97} 98 99 100# Parse a quoted multi-line string into words 101xorriso_parse() { 102 # $1 : The string which shall be parsed 103 # $2 : The number of concatenated input lines (= number of newlines + 1) 104 # return: 0= array is valid , 1= line incomplete , 2= other error 105 106 test "$xorriso_is_running" = 0 && return 1 107 xorriso_send_cmd "msg_op parse_silently "'"'"'' '' 0 0 $2"'"'$'\n'"$1" || \ 108 return 2 109 xorriso_recv_parse_reply <"$result_pipe" || xorriso_is_running=0 110 ret=$? 111 test "$xorriso_is_running" = 0 && ret=2 112 return "$ret" 113} 114 115 116# ------------- End of interpreter for quoted xorriso replies -------------- 117 118 119# Send one or more command lines to xorriso 120xorriso_send_cmd() { 121 # $1 : the lines to send 122 123 # >>> is it possible to have a timeout on echo ? 124 125 if test -p "$cmd_pipe" 126 then 127 echo -E "$1" >"$cmd_pipe" 128 else 129 xorriso_is_running=0 130 return 1 131 fi 132} 133 134 135# Make filenames safe for transport by wrapping them in quotes and 136# escaping quotes in their text 137xorriso_esc() { 138 echo -n "'" 139 echo -n "$1" | sed -e "s/'/'"'"'"'"'"'"'/g" 140 echo -n "'" 141} 142 143 144# A handler function for xorriso_cmd_and_handle_result 145xorriso_reply_to_stdout() { 146 echo "${reply_array[*]}" 147} 148 149 150# Let a handler inspect the result lines of a xorriso command line 151xorriso_cmd_and_handle_result() { 152 # $1: handler command word and possibly argument words 153 # $2: command line for xorriso 154 155 if test "$xorriso_is_running" = 0 156 then 157 return 1 158 fi 159 160 handler="$1" 161 xorriso_send_cmd "$2" || return 1 162 res=$(cat "$result_pipe") 163 ret=$? 164 if test "$xorriso_will_end" = 1 -o "$xorriso_is_running" = 0 -o "$ret" -ne 0 165 then 166 test -n "$res" && echo -n "$res" 167 xorriso_is_running=0 168 test "$ret" = 0 || return 1 169 return 0 170 fi 171 test -z "$res" && return 0 172 echo "$res" | \ 173 while read line 174 do 175 line_count=1 176 while true 177 do 178 xorriso_parse "$line" "$line_count" 179 ret=$? 180 test "$ret" = 0 && break 181 if test "$ret" = 2 182 then 183 return 1 184 fi 185 read addon 186 line="$line"$'\n'"$addon" 187 line_count=$(expr "$line_count" + 1) 188 done 189 # One can now make use of reply_array[0...(reply_count-1)] 190 $handler 191 done 192 return 0 193} 194 195 196# Execute -version and let xorriso_version_handler interpret reply 197xorriso_check_version() { 198 lookfor='^xorriso version : ' 199 xorriso_version=$("$xorriso" -version 2>/dev/null | grep "$lookfor" | \ 200 sed -e "s/${lookfor}//") 201 ret=$? 202 if test "$ret" -ne 0 -o "$xorriso_version" = "" 203 then 204 echo "SORRY: Program run '${xorriso}' -version did not yield a result." >&2 205 echo >&2 206 exit 2 207 fi 208 smallest=$((echo "$xorriso_version_req" ; echo "$xorriso_version" ) | \ 209 sort | head -1) 210 test "$smallest" = "$xorriso_version_req" && return 0 211 echo "SORRY: xorriso version too old: ${xorriso_version} . Need at least xorriso-${xorriso_version_req} ." >&2 212 echo >&2 213 exit 2 214} 215 216 217# To be executed on exit 218xorriso_cleanup() { 219 220 send_end_cmd=0 221 if test -p "$cmd_pipe" -a "$xorriso_is_running" = 1 222 then 223 if test "$normal_end" = 0 224 then 225 echo "Checking whether xorriso is still running ..." >&2 226 set -x 227 # Give xorriso time to abort 228 sleep 1 229 if ps | grep '^'"$xorriso_pid" >/dev/null 230 then 231 232 # >>> try to further confirm xorriso identity 233 234 send_end_cmd=1 235 fi 236 else 237 send_end_cmd=1 238 fi 239 fi 240 test "$normal_end" = 0 && set -x 241 if test "$send_end_cmd" = 1 242 then 243 echo "Sending xorriso an -end command ..." >&2 244 xorriso_send_cmd "end" && \ 245 test -p "$result_pipe" && cat "$result_pipe" >/dev/null 246 fi 247 test -p "$cmd_pipe" && rm "$cmd_pipe" 248 test -p "$result_pipe" && rm "$result_pipe" 249} 250 251 252# ---------------------------------- main --------------------------------- 253 254# Choose pipe names 255export cmd_pipe=/tmp/xorriso_stdin_pipe_$$ 256export result_pipe=/tmp/xorriso_stdout_pipe_$$ 257 258# Check the program whether it is modern enough 259xorriso_check_version "$xorriso" 260 261# Prepare for then end of this script 262trap xorriso_cleanup EXIT 263 264# Create the pipes and start xorriso 265mknod "$cmd_pipe" p 266mknod "$result_pipe" p 267"$xorriso" -abort_on NEVER -for_backup \ 268 -named_pipe_loop cleanup:buffered "$cmd_pipe" "$result_pipe" "-" & 269xorriso_pid=$! 270xorriso_is_running=1 271 272# Get a sign of life from xorriso before issuing the loop prompt 273xorriso_cmd_and_handle_result xorriso_reply_to_stdout \ 274 "print_info 'xorriso process ${xorriso_pid} started by $0'" 275echo >&2 276 277 278# Now get commands from the user, send them to xorriso and display them 279# via the simple handler xorriso_reply_to_stdout() 280while test "$xorriso_is_running" = 1 281do 282 if test -p "$cmd_pipe" 283 then 284 echo -n "xorriso> " >&2 285 else 286 echo "$0 : Lost contact to xorriso process $xorriso_pid" >&2 287 xorriso_is_running=0 288 break 289 fi 290 read line 291 if echo "$line" | grep '^-*end$' >/dev/null 292 then 293 break 294 fi 295 if echo "$line" | grep '^-*rollback_end$' >/dev/null 296 then 297 xorriso_will_end=1 298 fi 299 xorriso_cmd_and_handle_result xorriso_reply_to_stdout "$line" 300done 301 302# Prevent set -x in the exit handler 303normal_end=1 304 305