From d73f28ee4b6073b957346802de3343302e6ee26e Mon Sep 17 00:00:00 2001 From: Jesse Gardner Date: Thu, 15 Jul 2021 16:53:06 -0700 Subject: [PATCH] lv_api_do now contained within qq2clone as a base64 encoded tgz archive --- gen_all.bash | 17 +- qq2clone | 129 +- qq2clone_installer.bash | 1403 ++++++++--------- qq2clone_noarchive | 3186 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 4034 insertions(+), 701 deletions(-) create mode 100755 qq2clone_noarchive diff --git a/gen_all.bash b/gen_all.bash index b704b3c..667ac17 100755 --- a/gen_all.bash +++ b/gen_all.bash @@ -2,8 +2,7 @@ # Generate all files that need to be generated -declare -a arc_files=( qq2clone lv_api_do qq2clone.1 - qq2clone_completion.bash ) +declare -a inst_arc_files=( qq2clone qq2clone.1 qq2clone_completion.bash ) declare -a req_files=( "${arc_files[@]}" inst_fragment.bash "lv_api_do.c" man.pandoc ) @@ -24,6 +23,18 @@ done echo "Compiling lv_api_do" gcc lv_api_do.c -o lv_api_do -lvirt +# Generate qq2clone +echo "Generating qq2clone" +while IFS= read -r line; do + if [[ "$line" == "#REPLACE WITH ARCHIVE#" ]]; then + echo "archive='" + tar -cz lv_api_do | base64 + echo "'" + else + echo "$line" + fi +done < qq2clone_noarchive > qq2clone + # Generate installer echo "Generating installer script" @@ -33,7 +44,7 @@ echo "Generating installer script" echo "# This script generated automatically by gen_installer.bash" echo echo "archive='" - tar -cz "${arc_files[@]}" | base64 + tar -cz "${inst_arc_files[@]}" | base64 echo "'" echo cat inst_fragment.bash diff --git a/qq2clone b/qq2clone index 700a80b..13007ad 100755 --- a/qq2clone +++ b/qq2clone @@ -137,6 +137,20 @@ return 0 # closing lv_api_do into something that must be managed manually by the # coder +#=========================================================================# +lv_api_do_check () +# DESCRIPTION: See if lv_api_do is present in the expected location. If +# not, put it there +# INPUT: None +# OUTPUT: None +# PARAMETERS: None +#=========================================================================# +{ + local loc="/run/user/${UID}" + [[ -e "${loc}/lv_api_do" ]] && return + cd "$loc" + echo "$archive" | base64 -d | tar -zx +} #=========================================================================# lv_api_do_close () # DESCRIPTION: Tell lv_api_do to exit and close the extra pipe @@ -195,7 +209,7 @@ declare -g lv_api_temp; lv_api_temp="$(mktemp -d )" || temp_error mkfifo "${lv_api_temp}/lv_api_do_fifo" || fifo_error exec 4<>"${lv_api_temp}/lv_api_do_fifo" -"${QQ2_DIR}/lv_api_do" <&4 >&3 2>/dev/null & +"/run/user/${UID}/lv_api_do" <&4 >&3 2>/dev/null & local check read -r check <&3 @@ -438,10 +452,6 @@ read -r check \ { echo "Is the database corrupt? No CONFIG table!"; exit "$E_unexpected"; } >&2 -chmod +x "${QQ2_DIR}/lv_api_do" &>/dev/null || - { echo "lv_api_do is missing from $QQ2_DIR, or has bad permissions"; - exit "$E_permission"; } >&2 - declare -gA OPT declare -a opts local elem @@ -3137,6 +3147,114 @@ echo "$str" return 0 } + #-------------# + #@@@@@@@@@@@@@# + #---ARCHIVE---# + #@@@@@@@@@@@@@# + #-------------# + +# This section contains a base64 encoded archive added in with +# gen_all.bash. The last remaining section containing Bash scripting is +# ENTRY POINT, at the bottom of this file + +archive=' +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 +J/030Ir0wABQAAA= +' + #-----------------# #@@@@@@@@@@@@@@@@@# #---ENTRY POINT---# @@ -3148,6 +3266,7 @@ if ! ((QQ2_NOEXECUTE)); then #Ensure needed fds are not in use exec 3>&- 3<&- 4>&- 4<&-; + lv_api_do_check open_pipe if [[ -n "$QQ2_DIR" ]]; then : # If already set, use existing value diff --git a/qq2clone_installer.bash b/qq2clone_installer.bash index 6ef826b..ac509bf 100755 --- a/qq2clone_installer.bash +++ b/qq2clone_installer.bash @@ -3,699 +3,716 @@ # This script generated automatically by gen_installer.bash archive=' -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 -WKAKUqhSS94T92tcQpksinYKMqgz9aG30Ya3VcqsiH1W7+r99Y7SGgZE0+qgbGLR4s2PjmJ+0eEd -rje6w4uj7KpuFHXA8agMUE4Sd39GCqqDbzx7YeHwwuPKPb69ZSwNpvT44bazQGc2WU2ogdFOcT6F -9lAqwdB3QCdR/qLexP2O6Hkub7pR67UoiPy4NNgZdT5rvglWafE7tJOgNnbxXIvhf0ocKnxFsp4m -zJ46vYBLNMiNMKxaLyIMM4lE+QGM8CpHN5zNNLOcOb7xSWQDLe7Ojd3r8jkzwca6so0MmvwgEMzm -qfyA6y2aq0j678eFS9RKIRhMXQW7lR3XKvINrHRAbBf3k4x44sdE8fJvG0MlWf/06flzHw3Pnpk9 -Pb8r9SeisojRK+pwnj4z/ZHpY+fnp7WCBFS3f7pFxq7sCylcqbP6Ah5RwFb7sXLRGx5A4vjAYfhz -EH8dhF+HsAKMsErgQSNRRPWI0qiHQiFvCuMRNhGobBojEq3ipfRDFX5BRsGXZ86cmp54Ymu0zJqi -WhXSq13aRPWGw1IqpUzB0Z80ZSS/XGslnV+pf9gqtNDxfsd4ViVW/FK331qiF8LlG3qC74NVcglK -rnCMu+Mw4eg49xfuo4Oc7mIbY/B55JGH8LvyyENj9jd8Dh4cHxvLVQ6OPXKwUnl4/ACkVyqPHDyY -C8d2sU/600dnv2GYez4CqnJAvu3e/wX9/MD0yRN79+zRz/tyj+fw6bXv5ucjkv7qEVPmSO7R3Dvh -7wdz35+7A55vs/L531/a637fqdvhcvfu42f/+wM593uP9X3bgPHMvMP9zt1jyt1uPfvfD93lftvl -qL1Q0r3v525zv+1yODd3lvj5zknvW8Y5ts8tt1fK3Svl7p10v3N73W81n7fJv0elPv/b775f7iOS -z/8+nnO/1TDnfq9Xv5H2zkq599zHz/73P86536q9p6DcHbmdf9TynpP2stbhjb3ut9pno0A0PHxw -tFkvAbbXf7H04qMPlx4+WI7b5XHdL2wD99STp8/jcryKaWo5aYzyjO+fnTh6/tSP/0b79Kn7f+B/ -/NS13+m95/88rurYI3lykl8tsXp+f87sp1zup3Kf2HMPpamzMfKXfvQDX4z+9frq+eo9uYzP/wr/ -vjslfXpPevpqRv6/kpH/YEb6XEY9/z4j/cWM9MdyZi/Zn49ltPu3M+qZy8j/32Tkvyuj3X+YUc+r -GfU8kFHPbRn1PJCR/mMZ6e2M9LWM9J/ISB/NSP9qLj29CvnfBbvxniP8rM75D0F6PiX/Kckfevlz -QqTjCRvLLc3On1pCOcUq+g3vzp8i9ybzqLeSW1paXW+3lthH/xJnTc0I1bGa65NR7yOnTh6P4pqT -drq6TpkkqMMZQIKtx2MY893Jjx7KmVhzklG9z8o4U41PcUBzDE1AWqPm5YluZDeJxihTzSa/i022 -k+32xX7n6KbVIkxPDefm4Rximzl0lgozAZOAbvvWLi6hsX8OMPImEHy5uAf0aq4DBXsr8NDttS9i -Wrvfy61LjqiHTILl/kpulX9CbbUXq0srqBHT+FiExWrrHUjFlmW2sW+5FRzDkydnjx5bGi8f1L/G -yw/llJrBWPmxcuWA9fgorKl5qpQr1tNY+YBTEOHrXoB7t8G/2+HvbTmGq3dQGv56Wy5HT+a/O+Ub -4eTeXLiH4Srij+9pNN6JUPpnJa3//sbbsY5fFEC/B97hTwU4f6d28W7clf9S1fEL3wCs/m2535Tn -yr/A5ztyX5bnA/8HPt+We12ex/8ZPu/NfUfq1/eN1P/qu/n7Hi/9E5J+p3cu1POXnuBvvAPebp2n -16z0u6z0q1b691npr1vp77LS37DSv9dKV+ca77n3W+mhlf4BK31M6sE12mOlP2ql2/fbESt9n5U+ -Y6Xb+N5ZK/12K/0jVrqNJzxnpb/NSl+z0u+00jtWuk3OvWilf5eV/gkr/R1W+l+z0t9ppX/KSr/b -Sv8JK92+xH/SSrfh7z+w0t9tpf+clf4eK/3TVvp7rfRXrfTvsdJ/zUq/10r/gpX+vtytz63Prc9f -5M9/ufv7/2Tmpd+/c+aTt//HUQC7P/Jqb++1L8y89Ct3fpbeX3voT8q53B9d+9CfwtfdH6T8a/ji -j77yH69du/Ypet5Dz1/Uz3vp+TP6eR89/7x+vo2ef0o/307PP6af76DnH9TPb6PnF/TznfRc1c9v -p+en9HNAz1P6+bvouaKf30HP9+nnd9Lzu/TzXfS8Rz/fTc9/+B31fA+PXz+/i8evn7+bx6+f383j -18/v4fGrZ5jdRZrd47we8Pw3S+7zK97zj3jPW95z33te954j73nRez7vPZ/ynqe950nv+SHvueQ9 -f8h7/kve83u953d6z7d7z98uus9ft58r/+/sy198dublL8+89Luvn50/+crt98OOmHnlnT8b4Nfk -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 -h2+kIw7uMzzePR87l9vz4j17vu8db7sT28V04stDP0fx+/jbaGnh9sghAj3yB9euPYcI5F33nLjr -3r9893dt3PmJ3BPvn3jgwBCJ7bD8Avx7DsZv7wlMxwX8yH/m8aoP8oiRMNiE9vLI75m+656/uvfY -O++QfuB8/gDAM5ItqHenobPy/tfg36UB75HaXM94j23fCX2pw/sP5ZJtD+3JLovvj0vZrPd1eH8B -3p+w32+Z9z8M738Q3v9z+/3ef0IZ8P1P4z74ulxA+v3P6ve/Au//Kbx/9x7r/b5gD2bA978L6T8D -+yR03n+vfn8b7Iefgf2Td96/T78fgvf/M+yrdznv76T3qNdxHN7/A9hvpN504q57/ru9s3fd+9/u -m74rfOW26btGfvT243eN/dU7Zu569KW3PXnXkdZdj07dNTZ118jRu8Kjd9179K57jt51J8EN3K9f -gHpsucytz63Prc+tz63Prc+tz63Pn9eP0stReji2vrH9HcoPreshyLHS8Rj5fv5WuhFK/0fp4Chd -E6VLo/SAPuC9//p3rpFK/k+KUozCqf6aKLcoHZcvyHulq/IOIeeUjorS3bB1PvCjdG3uFX0ORQW+ -IeNTdIXSmVE6QWcDN/25t7v9fl2+lY6Sal+mRecDcobGt0eSviPPX5AM1+RZ9et1ef5xef/H8mzr -DN3Mj9a39j5jst5H5PusfD8n3x35/oR8f0q+f1K+f06+X5XvL8j3a/L9uiK2RDnrHvkO5XtMvo/I -91n5fk6+O7ZS13V8lJ7Zk8eOTYQj55f7rV4/fKx8oDxWqjzSp8fKx8fHymMHC5y8gzr3werem7JA -+2BVH01N36f1zt3023JXUtNv1+fDTb9Dnws3/W36/Ljpd+p95aa/Xe9HNz3Q+95N/y59Ptz0dyQZ -K5T+zlyYmn5X7hMp67gvd3fuU6np92h7DTf9XRoeuenfnaqMvC/3bq2H76a/J/dqavp7NXxz079H -wzU3/XtTz9U+gBIKDrnp7zOGJE660Td2078vkcb2G394zU9H+L0X5u2ed7vpd0n6ES/9Pkn/hJf+ -CLXx/tzIEdMefk7Q7+Q8rEs9r3r1bFL+5Hz+REb/s8b10/TuPbmFIf9Nev5/QvmT8/9rlJ5cry/S -3/cmxvVlSff7f2Avjje5/79Of5P77SO3oZ7jPblfl/nJyzm+cw+nt2WJ8zLR78vQV5+Q/D8mF+u7 -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 -ufX58/r5/wCd49nvAFgCAA== +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 +GaS7OTlTuPbNN5n1/eCmn11dF6+ftlUlsu0/bPVBb5Dr3y6vK7GBGpncz1Pl9UtUzft18nFxkDey +7fxODW+Lg2Xtzl9LZHKxaK3iS3UT7cR19NpcL6J6NNVOz0f9QSnRTKSy18VNcd1Z69F+KisXKplc +ahXXBgUjkuh2s+3bjTwn74e1W/99iXzXHwx9qVbCiKZL6b42S+U31XVpQD5Ur4vB3FZpRKqL5m6e +1Feju90unMmHJsna5XylP+YWvaS/8DiJ9xKprf8pE0rH7uYvvt0mWOg/PSlqLVdItO9GETLp82g4 +OQ2+TDPDjFqvjpo3s8RMvrkpm5uM/+YxUi30d+ObRbLoL3RDVU1eJ8NmorrMr3zB+UCPtoNKO5iJ +Puwa/kk1tRw/JfP+7Eu5uC0mpnVNnsvpKalwvMrOx6P1XI43dvNGeJwsd+L3oak8ziUzcUXepH0P +c3+5HWzqu8iscDmJNiK1jpI3ruVFsFjNBFeJqjZfTSPDVtQoNfKxTHReL/aLq6yZXfof/Ncvt3qs +E01r0/5d/6bta8ib0egpsUp0Jo3qZVnZBf13/UpLLjdalchyejuvPpb64/Tmqb3adSvRUDBdIvul +0i8ajUlsnFnGoqac3j7NM4PrS19/3Lrp7uTMU7lybwxHNxsj2Q7Gc/XJtWa2x/HUUk7U65O83FJu ++3KjMAslYvHssKKuN3I/lpkknvo3j+3VTXeeu3/wDR5L6274ujxuK3Xy5LJdjF/Phv7Uzd1MD4/D +mXJrtVk0+hutVZzcKPoiNerE8rvKolUuVOf9m1b7uhUNkmMb6s2qvkgtlO6Xs5XeOP2oyGFVe9q2 +Yt1GVY0vttfV2/6oX67msxF/QW7EcpfXveDgtj2fNJfKaDNIzIPj+OghP8qkbgvyoOa7XLYIl9Cq +LSqDRy3b7z2ttbvL7nAXug1OQk35pWrktbv7bXWpJZq92Xgzad1H70bhebVUXWZjl9n4brzbxFOE +/8kNfOTyr6rXt6tHZXBTW88jLzfqur+ptS4vl/3wzV1GS0znT5GRP/mUWYXTnehNu9DPb9ab2/vH +xDpqErl7Fp0kdvUZuZZ99/VC9/Ypp/hTd+pkcWuGssq8M9fq27vB/LEeC+Z3veuokproyXShmimZ +02w7mZxl5G6/2lP76WKoZEZnymVtqzX7vttExx8xGt3MMlsJZkbVzXzQvMtmtWnw+rF96a/UZsly +4jLVDtYH68nudjaZ9MqtyfXyVn94jM1TjSfjfiOnF5mwIg98mawZuunEOo27cLX50FOq694uXh4u +NneRjSGPH/XYtSbXyzO5EXppP+b1l9hj3a+mCzl1mQoWehn5UlVm/v7wKbyVfbtJ+HGpzOadVby0 +zE2MZXuSiRR2/fo8rCUyZX83qRMC3Un1M9k8ISXm0+0mtCNStHZ7rU7XRi+2ihazOb0rl+6rZDXr +9evVWE8VEqHdejB+Ko5mWTX6uO2WBpViZjdKpdqP8jh/00m11kn/Q7R0U20Mi8ngNmVucoXWIltd +Kt3hMlRr9XxNs7zWg7o6XWa3uc2q9aTrwdvqy7yamoZSK70SiTXHL3qratRi/li+3F30H2/jxWlt +W5tNYkM53W+vE9N1c9Tq3RR9+c56kiXMzUAO9mfl2mhW0lVyH5aqtduXwe3gtjssjDOhTFYbPqYS +w8IgGskNuuvxZTE2DqViS71j3NXl9D2584Z+330hnlUjL+t+cpHNXcv50bibGpHCdzdP7cnurqyv +m7tqoeAflnNFct3NL/Phx92jWryObxrBp1Atmatukxlyc04jOV//UctF9dZTcJJMmKlSonprLuO9 +7KKkpeaN/PZ+UbvOmLn4tZImvMwg1u3u4q2bkTy6TxrKuj9MdjKbbnejqOWn26rvcRR5WO864+Wu +RrbdJBkPjxbT8m7SC+aeWv6YcldVN7v8XT9llMd6eVtsdGbF5CbSqJsVuQZUuykXb+8SsWacCMXb +xUPvKVJ60le1mq6v4/7xtionV/NuddfPVzZyNj7VE61auFUohpTry/nTdJA17xb9WTe5e4mt0q1a +X7uf7nLT+FPBF7pPDl/8tVh3HL7Tw/5uQ+tnG/fVbXWynm7v1VlwdLOYGZPGxMjt7ieD0mx+e69k +9V0mFbm9Cy0K7cV2Vu/dxMPRyNy3ySjJYahuLKv6QzX90qs2VhX/wlyYj4nZ5ebxpZzyLzfhSrAx +HhDiM0nowRej3Nr00ql0b7aWX1bXEUIdoslbWXnypTf9xmqR8DfWxWDB2N1v+6NYr5B6CE51LWqW +Yy0tVo1NI/HhdlWoNqux3WUzHLsjbIjejNwVo/NLcoLvK7G+fnfd8uXXdXmV3fVy8tCM126i6iw7 +Xa20lt7dZe/73cunTCberY1uwqa86RUvh5X2WplPQpXo3azVTI8mxbqibvrzQaVWqfuW64xe9cvT +RD79tEsSMqRmM+N8Iji718pLM7HJdOb9ZTebVJeJcTVf6zfjT5dB//Q2+7JbDUrlSTQ5MardQeju +vl3wzYezofxi7AqhRq04nt0Gc+pqMcxvm8rjOFaNd+vxQUbX4vF6cFpa6zW/tpmH/Gr0aRCbTzI1 +o7rxy5VRMTJay6WEr3I7r2RnvXU3+zis3JUiy4w/2osO8rFK7Sm7SOXXDw9EUrkt1m438242Hc+X +2sV8ov60HpTNYnuudpORh2pus0tE7rK+drEbvu3FtmazO72dRjrtx/miZyTXm8dgqhNe+nsDRQ5u +H9r99WMsfxvf3JUMPRLuVEeJ8O0upjXzu+5ENiuth1Vj6XuS04Vtp7oo+xerRH+lXjbNXu9yGF4u +Y0H1MRlc9KtZfz10vZ4vR8nZY3QqR+Xb2/Ky3FLkpDZuhvqdh5fbUFIfDG98hURqR/iweWL80o9c +RkPd264ySi+zHbm2WC1SyWzBzD1G66uEGqzUdd3UR6HyYKGr/eRo3qs+DW6bckzOZuXuYyPt6/b1 +8VhNVcu94HW0cVtZ6fPBy2VsnS617xupulxYz+O1df4+HqqO74tP0XFc01K5TlSL9PL35W3k+vJa +a236L+PqfOSrtjO9m2hcT/RiqU1B1o2HxXR1nY6FN3r9Ti+Si0cvdY1yc3QX7+fm4UZjmb0tZxr1 +xjK36vW76XatQ7gTdRHKLlM+coFkMnn5Us7cl6JEEE487trpXa29i1ynputsMl2uEY5pTIT/lJwa +armHQWPYX19qyks6WSoFI6ltOO8PrwvxVHDt09R1Xh2bpdYukQsPEk1/5GYQifY622AvlWib2Wnj +IbmZLeNPW2ObfHp4LI5Wd6b/NlG6v3yIKTddZXdtbtO9cjrSrfqG1/7BdpesLJr6OhVvmIty7iG5 +7OcS/ng485LuTKcxOdLRWrFiqWfqiYw876Xk7r1/0M53BxnDr/Xb07SSqEc3asa3esr0W0Tq2oTJ +rdIdEjLmr05r1XxiF3/cJUaR60ZMH3YLW38zH135u6Puahu+aSq16OXWvL9+lLc5dbQrbtqzArg0 +d7bX4bp+KzfScl5tlDV9LRfbiVqsqmbka3UUqa6N+25mextJybObWqRAOCIzTXanWpNT8jQ92aYj +uduXdWrxJPtShAEOZmWjsppNZ+N13m9UmsG8n4hus7ZSLbQK1UQ+nlOnFX3W2lZv/OOBUquu28nx +w2al6I2WXHyIbVudcGujRHw7Qryjl0rrMpE0jcykv11VH8uDy1nnstOqz9addlOZb0NP6tNltR3u +6i+ddCtUHi2fypFruVrL+TeVxLYbnix3ykPMV77tz4JTwvPLyXY26W+v5f5wVF2W6w+LeS65IGN9 +Wu+qveg0l7y+6yU6635fTmSC0f5d4jYSXGWS66w58Teaxna29d32ExsitN5UQ+XkJBxaRttmtzlO +xSJxs7HJXc7919HWat7LRKqV62wyqd8nOuGunI6s09OHqhwjzFy/lMiErh/WesinZtXrlblujquF +ZGO8kXPDp3ImFJs3qqFS5nYxlVOz2eSmkCgmu9noJjlMrCqlnNwtyfeJWafjD01vt8bqwXiKdG81 +33W8khynomtVy9Q3m0FyWxkUtG33Mf/QCg70pGF0Q0+3jzvlpn2/fTBWWm7yeHlTCbbKkXYyT2SE +UtLstiP+5KqzSfqmm0WdsCWzze4lb8Rvt4Og/rid+Y1e86Xb6vUa/uwqamYz+nTWWhRSy2DcUIxl +tt3pxS/z3WQ6+dDPdTvtHeF4yT5rV8ab/k0kEc/f6KEXOagW8g+E649qvc4q2R8ksKBSLA3rD+ld +sB/Wi4Ny5qG+qK+Nl/pA3UZHbSJ3BZPtF73sq0cWiVqvU95eK8H78jKvJ7pt7enG8N/cmn2zOp6G +x7vZMC6XK8uoYaSMNTkm1U500n+6zg7j/ciNf7XZ7gprdX459gVjjVJUnncy+az+oIzzndp2Ne2n +9JtmdBCtm4X8xKyrD8F4NbZWtu3WLF8qlnbR8eRpK9d30d1cW3em5bjezgYbYV+6HN7UFk+TUMT/ +EL/p38ib8XUpudJvq9PePHezCq637e2lXBlXQCORmG8fkrN+clkfyN3Y9OW6/dDeLh+X1Ufl5Tbq +m2bam1ZjV2usd+GXkFxNXidn5eRTYzH37wb96CKdbBPxc1Be74xS8qb8GImtY6vB0+NqlAuv/c3I +rh8s9WP316twJurLrHeJariSikZKTX+1md9MtaQ81J9a60QsnJ5Xk4mdf7ZsdzbDaNRfrRaVx3LS +H1af+rp5L0/ns1WsE4tFluVEYvfk20Zm5qyvxdTMfOrv3cSatU7c3OiD9Kq6K+SXtUqpuS5vQ9G0 +sezm10+pVbKRqBeX/USzbuzml/7oZD6Tg53wuqjUfBu1N79etmKhWkbeZHdjchCHiadEKJhLDjT1 +4Z6IR3qxWO/NU+TT9l1o2F9ESis54e9U0xMzJBvb1mW/bT5WL9Wdr28s+3eyUZLzu+JkFexuookS +EYPyxqJgXPbvlsP+U2fZuRzrmc3spePvPV6OmqmG8dRepJur1uW0mIn2mqVRv5cwt767DNkCfaV7 +WXmQK48qWZzLeWv8uMp0itty5jaxiN7070qr9m5VnAZD/v6gH/On5PXtdJlo3DUvq6X8LpEdh/zb +Uqbq69bKiUgq3S9106ut0g6FZ3fz6m0i31p2lXlltRinp5s6Yce788YoWciq+qYY7i3vmpXVoDba +yS+XtViuRyhuW080fOPuQ7Kq31d7953MSrlJZVepy/Ky0Fy3Zq1EbtbSyt32SJ6H1UGpftt5bPe6 +rUT0MdPWo52Mmshlo8Xt4EUd3tfkXddXijWL8XCkG58tNmoybGb6w1RQ7czM8aJtXKqm0b7pqJdm +ZBlfLsO1kEbk5067QYifkjYS/nY75ScSYTbdIVda0tcZyLt4eP44WpXGkcvbhPZ03W49Vv27dDlr +dtrx+116dN2frzf3l5FQWbmrhy8nqWB4lItst4txfza+byRjqXLHbxhPPsLSZOr9ujYpx4f9u4FW +VELpzii5Gw9W+dXlZX0QbMVvY9d6b9d8qUceltfL5ENyG3kaz4q31w/3+XFTH99psznZI/c+/W4t +m41W8UHNFYJ3mfmGSBH5aSLb3xjB6mh10yw2V6PVMDvN3wyCfnW7udttjMbT6j62bM+Ll9sJ4fuT +KSL132QKvln/IdR8GWRfZkm9028tyWzpRDLrPz02Ne2lPzKrmeHjfa6idOex0VK9zKRf2rF+Q3lI +LRLjgTGKT8uJh4nczz36dz4lPAy2r+UVEcqWlXxNvb5/1K/LsWJ12bvbyE9KOLTohv1GMrdb7abD +fCdVij8mb4rDyuWNvzBqPAQrq8dE8yFZykc0X1GpRCbaXbM4MEr6JBXdhsbFSsqYL1s3LTX79GjE +LoPBtRzazh+0YKfdC91vycmZkC1H7r3QeHNZK9w9xtq1/Dya87UbRi0efKg0crXbSlEbv7yUIrll +sLy5bSRTer2Yeewkcs1M7740bIVCjaG/qNUn/XY0Oo4UoqS+QWOttR5u741Rt+Yb+StVuVEcX7cm +RrZ6O6y3O62b0O36TrneJJSHcSWhLaNarhLLkWPSTTdWy1Ghfj8vVmqFZCdXXCa6/cb/a+/au5tG +snz/XZ9Ck+YM8caPOG/oZmdDCBAgxMSheZllZFuOlciSsawkpsN+9q37qirJMqHZ7p3dc6KZQzu2 +VKrnfd/ffdr67eGz5sPP6tLfGT5v7mzsHW4lR29fNTcPdrdfXYWjnb3Z+vhsJ9no9541Ds+eNjdH +h43TjYcnM//ZxdVk/GX71fv4XStu/7Z59Gav8X62MrhQm/3exsqbncHL/Xht8Gz9/G3S2nk/uOhu +tBrvf9ubPN8eRFtaP9uJ3/UuRjtn0b3Zk61mejZd6SYvxhvBu1N9jjdb73fenuwdqHtPBsHKIDkc +r1/eO5/1Nhtxb5hF3YPm4HTr0efB2/bKm7eN+HJv5dQP/Y17/orf3ApO96LZ2r0no8HrwfFZe7T+ +bOtib/3pc9VcbUUrradbg43G++aXJ5oq3LuaTftnO5vhy25rZ2P/Ymdt93CykV11Z2Fy1mtMV95u +t6Ktx897/dfpo6i12bgaPzlpNbdWNUN5H6y/b2WPzs+ag/WVZ6uzq8F5Y/vq/Mu9xuDo7ZsXwy9v +vkRHvcez91uNL+uHW2/vPX+70ejNVtOdwVry8Kx/8Pjhytto66R7sK5W4vTd8cWo8aIff+mfjI/0 +BDw5u3fVaK2erD55v3ERrU3iqJ3N9ERFK+Eo3GyGzdZaa297P1sZt1YPk8nTtxfng8uL9cGe2n62 +fznYGK61DjYar7onKzsXweHhxN89b8z2Gq2Xh0F8Mb3ovxl/WQ3WNrdGB4Peo1dbaSNtbw7vZf6r +i5XZNFrpXUy2+l9W1NGpZmdR87k/et72x6N7cW/1LHgYPzk9eRGfXT4fbj958fndw1Z80n82ehrH +Ky9O3lxqqXgy3HrTPtUfo5Vu++2z8YveStRQzxqr66sHk9XL3Yevdnd3H6i73/b75l2oN7t+8/7Z +m3200L7jDP1L2i/2X8COAbvn5dH+2/291yf7JjFeN/fzfowgx1QDxxv0KW0dQjPCGOKLJG9nHYKi +13/V/2zApw396RcsF3XxyR+Hn/oJYaYriEUKYgwUMeF0GP/K8EGFYDrIUjgYeH4E4SUzCydowD4E +KUgizRAe+venR4f79//xtVEnzCADilNond8Jie6/8lMlz1RySDr2Gb6fA5xq5n7FEWYumJLueDa2 +NTYxKevTJIs/4Q+c73HnHxQZdIrFIbEoii18682VvP3p9vrXXrLi9eZf945VfW1tbMB/m9ubq+5/ +9bW5sb659VNzY3V7o7mxsb2mv282t5urP3mrf12X7JVBFVvP++ksSNPgG/fd9Pv/06veWfJ2s2kC +QHY9TPI8DWJEDsBY7pYf95Oet1bfVPpOVT956i1p6oHYvkveEmCHPA66kwzAnddW1+BvS6eW9APD +maq3n3oAI6zqrZYyIW+dmtRLg3ixkR9DsgvgaTae/3bo/XaYahqZK1nigjyrz73kco1ALFIKZO9y +EUIsO4jvbL97edRqH7TxvZ3Bh4cf5eX6j+OP3gf9n4OPRxjHht987Py9Xq97+PXe0eHh7stH+L2i +OyHVyN6Gr3Ai4Ra9JUylGh/iPCBYg0RaThM9qvOA6r1hwW8CSXRhtMyUmPGnof4pqKuHM5kiLNA6 +nkEwJwb+egPdHrA8CLWlXGKeMKq10q/aInXKhZ2CXmW+wYoQrHssbyHB+WHs96GKMVUD9KNpgLF8 +iHbLqcKMLrKMC9PzL3RvUlhwgwWF8/Ti4PDgZBfmrk3TLNFWmgtCQQKA4e986H3+ODW8c+Bz/XNs +eZhc5setLpPJeVqpl60DTHRqZ9psOp5AU4SRpxd3WTAYhL1QD7S+aHU5ttNpOM5GwSTJUqcMoJ8r +wanGwQQSFuDmLkSYgjRB+BYpQxSPYLIoWULWN0AsdcpdUiWA6pTnrW+qKwqKg1FAlKr+SU/KIEou +U4TuiC4wIQViawXZHPpYWPm0qhhYeQC15yE8mEaYxA0EsslMIlXxSZqrk8QL/DTUO0Tf7XejMB16 +pxN/PAyx8oMJMcZEDL3ak5IeuOVRUWKCWzqciAwp8JjETCeRjjGd9ZcAMa236ExixqFmE2zzwQBS +cUNT0hghTABHBW/muawrxgGkbSJtcC1OCOld3BD9ic2oboDxgYiW0rd1UB1wUQw+r0KkMK7WzN7U +h7p5MwRIxRFRyiPJrRg63/eiYIAERB+54ZTShvBjpzbEhBd+AuBfJmE/UHB//jfYKYBQDWtkUGUg +VFHPbKf2qtGpdSRBvspUBOkggCDT7u9i+pFCSVDmCTKkKYMI9h0MV+/uCFbppKXqD3XLvaoHTds9 +wJT49fEB0VdlC0jHSdyp9YOBn0VuYDrkUt/HfDuccgLC1AejLIHbvHdP3juedSirXr2BkigEw8sV +f+FXXHinUhXSaN9bhso+FaY4A2Y+tvkBNR8nHcrNV48SXEvflgJ3ksH94n5HSpd6bXhUTopeoiNe +v9QzSb4mNSKM8/UfbV9OqS/6zEhndv9QL9KFvfjeHgypB4BOoFqaQUwhJjfsefBFHjo3JqQK+2hs +J1JrF2oXgYD0GtCyEEXIUdUqnBcG6NKnye0uJn9/R3c/0ztxu6u2JuoTLe55o0Tva9yClJmdYPlV +t33Myl7Yfl3tRmmCTALaC1KEFQHmMObi5nDWIMPF6w0TwL+uSqVfxgbgQm2x4g44E5H6A6yJQUcD +H9d/jilT1dZtZ5p2HMBHqH7RpyOfxPr+PD/FsOVg6F+E8KqBN8/v7IS9ciYsmBDPsTAky5xTEs0q +3kQywWG/jceBfluoe9KHkvOAKZJA7WpmcwrIZc/UZ5jvQN0sDgiCUJYal6RQggDmCRMwL8PUpvtc +wmFnDDeF6cB+D4vwGiaK558/I73nvvNbOGdQr5emBEQ9ze1W0uJ7OflDT4JuQI9TbwLsNkSjB/el +YChVVHXqYla5yCr827EIplXG+qKSq4RpZn9W9DWh2AS9c71DcRM50kEE1Rl7AQwXl5+kPqoQDAWC +ZWsXFhKmCfcMjA/0A1gow5e5yARFwzsUfkKbA07vcRabQ4sLYASlHzuoKTUt2fHEOV4c7e1aKZ6o +upX0PC58jfhdWNQQ65OTjArqAuCv6sWWTHuVmgQfrQGVvaGuyr7VRxOrYwt9AljwQi2LXLkKlORs +YQsBoqY0IhkgpBgxGSFg95QrqhCioVNkHepyQ0lKmmbSDPAAwbd0eg01cOg55Q6ZJV848W2eeBC5 +1GstjOEnt+xFXjyjxWaOTYk7iNWW4yzK1lsqMpl337EZptQnI13TqoCuyTsB+ml+1e86DSHZGCff +T936Q7EI2A6PEUFuGSBtT9619tve0WOPFUOTGoJothW39wLycPOcXlD/GWhH7cdYxNGSte/nNLbN +37hNZy1wGnKL464areNfuVxaPC9OH+kIpto9ADEg0mYvIjwtwPxn4nW/QJNJWxLk9mimgNVZOolE +MPcAV1PHCrCMiRg7+q95tq4OYsJ9MIq5JpARCAJReA40HJuDaUGWDcc9i5FCEsShvoPEfWVrUOmB +4F6CcdEk6+dnlq4aQEUhG6hHw+pUFd4Jeo+vB6tVDszSTGfx1L+qq73SSXHngmvWBPzI/UU6LH7F +/XUtI9KQFsUApp5OVMEU4rEtRLdM+Znla2Un/Hv7NH+sS7uzqO9lHdRqIWxm2hOG5ZPuTRIT9xEV +F5CI5hU832wXU1WoS4DxfNjdjmsNagoLFV8A8kg0qy54rV2xtAyBHpVX5WYk5yQ7OkWgIvvAJbq4 +XVgsXNRZIVGqrH58FSiQEcnySwEZ2ywGJaNwOiXJQN2w6s5uXTBwEeADmAFOhpVBdGooGlpDYIbY +9Jf+DLDEAbsrCnshGKN4lBYRXYudWU9kSzzE4TBJ8FT6vV4IpeDw2JJAxSog4t3mdUCyMRjCDkQM +qFjbkF3ahmNHJnN3497r4+P9lyedmmVNwqv237jfKqwz6xQjtIVmy9shJS5XqBlzG0saJ4G1cCvb +G0Q09I12O+U60GY4qBhKgr8n5XrATjWldsZJaHdnCixWBKo0N00EJ1w+Uc5McP3a3EnI32OEVano +ht3AKryi5IQ4EGYyRicBE461zrl7y5IjMgqU95KtDJ3ao6PD3YOX+QU1I6je3JBe5E6tIEQWm/Hu +Ky74VlhnFL5ZW3RtuCXF4HwPixKrz1rTJ8H2u4qrwREFUVkzxoFFRMj3D5QEhPeGY2cUA1wJzfH0 +E25tWSXUP29tEHmMMXUoRVcOAXbET3MbQWGpK3dTFdQlEnexiIVI22SJ1d2aq7GQ355F3ap8e7Jk +nXXBnnQj9zkxdE4M6vCSkAYqJgGiZyxCgIq6uDt1tQ+4yE5FhtCdPSqw8KODIrT2DiGP00SSCcaP +WWcCK2g3EB0roHoQZki0kKjxoxLyjXEs6AHj9rtdqKoFfYORZ4xzhL4Ih2rz9oKSWJMIqHuBfMFs +U4tk6p0ZWHt0eJAKle9MXbWDwPDf0AgS+b1LI/ZjR76CsnTQxinNKKjTIyg57JrCwFKdXBLzQ0/G +D68hY83nFvGAxMw8GD0ijrNNhFeXF7VBZbMmSXY6/FOWkMm1/j95GCMkxMA8wEajdw0hZlgwLFjS +LB5H2ekpcePxcJaC+0CJe4pkfYDG7flAWnrJZJKNBQEd4eQI5h6kEqRJ0O+J3ryqx0QLpStPsxC9 +XOjlIBRgfrywk7C1H18UAsXPLYqt0k49Ze8ACmp/4AVq0aQbr13pPv/hoYC9iQaQq55sKqUZkB57 +GH/4XYT0n7ujKDTxmlm7Ss44jFj0oFMP9BYTv9wPd6dkkpV1ZDeg4o1j8rLY/rjPpGyDbsAnkxoT +HNpvsIx7VtH54OtNR33RTWTiV62rxwD/HOvGYoChBwZLp4BR7NnDWt5SmgymlyAOdWdKDv6fsdOq +9Hbjj8bhu9vZLcFXVekwY3MBiB2XsQG+Mybab/RKfS/nEmdoMLkI0A9/mQxAqh1nkzEAzoFqAfX+ +AIMO/HmiEnh9X+pjaNXLMhA+pXo0emQXYd+xxHcz0NCN3yuUESWkTSnijywQswoFD0YzYTFcmDD2 +5t6HEHmoXyvcUJYNG2FGFC3QUzA6Qywt5BLdZQZlSke4EIMk0rX3TwxHLUpitOr6jjZvItf4lVeC +ivEVL18fPtw/5s3DPMjg/EGFCEevNb5RD1hvFIipCWz+EboDCSGd3Lnuk67izDfZspHg88ITWlDX +0Njl9lWm4KNqT/0J9U94DbF1Z5pwJfCYhWmMJ4zb4mAFOV0kPX+rJVjIvKGNENDQMKe165zpDo3y +6RSLSlAcIRqOJtZw5C33AE0xFvEGhNMaorWzjQLdHI7eXyl4BaGlnK8+TaKgoMORfFE6dwsFDT0H +crYXzsWy/gZHAbEc/bTKKpyoJnr00gSUOAq7YJUDyKMQzDODSq6XhkuVbcUc4yJtZ+BQLnSIsbkY +91O+5augVzp4/ttMOwFd8SuBbFOowaLhQ/k0jLYIQTyqslFaBE60NFJ0kDUACRRmGKMWGOtpT2Iq +V4qaL+FjikHHlDVQwALEKgSofDjs+7ShOx/6nz9imSL8ZCVw+Qk5sv3JfQod6/Y3bxnVVtx+FqeX +++zAKs1rhRSxhK4aEteVKK0Q4SOyJGK3kaQOKE78LBaFN/XxyCqGMcBAZIjwKGGgYgQAG7kp+qBn +k0nQ5yzBEon9JOvaP/XDmlUgaczfF4JqlEKYBzgXe0GFj6YT3NGlijU2MoLpg3TIVKbHsBXyP38J +JonH6F4Y7VB1IoK0VjNO6/P6cJlGqt4I7bUl+yIp9pgzihhcQDd4iXBrFTqf6tiWw0U+RJ8/6mY6 +Hyaf9Z4gDhlQ6zaYKf8ePA7G/FLa4tXIaVFCZ3LSJp5VR5FSWI6Xj5qVAwlyl95dtYPxeDAnYnUz +zk/C74dosGlAli708458VFQEs4/sXnyUFJmdRmKSrBrzMHmFBQ7MWG/dRQPsu7yka4nqMf6G+yTN +0jE5D0xIYJGO5JsdlTf5iEkzzZMQ2HmCPBCSW6l6Ul6aotTAO9Y3djqcStKvL5IoGxWEbN2N2mU4 +XjC+P6czl4yIPN8VphHIlOa6lQ619PVX9gtf8B1zZFy18wKJ/iV35NmjSf0Snriof1CPKizwcHxX +bfHmMOZX62kGk17SC31Tjejb3Cz/OpCoviVsfbstErfg5DhWXFOSj1Qicn/THKRV93QbD7k+Ynr6 +9TnNdY0O1ILO0Y+5AMwbxw0BiSdP948dIdyVPCFGw32bOBZyWu1uiUEU+SerECyDVx0LN5oQcaLE +EqvA4BiBqjPVDOnccx24B0yLhhCVAxMmlnzCP4R3GqccsVWt3/kArVhFUnjwSLGo7T6lZxi0rT5R +WLjPBlqk6DNlHkiEA42HagrO1mwsMPwJV4gY4tKeSMCwM2+mlHsITiX6dAUspaf3R2C5eoihVppx +j0w7pdNteY4Jf/EjjqoEChD2KNSQwFdJSPYLrNEaFzj+hi1bbqV5ckQw6HhBG9ECOfWFIoDmvkao +3/mg9ZI7QfAtuVOZqs5lbr/UYYnC+lnUOA2m9HZirD5U19LCTRb5E+MzBNkWXgubLne4IDmIjkWL +Ap91UyEIuB7+ZEU5tJvkUhGYd4q+M+FIoyrC17MpnQNsld4OGT4EMbEBlgQEtYF3LFVETM2rB/qW +IdEGyhXQqq04f/KqMMezzqucIzSksV+zXniQA3rlAKe2rmMxzBkECydUXJHOYSWiuQ5xbIFT9QIl +LKTHceIA7haf5QkDW2PcD7Vs5kb6A/kEqgZGJvOrMp0Ei/5pLFkhdOzvq/qBXud4QJqBas6l6y0f +cuvNilqvbi/4NfUIo3+7oph8DkJcC3lawtR5AOkQcNxxvJ0F0QxG/K2rYy5UC7EY7LHGXc21aw02 +s17gyyCK5gZVXevUNqudD0P/43pZ35vYNNwEcYYs5K5XVLNTa67yc53adtmTcIf7kL6tOAUv/BSl +yNNJko3TXHVOWc5+n+MK6bQIyysOBI59Yf53naqgFbiBuivCxPxNbM7EvAywdxiZR7kPVmlgCwYL +kZhU7UEac1rJjR3o9ThJ0xD0LhwTZ1MUs1TQmulL6c2huZmOrnIcMiT/sdKKOyhNRuKOY9tcHeQR +0vGsQxNiNucnVPUmWueEV/QjiF0FSTKbgjlTK+kDTSXBM6XGIyOxi01IoahSGK+TdpCfcA6OQFuf +VSPJ5SFpBPe9sB7Uq7TtiExwHaFgSvbDcEA+cdM2bktstK528T5sG2/KNw7Pkndm5EdAwoG9czGP +1APdVBlDpK1ba/CY46QwINd8kUuTUCAfQB3XbMw8xbxFiADGY2HgWpOtnUcvHx88cQLKUHPDbF/i +BWyWJQsDMAlyLPV1a1PyILnRaiY5AoLmUAEtITIcsItkBnRTNEEGHLpnuakq4aaset7QMnBbVZKg +Ji8Tjmyi6Ikxe3OMua6eJpdA2KueTI6Jz3AbYG3dOp7ycd/I/bEwq48JSxTYB1MukUT14zavAbwi +F2HS5dowAze+GqJxJDJ3MqoaQyHEyKkFwVQGUV8CdPGNjzhOCKfXWLA0fVrFf/mQHe/n+gv5z/k+ +88yw1UwGINZBG2R7rinYt99byKrumLTqhg1QmO8ZBniaLmnhnMsaN6sL8hBs2K+ExP/AfJiskvI3 +lyevzEeG5giz8c92ZyaIi+JL9SSQz6dqSYocPzquGUcWB8pmn+TywPpcz8imPuqtq+8dpWwwh9Pl +WsxR0eE4Gdd4DswCE8/SmWYTI6+fTaRFSmjStLpKQiSNQVGakW7DTmnTTqm3HGD8br+SE/+dBryS +BsrWpP3p5OBw/+i13Q1v/JCtTSh1atUvgTNERbigagSGrmU8zdPJjEN43VQfJWwTX25srY5nsJD0 +88291CztOAWTO+fKjt3UscMKDtBtWlPJ4c3F7IPhpE5+XfoTBHFpANH0gWyAFkB7yPdOIaxPEzAf +i9cS4APwGnWp/wH6Z58Hf2kfamolIIWAvgccT6pXGc15fvjqe464oZs1CN0vTpLmV/tvdzUJ2s+b +BEpk2PLAsUdBN/RjGxLGFh9J91lYygUOKDrHqYG6eplc8meRJHEG0ORsqJ/jk6PVMnXCf6jzjaGW +thoQPN3gblyNIhkLj4RzShaFpJkUnEJXv9UhN4CVh8zpKXOh8jRMrXlgxp/JNaOnqpxgJkHm5myB +ZlmghxT6lKdDuxSEQL4GERPIcz8E8x6QJsiQxtgq8c2wAzYnpKBLw0hSlGJkBKpLbLBLp7XIx3lr +/6G5ImwU75/k0GN3IAkw7CPSQsldSTJIh2XMIpiE1pWYC2yll3B4qeN7Y9PSurcM3lFU+USQz3cZ +hLDKTfuxPLhBNsNNcR3FjcAx5MVjU4zuUMWwIonzMGAFZhbygWn/89GUBPHtccBavidknONHYQBi +2iXOqruDueycCnNDv8oioLlp+s+ntcURznLGnMStubhmI7sqmcFCRB8uDAbEwMYFe5ReGfh7HAVa +Q0QC7OAOGC6F+fDp1DGwlucfkpToI9/hCs+aQE71VlcoS5jeMltDaoaxFpztDvkgKIpIHA6KJ2zr +RIQevTJZbxik84GMBc+BE2+ru6I4mGSIxdTI9bDc9Sco1Eih+G52ilmOXU1loqx3LkKPr3IbpuJo +DVpOAx3Z6R+GWabO7gFljZMfHd4RpgqVcjIWFwJVJFeOI/Y4hnSQIWpF7hagjMqkv1ASDtAkyBMI ++nr2piK5A1/hmYI8Aj3bYTeMwumsoO+hNOFTogHmGSGCBJXMI8qulwUDpgWWpLCqdfWYOkrxVniW +zFKgBtvvCwQHbxew6pGtQf8WknlZ8c6hMpggzGDPJpicCILqkDJ+kJw6KBckmb1gBglOYqAzYZri +BkMNgeUpP5dGSI3qtUbSPQz7fbDjgEJpcw8p3ZgkhW6gqVlskpDxqTo9YCFYRDcqIrCgUYbwJoI+ +23h5zftZwLnA/mQEAAig5k/lVzBPpmnG553FAFlm2ccQJnsJuWdjhhRB/S1F4dqVC6dYUcxPGb9B +ucK4HfScEKeljoA1TXRNYVf+Wb8r+hE08/r1wSPHnYKaDJLWuTj4OMFyphh36mGG3zRR5I4B+hT3 +c6EBfIPHKCFOylBMt88gbphnVDRAawRkRxGfJFKSelkKpaj0IfbBHi4ixbyIVZfBYX6buDFTI2ZW +OTYZzURdZA3GVhRigH8/TDnHGylfwX+kx4THDg4DblBepWwCkk4yGFSVQ/0hXhaYctyD2AikImLO +5+EzBwbXT//bBmHrOqrnYYigCZT/c3IuBuJzpr0DNURbmzxJ7m4nYxMvIN4v59kwAjcS0qgYnMTE +q2g9IVksCYcJuholKrlT86Lgwp8Y1BpLZfROFIgf5QiFEugIPwvSFywyRl0GsmXndiwMh9gvUILC +lNnDQcZzJ6WbxqoXC+kNJDKnzO6Aais5cqFYwdi8wNoqpToaq25OE5HtosmdKrr2gagxUog500Lw +7EQO/DACUoMMJYuFg3DFwZSiDGE4YKZCUk09d4YiJErKyNmTVtxVxknNQgIS8GK/L/PoI44ys6xH +epZhKTrke72AaJkALKUVpJqctFtELHGJA++cXGdp7gvJOpI7yOSHxAiFOQoUA3OlOxORiXwYjsH4 +ML0MglzuLZ8d60cUjBQtdT0+cHXeD9Pw4xxKIXXbhPWwD80p62dqbw9s0JhR6yHEH2QQlR8Y2Rrw +4IrNWh41zsFCHBp4fCEzGNM7ShyldbUn65uXwQSDROJb2UrANm7R6PTpBhu2rwb6fEVEYCcsVhVs +1nQGDTBBbvbmuJZ6ZNk4GjFN13AOCC+DmTMY3vVGmsw4rgGj3vS4iKAyI0MiaDIjy9eM95o9eGyi +RZgxkhksEwDRoRsQv1gGxIUAyi3qgb3uZvE089ZW66sbFcOhsdQiB2Bh0At6f3ljo7mdqC8yaVC3 +rZySfyf79oikmJSp2GvtnjwljdynHuPJUEgpMDFbs0EwslBYgo9ZUCXN0zmmEwYWDkPnZii3lAkT +PogTSGmsiLIo7LqIk2air/1uchHcsCnsQvW7Kv2sxeFgfeHGz+921z0APZWWqsqZTxQoyPvgBDmA +EJ1Ps7ihd2QtU21XXLU+A8dQaAKCXRSQXMiewufy9kQKDnLBHZhGyaMCg8FNyAGwCeDOvOQiqXBc +8/Z95yyGohuV+BTQBY0BSShUpAZxD1RXDPCjoAZXpkWS7PcvtKTFtBogbP+YqeCmjHqb3wOk++Hr +J5xFUBKSJHYsNxwJAyADIOJGlcbdbAGDGp3aK5l7kDZS4riQOgFnxoR5WTwiluYBVA7I8yCLe6RG +gSIxScAtxWRXIclAdy7va+kjQqdNzGQiHcHUD4occRMzCcGtl6AeNKWkMZAc+ogSIUqcWFHEUOKE +fPQl8KjqYbCYlokBaA3rjTNMUZqPCTZenLo6TNAWcY6gAWjzABwZ3uNAmWR+odYtdS8/Ruy/QFhY +lwZp8cBhgEvlYU8sRTe6Py+l37OBq93sFDehJhojmHsIqyDXyghciNgp3NfKSl48i+SrkEa00F4X +fQoMNBDJheGteg+kAVoqSE45QOVhRPHbBx4ouhBBnowQ0gesOpqPTPWceqAb0iM0sfoVHIJJlbUp +EwfRCPTO1IOCr6b3vbNTf9KPg8n22s69zgd/+hEU8yTWGk+k2d2IrfYHJ95vuy9eFwz3zVU6Jy8T +RwtH1t3rAZenzIIJ/Rc4gUBaokEk31STmjoWwCyTqkWwXloMDAOLXa3VOQ+hadzMHswgIpMoIjj6 +EyOYgKKUZJbx5d+9Ru8+iClqQJhkRPEVHPVk/K5VByrLfJtSaBE2oMjelX/HOoeB0bkQRmiz+2sU +w2Bf4+BXCA/FaYPXq6KLAQV8zH4mAcPF/bEtUq45Z+hgY3lfRnPDTIQDRIYWJ33KYptWwK/LP7xZ +OkJRtIXu55/ZomcYoA9IT4/RDHIPI4Qs6SpEfOH9+kjkG9sWWy/4AHC+StA3yVXh+IamJkDDcSkG +QEq1lhQWw2WbO9xj2tShSRi4nCRAXQC+CmA0ckuWb+EetfDaamHk2NZbwCcSY2NvGMFgGJ4OwU1n +H+EJAEkdmYcxUuvjuvv65OnRcVs9A4LqPaHzXb+FG5+7ZJY/WTkby6H/me8AlO/tzc0F+N+rm1vb +a4j/vb61trm6BfjfG9vNrVv87/+N6+e/NbQi2IAlV+rnOZXLlfuV+mQ0yuWK97tSJbUHSisWVJaU +KWvAz3x1FRMsKnB9LQlOTaX6QS8C3lXzHZgO+RKTyQhuCs2/tQl+9YsmOcqz9z9YhveZPz/8x8ev +S/obuHXJqyjMHPvV+3V5idWiJa9WI0Dmhd3s6PaX0iAC1wFyErRySkxRe6nidnzv6LDtPX6xq4Vn ++Ki7Q8Hjgi6HgV7iKAUrjmVlFBvv/k3BUfB+9GqhT5Y4oL0L44DhHwuEwvq7vYcTILAlyjfyJiP9 +f8qBgQ+YQwPxifhPTf9KeisHMeqZwzHBcCwHwe5j6p+naT5hzoJewp8Q9VV/D2InagAe6wEedSQT +GDrR6Ex/GRsPI3rER19RCkwikfdit33yaff4iXfy9KCNHx5ufDJftiCOCehaqpaXYTVan/beHB0/ +8v7dW/UqFe/vf9evlruhFgbeAne0P9xZXnYeqHnNSkXvnrl2mqYd58U3NLVGTUmXi3fbe+EuGcGD +JZ7sa94K17ADrmkFryeja5PGdC15VtewfNeS5XPttnXnd/n8Fdf2mtf2mnfHklJY+EP6uOQ9+C/v +P5fv1ht3r+827laoBoge9e9yAHG3t473Wy/e4ZkCEnKq1YvaINfMtTedeEudWJ9D/T+v8osc+VWo +GuIenjQ7BYcsokcpKotS7A+ok24tFOeRB8t6jLhN8dRX9K+tB0u12pKSGitLd2S5eHCd2jWdlWs6 +fNewpStWvLxDNEpqojhPP/CW5KZaGvvjdJhMl751d03/vLDjJTSr8q1eGyvItf5UueO2a9bGeQGu +DoVpgJGlhjSjhgYAWp1a37vbie8ueKfuPRGupcUDwCaRSmHU6Dd67+zDfM/zDYLdUoLSKccrGQx0 +4yba2oP4a4/CrT2OyfYqZTPrfEFz6wRnL+qpHjMMacnsen3D3/QtzpH/zpmBgVyNInwRluIhMga2 +DiyPAynvnt59Iyi/A/Z9+DuEykIuiYB+M6+j2+AJe1vhBt6BcA/18g60asv4yMsf8A+/eF29b869 +Narj42GGtTL/yRc8kocLNYlkEu3P8OICK7LzaTp5M9mkEdh28+8tzjduQg7sqTG6EcY58B+MyMN/ +dUzpKaax/D0B0OB+sjWaCoNjbv7njKjQRuHQwKG6hpHlj8zc6AlRmWBjLXY8YbWKudNEmlpsQzsL +bqi0DJ4LSBXmmecGK0aZe4rk2GzNChWX0v9nNh66hB84B8JjLS+HD1Z/CX+98/vPhVP7S7iyAgW+ +cIfLcvze+po/3kt3wiWcXz1p+mfhHV8LexXeR7QBPomQWNoSdxxPAogCumfwzFdHoFA38cMWdVXL +mm/MO/8NGs+xxorS3NCkntcee1byNtL4v1pzuL1ur9vr9rq9bq/b6/a6vW6v2+v2ur1ur9vr9rq9 +bq/b6/a6vW6v2+v2ur1ur9vr/9r13w52vnUAMAIA ' # Tail end of the installer script, following the tar archive diff --git a/qq2clone_noarchive b/qq2clone_noarchive new file mode 100755 index 0000000..ae90968 --- /dev/null +++ b/qq2clone_noarchive @@ -0,0 +1,3186 @@ +#!/bin/bash +#shellcheck disable=1090 disable=2012 + + #--------------------# + #@@@@@@@@@@@@@@@@@@@@# + #---LITERAL VALUES---# + #@@@@@@@@@@@@@@@@@@@@# + #--------------------# + +E_permission=10 # No permission for access or file does not exist +E_depends=11 # Lacking required software +E_args=12 # Bad command line arguments or arguments specify illegal + # action +E_template=13 # Problem with a template +E_extcom=14 # An external command failed +E_xml=15 # Malformed XML or issue processing XML +E_libvirt=16 # Invokation of a libvirt tool was unsuccesful +E_timeout=17 # Timeout was exceeded before spice connection to VM + # was established +E_file=18 # Expected file does not exist or is of wrong type/format +E_unexpected=19 # Probably a bug in qq2clone + +# lv_api_do prints one of these when started +CONN_BAD="# No Connection" +CONN_GOOD="# Connected" + +# lv_api_do prints one of these immediately following a line of input +BAD_REQ="# Bad Request" +FATAL="# Fatal error" +GOOD="# Making API Request" +NOMATCH="# No matching domain" + + #---------------------------------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---NAMED PIPE FOR PASSING DATA BETWEEN FUNCTIONS---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---------------------------------------------------# + +#=========================================================================# +check_pipe () +# DESCRIPTION: See if pipe is open +# INPUT: None +# OUTPUT: Return value +# PARAMETERS: None +#=========================================================================# +{ +local type +type="$(file -bL /proc/self/fd/3)" +if [[ ! "$type" =~ fifo ]]; then + return 1 +fi +return 0 +} +#=========================================================================# +open_pipe () +# DESCRIPTION: Open a named pipe in read/write mode on fd3 +# INPUT: None +# OUTPUT: None +# PARAMETERS: None +#=========================================================================# +{ +check_pipe && return +local fifo_path +fifo_path=$(mktemp -d) || temp_error +#shellcheck disable=2064 +trap "exec 3>&-; exec 3<&-;rm -rf $fifo_path" EXIT +mkfifo "$fifo_path/fifo" || fifo_error +exec 3<>"$fifo_path/fifo" +return 0 +} +#=========================================================================# +read_pipe () +# DESCRIPTION: Flushes the contents of the named pipe to stdout, +# nonblocking +# INPUT: None +# OUTPUT: Contents of named pipe on fd3 +# PARAMETERS: $1: (Optional) If 1, read data out but also write it back +# into the pipe +#=========================================================================# +{ +# Note: This implementation allows for things like this to work: +# tr "a" "b" < <(read_pipe) | write_pipe 1 +echo "EOF" >&3 +local line match +while IFS= read -r line <&3; do + # write_pipe puts a + at the start of every line + if [[ "$line" =~ ^\+(.*)$ ]]; then + match="${BASH_REMATCH[1]}" + echo "$match" + (($#)) && (($1 == 1)) && write_pipe 0 "$match" + else + [[ "$line" == "EOF" ]] || unexpected_error "read_pipe" + break + fi +done +return 0 +} +#=========================================================================# +write_pipe () +# DESCRIPTION: Write information to the named pipe, nonblocking unless it +# is told to look for input on stdin and nothing is sent there. Works in +# conjunction with read_pipe to make read_pipe non-blocking +# INPUT: Tell write_pipe whether information is coming on stdin or from +# a parameter, then pass information +# OUTPUT: None +# PARAMETERS: $1: '0' if passing another parameter(s), '1' if writing to +# stdin instead. +# $2 and on: If $1 is 0, write_pipe will write the remaining parameters +#=========================================================================# +{ +# + is put at the beginning of every line echoed to the pipe, so that +# read_pipe can operate in a non-blocking manner +local line +{ [[ "$1" == "0" ]] || [[ "$1" == "1" ]]; } || unexpected_error write_pipe +if (($1)); then + while IFS= read -r line; do + echo "+$line" >&3 + done +else + shift + echo "$@" | while IFS= read -r line; do + echo "+$line" >&3 + done +fi +return 0 +} + + #-------------------# + #@@@@@@@@@@@@@@@@@@@# + #---USE LV_API_DO---# + #@@@@@@@@@@@@@@@@@@@# + #-------------------# + +# lv_api_do is accessed in the background because it allows for only one +# subshell to be invoked when using lv_api_do repeatedly. Makes qq2clone +# more efficient (significantly, in some cases) but makes opening and +# closing lv_api_do into something that must be managed manually by the +# coder + +#=========================================================================# +lv_api_do_check () +# DESCRIPTION: See if lv_api_do is present in the expected location. If +# not, put it there +# INPUT: None +# OUTPUT: None +# PARAMETERS: None +#=========================================================================# +{ + local loc="/run/user/${UID}" + [[ -e "${loc}/lv_api_do" ]] && return + cd "$loc" + echo "$archive" | base64 -d | tar -zx +} +#=========================================================================# +lv_api_do_close () +# DESCRIPTION: Tell lv_api_do to exit and close the extra pipe +# INPUT: None +# OUTPUT: None +# PARAMETERS: None +#=========================================================================# +{ + echo "exit" >&4 + exec 4>&- 4<&- + rm -rf "${lv_api_temp:?}" + return 0 +} +#=========================================================================# +lv_api_do_comm () +# DESCRIPTION: Issue a command to lv_api_do +# INPUT: The command +# OUTPUT: Return 0/1 on success/failure. lv_api_do output can be accessed +# with read_pipe. Exit and error message if lv_api_do encounters +# a fatal error +# PARAMETERS: $@: command string to lv_api_do +#=========================================================================# +{ +# Ensure lv_api_do is open +( : >&4 ; ) &>/dev/null || unexpected_error lv_api_do_comm + +echo "$*" >&4 +local check +read -r check <&3 +[[ "$check" == "$BAD_REQ" ]] && unexpected_error lv_api_do_comm +[[ "$check" == "$NOMATCH" ]] && return 1 +[[ "$check" == "$FATAL" ]] && + { echo "Error using libvirt API" >&2; exit "$E_libvirt"; } +[[ "$check" == "$GOOD" ]] || unexpected_error lv_api_do_comm + +# This loop avoids a race condition when trying to read_pipe later by +# ensuring that lv_api_do has finished its output before this function +# returns +local line +while read -r line <&3; do + [[ "$line" == "EOF" ]] && break + echo "$line" >&3 +done + +return 0 +} +#=========================================================================# +lv_api_do_open () +# DESCRIPTION: Open lv_api_do in background +# INPUT: None +# OUTPUT: Return 0 on success, exit on failure +# PARAMETERS: None +#=========================================================================# +{ +declare -g lv_api_temp; +lv_api_temp="$(mktemp -d )" || temp_error +mkfifo "${lv_api_temp}/lv_api_do_fifo" || fifo_error +exec 4<>"${lv_api_temp}/lv_api_do_fifo" +"/run/user/${UID}/lv_api_do" <&4 >&3 2>/dev/null & + +local check +read -r check <&3 +[[ "$check" == "$CONN_BAD" ]] && lv_api_do_bad_conn +[[ "$check" == "$CONN_GOOD" ]] || unexpected_error lv_api_do_open + +return 0 +} + + #-------------------------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---GET/ALTER CONFIGURATION, CHECK SYSTEM---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #-------------------------------------------# + +#=========================================================================# +check_config () +#= DESCRIPTION: Given a name or name/value pair, check if it is a +#= valid configuration option +#= INPUT: Either a name or name value pair +#= OUTPUT: Return 1 if the name is not a valid config option or if the +#= given value does is not valid for the given name. Return 0 else +#= PARAMETERS: $1: Name of config option, $2: (optional) value of option +#=========================================================================# +{ +(($#)) || unexpected_error check_config +declare -A def_opt +def_opt[TEMPLATE]=".*" +def_opt[TEMPLATE_DIR]="^/.*" +def_opt[QUIET]="^[01]$" +def_opt[USE_SPICE]="^[01]$" +def_opt[SPICY]="^[01]$" +def_opt[S_TIMEOUT]="^[0-9]+$" +def_opt[NORUN]="^[01]$" +def_opt[STORAGE]="^/.*" + +(( $# == 1 )) && + { [[ " ${!def_opt[*]} " =~ [[:space:]]${1}[[:space:]] ]]; + return $?; } + +local patt="${def_opt["${1}"]}" +[[ -n "$patt" ]] || return 1 +[[ "$2" =~ $patt ]] || return 1 + +return 0 +} +#=========================================================================# +check_depends () +# DESCRIPTION: Check that required software is present during initial auto- +# configuration +# INPUT: None +# OUTPUT: Return 0 on success or exits with descriptive message on failure +# PARAMETERS: None +#=========================================================================# +{ +local elem missing=0 + +# These we need to check for +local -a depends=( virsh virt-clone virt-xml virt-xml-validate qemu-img \ + xmllint sqlite3) + +# These are from gnu-coreutils, util-linux, or are simply extremely common +# and almost certainly present. However, checking for any external +#command invoked is harmless and may even help 1/10000 times +depends=( "${depends[@]}" basename chmod date dirname file grep less ls \ + md5sum mkfifo mkdir mktemp mv rm sed sort touch uniq uuidgen uuidparse \ + vi dirname ) + +(( BASH_VERSINFO[0] >= 4 )) || + { echo "This script must be run with Bash version 4.0+" + exit "$E_depends"; } >&2 + +for elem in "${depends[@]}"; do + if ! { command -v "$elem"; } &>/dev/null; then + ((missing++)) + echo "Missing required software: $elem" >&2 + fi +done + +((missing)) && + { echo "This script won't run until you install the listed software" >&2; + exit "$E_depends"; } + +return 0 +} +#=========================================================================# +disp_conf_names () +# DESCRIPTION: Display the name and value of all configuration options +# INPUT: None +# OUTPUT: Echoes config name="value" pairs +# PARAMETERS: None +#=========================================================================# +{ +local name value +while read -r name; do + read -r value + echo "'$name'='$value'" +done < <(sqlite3 "select name,value from CONFIG") +return 0 +} +#=========================================================================# +disp_conf_desc () +# DESCRIPTION: Display the description of a config option to the user +# INPUT: The name of the option +# OUTPUT: Echoes relevant lines of information +# PARAMETERS: $1: The config option name +#=========================================================================# +{ +if [[ "$1" == "TEMPLATE_DIR" ]]; then + echo "This is the where template XML files will be kept" + echo + echo "Default value: '${QQ2_DIR}/templates'" +elif [[ "$1" == "TEMPLATE" ]]; then + echo "This template will be used for commands like clone, rm, destroy" + echo "when option --template/-t is not specified" + echo + echo "Default value: '' (empty, disabled)" +elif [[ "$1" == "QUIET" ]]; then + echo "If set to 1, most non-error output will be suppressed" + echo + echo "Default value: '0'" +elif [[ "$1" == "SPICY" ]]; then + echo "If set to 1, use spicy as the default spice client instead of" + echo "virt-viewer. If virt-viewer is installed during the initial setup," + echo "the default value is '1' (enabled). Otherwise, the default value" + echo "is '0'" +elif [[ "$1" == "USE_SPICE" ]]; then + echo "If set to 1, attempt to connect to the spice graphics of a virtual" + echo "machine by default when cloning it, if it is configured to use" + echo "spice graphics. qq2clone can do this using the programs spicy and" + echo "virt-viewer. If either is installed on your system during the" + echo "first run, the default value is '1' (enabled). Otherwise, the" + echo "default value is '0'" +elif [[ "$1" == "S_TIMEOUT" ]]; then + echo "Wait this many seconds before timing out when trying to connect to" + echo "a virtual machine's spice graphics." + echo + echo "Default value: '10'" +elif [[ "$1" == "NORUN" ]]; then + echo "If set to 1, do not automatically run a machine after cloning it." + echo + echo "Default value: '0'" +elif [[ "$1" == "STORAGE" ]]; then + echo "The default location to store clone images when creating them." + echo "Changing this location is fine, but it is a good idea to ensure" + echo "that whatever location you do choose is only used by qq2clone" + echo + echo "Default value: '${QQ2_DIR}/qq2clone-pool'" +else + echo "No such configuration option '$1'" + return 1 +fi +return 0 +} +#=========================================================================# +first_run_setup () +# DESCRIPTION: Generate a new database with default config values, +# create subdirectories of QQ2_DIR +# INPUT: None +# OUTPUT: None +# PARAMETERS: None +#=========================================================================# +{ +make_dir "${HOME}/.config" +echo "$QQ2_DIR" > "${HOME}/.config/qq2clone" || + { + echo "Failed to write to config file: ${HOME}/.config/qq2clone" + unexpected_error first_run_setup + } >&2 + +# Default locations of key directories +local TEMPLATE_DIR="${QQ2_DIR}/templates" +local POOL_DIR="${QQ2_DIR}/qq2clone-pool" + +check_depends + +make_dir "$QQ2_DIR" +make_dir "$TEMPLATE_DIR" +make_dir "$POOL_DIR" +check_rw -r "$QQ2_DIR" + +local use_spice spicy +if command -v virt-viewer &>/dev/null; then + use_spice=1 + spicy=0 +elif command -v spicy &>/dev/null; then + use_spice=1 + spicy=1 +else + use_spice=0 + spicy=0 +fi + +if [[ -e "${QQ2_DIR}/qq2clone.db" ]]; then + echo "A qq2clone database alreadys exists at ${QQ2_DIR}/qq2clone.db" + echo "Overwrite this database and create one with default values?" + if prompt_yes_no; then + check_rw "${QQ2_DIR}/qq2clone.db" + rm -f "${QQ2_DIR}/qq2clone.db" || unexpected_error first_run_setup + else + return 0 + fi +fi + +sqlite3 <&2 + +declare -gA OPT +declare -a opts +local elem +opts=(TEMPLATE_DIR TEMPLATE QUIET USE_SPICE SPICY S_TIMEOUT NORUN \ + STORAGE) +for elem in "${opts[@]}"; do + OPT["$elem"]="$(sqlite3 \ + "select value from CONFIG where name=\"$elem\"")" +done +OPT[COPY_DISKS]=0 # Hardcoded default, overriden with --copy-disks/-C +} +#=========================================================================# +write_config () +# DESCRIPTION: Write an option name and value pair to config table. +# Checks that the option name and value are good. +# INPUT: Name and value of configuration option +# OUTPUT: Return 0 on success, 1 on bad option, 2 on bad value +# PARAMETERS: $1: Name of variable, $2: Value of variable +#=========================================================================# +{ +check_config "$1" || return 1 +check_config "$1" "$2" || return 2 + +sqlite3 "update CONFIG set value='$2' where name='$1';" + +return 0 +} + + #-----------------------# + #@@@@@@@@@@@@@@@@@@@@@@@# + #---USAGE INFORMATION---# + #@@@@@@@@@@@@@@@@@@@@@@@# + #-----------------------# + +#=========================================================================# +usage () +# DESCRIPTION: Output basic usage information +# INPUT: None +# OUTPUT: Echo information to stdout to be read by the user +# PARAMETERS: None +#=========================================================================# +{ +(( OPT[QUIET] )) && return 0 +echo "qq2clone: quick qcow2 clone" +echo +echo "Description:" +echo " Create and manage QEMU/KVM VMs using template machines and qcow2" +echo " images with backing files" +echo +echo "Usage:" +echo " qq2clone [OPTION]... [COMMAND] [ARGUMENT]..." +echo +echo ' options: --connection/-c (URI) --no-spice/-f --help/-h' +echo ' --no-run/-n --quiet/-q --quieter/-Q --run/-r --spicy/-S' +echo ' --storage/-s (filepath/pool-name) --template/-t (name)' +echo ' --use-spice/-g --verbose/-v --virt-viewer/-V' +echo +echo " commands: check clone config connect copy-template delete-template" +echo " destroy edit exec import-template list list-templates" +echo " modify-template restore resume rm rm-wipe rm-shred save" +echo " save-rm start suspend" +echo +echo " For more information, see: man qq2clone" +return 0 +} + + #-----------------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---INPUT/OUTPUT HELPER FUNCTIONS---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #-----------------------------------# + + +#=========================================================================# +prompt_num () +# DESCRIPTION: Prompt user for a number between $1 and $2 +# INPUT: Inclusive endpoints of accepted interval, where the right hand +# endpoint is less than 10 +# OUTPUT: Echo choice when proper input is received +# PARAMETERS: $1: LH of interval, $2: RH of interval +#=========================================================================# +{ +{ (( $1 > -1 )) && (( $1 < $2 )) && (( $2 < 10 )) ; } || \ + unexpected_error prompt_num +local n +read -rsn 1 n +{ [[ "$n" =~ ^[0-9]$ ]] && (($1 <= n)) && ((n <= $2)); } || + { echo "Enter a number from $1 to $2" >&2; + prompt_num "$1" "$2"; + return 0; } +echo "$n" +return 0 +} +#=========================================================================# +prompt_yes_abort () +# DESCRIPTION: Prompt user to enter y, or any other key to abort +# INPUT: A keystroke +# OUTPUT: Prompts for input, returns 0 for Y/y and 1 for else +# PARAMETERS: $1, $2: (Optional) override disp with $1 and patt with $2 +#=========================================================================# +{ +local disp="Press (y) to accept, anthing else to abort" patt="^[Yy]$" +[[ -n "$1" ]] && disp="$1" +[[ -n "$2" ]] && patt="$2" +local char +echo "$disp" +read -rn 1 char +echo +[[ "$char" =~ $patt ]] && return 0 + return 1 +} +#=========================================================================# +prompt_yes_no () +# DESCRIPTION: Prompt user to enter y or n, repeatedly until they do +# INPUT: Keystrokes +# OUTPUT: Prompts for input, returns 1 for N/n or 0 for Y/y +# PARAMETERS: None +#========================================================================= +# +{ +local char +until [[ "$char" =~ ^[YyNn]$ ]]; do + echo "Press (y)/(n) for yes/no" + read -rn 1 char + echo +done +[[ "$char" =~ ^[Nn]$ ]] && return 1 +return 0 +} + + #-----------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---PARSE/SEARCH/MODIFY XML---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #-----------------------------# + +#=========================================================================# +do_virt_xml () +# DESCRIPTION: Run a given virt-xml command, reading from and writing to +# the named pipe +# INPUT: Parameters to send to virt-xml +# OUTPUT: Nothing except on error +# PARAMETERS: $@: Passed to virt-xml +#=========================================================================# +{ +local xml +xml="$(virt-xml "$@" <<<"$(read_pipe)" 2>/dev/null)" || + { echo "Attempt to generate xml with virt-xml failed." + echo "This is probably a bug in qq2clone" + exit "$E_unexpected" ; } >&2 + +write_pipe 1 <<<"$xml" +return 0 +} +#=========================================================================# +find_tag () +# DESCRIPTION: Use xmllint to do an xpath search of xml and write_pipe +# all matches +# INPUT: Xpath and XML +# OUTPUT: Write one match per line +# PARAMETERS: $1: Xpath, $2: XML location, or leave blank to read from +# stdin +#=========================================================================# +{ +if [[ -n "$2" ]]; then + write_pipe 1 <"$2" +else + local line + while read -r line; do + write_pipe 0 "$line" + done +fi + +xmllint --xpath "$1" --auto |& grep -qi 'xpath error' && + unexpected_error find_tag + +xmllint --noblanks --dropdtd --nowarning --xpath "$1" \ + 2>/dev/null <(read_pipe) | write_pipe 1 + +return 0 +} +#=========================================================================# +get_attr_value () +# DESCRIPTION: Given an attribute="value" pair, echo the value +# INPUT: Attribute value pair +# OUTPUT: Value, or unexpected_error if input doesn't match pattern (do not +# rely on this function for checking that a string is a name=value pair +# PARAMETERS: $1: attribute="value" +#=========================================================================# +{ +p="$(strip_ws "$1")" +[[ "$p" =~ ^[^\=]+\=[[:space:]]*[^[:space:]](.*).$ ]] && + { echo "${BASH_REMATCH[1]}"; return 0; } +unexpected_error get_attr_value +return 0 +} +#=========================================================================# +get_disk_devices () +# DESCRIPTION: Find all disk device file locations from an XML file +# INPUT: libvirt domain XML file on stdin +# OUTPUT: writepipe each file location +# PARAMETERS: None +#=========================================================================# +{ +find_tag '//devices/disk[@type="file"][@device="disk"]/source/@file' +local line val +while read -r line; do + val="$(get_attr_value "$line")" || unexpected_error get_disk_devices + write_pipe 0 "$val" +done < <(read_pipe) +return 0 +} +#=========================================================================# +get_disk_devices_db () +# DESCRIPTION: Like get_disk_devices, but get info from the database +# INPUT: Machine number, or omit to get template info +# OUTPUT: writepipe each file location +# PARAMETERS: $1: (Optional) machine number +#=========================================================================# +{ +local query disk +if (($#)); then + query="select disks from CLONES where id='$1' \ + and template='${OPT[TEMPLATE]}';" +else + query="select disks from TEMPLATES where name='${OPT[TEMPLATE]}';" +fi +while read -r disk; do + write_pipe 0 "$disk" +done < <(sqlite3 "$query") +return 0 +} +#=========================================================================# +has_spice () +# DESCRIPTION: Check whether a machine supports spice graphics +# INPUT: A machine number +# OUTPUT: Returns 0 if yes and 1 if no +# PARAMETERS: $1: A machine number +#=========================================================================# +{ +local uuid +uuid="${CL_MAP["$1"]}" +find_tag '//devices/graphics[@type="spice"]' < <(virsh dumpxml "$uuid") +local match=0 line +while read -r line; do + match=1 +done < <(read_pipe) +((match)) && return 0 +return 1 +} + + #--------------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---FILESYSTEM/DB INTERACTIONS---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #--------------------------------# + +#=========================================================================# +copy_file () +# DESCRIPTION: Copy file $1 to $2 and give error messages, exit on error +# INPUT: File to copy +# OUTPUT: Error messages and exit codes as needed +# PARAMETERS: $1: File to copy, $2: Location to copy to +#=========================================================================# +{ +(($# == 2)) || unexpected_error copy_file +check_rw "$1" "$(dirname "$2")" +[[ -e "$2" ]] && check_rw "$2" +cp -fR "$1" "$2" &>/dev/null || unexpected_error copy_file +return 0 +} +#=========================================================================# +get_md5 () +# DESCRIPTION: Get md5sum of a file without the trailing filename +# INPUT: A filepath +# OUTPUT: The md5sum +# PARAMETERS: $1: Filepath +#=========================================================================# +{ +local md5 +check_rw "$1" || unexpected_error get_md5 +md5="$(md5sum "$1")" +[[ "$md5" =~ ^[[:space:]]*([^[:space:]]+)([[:space:]]|$) ]] +echo "${BASH_REMATCH[1]}" +return 0 +} +#=========================================================================# +make_dir () +# DESCRIPTION: Make a directory at given location or exit with error +# message +# INPUT: Filepath +# OUTPUT: Error messages and exit code as needed +# PARAMETERS: $1: Filepath of directory to make +#=========================================================================# +{ +(($# == 1)) || unexpected_error make_dir +if [[ -e "$1" ]]; then + [[ -d "$1" ]] || + { echo "Tried to create directory:" + echo "$1" + echo "but it already exists and is not a directory" + exit "$E_file"; } >&2 + check_rw "$1" + return 0 +fi +mkdir -p "$1" &>/dev/null +check_rw "$1" +return 0 +} +#=========================================================================# +move_file () +# DESCRIPTION: Move file $1 to $2 or give error messages, exit on error +# INPUT: File to move, new location +# OUTPUT: Error messages and exit codes as needed +# PARAMETERS: $1: File to move, $2: Location to move to +#=========================================================================# +{ +(($# == 2)) || unexpected_error move_file +check_rw "$1" "$(dirname "$2")" +if [[ -e "$2" ]]; then + chmod +rw "$2" || + { echo "No permission to write $2" >&2; exit "$E_permission"; } +fi +mv -f "$1" "$2" &>/dev/null || unexpected_error move_file +return 0 +} +#=========================================================================# +write_file () +# DESCRIPTION: Write contents of named pipe to file or error and exit +# INPUT: Filepath as parameter, content via write_pipe +# OUTPUT: Error messages and exit codes as needed +# PARAMETERS: $1: Filepath +#=========================================================================# +{ +(($# == 1)) || unexpected_error write_file +touch "$1" +check_rw "$1" +[[ -d "$1" ]] && unexpected_error write_file +local temp1 temp2 +temp1="$(mktemp)" || temp_error +temp2="$(mktemp)" || { rm -f "$temp1" &>/dev/null; temp_error; } +cp "$1" "$temp1" || + { rm -f "$temp1" "$temp2" &>/dev/null; unexpected_error write_file; } +read_pipe > "$temp2" || + { rm -f "$temp1" "$temp2" &>/dev/null; unexpected_error write_file; } +mv -f "$temp2" "$1" &> /dev/null || + { rm -f "$1" &>/dev/null; mv -f "$temp1" "$1" &>/dev/null; + rm -f "$temp1" "$temp2" &>/dev/null; unexpected_error write_file; } +return 0 +} +#=========================================================================# +sqlite3 () +# DESCRIPTION: Pass arguments to sqlite3 binary, prepending basic +# parameters that are always used +# INPUT: Arguments to sqlite3 +# OUTPUT: Dependent on sqlite3 +# PARAMETERS: Arbitrary +#=========================================================================# +{ +$(unset sqlite3; command -v sqlite3) --batch --separator $'\n' \ + "${QQ2_DIR}/qq2clone.db"\ + "$@" || unexpected_error sqlite3 +} + + #-----------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---IMPORT/MODIFY TEMPLATES---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #-----------------------------# + +#=========================================================================# +commit_image () +# DESCRIPTION: Commit changes from staging image(s) to template image(s) +# INPUT: Parameters to calling function +# OUTPUT: Status updates, prompts, error messages +# PARAMETERS: $@ from calling function +#=========================================================================# +{ +if (( ${#CL_MAP[@]} + ${#BAD_CL[@]} > 1)); then + echo "Cannot commit image while there are clones. Aborting." >&2 + exit "$E_args" +fi + +local disk check t d + +get_disk_devices_db +while read -r disk; do + while read -r t; do + check="$(sqlite3 "select exists \ + (select * from CLONES where template='$t');")" + ((check)) || continue + while read -r d; do + if [[ "$d" == "$disk" ]]; then + echo "Although this template has no clones, template" + echo "$t does. These templates share disk:" + echo + echo " $disk" + echo + echo "If changes are committed, these clones may become" + echo "corrupted. To avoid this, retrieve any information you" + echo "need from these clones and then delete them. Aborting." + exit "$E_args" + fi >&2 + done < <(sqlite3 "select disks from TEMPLATES where name='$t';") + done < <(sqlite3 "select name from TEMPLATES where \ + not name='${OPT[TEMPLATE]}';") +done < <(read_pipe) + +if (($# < 3)); then + echo "This operation has the potential to corrupt your master template" + echo "image if it is interrupted." + if ((OPT[QUIET] )); then + echo "Append argument force to continue" >&2 + exit "$E_args" + fi + prompt_yes_abort || exit 0 +fi + +while read -r disk; do + ((OPT[QUIET])) || echo "Committing $disk..." + output="$(qemu-img commit -d "$disk" 2>&1)" || + { echo "$output"; echo "Operation failed"; + exit "$E_unexpected"; } >&2 + rm -f "$disk" &>/dev/null || + { echo "Failed to delete old image. Permission issue?"; + echo "Process may not have completed succesfully"; + exit "$E_permission"; } >&2 +done < <(sqlite3 "select disks from CLONES where id='0' and\ + template='${OPT[TEMPLATE]}';") +delete_machine 0 0 + +return 0 +} +#=========================================================================# +get_template_name () +# DESCRIPTION: Helper for exec_com_import_template. write_pipes the +# original name from the xml, then the new one +# INPUT: XML is write_piped, and argument to exec_com_import_template +# giving the name to import template with is optionally provided +# OUTPUT: See description. Error messages if name is bad +# PARAMETERS: $1: (optional) Template name, overrides value from XML +#=========================================================================# +{ +local name char +name="$(strip_ws "$1")" + +if [[ -n "$name" ]]; then + valid_xml_name_check "$name" + template_name_available "$name" +fi + +local xmlname +find_tag '//name/text()' <<<"$(read_pipe)" +while read -r line; do + line="$(strip_ws "$line")" + if [[ -n "$xmlname" ]]; then + xmlname="${xmlname}${line}" + else + xmlname="$line" + fi +done < <(read_pipe) +write_pipe 0 "$xmlname" + +if [[ -z "$name" ]]; then + name="$xmlname" +fi + +write_pipe 0 "$name" +return 0 +} +#=========================================================================# +import_get_xml () +# DESCRIPTION: Determine if argument to exec_com_import_template is a +# libvirt domain on the current connection or a filepath, check that it +# is valid, and write_pipe the xml +# INPUT: argument designating template XML or domain name/uuid +# OUTPUT: Error messages as needed, write_pipes XML on success +# PARAMETERS: $1: $1 from calling funcion +#=========================================================================# +{ +if [[ "$1" =~ ^/ ]]; then + { [[ -e "$1" ]] && [[ -r "$1" ]] ; } || + { echo "No read permission for $1 or file does not exist" + exit "$E_permission" ; } >&2 + virt-xml-validate "$1" &> /dev/null || + { virt-xml-validate "$1"; + echo "File $1 is not a valid libvirt domain XML document" + exit "$E_xml" ; } >&2 + write_pipe 1 <"$1" +else + virsh dominfo "$1" &>/dev/null || + { echo "Cannot access libvirt domain with name/uuid $1. " + echo "Wrong connection URI? Currently $LIBVIRT_DEFAULT_URI" + exit "$E_libvirt"; } >&2 + local line uuid + while read -r line; do + if [[ "$line" =~ \ + ^[[:space:]]*[Uu][Uu][Ii][Dd]\:[[:space:]]*([^[:space:]]+) ]]; then + uuid="${BASH_REMATCH[1]}" + fi + done < <(virsh dominfo "$1") + local check=0 + check="$(sqlite3 "select exists (select * from CLONES \ + where uuid='$uuid');")" + if ((check)); then + echo "Cannot import a clone as a template" >&2 + exit "$E_template" + fi + virsh dumpxml --inactive "$1" 2>/dev/null | write_pipe 1 +fi +return 0 +} +#=========================================================================# +rename_template () +# DESCRIPTION: Change template name, and all of its clone names +# INPUT: A current template name, and a new one +# OUTPUT: Status updates, error messages +# PARAMETERS: $@ from calling function exec_com_modify_template +#=========================================================================# +{ +local old_name="$1" new_name="$3" +local tdir="${OPT[TEMPLATE_DIR]}" +local xml="${tdir}/${1}.xml" +check_rw "$xml" + +OPT[TEMPLATE]="$old_name" + + +write_pipe 1 <"$xml" +template_name_available "$new_name" +valid_xml_name_check "$new_name" +do_virt_xml --edit --metadata name="$new_name" + +xml="${tdir}/${new_name}.xml" +write_file "$xml" +rm -f "${tdir}/${old_name}.xml" &>/dev/null +sqlite3 "update TEMPLATES set name='${new_name}' where name='${old_name}';" +OPT[TEMPLATE]="$new_name" +check_template &>/dev/null # Just to update md5sum + +((OPT[QUIET])) || echo "Template name changed"; + + +if (( ${#CL_MAP[@]} + ${#BAD_CL[@]} )); then + if ! ((OPT[QUIET] == 2)); then + echo "Now renaming clones" + local machines_on + machines_on="$(get_target_set destroy)" + [[ -n "$machines_on" ]] && + { echo "All clones that are not turned off will not be renamed." + echo "qq2clone will still know they are clones of $new_name," + echo "but in virsh and virt-viewer their old name will remain." + echo + echo "Shut down any running clones of $new_name you wish renamed" + echo "and press enter when ready to proceed." + read -rs + echo ; } >&2 + fi + + local id uuid cl_name + while read -r id; do + read -r uuid + cl_name="$(unique_name_uuid 0 "${new_name}#$id")" + virsh domrename "$uuid" "$cl_name" &>/dev/null + sqlite3 "update CLONES set template='$new_name' where\ + template='$old_name';" + done < <( sqlite3 "select id,uuid from CLONES where \ + template='$old_name'" ) +fi + +(( OPT[QUIET] )) || echo "Template rename complete" +exit 0 +} +#=========================================================================# +user_undefine_domain () +# DESCRIPTION: Prompt the user to undefine libvirt domain (or not) +# INPUT: Domain name +# OUTPUT: Gives info to and prompts user +# PARAMETERS: $1: Domain name +#=========================================================================# +{ +((OPT[QUIET] == 2)) && return 0 +echo +echo "Would you like to undefine the libvirt domain this template" +echo "was made from? This prevents the original domain from being" +echo "accidentally run, altering the template disk and potentially" +echo "corrupting any clones of that template." +echo +echo "This will apply every flag listed in 'man virsh' for command" +echo "'undefine' that may be required to succeed. I.e., snapshot" +echo "and checkpoint metadata, managed save images, etc. will be" +echo "discarded." +echo +if prompt_yes_no; then + virsh domstate "$1" 2>/dev/null | grep -q "shut off" || + virsh domstate "$1" 2>/dev/null | grep -q "crashed" || + { echo "This domain is still running, so make sure you turn it off"; + echo "before making clones from this template. Otherwise, it will" + echo "continue modifying the template storage device even" + echo "though it is undefined."; } >&2 + if virsh undefine --managed-save --checkpoints-metadata\ + --snapshots-metadata --nvram "$1" &> /dev/null; then + echo "Domain undefined." + else + echo "Could not undefine domain. Import still completed." + fi +fi +} + + #-------------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---ERROR MESSAGES AND CHECKS---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #-------------------------------# + +#=========================================================================# +arg_error () +# DESCRIPTION: If args are too few, too many, or simply wrong, this +# function provides a concise way to exit with proper message and code +# INPUT: Type of problem, name of command, name of bad arg +# OUTPUT: Echo error message, exit with E_args +# PARAMETERS: $1: 0) too few args 1) too many args 2) incorrect arg +# $2: The command, $3: in the case of incorrect arguments, the bad +# argument in question (omit otherwise) +#=========================================================================# +{ +local line +if (( $1 == 0 )); then + echo "Too few arguments to qq2clone $2" +elif (( $1 == 1 )); then + echo "Too many arguments to qq2clone $2" +else + echo "Bad argument to qq2clone $2: $3" +fi +exit "$E_args" +} >&2 +#=========================================================================# +check_dir () +# DESCRIPTION: Checks that a directory can be written to +# INPUT: A filepath +# OUTPUT: Error messages and exit codes as needed +# PARAMETERS: $1: Filepath +#=========================================================================# +{ +[[ "$1" =~ ^/ ]] || + { echo "Invalid filepath $1 specified. Use an absolute filepath"; + exit "$E_args"; } +mkdir -p "$1" &>/dev/null +{ [[ -d "$1" ]] && [[ -w "$1" ]]; } || + { echo "Cannot create $1 or cannot write to directory, check "; + echo "filepath and permissions"; + exit "$E_permission"; } +return 0 +} >&2 +#=========================================================================# +check_rw () +# DESCRIPTION: Provide an error message and exit if specified file cannot +# be read and written to. If file is a directory and a preceding +# argument is '-r', check recursively +# INPUT: A filepath (preferably fully qualified as a file could technically +# be named '-r') +# OUTPUT: Error messages and exit codes as needed +# PARAMETERS: $@: Filepaths to check +#=========================================================================# +{ +local redir +if [[ "$1" == "-r" ]]; then + redir=1; shift +else + redir=0 +fi + +while (($#)); do + if { chmod +rw "$1" || { [[ -w "$1" ]] && [[ -r "$1" ]]; } || + readlink "$1" ; } &>/dev/null; +then + shift + elif [[ -e "$1" ]]; then + echo "No read/write permissions for $1" >&2 + exit "$E_permission" + else + echo "The filepath $1 either does not exist or cannot be seen " >&2 + echo "with current permissions" + exit "$E_permission" + fi + local type line + type="$(file -b "$1")" + if [[ "$type" =~ directory ]] && ((redir)); then + while read -r line; do + check_rw -r "$line" + done < <(find "$1" 2>/dev/null) + fi +done +return 0 +} >&2 +#=========================================================================# +check_template () +# DESCRIPTION: Check if OPT[TEMPLATE] is defined. If it is, see if its +# md5sum is in agreement with the database. If it isn't, update the +# database and see if it is valid. Make sure that aspect of the db is +# updated too. Return 1 if template is not defined, or 2 if it is not +# valid +# INPUT: None +# OUTPUT: Error message and exit +# PARAMETERS: None +#=========================================================================# +{ +local md5 md5_curr valid + +check_template_exists || return 1 + +md5="$(sqlite3 "select md5sum from TEMPLATES where \ + name='${OPT[TEMPLATE]}';")" + +[[ -e "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" ]] || + { sqlite3 "update TEMPLATES set md5sum='0',valid='0' \ + where name='${OPT[TEMPLATE]}';"; return 2; } + +valid="$(sqlite3 "select valid from TEMPLATES where \ + name='${OPT[TEMPLATE]}';")" + +check_rw "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" +local md5_curr +md5_curr="$(get_md5 "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml")" + +[[ "$md5" == "$md5_curr" ]] && [[ "$valid" == "1" ]] && return 0 +[[ "$md5" == "$md5_curr" ]] && [[ "$valid" == "0" ]] && return 2 +[[ "$md5" == "$md5_curr" ]] && unexpected_error check_template + +valid=0 +virt-xml-validate "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" \ + &>/dev/null && valid=1 +sqlite3 "update TEMPLATES set md5sum='$md5_curr',valid='$valid' \ + where name='${OPT[TEMPLATE]}';" + +local disks +if ((valid)); then + get_disk_devices < "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" + disks="$(read_pipe)" + sqlite3 "update TEMPLATES set disks='$disks',valid='$valid' \ + where name='${OPT[TEMPLATE]}';" +fi + +((valid)) || return 2 +return 0 +} +#=========================================================================# +check_template_disks () +# DESCRIPTION: Verify that the disks named by a template exist, can be read +# and are not locked. This check is not needed for most commands, but +# when it is needed, check_template should be succesfully run first to +# verify that the disks column in the database is correct +# INPUT: None +# OUTPUT: Error messages and exit if needed +# PARAMETERS: None +#=========================================================================# +{ +local disk qemu_out +while read -r disk; do + [[ -e "$disk" ]] || + { echo "Template ${OPT[TEMPLATE]} refers to $disk, which either"; + echo "does not exist or cannot be seen with current permissions"; + exit "$E_template"; } >&2 + [[ -r "$disk" ]] || + { echo "Template ${OPT[TEMPLATE]} refers to $disk, but the file" ; + echo "cannot be read"; + exit "$E_permission"; } + qemu_out="$(qemu-img info "$disk" 2>&1)" || + { echo "When checking the disk file $disk with qemu-img, the"; + echo "following problem was encountered:"; + echo "$qemu_out"; + exit "$E_libvirt"; } >&2 +done < <( sqlite3 "select disks from TEMPLATES where \ + name='${OPT[TEMPLATE]}';") + +return 0 +} +#=========================================================================# +check_template_exists () +# DESCRIPTION: There are a few places where it is necessary to check that +# a template exists, but not the rest of check_template, so this is its +# own function +# INPUT: None +# OUTPUT: Return 0 if OPT[TEMPLATE] exists and 1 if it does not +# PARAMETERS: None +#=========================================================================# +{ +local check +check="$(sqlite3 "select exists ( select * from TEMPLATES where\ + name='${OPT[TEMPLATE]}');")" +((check)) && return 0 +return 1 +} +#=========================================================================# +fifo_error () +# DESCRIPTION: Error to display if fifo creation files +# INPUT: None +# OUTPUT: Error message and exit code +# PARAMETERS: None +#=========================================================================# +{ + echo "Cannot make fifo" + exit "$E_extcom" +} >&2 +#=========================================================================# +lv_api_do_bad_conn () +# DESCRIPTION: Error displayed when lv_api_do cannot connect to API +# INPUT: None +# OUTPUT: Error message and exit code +# PARAMETERS: None +#=========================================================================# +{ + echo "Cannot connect to libvirt API" + exit "$E_libvirt" +} 2>/dev/null +#=========================================================================# +set_error () +# DESCRIPTION: Used when convert_to_seq fails +# INPUT: None +# OUTPUT: Error message and exit +# PARAMETERS: None +#=========================================================================# +{ +echo "Improper or badly formatted argument specifying machine or set of " +echo "machines" +exit "$E_args" +} >&2 +#=========================================================================# +target_error () +# DESCRIPTION: Used when intersection of user-specified set and set of +# existing machines that are valid targets for current command results in +# empty set +# INPUT: Name of command +# OUTPUT: Error message and exit +# PARAMETERS: $1: Name of command invoked with set +#=========================================================================# +{ +echo "Specified set of machines does not contain any valid targets" +echo "for $1 to operate on" +exit "$E_args" +} >&2 +#=========================================================================# +stage_error () +# DESCRIPTION: When an action is attempted on a 'staging' clone, (one +# created by modify-template prepare-image) but that clone is listed in +# BAD_CL, this message is displayed +# INPUT: None +# OUTPUT: Error message and exit +# PARAMETERS: None +#=========================================================================# +{ +echo "A clone staging changes to the template iamge was previously made," +echo "but it is now missing. Restore it manually, connect to the" +echo "appropriate URI if it is on another connection, or delete it from" +echo "qq2clone's database using the command:" +echo +echo " qq2clone check ${OPT[TEMPLATE]}" +echo +echo "(This clone will have ID: 0)" +exit "$E_permission" +} >&2 +#=========================================================================# +temp_error () +# DESCRIPTION: If mktemp fails, this function should be invoked +# INPUT: None +# OUTPUT: Error message and exit with E_extcom +# PARAMETERS: None +#=========================================================================# +{ +echo "Attempt to create a temp file with mktemp failed" +exit "$E_extcom" +} >&2 +#=========================================================================# +template_error () +# DESCRIPTION: Takes a return code from check_template, gives appropriate +# error message and exits if it is nonzero +# INPUT: Check_template return status +# OUTPUT: Error message and exit code or nothing +# PARAMETERS: $1: Return code from check_template +#=========================================================================# +{ +(($1 == 1)) && + { echo "The template '${OPT[TEMPLATE]}' does not exist"; + exit "$E_template"; } +(($1 == 2)) && + { echo "The template '${OPT[TEMPLATE]}' is not valid due to bad"; + echo -n "or missing XML at location:"; + echo + echo " ${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml"; + echo + exit "$E_template"; } +return 0 +} >&2 +#=========================================================================# +template_name_available () +# DESCRIPTION: Check that the template name is available, and give an +# appropriate error message if not +# INPUT: A name +# OUTPUT: An error message if needed +# PARAMETERS: $1: Template name to check +#=========================================================================# +{ +local name +while IFS= read -r name; do + if [[ "$name" == "$1" ]]; then + echo "The name $1 belongs to an existing template" + exit "$E_template" + fi +done < <(sqlite3 "select name from TEMPLATES;") +if [[ -e "${OPT[TEMPLATE_DIR]}/${1}.xml" ]]; then + echo "Although template name $1 is not currently in use," + echo "a file where this template's XML document belongs already" + echo "exists. Move or delete this file:" + echo + echo " ${OPT[TEMPLATE_DIR]}/${1}.xml" + exit "$E_template" +fi +return 0 +} >&2 +#=========================================================================# +unexpected_error () +# DESCRIPTION: Error on unexpected event, which is likely a bug in qq2clone +# INPUT: None +# OUTPUT: Error message and exit code +# PARAMETERS: $1: function name where error occurred +#=========================================================================# +{ +echo "qq2clone has encountered an unexpected problem." +echo "The problem occurred in function: $1" +exit "$E_unexpected" +} >&2 +#=========================================================================# +valid_xml_name_check () +# DESCRIPTION: Check that XML is valid after modifying name and return 0 +# if so, exit with error message else +# INPUT: write_piped XML file and new name as parameter. Leaves XML in +# pipe after execution +# OUTPUT: Error message and exit code if needed +# PARAMETERS: $1: The new name +#=========================================================================# +{ +virt-xml --edit --metadata name="$1"<<<"$(read_pipe 1)" &>/dev/null || + { echo "When trying to use name $1 to generate an xml" + echo "file, there was an error - this name is not acceptable" + echo "for a libvirt domain. Try another." + exit "$E_libvirt" ; } >&2 +} >&2 + + #--------------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---HELPERS FOR EXEC_COM_CHECK---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #--------------------------------# + +#=========================================================================# +delete_template_and_clones () +# DESCRIPTION: Delete a template and all of its clones +# INPUT: None +# OUTPUT: Status updates +# PARAMETERS: None +#=========================================================================# +{ +echo +hr +echo +echo "DELETING TEMPLATE: ${OPT[TEMPLATE]}" +local id disk +echo +local fail=0 +echo " Deleting all defined clone domains" +for id in "${!CL_MAP[@]}"; do + echo " Attempting to delete ${OPT[TEMPLATE]}#${id} ${CL_MAP["$id"]}..." + if ( delete_machine "$id" ) &> /dev/null; then + echo " Success." + else + echo " Failed." + fail=1 + fi +done +if ((fail)) || (( ${#BAD_CL[@]} )); then + echo + echo " Manually deleting files and/or undefining any remaining domains" + while read -r id; do + while read -r disk; do + [[ -z "$disk" ]] && continue + rm -f "$disk" &>/dev/null || + [[ -e "$disk" ]] && + { echo "Failed to delete $disk, check permissions. Aborting" >&2; + exit "$E_permission"; } + done < <(sqlite3 "select disks from CLONES where id='$id' and \ + template='${OPT[TEMPLATE]}'") + sqlite3 "delete from CLONES where id='$id' and \ + template='${OPT[TEMPLATE]}';" + echo " Deleted ${OPT[TEMPLATE]}#${id} ${CL_MAP["$id"]}" + done < <(sqlite3 "select id from CLONES where \ + template='${OPT[TEMPLATE]}';") +fi +echo +echo " All clones deleted." +echo +rm -f "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" &>/dev/null +if [[ -e "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" ]]; then + echo "Failed to delete template XML at" >&2 + echo "${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" >&2 + echo "Aborting" + exit "$E_permission" +fi +sqlite3 "delete from TEMPLATES where name='${OPT[TEMPLATE]}';" +echo "TEMPLATE DELETED: Template ${OPT[TEMPLATE]} deleted." +return 0 +} +#=========================================================================# +prompt_delete_bad_clones () +# DESCRIPTION: Iterate through missing clones, prompting user before +# taking action +# INPUT: None +# OUTPUT: Prompts and status updates to user +# PARAMETERS: None +#=========================================================================# +{ +local id i=0 total="${#BAD_CL[@]}" disk prompt=1 select +local t="${OPT[TEMPLATE]}" +for id in "${!BAD_CL[@]}"; do + ((i++)) + echo + hr + echo + echo "MISSING CLONE ${i} / $total" + echo " ID: $id" + echo "UUID: ${BAD_CL["$id"]}" + while read -r disk; do + echo "DISK: $disk" + done < <(sqlite3 "select disks from CLONES where id='$id' and\ + template='${t}';") + echo + if ((prompt)); then + echo " (1) Delete clone from database, DO NOT delete disk files" + echo " (2) Delete clone from database, DO delete disk files" + echo " (3) Skip this clone" + echo " (4) Do option (1) for all missing clones of this template" + echo " (5) Do option (2) for all missing clones of this template" + echo " (6) Abort: leave the clones as they are" + select="$(prompt_num 1 6)" + (( select == 6 )) && { echo "Abort"; return 0; } + (( select == 5 )) && { select=2; prompt=0; } + (( select == 4 )) && { select=1; prompt=0; } + (( select == 3 )) && { echo "Skipping"; echo; continue; } + fi + echo + if ((select==2)); then + while read -r disk; do + [[ -e "$disk" ]] || + { echo " $disk :" + echo " Already deleted or has been moved" + continue; } + if rm -f "$disk" &>/dev/null; then + echo " Deleted $disk" + else + echo " Failed to delete $disk" + fi + done < <(sqlite3 "select disks from CLONES where id='$id' and\ + template='${t}';") + fi + sqlite3 "delete from CLONES where id='$id' and template='$t';" + echo " Clone deleted from database" + echo +done +return 0 +} + + #-----------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---INTERACT WITH VIRSH/VMs---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #-----------------------------# + +#=========================================================================# +clone () +# DESCRIPTION: Clone a virtual machine from OPT[TEMPLATE] +# INPUT: If desired, designate that clone should have special ID 0 +# OUTPUT: Echo message when complete or on error +# PARAMETERS: $1: (Optional) If '0', create clone intended for staging +# changes to a base template image +#=========================================================================# +{ +local base_mach_name line check i +local txml="${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" + +if [[ "$1" == "0" ]]; then + # ID reserved for clone where changes to template image are staged + i="0" + check="$(sqlite3 "select exists ( select * from CLONES where id='0' and \ + template='${OPT[TEMPLATE]}');")" + ((check)) && return 1 + base_mach_name="${OPT[TEMPLATE]}#STAGING" +else + for((i=1;;i++)); do + check="$(sqlite3 "select exists ( select * from CLONES where id='$i' \ + and template='${OPT[TEMPLATE]}');")" + (("$check")) || break + done + base_mach_name="${OPT[TEMPLATE]}#${i}" +fi + +local name uuid +{ + read -r name + read -r uuid +} < <(unique_name_uuid 2 "$base_mach_name") + + +local storage="${OPT[STORAGE]}" +declare -a f_arr +local img new_img j=-1 type + +local disks +disks="$(sqlite3 "select disks from TEMPLATES where\ + name='${OPT[TEMPLATE]}';")" + +trap 'rm -f "${storage}/${name}.${uuid:?}.*"' INT +while read -r img; do + ((j++)) + new_img="${storage}/${name}.${uuid}.${j}.qcow2" + type="$(get_format "$img")" + qemu-img create -f qcow2 -F "$type" -b "$img" "$new_img"\ + &>/dev/null || + { rm -f "${storage}/${name}.${uuid:?}.*"; + unexpected_error clone; } + f_arr[${#f_arr[@]}]="-f" + f_arr[${#f_arr[@]}]="$new_img" +done < <(echo "$disks") + +virt-clone --original-xml "$txml" --name "$name" --uuid "$uuid"\ + --preserve-data "${f_arr[@]}" &>/dev/null || + { rm -f "${storage}/${name}.${uuid:?}.*"; + unexpected_error clone; } + +disks="" +local before=0 +for ((j=1;j<${#f_arr[@]};j+=2)); do + if ((before)); then + disks="$(echo "$disks";echo "${f_arr["$j"]}")" + else + before=1 + disks="${f_arr["$j"]}" + fi +done + +sqlite3 "insert into CLONES values \ + ('$uuid','$i','${OPT[TEMPLATE]}','$disks');" + +((OPT[QUIET])) || echo "Cloned: $name $uuid" + +CL_MAP["$i"]="$uuid" +CL_STATE["$i"]="off" + +trap 'exit' INT +if (( OPT[NORUN] )); then + return 0 +elif ((OPT[USE_SPICE])); then + connect "$i" +else + start_domain "$i" +fi + +return 0 +} +#=========================================================================# +connect () +# DESCRIPTION: Run machine. If it has spice graphics, connect to graphical +# console with virt-viewer/spicy +# INPUT: Machine number +# OUTPUT: None except on error +# PARAMETERS: $1: Machine number +#=========================================================================# +{ +if (( OPT[SPICY] )); then + command -v spicy &> /dev/null || + { echo "Cannot find command spicy" >&2; exit "$E_extcom"; } +else + command -v virt-viewer &> /dev/null || + { echo "Cannot find command virt-viewer" >&2; exit "$E_extcom"; } +fi + +start_domain "$1" + +local uuid +uuid="${CL_MAP["$1"]}" +has_spice "$1" || return 0 + +local spice +read -ra spice < <(get_spice "$1") || + { echo "Machine did not become available before timeout" >&2; + exit "$E_timeout"; } +(( $1 == 0 )) && set -- "STAGING" +if (( OPT[SPICY] )); then + command -v spicy &> /dev/null || + { echo "Cannot find command spicy" >&2; exit "$E_extcom"; } + nohup spicy --title "${OPT[TEMPLATE]}#$1" -h "${spice[0]}" \ + -p "${spice[1]}" &>/dev/null & +else + command -v virt-viewer &> /dev/null || + { echo "Cannot find command virt-viewer" >&2; exit "$E_extcom"; } + nohup virt-viewer --uuid "$uuid" &>/dev/null & +fi + +return 0 +} +#=========================================================================# +copy_disks () +# DESCRIPTION: Go through XML file, find all disk images, and copy them. +# A base name is provided, and new files placed in OPT[STORAGE] +# INPUT: XML file in pipe +# OUTPUT: Altered XML in pipe, and new image files created +# PARAMETERS: $1: Base name for disks +#=========================================================================# +{ +(($#==1)) || unexpected_error copy_disks +local elem i=0 name xml +declare -a disks +xml="$(read_pipe 1)" +[[ -n "$xml" ]] || unexpected_error copy_disks +read_pipe | get_disk_devices + +while read -r line; do disks=("${disks[@]}" "$line"); done < <(read_pipe) +write_pipe 1 <<<"$xml" +RANDOM="$$" + +for elem in "${disks[@]}"; do + ((i++)) + name="${1}.${i}" + while [[ -e "${OPT[STORAGE]}/${name}.qcow2" ]]; do + name="${1}.${i}-${RANDOM}" + done + ((OPT[QUIET])) || echo "Copying disk ${elem}..." + copy_file "$elem" "${OPT[STORAGE]}/${name}.qcow2" + do_virt_xml --edit path="$elem" --disk \ + path="${OPT[STORAGE]}/${name}.qcow2" +done + +return 0 +} +#=========================================================================# +delete_machine () +# DESCRIPTION: Delete a clone +# INPUT: Machine number +# OUTPUT: None +# PARAMETERS: $1: machine number, $2: 0 to just delete disks, 1 to wipe, 2 +# to shred +#=========================================================================# +{ +local uuid +uuid="${CL_MAP["$1"]}" + +local line disks before=0 +while read -r line; do + ((before)) && disks="${disks},"; before=1 + disks="${disks}$line" +done < <(sqlite3 "select disks from CLONES where id='$1' and\ + template='${OPT[TEMPLATE]}';") + +declare -a undef_args +undef_args=( '--managed-save' '--snapshots-metadata' '--nvram' \ + '--checkpoints-metadata' ) +if (( $2 < 2 )); then + undef_args=( "${undef_args[@]}" '--storage' "$disks") +fi +if (($2==1)); then + undef_args=( "${undef_args[@]}" "--wipe-storage" ) +fi + +destroy_domain "$1" &>/dev/null + +if (( $2 == 2 )); then + local disk + echo "Shredding ${OPT[TEMPLATE]}#$1 disks..." + while read -r disk; do + { + cd "$(dirname "$disk")" && + { shred -vf "$(basename "$disk")" 2>&1 | sed "s/^./ &/"; } && + rm -f "$disk" &>/dev/null + } || unexpected_error delete_machine + done < <(sqlite3 "select disks from CLONES where id='$1' and\ + template='${OPT[TEMPLATE]}';") +fi + +local virsh_out +virsh_out="$(virsh undefine "$uuid" "${undef_args[@]}" 2>&1)" || + { echo "$virsh_out"; unexpected_error delete_machine; } + +sqlite3 "delete from CLONES where id='$1' and \ + template='${OPT[TEMPLATE]}';" + +return 0 +} +#=========================================================================# +destroy_domain () +# DESCRIPTION: Invoke virsh destroy on given machine +# INPUT: A machine number +# OUTPUT: None +# PARAMETERS: A machine number +#=========================================================================# +{ +local uuid +uuid="${CL_MAP["$1"]}" +virsh destroy "$uuid" &>/dev/null +return 0 +} +#=========================================================================# +discard_save () +# DESCRIPTION: Delete a saved state file associated with a clone +# INPUT: A saved machine number +# OUTPUT: Error message, exit code if needed +# PARAMETERS: $1: A saved machine number +#=========================================================================# +{ +local virsh_out +virsh_out="$(virsh managedsave-remove "${CL_MAP["$1"]}" 2>&1)" || + { echo "$virsh_out"; exit "${E_libvirt}"; } +return 0 +} +#=========================================================================# +edit_xml () +# DESCRIPTION: Edit and verify OPT[TEMPLATE]'s XML file +# INPUT: None +# OUTPUT: Status updates to user, error messages as needed +# PARAMETERS: None +#=========================================================================# +{ +local xml="${OPT[TEMPLATE_DIR]}/${OPT[TEMPLATE]}.xml" +[[ -e "$xml" ]] || + { echo "The template XML is missing from $xml" + echo "There is nothing to edit." + exit "$E_template"; } >&2 + +check_template_exists || template_error $? + +local temp +temp="$(mktemp)" || temp_error +trap 'rm -f "$temp" &>/dev/null;' INT + +local ed_com="vi" +[[ -n "$EDITOR" ]] && ed_com="$EDITOR" +[[ -n "$VISUAL" ]] && ed_com="$VISUAL" + +local md5_curr md5_old +md5_old="$(get_md5 "$xml")" + +copy_file "$xml" "$temp" + +local loop=1 +while ((loop)); do + "$ed_com" "$temp" || + { echo "Editing XML with $ed_com failed" >&2; + rm -f "$temp" &>/dev/null; + exit "$E_extcom"; } + md5_curr="$(get_md5 "$temp")" + [[ "$md5_old" == "$md5_curr" ]] && + { ((OPT[QUIET])) || echo "No changes made to original XML"; + rm "$temp"; + exit 0; } + + local virt_message="" + if virt_message="$(virt-xml-validate "$temp" 2>&1)"; then + loop=0 + else + echo >&2 + echo "$virt_message" >&2 + echo "Changes resulted in malformed XML file. " >&2 + prompt_yes_abort \ + "Press (e) to edit again, anything else to abort and revert" \ + "^[Ee]$" >&2 || { rm "$temp" &>/dev/null; exit "$E_xml"; } + fi +done +move_file "$temp" "$xml" +check_template + +((OPT[QUIET])) || echo "XML modified" +trap 'exit' INT + +return 0 +} +#=========================================================================# +get_format () +# DESCRIPTION: Find format of given virtual machine image file +# INPUT: Absolute filepath to a virtual machine image file +# OUTPUT: Echoes the name of the format +# PARAMETERS: $1: Filepath +#=========================================================================# +{ +local line level=0 +while read -r line; do + [[ "$line" =~ \{[[:space:]]*$ ]] && { ((level++)); continue; } + [[ "$line" =~ \},?[[:space:]]*$ ]] && { ((level--)); continue; } + if ((level == 1)); then + [[ "$line" =~ \"format\":[[:space:]]*\"(.*)\" ]] && + { echo "${BASH_REMATCH[1]}"; + return 0; } + fi +done < <(qemu-img info --output=json "$1") +return 1 +} +#=========================================================================# +get_template_list () +# DESCRIPTION: List existing templates, alphabetically ordered, one per +# line +# INPUT: None +# OUTPUT: List of templates +# PARAMETERS: None +#=========================================================================# +{ +sqlite3 "select name from TEMPLATES;" | sort +return 0 +} +#=========================================================================# +get_spice () +# DESCRIPTION: Get the spice host and port of a running machine +# INPUT: The machine number +# OUTPUT: Echoes '$hostname $port' pertaining to spice connection +# PARAMETERS: $1: The machine number +#=========================================================================# +{ +local uuid time line spice state +time="$(date +%s)" +uuid="${CL_MAP["$1"]}" +until (( OPT[S_TIMEOUT] <= $(date +%s)-time )) ; do + spice="$(virsh domdisplay --type spice "$uuid" 2>&1)" + [[ "$spice" =~ ^'spice://'(.+):(.+)$ ]] || continue + echo "${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"; + return 0; +done +return 1 +} +#=========================================================================# +get_state () +# DESCRIPTION: Get the state of a machine by number +# INPUT: The number of a clone managed by qq2clone +# OUTPUT: Echoes the state of the machine +# PARAMETERS: $1: Machine number +#=========================================================================# +{ +echo "${CL_STATE["$1"]}" +return 0 +} +#=========================================================================# +get_state_set () +# DESCRIPTION: List all machines in a given state +# INPUT: Name of a state +# OUTPUT: Echoes a space delimited list of machine numbers (can be empty) +# PARAMETERS: $1: state name +#=========================================================================# +{ +local id before=0 state +while read -r id; do + state="$(get_state "$id" )" + if [[ "$state" == "$1" ]] || [[ "$1" == "all" ]]; then + [[ "$id" == "0" ]] && continue + ((before)) && echo -n " "; before=1 + echo -n "$id " + fi +done < <(echo "${!CL_MAP[@]}" | tr " " "\n") +echo +return 0 +} +#=========================================================================# +get_target_set () +# DESCRIPTION: Get the set of all machines that a command may legally +# operate on +# INPUT: A command name +# OUTPUT: Echoes a space delimited set of machine numbers (can be empty) +# PARAMETERS: $1: The command name +#=========================================================================# +{ +local id before=0 statelist state +statelist="$(list_states "$1")" +while read -r id; do + state="$(get_state "$id" )" + if [[ "$statelist" =~ all ]] || [[ "$statelist" =~ $state ]] ; then + [[ "$id" == "0" ]] && continue + ((before)) && echo -n " "; before=1 + echo -n "$id" + fi +done < <(echo "${!CL_MAP[@]}" | tr " " "\n") +echo +return 0 +} +#=========================================================================# +list_display () +# DESCRIPTION: Display list of clones and their state to user +# INPUT: Optionally, pass argument "1" to print detailed xml list +# OUTPUT: Clone list +# PARAMETERS: $1: Set to one to print xml summary instead of a regular +# list +#=========================================================================# +{ +declare -A statelist +local line state + +if [[ -n "${CL_MAP[0]}" ]]; then + statelist["${CL_STATE[0]}"]="0" +fi + +while read -r line; do + [[ -z "$line" ]] && continue + state="$(get_state "$line")" + if [[ -n "${statelist["$state"]}" ]]; then + statelist["$state"]="${statelist["$state"]} $line" + else + statelist["$state"]="$line" + fi +done < <(get_state_set all | tr " " "\n") + +declare -a states machines +read -ra states \ + < <(echo "${!statelist[@]}" |tr " " "\n" | sort | tr "\n" " ") +local state m +if (($1)); then +#shellcheck disable=2119 +# This is only a (functioning) mock implementation meant as a proof of +# concept for what XML describing qq2clone's current state may be like +# For this feature to be complete, it would: use a defined format, be +# implemented with proper, modular code, and contain all information to +# fully define qq2clone's state except for machine images and domain xml. + echo " " +else + echo "[${OPT[TEMPLATE]}]"; + if [[ -z "${statelist[*]}" ]]; then + echo " No clones" + else + for state in "${states[@]}"; do + read -ra machines <<<"$(strip_ws "${statelist["$state"]}")" + echo -n " ${state}: "; + for elem_mach in "${machines[@]}"; do + (( elem_mach )) || { echo -n "[#0: STAGING] "; continue; } + echo -n "#$elem_mach " + done + echo + done + fi +fi +return 0 +} +#=========================================================================# +list_states () +# DESCRIPTION: Helper for get_target_set. Lists machine states that a +# given command can act on. States are the same as listed in man virsh, +# but "shut off" is "off", "in shutdown" is "in-shutdown", "saved" is +# added, and "all" addresses machines in any state +# INPUT: The command name +# OUTPUT: Echoes a space delimited list of states +# PARAMETERS: $1: The command name, or if no arguments list all states +# as a space delimited list +#=========================================================================# +{ +if (($#)); then + if [[ "$1" == connect ]]; then + echo "all" + elif [[ "$1" == destroy ]]; then + echo "running idle paused in-shutdown pmsuspended" + elif [[ "$1" == exec ]]; then + echo "all" + elif [[ "$1" == restore ]]; then + echo "saved" + elif [[ "$1" == resume ]]; then + echo "paused" + elif [[ "$1" == rm ]]; then + echo "all" + elif [[ "$1" == rm-wipe ]]; then + echo "all" + elif [[ "$1" == rm-shred ]]; then + echo "all" + elif [[ "$1" == save ]]; then + echo "running pmsuspended idle paused paused" + elif [[ "$1" == save-rm ]]; then + echo "saved" + elif [[ "$1" == start ]]; then + echo "off crashed saved" + elif [[ "$1" == suspend ]]; then + echo "running pmsuspended idle" + fi +else + echo -n "all crashed idle in-shutdown off paused pmsuspended running" + echo " saved" +fi +return 0 +} +#=========================================================================# +load_template () +# DESCRIPTION: Run check_template, build global arrays CL_MAP[ID]=UUID, +# CL_STATE[ID]=STATE, and BAD_CL[ID]=UUID +# INPUT: None +# OUTPUT: None +# PARAMETERS: None +#=========================================================================# +{ +check_template +unset BAD_CL CL_MAP CL_STATE NAME_MAP +declare -ga BAD_CL CL_MAP CL_STATE NAME_MAP + +local t="${OPT[TEMPLATE]}" + +local check +check="$(sqlite3 "select exists ( select id,uuid from CLONES where \ + template='${OPT[TEMPLATE]}' );")" +((check)) || return 0 + +# Build array of all UUIDs -> IDs for template's clones +declare -A uuid_map +local id uuid +while read -r id; do + read -r uuid + uuid_map["$uuid"]="$id" +done < <(sqlite3 "select id,uuid from CLONES where template='$t';") + +lv_api_do_open + +lv_api_do_comm list +while read -r uuid; do + [[ -n "${uuid_map["$uuid"]}" ]] && + CL_MAP["${uuid_map["$uuid"]}"]="$uuid" +done < <(read_pipe); + +local match _uuid +for uuid in "${!uuid_map[@]}"; do + match=0 + for _uuid in "${CL_MAP[@]}"; do + [[ "$uuid" == "$_uuid" ]] && { match=1; break; } + done + ((match)) && continue + BAD_CL["${uuid_map["$uuid"]}"]="$uuid" +done + +local state="" name="" +for id in "${!CL_MAP[@]}"; do + uuid="${CL_MAP["$id"]}" + lv_api_do_comm get_state "$uuid" && state="$(read_pipe)" + CL_STATE["$id"]="$state" + lv_api_do_comm get_name "$uuid" && name="$(read_pipe)" + NAME_MAP["$id"]="$name" +done + +lv_api_do_close + +return 0 +} +#=========================================================================# +save_domain () +# DESCRIPTION: Save the state of a machine to disk +# INPUT: Machine number +# OUTPUT: None +# PARAMETERS: $1: Machine number +#=========================================================================# +{ +local uuid +uuid="${CL_MAP["$1"]}" +virsh managedsave "$uuid" &>/dev/null || + { echo "Failed to save domain ${OPT[TEMPLATE]}#${1}"; + echo "Does it have shared directories mounted?"; + exit "$E_libvirt"; } >&2 +return 0 +} +#=========================================================================# +start_domain () +# DESCRIPTION: If a domain is not running, start it +# INPUT: VM number or "staging" +# OUTPUT: None, except on error. Returns 0 if machine is running +# PARAMETERS: $1: Machine number +#=========================================================================# +{ + +local state uuid +uuid="${CL_MAP["$1"]}" + +state="$(get_state "$1")" + +if [[ "$state" =~ ^(off|crashed|saved)$ ]]; then + virsh start "$uuid" >/dev/null || + { echo "Virsh failed to start domain" >&2; + exit "$E_libvirt"; } +elif [[ "$state" == "paused" ]]; then + virsh resume "$uuid" >/dev/null || + { echo "Virsh failed to resume domain" >&2; + exit "$E_libvirt"; } +fi + +return 0 +} +#=========================================================================# +suspend_domain () +# DESCRIPTION: Suspend execution state of machine +# INPUT: A machine number +# OUTPUT: None +# PARAMETERS: $1: A machine number +#=========================================================================# +{ +local uuid +uuid="${CL_MAP["$1"]}" +virsh suspend "$uuid" &>/dev/null +} +#=========================================================================# +unique_name_uuid () +# DESCRIPTION: Generate a name and/or uuid unique within libvirt connection +# INPUT: Choice of uuid, name or both, and base machine name if requesting +# name +# OUTPUT: Echo name and uuid in that order, on separate lines +# PARAMETERS: $1: 0 for name only, 1 for uuid only, or 2 for both +# $2: Base machine name (required unless $1 is 1) +#=========================================================================# +{ # TODO there is no reason for this to be one function +local name="$2" uuid loop line unique list + +if (($1 != 1)); then + RANDOM=$$ + list="$(virsh list --all --name)" + unique=0 + until ((unique)); do + while read -r line; do + [[ -z "$line" ]] && continue + if [[ "$line" == "$name" ]]; then + name="${2}___${RANDOM}" + continue 2 + fi + done < <(echo "$list") + unique=1 + done + echo "$name" +fi + +if (($1 != 0)); then + list="$(virsh list --all --uuid)" + list="${list}$(echo;ls -1 "${OPT[STORAGE]}")" + unique=0 + uuid="$(uuidgen -r)" + until ((unique)); do + while read -r line; do + [[ -z "$line" ]] && continue + if [[ "$line" =~ .*"$uuid".* ]]; then + uuid="$(uuidgen -r)" + continue 2 + fi + done < <(echo "$list") + unique=1 + done + echo "$uuid" +fi + +return 0 +} + + #---------------------------------------------# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---PARSE COMMAND STRING AND INVOKE COMMAND---# + #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# + #---------------------------------------------# + +# Generally, user input should be checked in this section. When functions +# from other sections omit testing that user-defined values are valid, +# this is why + +#=========================================================================# +convert_to_seq () +# DESCRIPTION: Take a set of the format described in the man page and echo +# it as an ordered ascending, space delimited sequence of valid machine +# numbers +# INPUT: A set +# OUTPUT: A sequence of numbers. Returns 1 if bad set +# PARAMETERS: $1: A set +#=========================================================================# +{ +{ [[ "$1" =~ ^[,-] ]] || [[ "$1" =~ [,-'^']$ ]] || + [[ "$1" =~ [,-][,-] ]] || [[ "$1" =~ [[:space:]] ]] || + [[ "$1" =~ ^.(.*[^',']\^) ]]; } && return 1 + +declare -a parts +IFS="," read -ra parts <<<"$1" +local states i p not LH RH minus plus +states="$(list_states| tr " " "|")" + +for ((i=0;i<${#parts[@]};i++)); do + p="${parts["$i"]}" + not=0 + if [[ "${p:0:1}" == "^" ]]; then + p="${p:1}" + not=1 + fi + + if [[ "$p" =~ ^${states}$ ]]; then + p="$(get_state_set "$p")" + elif [[ "$p" =~ ^([0-9]+)'-'([0-9]+)$ ]]; then + LH="${BASH_REMATCH[1]}"; RH="${BASH_REMATCH[2]}"; + ((RH>LH)) || return 1 + ((LH>0)) || return 1 + for ((p=LH;LH0)) || return 1 + else + return 1 + fi + + if ((not)); then + minus="$minus $p" + else + plus="$plus $p" + fi +done +[[ "$plus $minus" =~ [^0-9' '] ]] && return 1 + +local n before=0 +while read -r n; do + [[ -z "$n" ]] && continue + [[ " $minus " =~ [[:space:]]${n}[[:space:]] ]] && continue + ((before)) && echo -n " "; before=1 + echo -n "$n" +done < <( tr " " "\n" <<<"$plus" | sort -n | uniq ) +echo + +return 0 +} +#=========================================================================# +exec_com () +# DESCRIPTION: Apply flags to modify script behavior, determine which +# command the user has invoked, and perform some parsing and +# validating of input until it's time to hand off to a more specific +# function +# INPUT: All positional parameters sent to qq2clone +# OUTPUT: Error messages/exit values as needed +# PARAMETERS: Pass "$@" directly here from the global scope +#=========================================================================# +{ +parse_flags "$@" +local offset +offset="$(read_pipe)" +shift "$offset" +local com +com="$1" +shift + +local verbose_coms +verbose_coms="config|check|list|list-templates|exec|edit|modify-template" +if (( OPT[QUIET] == 2)) && [[ ! "$com" =~ ^($verbose_coms)$ ]]; then + exec &>/dev/null +fi + +virsh uri |& grep -qi ^QEMU || + { echo "Current libvirt URI is not QEMU:///" >&2; exit "$E_libvirt"; } + +[[ -n "$com" ]] || { usage >&2; exit "$E_args"; } + +# Commands which don't want check_template run (in advance of calling them +# anyway) +if [[ "$com" == "check" ]]; then + exec_com_check "$@" + exit 0 +elif [[ "$com" == "config" ]]; then + exec_com_config "$@" + exit 0 +elif [[ "$com" == "copy-template" ]]; then + exec_com_copy_template "$@" + exit 0 +elif [[ "$com" == "delete-template" ]]; then + exec_com_delete_template "$@" + exit 0 +elif [[ "$com" == "import-template" ]]; then + exec_com_import_template "$@" + exit 0 +elif [[ "$com" == "list-templates" ]]; then + exec_com_list_templates "$@" + exit 0 +elif [[ "$com" == "modify-template" ]]; then + exec_com_modify_template "$@" + exit 0 +elif [[ "$com" == "edit" ]]; then + exec_com_edit "$@" + exit 0 +elif [[ "$com" == "list" ]]; then + exec_com_list "$@" + exit 0 +fi + +# Clone and the set commands below get check_template run +if [[ "$com" == "clone" ]]; then + check_template; template_error "$?" + load_template + exec_com_clone "$@" + exit 0 +fi + +# All remaining commands require similiar logic to invoke, and act on sets +# of machines. set_coms[$com] provides a list of arguments to exec_com_set +declare -A set_coms +set_coms["connect"]="connect Connected" +set_coms["destroy"]="destroy_domain Destroyed" +set_coms["exec"]="This one is a special case, this text isn't used" +set_coms["restore"]="start_domain Restored" +set_coms["resume"]="start_domain Resumed" +set_coms["rm"]="delete_machine Deleted 0" +set_coms["rm-wipe"]="delete_machine Deleted_and_wiped 1" +set_coms["rm-shred"]="delete_machine Deleted_and_shredded 2" +set_coms["save"]="save_domain Saved" +set_coms["save-rm"]="discard_save Discarded_saved_state 0" +set_coms["start"]="start_domain Started" +set_coms["suspend"]="suspend_domain Suspended" + +local match=0 elem +for elem in "${!set_coms[@]}"; do + [[ "$elem" == "$com" ]] && { match=1; break; } +done +((match)) || { echo "Unknown command $com" >&2; exit "$E_args"; } +(($#)) || arg_error 0 "$com" + +load_template + +local seq +seq="$(convert_to_seq "$1")" || set_error +shift + +local set +set="$(seq_intersection "$seq" "$(get_target_set "$com")")" +[[ -n "$set" ]] || target_error "$com" + +declare -a command_array +read -ra command_array <<<"${set_coms["$com"]}" +if [[ "$com" == exec ]]; then + exec_com_exec "$set" "$@" + exit 0 +else + (($#)) && arg_error 1 "$com" +fi + +exec_com_set "$set" "${command_array[@]}" +exit 0 +} +#=========================================================================# +exec_com_check () +# DESCRIPTION: Attempt to find and solve problems regarding +# inconsistency between the database and UUIDs present on the libvirt +# connection, files in qq2clone's pool that aren't associated with a +# machine on the connection, or invalid template XML +# INPUT: Specify a template name, or nothing to act on all templates +# OUTPUT: Prompts and status updates +# PARAMETERS: $1: (optional) template name +#=========================================================================# +{ +(($# > 1)) && arg_error 1 check +local t + +declare -a templates +if (($#)); then + check_template_exists "$1" || template_error 1 + templates[0]="$1" +else + while read -r t; do + templates=( "${templates[@]}" "$t" ) + done < <(get_template_list) +fi + +for t in "${templates[@]}"; do + echo "BEGIN CHECK TEMPLATE: $t" + echo + OPT[TEMPLATE]="$t" + load_template + if check_template; then + echo "XML: Valid" + else + echo "XML: Invalid or missing" + echo + echo "Fix manually by repairing or replacing XML file at:" + echo + echo " ${OPT[TEMPLATE_DIR]}/${t}.xml" + echo + echo "qq2clone cannot repair bad XML. Fix this problem manually, or" + echo "allow qq2clone to delete the template and all of its clones." + echo + echo "Delete $t and all of its clones?" + echo "(Backing template disk files will not be touched)" + echo + if prompt_yes_no; then + delete_template_and_clones + echo + hr + continue + fi + fi + echo + + local n sum + + sum="$(( ${#BAD_CL[@]} + ${#CL_MAP[@]} ))" + echo "TOTAL CLONES: $sum" + if (( ${#BAD_CL[@]} )); then + echo + echo "Of these clones, there are some that have either been deleted" + echo "or undefined by a tool other than qq2clone, or exist on" + echo "another libvirt URI and cannot presently be seen." + echo + echo "TOTAL MISSING CLONES: ${#BAD_CL[@]}" + prompt_delete_bad_clones + fi + echo + echo "END CHECK TEMPLATE: $t" + echo + hr + echo +done + +exit 0 +} +#=========================================================================# +exec_com_clone () +# DESCRIPTION: Create clones of OPT[TEMPLATE] +# INPUT: A positive number, or nothing to create 1 clone +# OUTPUT: Outputs a total at the end, error messages/exit codes as needed +# PARAMETERS: $1: (Optional) a number +#=========================================================================# +{ +(( $# < 2 )) || arg_error 1 "clone" +if (($#)); then + [[ "$1" =~ ^[0-9]+$ ]] || arg_error 2 "clone" "$1" +fi + +check_template_disks + +(( $# == 0 )) && { clone; exit 0; } + +local i +for ((i=0;i<$1;i++)); do + clone +done + +exit 0 +} +#=========================================================================# +exec_com_config () +# DESCRIPTION: View or change configuration options +# INPUT: subcommand and further arguments +# OUTPUT: Varies +# PARAMETERS: $1: Subcommand list, info, or edit, $2: option name (for +# info and edit), $3: new option value (for edit) +#=========================================================================# +{ + +if ((OPT[QUIET] == 2)); then + [[ "$1" =~ ^(list|info)$ ]] || exec &>/dev/null +fi + +(( $# )) || arg_error 0 config + +if [[ "$1" == "list" ]]; then + [[ -n "$2" ]] && arg_error 1 "config list" + disp_conf_names + exit 0 +fi + +local option +read -r option < <(echo "$2" | tr "[:lower:]" "[:upper:]") + +if [[ "$1" == "info" ]]; then + [[ -n "$2" ]] || arg_error 0 "config info" + [[ -n "$3" ]] && arg_error 1 "config info" + disp_conf_desc "$option" || exit "$E_args" + exit 0 +fi + +if [[ "$1" == "edit" ]]; then + [[ -n "$2" ]] || arg_error 0 "config edit" + [[ -n "$4" ]] && arg_error 1 "config edit" + check_config "$option" || { echo "Unknown option: $option"; + exit "$E_args"; } + local line + if (($#==3));then + line="$3" + else + ((OPT[QUIET]==2)) && exit "$E_args" + echo "Enter new value for $2 without quotes:" + read -r line + line="$(strip_ws "$line")" + fi + local retval + write_config "$option" "$line" || retval="$?" + (( retval == 1 )) && arg_error 2 "config edit" "$2" + (( retval == 2 )) && + { echo "Bad value for option $option: $line"; exit "$E_args"; } + echo "Configuration value has been saved" + exit 0 +fi + +arg_error 2 config "$1" +} +#=========================================================================# +exec_com_copy_template () +# DESCRIPTION: Copy an existing template with a new name +# INPUT: The old and new template name +# OUTPUT: Status update/error messages +# PARAMETERS: $1: Existing template, $2: Copy's name +#=========================================================================# +{ +(($# < 2)) && arg_error 0 copy-template +(($# > 2)) && arg_error 1 copy-template +local old new +old="${OPT[TEMPLATE_DIR]}/$1.xml" +new="${OPT[TEMPLATE_DIR]}/$2.xml" + +OPT[TEMPLATE]="$1" +check_template || template_error "$?" + +template_name_available "$2" + +write_pipe 1 <"${old}" +valid_xml_name_check "$2" +do_virt_xml --edit --metadata name="$2" + +((OPT[COPY_DISKS])) && copy_disks "$2" + +write_file "$new" + +local md5 +md5="$(get_md5 "$new")" + +local disks +get_disk_devices <"$new" +disks="$(read_pipe)" + +sqlite3 "insert into TEMPLATES values ('$2','$md5','$disks','1');" + +(( OPT[QUIET] )) || + echo "Copy \"$2\" of template \"$1\" made successfully" +exit 0 +} +#=========================================================================# +exec_com_delete_template () +# DESCRIPTION: Delete an existing template +# INPUT: A template name +# OUTPUT: Status updates/error messages +# PARAMETERS: $1: Template name +#=========================================================================# +{ +(( $# )) || arg_error 0 "delete-template" +(( $# > 1 )) && arg_error 1 "delete-template" +local txml="${OPT[TEMPLATE_DIR]}/${1}.xml" +OPT[TEMPLATE]="$1" +load_template +check_template; template_error "$?" + +if [[ ! -e "$txml" ]]; then + echo "No template named $1 exists" >&2 + exit "$E_template" +fi + +local char +if ! ((OPT[QUIET])); then + echo "Are you sure you want to delete template $1? Storage volumes" + echo "will not be touched." + prompt_yes_abort || exit 0 +fi + +local check +check="$(sqlite3 "select exists \ + (select * from CLONES where template='$1');")" +if ((check));then + echo "Clones must be deleted before their parent template" + echo "This can be done with:" + echo + echo " qq2clone -t ${OPT[TEMPLATE]} rm all" + echo " qq2clone modify-template ${OPT[TEMPLATE]} discard-image" + exit "$E_args" +fi >&2; + +check_rw "$txml" +rm -f "$txml" &>/dev/null || unexpected_error exec_com_delete_template +sqlite3 "delete from TEMPLATES where name='$1';" + +((OPT[QUIET])) || echo "Template $1 deleted" +exit +} +#=========================================================================# +exec_com_edit () +# DESCRIPTION: Edit the XML of a clone +# INPUT: A machine number +# OUTPUT: Status messages/errors +# PARAMETERS: $1: A machine number +#=========================================================================# +{ + virsh edit "${CL_MAP["$1"]}" + exit 0 +} +#=========================================================================# +exec_com_exec () +# DESCRIPTION: Execute arbitrary commands in a context where $uuid, $name, +# and $disks are defined +# INPUT: A set of machines and a command string +# OUTPUT: Dependent on input +# PARAMETERS: $1: A set of machine numbers, $2 and on: arbitrary +#=========================================================================# +{ +declare -a machines +read -ra machines <<<"$1" +shift +local elem uuid disks +for elem in "${machines[@]}"; do + uuid="${CL_MAP["$elem"]}" + name="${NAME_MAP["$elem"]}" + disks="$(sqlite3 "select disks from CLONES where id='$elem' and \ + template='${OPT[TEMPLATE]}';")" + export uuid name disks + bash -ic "eval '$*'" || + { ((OPT[QUIET]==2)) || echo "Iteration of exec failed, abort" >&2; + exit "$E_args"; } +done +exit 0 +} +#=========================================================================# +exec_com_import_template () +# DESCRIPTION: Import xml from a libvirt domain, or from a file +# INPUT: A filepath, or a libvirt domain name/uuid +# OUTPUT: Status updates if not OPT["QUIET"], error messages if named +# domain/xml does not exist +# PARAMETERS: +# $1: Absolute filepath to a libvirt domain XML file, or the name/uuid of +# a domain defined on the current libvirt connection +# $2: Optional. If set, use this value for template name rather than +# the one in domain XML +#=========================================================================# +{ +(( $# < 1 )) && arg_error 0 import-template +(( $# > 2 )) && arg_error 1 import-template +local xml +import_get_xml "$1" +xml="$(read_pipe)" + +find_tag '//domain[@type="kvm"]/@type'<<<"$xml" +local match +match="$(read_pipe)" +if [[ -z "$match" ]]; then + find_tag '//domain[@type="qemu"]/@type'<<<"$xml" + match="$(read_pipe)" + if [[ -z "$match" ]]; then + echo "Domain must be of type QEMU or KVM" >&2 + exit "$E_template" + fi +fi + +write_pipe 1 <<<"$xml" +get_template_name "$2" +local xmlname name +{ +read -r xmlname +read -r name +} < <(read_pipe) + +write_pipe 1 <<<"$xml" +do_virt_xml --edit --metadata name="$name" + +((OPT[COPY_DISKS])) && copy_disks "$name" + +write_file "${OPT[TEMPLATE_DIR]}/${name}.xml" + +get_disk_devices <"${OPT[TEMPLATE_DIR]}/${name}.xml" +local disks +disks="$(read_pipe)" + +local md5 +md5="$(get_md5 "${OPT[TEMPLATE_DIR]}/${name}.xml")" + +sqlite3 "insert into TEMPLATES values ('$name','$md5','$disks','1');" + +((OPT[QUIET])) || echo "Machine imported as: \"$name\"" + +if [[ "$1" =~ ^[^/] ]] && ! (( OPT[QUIET] )) ; then + user_undefine_domain "$xmlname" +fi + +exit 0 +} +#=========================================================================# +exec_com_list () +# DESCRIPTION: List clones +# INPUT: Nothing, "all", or "xml" +# OUTPUT: A list of clones and their state +# PARAMETERS: $1: (optional) "all" to run this command for all templates, +# "xml" to produce an xml document with detailed information about +# qq2clone's overall state +#=========================================================================# +{ +(( $# > 1)) && arg_error 1 "list" +if (($#)); then + local line + if [[ "$1" == "all" ]]; then + local before=0 + while read -r line; do + ((before)) && echo; before=1 + OPT[TEMPLATE]="$line" + load_template + list_display 0 + done < <(get_template_list) + elif [[ "$1" == "xml" ]]; then + echo "" + local name value + while read -r name; do + read -r value + echo " " + done < <(sqlite3 "select name,value from CONFIG;") + echo " ${LIBVIRT_DEFAULT_URI:-missing}" + while read -r line; do + OPT[TEMPLATE]="$line" + load_template + list_display 1 + done < <(get_template_list) + echo "" + else + arg_error 2 "list" "$1" + fi +else + [[ -z "${OPT[TEMPLATE]}" ]] && + { ((OPT[QUIET])) || echo "Specify the template to list" >&2 + exit "$E_template"; } + check_template_exists || template_error 1 + load_template + list_display +fi +exit 0 +} +#=========================================================================# +exec_com_list_templates () +# DESCRIPTION: List all template names +# INPUT: None +# OUTPUT: A list of template names +# PARAMETERS: None +#=========================================================================# +{ +(($#)) && arg_error 1 list-templates +get_template_list +exit 0 +} +#=========================================================================# +exec_com_modify_template () +# DESCRIPTION: Modify image(s) of an existing template +# INPUT: Template name, subcommand, further arguments +# OUTPUT: Status updates/error messages +# PARAMETERS: $1: Template name, $2 and on: subcommand and further +# arguments, see man page or read the if/elifs below +#=========================================================================# +{ +if ((OPT[QUIET] == 2)); then + [[ "$2" == "edit" ]] || exec &>/dev/null +fi + +(($#<2)) && arg_error 0 modify-template +(($#>3)) && arg_error 1 modify-template +if (($#==3)); then + { [[ "$2" == "commit-image" ]] || [[ "$2" == "rename" ]] ; } || + arg_error 2 modify-template "$1" "$2" "$3" +fi +OPT[TEMPLATE]="$1" + +if [[ "$2" == "edit" ]]; then + edit_xml + exit 0 +fi +check_template; template_error "$?" +load_template + +local is_staging=0 +[[ -n "${CL_STATE[0]}" ]] && is_staging=1 +[[ -n "${BAD_CL[0]}" ]] && is_staging=2 + +if [[ "$2" == "prepare-image" ]]; then + OPT[NORUN]=1 + ((is_staging == 2)) && stage_error + ((is_staging)) || { clone 0; load_template; } + connect 0 + +elif [[ "$2" == "commit-image" ]]; then + ((is_staging == 2)) && stage_error + if (($#==3)); then + [[ "$3" == "force" ]] || arg_error 2 modify-template "$1" "$2" "$3" + fi + ((is_staging)) || + { echo "No changes are staged" >&2; exit "$E_args"; } + commit_image "$@" + +elif [[ "$2" == "destroy-image" ]]; then + ((is_staging == 2)) && stage_error + local state uuid + state="$(get_state 0)" + [[ "$state" == "running" ]] || + { echo "Domain is not running" >&2; exit "$E_args"; } + uuid="${CL_MAP[0]}" + virsh destroy "$uuid" &>/dev/null + +elif [[ "$2" == "discard-image" ]]; then + ((is_staging == 2)) && stage_error + ((is_staging)) || + { echo "No image to discard" >&2; exit "$E_args"; } + delete_machine 0 0 + ((OPT[QUIET])) || echo "Image discarded" + +elif [[ "$2" == rename ]]; then + (( $#==3)) || arg_error 0 "modify-template $1 $2" + rename_template "$@" +else + arg_error 2 "modify-template" "$2" +fi +exit 0 +} +#=========================================================================# +exec_com_set () +# DESCRIPTION: Any qq2clone command that acts on a set of machines, with +# the exception of exec, uses this function to iterate over all machines +# in the set +# INPUT: Set of machines to act on, command to invoke, text to display to +# user, and any additional parameters to pass on +# OUTPUT: Status updates after each iteration +# PARAMETERS: $1: the set to act on, $2: Function name, $3: Text to add +# onto status update at end of function, with _ replaced by space, $4 +# and on: passed on to function called +#=========================================================================# +{ +local set com text +set="$1"; shift +com="$1"; shift +text="$1"; shift + +declare -a machines +read -ra machines <<<"$set" + +while [[ "$text" =~ (.+)_+(.+) ]]; do + text="${BASH_REMATCH[1]} ${BASH_REMATCH[2]}" +done + +local elem +for elem in "${machines[@]}"; do + "$com" "$elem" "$@" + ((OPT[QUIET])) || + echo "${text}: ${OPT[TEMPLATE]}#${elem} ${CL_MAP["$elem"]}" +done + +exit 0 +} +#=========================================================================# +hr () +# DESCRIPTION: Horizontal rule, constructed with - +# INPUT: None +# OUTPUT: Lots of - +# PARAMETERS: None +#=========================================================================# +{ +echo ---------------------------------------------------------------------- +return 0 +} +#=========================================================================# +parse_flags () +# DESCRIPTION: Check all flags and change global variables accordingly +# INPUT: exec_com passes $@ here, containing all cmd line parameters +# OUTPUT: write_pipe the number by which exec_com should shift, +# or if unknown option is encountered exit with error message/code +# PARAMETERS: $@: Parameters to exec_com, originally from command line +#=========================================================================# +{ +# Check for --quiter/-Q first +declare -a args +local d=0 +args=( "$@" ) +exec 8>&1 +exec 9>&2 + +[[ "${args[0]}" == "--quieter" ]] && args[0]="-Q" +if [[ "${args[0]}" =~ ^\-Q ]]; then + OPT[QUIET]=2 + exec &>/dev/null +fi + +local short=":c:Cfghnqrs:St:vV" +local long="connection=c,copy-disks=C,no-spice=f,use-spice=g,help=h," +long="${long}no-run=n,quiet=q,run=r,storage=s,spicy=S," +long="${long}template=t,verbose=v,virt-viewer=V" + +short_flags "$short" "$long" "${args[@]}" +read -ra args < <(read_pipe) +set -- "${args[@]}" + +local opt optstring +while getopts "${short}Q" opt; do + case "$opt" in + c) LIBVIRT_DEFAULT_URI="$OPTARG" + export LIBVIRT_DEFAULT_URI + virsh list &>/dev/null || + { echo "Virsh cannot connect to URI \"$OPTARG\", exiting" >&2; + exit "$E_args"; } + ;; + C) OPT[COPY_DISKS]=1 + ;; + f) OPT[USE_SPICE]=0 + ;; + g) OPT[USE_SPICE]=1 + ;; + h) ((OPT[QUIET]==2)) && exit "$E_args" + ((OPT[QUIET]=0)); usage; exit 0 + ;; + n) OPT[NORUN]=1 + ;; + q) (( OPT[QUIET] )) || OPT[QUIET]=1 + ;; + Q) : # Handled above + ;; + r) OPT[NORUN]=0 + ;; + s) storage_opt "$OPTARG" + ;; + S) OPT[USE_SPICE]=1; OPT[SPICY]=1 + ;; + t) OPT[TEMPLATE]="$OPTARG" + check_template_exists; template_error $? + ;; + v) OPT[QUIET]=0 + ;; + V) OPT[USE_SPICE]=1; OPT[SPICY]=0 + ;; + :) [[ "$long" =~ (,|^)([^,]+)=$OPTARG ]] + optstring="--${BASH_REMATCH[2]}/-${OPTARG}" + echo "Required argument to $optstring not found" >&2 + exit "$E_args" + ;; + *) echo "Option \"$OPTARG\" is not recognized" >&2 + exit "$E_args" + esac +done + +((OPTIND+=d)) +{ [[ -z "$OPTIND" ]] || (( OPTIND < 1 )) ; } && OPTIND=1 + +if [[ "${OPT[STORAGE]}/" =~ ^("${OPT[TEMPLATE_DIR]}/") ]]; then + echo "Invalid storage location ${OPT[STORAGE]}" + exit "$E_args" +fi + +write_pipe 0 $(( OPTIND-1 )) +exec 1>&8 8>&- +exec 2>&9 9>&- + +return 0 +} +#=========================================================================# +seq_intersection () +# DESCRIPTION: Echo the intersection of two integer sets +# INPUT: Two space delimited integer sets +# OUTPUT: The intersection of the two sets, space delimited, ordered +# ascending +# PARAMETERS: $1, $2: Integer sets +#=========================================================================# +{ +local n before=0 +while read -r n; do + [[ -z "$n" ]] && continue + [[ ! " $2 " =~ [[:space:]]${n}[[:space:]] ]] && continue + ((before)) && echo -n " "; before=1 + echo -n "$n" +done < <(tr " " "\n" <<<"$1" | sort -n | uniq) +echo + +return 0 +} +#=========================================================================# +short_flags () +# DESCRIPTION: translate long option names into short ones +# INPUT: A string describing all short options, another mapping long +# names to their short equivalents, and the arguments to check +# OUTPUT: write_pipe the parameters $3 and on passed to this function, +# but with long names translated to short ones +# PARAMETERS: $1: a string of the type used by builtin getopts. Must +# include ALL options, even those without a long name counterpart +# $2: a string of the form a-long=a,b-long=b +# $3 and on: all arguments to be checked +#=========================================================================# +{ +local s_string="$1" l_string="$2" +shift 2 +declare -a short_args=( "$@" ) +local elem i + +for ((i=0;i<${#short_args[@]};i++)); do + elem="${short_args["$i"]}" + if [[ "$elem" == "--" ]]; then + break + elif [[ "$elem" =~ ^-- ]]; then + elem="${elem:2}" + if [[ "$l_string" =~ (^|,)($elem)=(.) ]]; then + elem="${BASH_REMATCH[3]}" + short_args["$i"]="-$elem" + ((i--)) + else + echo "Unknown option: $elem" >&2 + exit "$E_args" + fi + elif [[ "$elem" =~ ^- ]]; then + local len=$(( ${#elem} - 1 )) + elem="${elem:${len}}" + if [[ "$s_string" =~ $elem: ]]; then + ((i++)) + fi + else + break + fi +done + +write_pipe 0 "${short_args[*]}" +return 0 +} +#=========================================================================# +storage_opt () +# DESCRIPTION: Helper for parse_flags. Handles checking and setting user +# option defining OPT[STORAGE] +# INPUT: $OPTARG to -s option +# OUTPUT: None, except on error +# PARAMETERS: $1: argument to --storage/-s +#=========================================================================# +{ +if [[ "$1" =~ ^/ ]]; then + OPT["STORAGE"]="$1" +else + virsh pool-info "$1" &>/dev/null || + { echo "No such pool \"$1\" exists on current libvirt connection" >&2; + exit "$E_args"; } + local line match=0 + virsh pool-dumpxml "$1" 2>/dev/null | + find_tag "//pool[@type='dir']/target/path" + while read -r line; do + match=1 + [[ "$line" =~ ^[\<\>] ]] || OPT[STORAGE]="$line" + done < <(read_pipe) + ((match)) || + { echo "Specified pool is not of type dir, so it is not supported by" + echo "qq2clone at this time" + exit "$E_args"; } >&2 +fi +check_dir "${OPT[STORAGE]}" +return 0 +} +#=========================================================================# +strip_ws () +# DESCRIPTION: Strip any leading and trailing whitespace +# INPUT: A string +# OUTPUT: Echo the result +# PARAMETERS: $1: String to strip +#=========================================================================# +{ +local str="$1" +if [[ "$str" =~ ^[[:space:]]+([^[:space:]].*)$ ]]; then + str="${BASH_REMATCH[1]}" +fi +if [[ "$str" =~ ^(.*[^[:space:]])[[:space:]]+$ ]]; then + str="${BASH_REMATCH[1]}" +fi +echo "$str" +return 0 +} + + #-------------# + #@@@@@@@@@@@@@# + #---ARCHIVE---# + #@@@@@@@@@@@@@# + #-------------# + +# This section contains a base64 encoded archive added in with +# gen_all.bash. The last remaining section containing Bash scripting is +# ENTRY POINT, at the bottom of this file + +#REPLACE WITH ARCHIVE# + + #-----------------# + #@@@@@@@@@@@@@@@@@# + #---ENTRY POINT---# + #@@@@@@@@@@@@@@@@@# + #-----------------# + +if ! ((QQ2_NOEXECUTE)); then + + #Ensure needed fds are not in use + exec 3>&- 3<&- 4>&- 4<&-; + + lv_api_do_check + open_pipe + if [[ -n "$QQ2_DIR" ]]; then + : # If already set, use existing value + elif [[ -e "${HOME:?}/.config/qq2clone" ]]; then + QQ2_DIR="$(<"${HOME}/.config/qq2clone")" + else + QQ2_DIR="${HOME}/storage-qq2clone" + fi + [[ "$1" == "setup" ]] && { first_run_setup; exit $?; } + get_config + exec_com "$@" + exit 0 +fi