OpenWrt – Diff between revs 2 and 3
?pathlinks?
Rev 2 | Rev 3 | |||
---|---|---|---|---|
1 | #!/usr/bin/env bash |
1 | #!/usr/bin/env bash |
|
2 | # |
2 | # |
|
3 | # Script to install host system binaries along with required libraries. |
3 | # Script to install host system binaries along with required libraries. |
|
4 | # |
4 | # |
|
5 | # Copyright (C) 2012-2017 Jo-Philipp Wich <jo@mein.io> |
5 | # Copyright (C) 2012-2017 Jo-Philipp Wich <jo@mein.io> |
|
6 | # |
6 | # |
|
7 | # This program is free software; you can redistribute it and/or modify |
7 | # This program is free software; you can redistribute it and/or modify |
|
8 | # it under the terms of the GNU General Public License as published by |
8 | # it under the terms of the GNU General Public License as published by |
|
9 | # the Free Software Foundation; either version 2 of the License, or |
9 | # the Free Software Foundation; either version 2 of the License, or |
|
10 | # (at your option) any later version. |
10 | # (at your option) any later version. |
|
11 | # |
11 | # |
|
12 | # This program is distributed in the hope that it will be useful, |
12 | # This program is distributed in the hope that it will be useful, |
|
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
15 | # GNU General Public License for more details. |
15 | # GNU General Public License for more details. |
|
16 | # |
16 | # |
|
17 | # You should have received a copy of the GNU General Public License |
17 | # You should have received a copy of the GNU General Public License |
|
18 | # along with this program; if not, write to the Free Software |
18 | # along with this program; if not, write to the Free Software |
|
19 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
20 | |
20 | |
|
21 | DIR="$1"; shift |
21 | DIR="$1"; shift |
|
22 | |
22 | |
|
23 | _cp() { |
23 | _cp() { |
|
24 | cp ${VERBOSE:+-v} -L "$1" "$2" || { |
24 | cp ${VERBOSE:+-v} -L "$1" "$2" || { |
|
25 | echo "cp($1 $2) failed" >&2 |
25 | echo "cp($1 $2) failed" >&2 |
|
26 | exit 1 |
26 | exit 1 |
|
27 | } |
27 | } |
|
28 | } |
28 | } |
|
29 | |
29 | |
|
30 | _mv() { |
30 | _mv() { |
|
31 | mv ${VERBOSE:+-v} "$1" "$2" || { |
31 | mv ${VERBOSE:+-v} "$1" "$2" || { |
|
32 | echo "mv($1 $2) failed" >&2 |
32 | echo "mv($1 $2) failed" >&2 |
|
33 | exit 1 |
33 | exit 1 |
|
34 | } |
34 | } |
|
35 | } |
35 | } |
|
36 | |
36 | |
|
37 | _md() { |
37 | _md() { |
|
38 | mkdir ${VERBOSE:+-v} -p "$1" || { |
38 | mkdir ${VERBOSE:+-v} -p "$1" || { |
|
39 | echo "mkdir($1) failed" >&2 |
39 | echo "mkdir($1) failed" >&2 |
|
40 | exit 2 |
40 | exit 2 |
|
41 | } |
41 | } |
|
42 | } |
42 | } |
|
43 | |
43 | |
|
44 | _ln() { |
44 | _ln() { |
|
45 | ln ${VERBOSE:+-v} -sf "$1" "$2" || { |
45 | ln ${VERBOSE:+-v} -sf "$1" "$2" || { |
|
46 | echo "ln($1 $2) failed" >&2 |
46 | echo "ln($1 $2) failed" >&2 |
|
47 | exit 3 |
47 | exit 3 |
|
48 | } |
48 | } |
|
49 | } |
49 | } |
|
50 | |
50 | |
|
51 | _relpath() { |
51 | _relpath() { |
|
52 | local base="$(readlink -f "$1")" |
52 | local base="$(readlink -f "$1")" |
|
53 | local dest="$(readlink -f "$2")" |
53 | local dest="$(readlink -f "$2")" |
|
54 | local up |
54 | local up |
|
55 | |
55 | |
|
56 | [ -d "$base" ] || base="${base%/*}" |
56 | [ -d "$base" ] || base="${base%/*}" |
|
57 | [ -d "$dest" ] || dest="${dest%/*}" |
57 | [ -d "$dest" ] || dest="${dest%/*}" |
|
58 | |
58 | |
|
59 | while true; do |
59 | while true; do |
|
60 | case "$base" |
60 | case "$base" |
|
61 | in "$dest"/*) |
61 | in "$dest"/*) |
|
62 | echo "$up/${base#$dest/}" |
62 | echo "$up/${base#$dest/}" |
|
63 | break |
63 | break |
|
64 | ;; |
64 | ;; |
|
65 | *) |
65 | *) |
|
66 | dest="${dest%/*}" |
66 | dest="${dest%/*}" |
|
67 | up="${up:+$up/}.." |
67 | up="${up:+$up/}.." |
|
68 | ;; |
68 | ;; |
|
69 | esac |
69 | esac |
|
70 | done |
70 | done |
|
71 | } |
71 | } |
|
72 | |
72 | |
|
73 | _runas_so() { |
73 | _runas_so() { |
|
74 | cat <<-EOT | ${CC:-gcc} -x c -fPIC -shared -o "$1" - |
74 | cat <<-EOT | ${CC:-gcc} -x c -fPIC -shared -o "$1" - |
|
75 | #include <unistd.h> |
75 | #include <unistd.h> |
|
76 | #include <stdio.h> |
76 | #include <stdio.h> |
|
77 | #include <stdlib.h> |
77 | #include <stdlib.h> |
|
78 | |
78 | |
|
79 | int mangle_arg0(int argc, char **argv, char **env) { |
79 | int mangle_arg0(int argc, char **argv, char **env) { |
|
80 | char *arg0 = getenv("RUNAS_ARG0"); |
80 | char *arg0 = getenv("RUNAS_ARG0"); |
|
81 | |
81 | |
|
82 | if (arg0) { |
82 | if (arg0) { |
|
83 | argv[0] = arg0; |
83 | argv[0] = arg0; |
|
84 | unsetenv("RUNAS_ARG0"); |
84 | unsetenv("RUNAS_ARG0"); |
|
85 | } |
85 | } |
|
86 | |
86 | |
|
87 | return 0; |
87 | return 0; |
|
88 | } |
88 | } |
|
89 | |
89 | |
|
90 | #ifdef __APPLE__ |
90 | #ifdef __APPLE__ |
|
91 | __attribute__((section("__DATA,__mod_init_func"))) |
91 | __attribute__((section("__DATA,__mod_init_func"))) |
|
92 | #else |
92 | #else |
|
93 | __attribute__((section(".init_array"))) |
93 | __attribute__((section(".init_array"))) |
|
94 | #endif |
94 | #endif |
|
95 | static void *mangle_arg0_constructor = &mangle_arg0; |
95 | static void *mangle_arg0_constructor = &mangle_arg0; |
|
96 | EOT |
96 | EOT |
|
97 | |
97 | |
|
98 | [ -x "$1" ] || { |
98 | [ -x "$1" ] || { |
|
99 | echo "compiling preload library failed" >&2 |
99 | echo "compiling preload library failed" >&2 |
|
100 | exit 5 |
100 | exit 5 |
|
101 | } |
101 | } |
|
102 | } |
102 | } |
|
103 | |
103 | |
|
104 | _patch_ldso() { |
104 | _patch_ldso() { |
|
105 | _cp "$1" "$1.patched" |
105 | _cp "$1" "$1.patched" |
|
106 | sed -i -e 's,/\(usr\|lib\|etc\)/,/###/,g' "$1.patched" |
106 | sed -i -e 's,/\(usr\|lib\|etc\)/,/###/,g' "$1.patched" |
|
107 | |
107 | |
|
108 | if "$1.patched" 2>&1 | grep -q -- --library-path; then |
108 | if "$1.patched" 2>&1 | grep -q -- --library-path; then |
|
109 | _mv "$1.patched" "$1" |
109 | _mv "$1.patched" "$1" |
|
110 | else |
110 | else |
|
111 | echo "binary patched ${1##*/} not executable, using original" >&2 |
111 | echo "binary patched ${1##*/} not executable, using original" >&2 |
|
112 | rm -f "$1.patched" |
112 | rm -f "$1.patched" |
|
113 | fi |
113 | fi |
|
114 | } |
114 | } |
|
115 | |
- | ||
116 | _patch_glibc() { |
- | ||
117 | _cp "$1" "$1.patched" |
- | ||
118 | sed -i -e 's,/usr/\(\(lib\|share\)/locale\),/###/\1,g' "$1.patched" |
- | ||
119 | |
- | ||
120 | if "$1.patched" 2>&1 | grep -q -- GNU; then |
- | ||
121 | _mv "$1.patched" "$1" |
- | ||
122 | else |
- | ||
123 | echo "binary patched ${1##*/} not executable, using original" >&2 |
- | ||
124 | rm -f "$1.patched" |
- | ||
125 | fi |
- | ||
126 | } |
- | ||
127 | |
115 | |
|
128 | for LDD in ${PATH//://ldd }/ldd; do |
116 | for LDD in ${PATH//://ldd }/ldd; do |
|
129 | "$LDD" --version >/dev/null 2>/dev/null && break |
117 | "$LDD" --version >/dev/null 2>/dev/null && break |
|
130 | LDD="" |
118 | LDD="" |
|
131 | done |
119 | done |
|
132 | |
120 | |
|
133 | [ -n "$LDD" -a -x "$LDD" ] || LDD= |
121 | [ -n "$LDD" -a -x "$LDD" ] || LDD= |
|
134 | |
122 | |
|
135 | for BIN in "$@"; do |
123 | for BIN in "$@"; do |
|
136 | [ -n "$BIN" -a -n "$DIR" ] || { |
124 | [ -n "$BIN" -a -n "$DIR" ] || { |
|
137 | echo "Usage: $0 <destdir> <executable> ..." >&2 |
125 | echo "Usage: $0 <destdir> <executable> ..." >&2 |
|
138 | exit 1 |
126 | exit 1 |
|
139 | } |
127 | } |
|
140 | |
128 | |
|
141 | [ ! -d "$DIR/lib" ] && { |
129 | [ ! -d "$DIR/lib" ] && { |
|
142 | _md "$DIR/lib" |
130 | _md "$DIR/lib" |
|
143 | _md "$DIR/usr" |
131 | _md "$DIR/usr" |
|
144 | _ln "../lib" "$DIR/usr/lib" |
132 | _ln "../lib" "$DIR/usr/lib" |
|
145 | } |
133 | } |
|
146 | |
134 | |
|
147 | [ ! -x "$DIR/lib/runas.so" ] && { |
135 | [ ! -x "$DIR/lib/runas.so" ] && { |
|
148 | _runas_so "$DIR/lib/runas.so" |
136 | _runas_so "$DIR/lib/runas.so" |
|
149 | } |
137 | } |
|
150 | |
138 | |
|
151 | LDSO="" |
139 | LDSO="" |
|
152 | |
140 | |
|
153 | [ -n "$LDD" ] && [ -x "$BIN" ] && file "$BIN" | grep -sqE "ELF.*(executable|interpreter)" && { |
141 | [ -n "$LDD" ] && [ -x "$BIN" ] && file "$BIN" | grep -sqE "ELF.*(executable|interpreter)" && { |
|
154 | for token in $("$LDD" "$BIN" 2>/dev/null); do |
142 | for token in $("$LDD" "$BIN" 2>/dev/null); do |
|
155 | case "$token" in */*.so*) |
143 | case "$token" in */*.so*) |
|
156 | dest="$DIR/lib/${token##*/}" |
- | ||
157 | ddir="${dest%/*}" |
- | ||
158 | |
- | ||
159 | case "$token" in |
144 | case "$token" in |
|
160 | */ld-*.so*) LDSO="${token##*/}" ;; |
145 | *ld-*.so*) LDSO="${token##*/}" ;; |
|
161 | esac |
146 | esac |
|
- | 147 | |
||
- | 148 | dest="$DIR/lib/${token##*/}" |
||
- | 149 | ddir="${dest%/*}" |
||
162 | |
150 | |
|
163 | [ -f "$token" -a ! -f "$dest" ] && { |
151 | [ -f "$token" -a ! -f "$dest" ] && { |
|
164 | _md "$ddir" |
152 | _md "$ddir" |
|
165 | _cp "$token" "$dest" |
153 | _cp "$token" "$dest" |
|
166 | case "$token" in |
- | ||
167 | */ld-*.so*) _patch_ldso "$dest" ;; |
154 | [ -n "$LDSO" ] && _patch_ldso "$dest" |
|
168 | */libc.so.6) _patch_glibc "$dest" ;; |
- | ||
169 | esac |
- | ||
170 | } |
155 | } |
|
171 | ;; esac |
156 | ;; esac |
|
172 | done |
157 | done |
|
173 | } |
158 | } |
|
174 | |
159 | |
|
175 | # is a dynamically linked executable |
160 | # is a dynamically linked executable |
|
176 | if [ -n "$LDSO" ]; then |
161 | if [ -n "$LDSO" ]; then |
|
177 | echo "Bundling ${BIN##*/}" |
162 | echo "Bundling ${BIN##*/}" |
|
178 | |
163 | |
|
179 | RUNDIR="$(readlink -f "$BIN")"; RUNDIR="${RUNDIR%/*}" |
164 | RUNDIR="$(readlink -f "$BIN")"; RUNDIR="${RUNDIR%/*}" |
|
180 | RUN="${LDSO#ld-}"; RUN="run-${RUN%%.so*}.sh" |
165 | RUN="${LDSO#ld-}"; RUN="run-${RUN%%.so*}.sh" |
|
181 | REL="$(_relpath "$DIR/lib" "$BIN")" |
166 | REL="$(_relpath "$DIR/lib" "$BIN")" |
|
182 | |
167 | |
|
183 | _mv "$BIN" "$RUNDIR/.${BIN##*/}.bin" |
168 | _mv "$BIN" "$RUNDIR/.${BIN##*/}.bin" |
|
184 | |
169 | |
|
185 | cat <<-EOF > "$BIN" |
170 | cat <<-EOF > "$BIN" |
|
186 | #!/usr/bin/env bash |
171 | #!/usr/bin/env bash |
|
187 | dir="\$(dirname "\$0")" |
172 | dir="\$(dirname "\$0")" |
|
188 | export RUNAS_ARG0="\$0" |
173 | export RUNAS_ARG0="\$0" |
|
189 | export LD_PRELOAD="\$dir/${REL:+$REL/}runas.so" |
174 | export LD_PRELOAD="\$dir/${REL:+$REL/}runas.so" |
|
190 | exec "\$dir/${REL:+$REL/}$LDSO" --library-path "\$dir/${REL:+$REL/}" "\$dir/.${BIN##*/}.bin" "\$@" |
175 | exec "\$dir/${REL:+$REL/}$LDSO" --library-path "\$dir/${REL:+$REL/}" "\$dir/.${BIN##*/}.bin" "\$@" |
|
191 | EOF |
176 | EOF |
|
192 | |
177 | |
|
193 | chmod ${VERBOSE:+-v} 0755 "$BIN" |
178 | chmod ${VERBOSE:+-v} 0755 "$BIN" |
|
194 | fi |
179 | fi |
|
195 | done |
180 | done |
|
196 | |
181 | |