|
1 | 1 | #!/bin/sh -eu |
2 | 2 |
|
| 3 | +# defaults |
| 4 | +use_bundled_libva_default=0 |
| 5 | + |
3 | 6 | # if not run from AppImage (eg. extracted), use default values |
4 | 7 | APPIMAGE=${APPIMAGE-none} |
5 | 8 | ARGV0=${ARGV0-$0} |
6 | 9 |
|
7 | | -DIR=`dirname $0` |
8 | | -export LD_LIBRARY_PATH=$DIR/usr/lib${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"} |
| 10 | +DIR=$(dirname "$0") |
| 11 | +AI_LIB_PATH=$DIR/usr/lib |
| 12 | +export LD_LIBRARY_PATH="$AI_LIB_PATH"${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"} |
| 13 | +LD_PRELOAD=${LD_PRELOAD-} |
9 | 14 | # there is an issue with running_from_path() which evaluates this executable |
10 | 15 | # as being system-installed |
11 | 16 | #export PATH=$DIR/usr/bin:$PATH |
12 | | -export QT_QPA_FONTDIR=$DIR/usr/lib/fonts |
13 | | -export QT_PLUGIN_PATH=$DIR/usr/lib/qt5/plugins |
14 | | -export QT_QPA_PLATFORM_PLUGIN_PATH=$QT_PLUGIN_PATH/platforms |
15 | | -if [ -d "$DIR/usr/lib/va" ] && [ -z "${LIBVA_DRIVERS_PATH:-}" ]; then |
16 | | - export LIBVA_DRIVERS_PATH=$DIR/usr/lib/va |
17 | | -fi |
| 17 | +export QT_QPA_FONTDIR="$DIR/usr/share/fonts" |
| 18 | +export UG_FONT_DIR="$DIR/usr/share/fonts" |
| 19 | +QT_PLUGIN_PATH=$(set -- "$DIR"/usr/lib/qt?/plugins; echo "$1") |
| 20 | +export QT_PLUGIN_PATH |
| 21 | +export QT_QPA_PLATFORM_PLUGIN_PATH="$QT_PLUGIN_PATH/platforms" |
| 22 | +bold=$(tput bold || true) |
| 23 | +red=$(tput setaf 1 || true) |
| 24 | +reset=$(tput sgr0 || true) |
| 25 | + |
| 26 | +get_tools() { |
| 27 | + find "$DIR/usr/bin" -mindepth 1 -exec basename {} \; | tr '\n' ' ' |
| 28 | +} |
18 | 29 |
|
19 | 30 | usage() { |
20 | 31 | printf "usage:\n" |
21 | | - printf "\t$ARGV0 [--gui [args]]\n" |
| 32 | + printf "\t${bold}${red}%s${reset} ${bold}[--gui [args]]${reset}\n" "$ARGV0" |
22 | 33 | printf "\t\tinvokes GUI\n" |
23 | 34 | printf "\n" |
24 | | - printf "\t$ARGV0 --appimage-help\n" |
| 35 | + printf "\t${bold}${red}%s${reset} ${bold}--appimage-help${reset}\n" "$ARGV0" |
25 | 36 | printf "\t\tprints AppImage related options\n" |
26 | 37 | printf "\n" |
27 | | - printf "\t$ARGV0 -h|--help|--fullhelp\n" |
28 | | - printf "\t\tprints this help (extended version with --fullhelp)\n" |
| 38 | + printf "\t${bold}${red}%s${reset} ${bold}-h | --help | --fullhelp${reset}\n" "$ARGV0" |
| 39 | + printf "\t\tprints this help (extended version with ${bold}--fullhelp${reset})\n" |
29 | 40 | printf "\n" |
30 | | - printf "\t$ARGV0 -m|--man [uv|hd-rum-transcode]\n" |
| 41 | + printf "\t${bold}${red}%s${reset} ${bold}-m|--man [uv|hd-rum-transcode]${reset}\n" "$ARGV0" |
31 | 42 | printf "\t\tprints manual page\n" |
32 | 43 | printf "\n" |
33 | | - printf "\t$ARGV0 -u|--update [args]\n" |
| 44 | + printf "\t${bold}${red}%s${reset} ${bold}-u|--update [args]${reset}\n" "$ARGV0" |
34 | 45 | printf "\t\tupdates AppImage (args will be passed to appimageupdatetool)\n" |
35 | 46 | printf "\n" |
36 | | - printf "\t$ARGV0 --tool uv --help\n" |
| 47 | + printf "\t${bold}${red}%s${reset} ${bold}-o|--tool uv --help${reset}\n" "$ARGV0" |
37 | 48 | printf "\t\tprints command-line UltraGrid help\n" |
38 | 49 | printf "\n" |
39 | | - printf "\t$ARGV0 --tool <t> [args]\n" |
| 50 | + printf "\t${bold}${red}%s${reset} ${bold}-o|--tool <t> [args]${reset}\n" "$ARGV0" |
40 | 51 | printf "\t\tinvokes specified tool\n" |
41 | | - printf "\t\ttool may be: $(ls $DIR/usr/bin | tr '\n' ' ')\n" |
| 52 | + printf "\t\ttool may be one of: ${bold}%s${reset}\n" "$(get_tools)" |
42 | 53 | printf "\n" |
43 | | - printf "\t$ARGV0 args\n" |
| 54 | + printf "\t${bold}${red}%s${reset} ${bold}args${reset}\n" "$ARGV0" |
44 | 55 | printf "\t\tinvokes command-line UltraGrid\n" |
45 | 56 | printf "\n" |
46 | 57 | } |
47 | 58 |
|
48 | 59 | usage_aux() { |
49 | 60 | printf "environment variables:\n" |
50 | | - printf "\tULTRAGRID_AUTOUPDATE: 1 - try to autoupdate; 0 - disable update advice\n" |
51 | | - printf "\tULTRAGRID_USE_FIREJAIL: run the UltraGrid executable with firejail. If\n" |
52 | | - printf "\t the variable contains printf a profile path\n" |
53 | | - printf "\t (ends with '.profile'), it will be used.\n" |
| 61 | + printf "\tULTRAGRID_AUTOUPDATE: 1 - try to autoupdate; 0 - disable update advice\n" |
| 62 | + printf "\tULTRAGRID_BUNDLED_LIBVA: 1 - use bundled libva; 0 - use system libva (if available), default %d\n" $use_bundled_libva_default |
| 63 | + printf "\tULTRAGRID_USE_FIREJAIL: run the UltraGrid executable with firejail. If\n" |
| 64 | + printf "\t the variable contains printf a profile path\n" |
| 65 | + printf "\t (ends with '.profile'), it will be used.\n" |
54 | 66 | printf "\n" |
55 | 67 | } |
56 | 68 |
|
57 | 69 | update_notify_days=90 |
58 | 70 | ## Print update hint if UG binary is older than $update_notify_days days, if $ULTRAGRID_AUTOUPDATE=1 triggers update. |
59 | 71 | handle_updates() { |
60 | | - if [ $APPIMAGE = none ]; then |
| 72 | + if [ "$APPIMAGE" = none ]; then |
61 | 73 | return |
62 | 74 | fi |
63 | | - if [ -n ${ULTRAGRID_AUTOUPDATE-""} ]; then |
64 | | - if [ $ULTRAGRID_AUTOUPDATE -eq 1 ]; then |
65 | | - $DIR/appimageupdatetool $APPIMAGE |
| 75 | + if [ -n "${ULTRAGRID_AUTOUPDATE-}" ]; then |
| 76 | + if [ "$ULTRAGRID_AUTOUPDATE" -eq 1 ]; then |
| 77 | + "$DIR/appimageupdatetool" "$APPIMAGE" |
66 | 78 | fi |
67 | 79 | return |
68 | 80 | fi |
69 | | - if expr $APPIMAGE : '.*continuous' > /dev/null; then |
| 81 | + if expr "$APPIMAGE" : '.*continuous' > /dev/null; then |
70 | 82 | update_notify_days=30 |
71 | 83 | fi |
72 | | - APPIMAGE_MTIME=$(stat --format=%Y $APPIMAGE) |
| 84 | + APPIMAGE_MTIME=$(stat -c %Y "$APPIMAGE") |
73 | 85 | CURR_TIMESTAMP=$(date +%s) |
74 | | - if [ $CURR_TIMESTAMP -lt $(($APPIMAGE_MTIME + $update_notify_days * 24 * 60 * 60)) ]; then |
| 86 | + if [ "$CURR_TIMESTAMP" -lt $((APPIMAGE_MTIME + update_notify_days * 24 * 60 * 60)) ]; then |
75 | 87 | return |
76 | 88 | fi |
77 | | - printf "UltraGrid binary older than $update_notify_days days, consider checking updates:\n" |
| 89 | + printf "UltraGrid binary older than %d days, consider checking updates:\n" $update_notify_days |
78 | 90 | printf "\n" |
79 | | - printf "$ARGV0 -u\n" |
| 91 | + printf "%s -u\n" "$ARGV0" |
80 | 92 | printf "\t- updates AppImage\n" |
81 | | - printf "$ARGV0 -u -j; [ \$? -eq 1 ] && echo Update available || echo No update available\n" |
| 93 | + printf "%s -u -j; [ \$? -eq 1 ] && echo Update available || echo No update available\n" "$ARGV0" |
82 | 94 | printf "\t- check for update without actually updating\n" |
83 | | - printf "$ARGV0 -u -h\n" |
| 95 | + printf "%s -u -h\n" "$ARGV0" |
84 | 96 | printf "\t- prints update options\n" |
85 | 97 | printf "\n" |
86 | 98 | printf "Hint: you can set environment variable ULTRAGRID_AUTOUPDATE to 1 for automatic update or 0 to suppress the above message.\n" |
87 | 99 | printf "\n" |
88 | 100 | } |
89 | 101 |
|
| 102 | +get_dynamic_loader() { |
| 103 | + LOADER_LIST='/lib64/ld-linux-*so* /lib/ld-linux-*so* /lib*/ld-linux-*so*' |
| 104 | + for LOADER in $LOADER_LIST; do |
| 105 | + for n in $LOADER; do |
| 106 | + if [ -x "$n" ]; then |
| 107 | + echo "$n" |
| 108 | + return |
| 109 | + fi |
| 110 | + done |
| 111 | + done |
| 112 | +} |
| 113 | + |
| 114 | +## Tries to find system libva. If found it is preloaded (+libva-drm+libva-x11) |
| 115 | +## @retval 0 if preloaded; 1 otherwise |
| 116 | +set_libva_ld_preload() { |
| 117 | + if [ ! -f "$AI_LIB_PATH/ultragrid/ultragrid_vcompress_libavcodec.so" ]; then |
| 118 | + return 1 |
| 119 | + fi |
| 120 | + LOADER=$(get_dynamic_loader) |
| 121 | + if [ ! -x "$LOADER" ]; then |
| 122 | + return 1 |
| 123 | + fi |
| 124 | + AI_LIBAVCODEC_LIB=$(LD_TRACE_LOADED_OBJECTS=1 "$LOADER" "$AI_LIB_PATH/ultragrid/ultragrid_vcompress_libavcodec.so" | grep libavcodec.so | grep -v 'not found' | awk '{print $3}') |
| 125 | + if [ -z "$AI_LIBAVCODEC_LIB" ]; then |
| 126 | + return 1 |
| 127 | + fi |
| 128 | + S_LD_LIBRARY_PATH=$LD_LIBRARY_PATH |
| 129 | + LD_LIBRARY_PATH= |
| 130 | + LIBVA_LIB=$(LD_TRACE_LOADED_OBJECTS=1 "$LOADER" "$AI_LIBAVCODEC_LIB" | grep libva.so | grep -v 'not found' | awk '{print $3}') |
| 131 | + LD_LIBRARY_PATH=$S_LD_LIBRARY_PATH |
| 132 | + if [ -z "$LIBVA_LIB" ]; then |
| 133 | + return 1 |
| 134 | + fi |
| 135 | + libva_libs=$LIBVA_LIB |
| 136 | + # add also libva-drm, libva-x11 if present |
| 137 | + for n in libva-drm libva-x11; do |
| 138 | + NAME=$(echo "$LIBVA_LIB" | sed s/libva/$n/) |
| 139 | + if [ -f "$NAME" ]; then |
| 140 | + libva_libs=$libva_libs:$NAME |
| 141 | + fi |
| 142 | + done |
| 143 | + export LD_PRELOAD="$libva_libs${LD_PRELOAD:+:$LD_PRELOAD}" |
| 144 | + return 0 |
| 145 | +} |
| 146 | + |
| 147 | +## Tries to set LD_PRELOAD to system libva (see set_libva_ld_preload()). If failed, sets path to bundled libva drivers. |
| 148 | +setup_vaapi() { |
| 149 | + ULTRAGRID_BUNDLED_LIBVA=${ULTRAGRID_BUNDLED_LIBVA:-$use_bundled_libva_default} |
| 150 | + if [ "$ULTRAGRID_BUNDLED_LIBVA" -ne 1 ]; then |
| 151 | + if ! set_libva_ld_preload; then |
| 152 | + echo "${bold}${red}Could not set system libva, using bundled libraries instead!${reset}" >&2 |
| 153 | + ULTRAGRID_BUNDLED_LIBVA=1 |
| 154 | + fi |
| 155 | + fi |
| 156 | + if [ "$ULTRAGRID_BUNDLED_LIBVA" -eq 1 ]; then |
| 157 | + if [ -d "$DIR/usr/lib/va" ] && [ -z "${LIBVA_DRIVERS_PATH:-}" ]; then |
| 158 | + export LIBVA_DRIVERS_PATH="$AI_LIB_PATH/va" |
| 159 | + fi |
| 160 | + fi |
| 161 | +} |
| 162 | + |
| 163 | +## Parse params to get whitelists that may be needed to add |
| 164 | +## @todo spaces inside paths doesn't work |
| 165 | +get_firejail_whitelist() { |
| 166 | + separator='' |
| 167 | + playback_path=$(echo "$@" | sed -n 's/.*--playback \([^ :]*\).*/\1/p') |
| 168 | + if [ -n "$playback_path" ]; then |
| 169 | + printf -- "$separator--whitelist=%s" "$playback_path" |
| 170 | + separator=' ' |
| 171 | + fi |
| 172 | + # print every argument of "filename=" or "file=" pattern |
| 173 | + for n in "$@"; do |
| 174 | + file_path=$(echo "$n" | sed -n -e 's/.*filename=\([^:]*\).*/\1/p' -e 's/.*file=\([^:]*\).*/\1/p') |
| 175 | + if [ -n "$file_path" ]; then |
| 176 | + printf -- "$separator--whitelist=%s" "$file_path" |
| 177 | + separator=' ' |
| 178 | + fi |
| 179 | + done |
| 180 | + if [ -z "$separator" ]; then |
| 181 | + printf -- "--private" |
| 182 | + fi |
| 183 | +} |
| 184 | + |
| 185 | +setup_vaapi |
| 186 | +# shellcheck source=/dev/null |
| 187 | +. "$DIR/scripts/jack_preload.sh" |
| 188 | + |
90 | 189 | RUN= |
91 | | -if [ -n "${ULTRAGRID_USE_FIREJAIL-}" ]; then |
| 190 | +if [ -n "${ULTRAGRID_USE_FIREJAIL-}" ] && [ "$ULTRAGRID_USE_FIREJAIL" != 0 ] && [ "$ULTRAGRID_USE_FIREJAIL" != no ]; then |
92 | 191 | command -v firejail >/dev/null || { echo "Firejail not present in system!"; exit 1; } |
93 | | - if expr $ULTRAGRID_USE_FIREJAIL : '.*\.profile' >/dev/null; then |
| 192 | + if expr "$ULTRAGRID_USE_FIREJAIL" : '.*\.profile' >/dev/null; then |
94 | 193 | FIREJAIL_OPTS="--profile=$ULTRAGRID_USE_FIREJAIL" |
95 | 194 | else |
96 | | - FIREJAIL_OPTS="--caps.drop=all --ipc-namespace --nonewprivs --noroot --protocol=unix,inet,inet6,netlink --seccomp --shell=none --disable-mnt --private-bin=none --private-opt=none --private --read-only=/tmp --writable-var" |
97 | | - FIREJAIL_OPTS="$FIREJAIL_OPTS --private-etc=alsa,group,hostname,ld.so.conf,ld.so.cache,ld.so.conf.d,nsswitch.conf,passwd,resolv.conf" |
| 195 | + FJ_TMPDIR=${TMPDIR-/tmp/ultragrid-$(id -u)} |
| 196 | + FIREJAIL_OPTS="--caps.drop=all --ipc-namespace --nonewprivs --noroot --protocol=unix,inet,inet6,netlink --seccomp --shell=none --disable-mnt --private-bin=none --private-opt=none --read-only=/tmp --mkdir=$FJ_TMPDIR --read-write=$FJ_TMPDIR --writable-var" |
| 197 | + FIREJAIL_OPTS="$FIREJAIL_OPTS $(get_firejail_whitelist "$@") --private-etc=alsa,group,hostname,ld.so.conf,ld.so.cache,ld.so.conf.d,nsswitch.conf,passwd,resolv.conf --ignore=novideo" |
98 | 198 | fi |
99 | 199 | if firejail --version | grep -iq "d-\{0,1\}bus.*enabled"; then |
100 | 200 | FIREJAIL_OPTS="$FIREJAIL_OPTS --dbus-user=none --dbus-system=none" |
101 | 201 | fi |
102 | 202 | if firejail --help | grep -q -- --keep-var-tmp; then |
103 | 203 | FIREJAIL_OPTS="$FIREJAIL_OPTS --keep-var-tmp" |
104 | 204 | fi |
105 | | - RUN="firejail --env=LD_LIBRARY_PATH=${LD_LIBRARY_PATH} $FIREJAIL_OPTS " |
| 205 | + RUN="firejail --env=LD_PRELOAD=${LD_PRELOAD} --env=LD_LIBRARY_PATH=${LD_LIBRARY_PATH}${FJ_TMPDIR+ --env=TMPDIR=${FJ_TMPDIR}} --env=UG_FONT_DIR=${UG_FONT_DIR} $FIREJAIL_OPTS " |
106 | 206 | fi |
107 | 207 |
|
108 | | -if [ $# -eq 0 -o x"${1-}" = x"--gui" ]; then |
| 208 | +if [ $# -eq 0 ] || [ "${1-}" = "--gui" ]; then |
109 | 209 | handle_updates |
110 | | - [ $# -eq 0 ] && usage || shift |
111 | | - if [ -x $DIR/usr/bin/uv-qt ]; then |
112 | | - $DIR/usr/bin/uv-qt --with-uv $DIR/usr/bin/uv "$@" |
| 210 | + if [ $# -eq 0 ]; then usage; else shift; fi |
| 211 | + if [ -x "$DIR/usr/bin/uv-qt" ]; then |
| 212 | + "$DIR/usr/bin/uv-qt" --with-uv "$DIR/usr/bin/uv" "$@" |
113 | 213 | else |
114 | 214 | echo "GUI was not compiled in!" >&2 |
115 | 215 | exit 1 |
116 | 216 | fi |
117 | | -elif [ x"$1" = x"--tool" ]; then |
| 217 | +elif [ "$1" = "-o" ] || [ "$1" = "--tool" ]; then |
118 | 218 | handle_updates |
119 | 219 | TOOL=$2 |
120 | 220 | shift 2 |
121 | | - ${RUN}$DIR/usr/bin/$TOOL "$@" |
122 | | -elif [ x"$1" = x"-h" -o x"$1" = x"--help" ]; then |
| 221 | + if [ "$TOOL" = help ]; then |
| 222 | + printf "available tools: ${bold}%s${reset}\n" "$(get_tools)" |
| 223 | + exit 0 |
| 224 | + fi |
| 225 | + # shellcheck disable=SC2086 |
| 226 | + ${RUN}"$DIR/usr/bin/$TOOL" "$@" |
| 227 | +elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then |
123 | 228 | usage |
124 | 229 | exit 0 |
125 | | -elif [ x"$1" = x"--fullhelp" ]; then |
| 230 | +elif [ "$1" = "--fullhelp" ]; then |
126 | 231 | usage |
127 | 232 | usage_aux |
128 | 233 | exit 0 |
129 | | -elif [ x"$1" = x"-m" -o x"$1" = x"--man" ]; then |
| 234 | +elif [ "$1" = "-m" ] || [ "$1" = "--man" ]; then |
130 | 235 | PAGE=${2:-uv} |
131 | | - cat $DIR/usr/share/man/man1/$PAGE.1 | man -l - |
132 | | -elif [ x"$1" = x"-u" -o x"$1" = x"--update" ]; then |
| 236 | + man -l "$DIR/usr/share/man/man1/$PAGE.1" |
| 237 | +elif [ "$1" = "-u" ] || [ "$1" = "--update" ]; then |
133 | 238 | shift |
134 | 239 | unset LD_LIBRARY_PATH |
135 | | - touch $APPIMAGE # update AppImage mtime to avoid update notices if there are no updates avalable but were checked for |
136 | | - $DIR/appimageupdatetool ${1+"$@" }$APPIMAGE |
| 240 | + touch "$APPIMAGE" # update AppImage mtime to avoid update notices if there are no updates avalable but were checked for |
| 241 | + "$DIR/appimageupdatetool" ${1+"$@" }"$APPIMAGE" |
137 | 242 | else |
138 | 243 | handle_updates |
139 | | - ${RUN}$DIR/usr/bin/uv "$@" |
| 244 | + # shellcheck disable=SC2086 |
| 245 | + ${RUN}"$DIR/usr/bin/uv" "$@" |
140 | 246 | fi |
141 | 247 |
|
142 | 248 | exit $? |
0 commit comments