improvements
[automated-distro-installer] / fai / config / distro-install-common / ethusb-static
1 #!/bin/bash
2 # I, Ian Kelling, follow the GNU license recommendations at
3 # https://www.gnu.org/licenses/license-recommendations.en.html. They
4 # recommend that small programs, < 300 lines, be licensed under the
5 # Apache License 2.0. This file contains or is part of one or more small
6 # programs. If a small program grows beyond 300 lines, I plan to switch
7 # its license to GPL.
8
9 # Copyright 2024 Ian Kelling
10
11 # Licensed under the Apache License, Version 2.0 (the "License");
12 # you may not use this file except in compliance with the License.
13 # You may obtain a copy of the License at
14
15 # http://www.apache.org/licenses/LICENSE-2.0
16
17 # Unless required by applicable law or agreed to in writing, software
18 # distributed under the License is distributed on an "AS IS" BASIS,
19 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 # See the License for the specific language governing permissions and
21 # limitations under the License.
22
23 # usage $0 [-c] [off]
24 # off: Turn off static ip.
25 # -c config only, don't tell networkmanager to change anything
26 # -f force interface reup
27
28 # shellcheck disable=SC2317 # false positive
29
30 if ! test "$BASH_VERSION"; then echo "error: shell is not bash" >&2; exit 1; fi
31 shopt -s inherit_errexit 2>/dev/null ||: # ignore fail in bash < 4.4
32 set -eE -o pipefail
33 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
34
35 m() { printf "%s\n" "$*"; "$@"; }
36
37
38 set-dynamic() {
39
40 reup=false
41 if [[ $cur_state == activated ]]; then
42 reup=true
43 fi
44
45 if [[ $cur_method != auto ]]; then
46 args+=(ipv4.method auto)
47 fi
48 if [[ $cur_ip != -- ]]; then
49 args+=(-ipv4.addresses "$ipv4_addresses")
50 fi
51 if [[ $cur_dns != -- ]]; then
52 args+=(-ipv4.dns "$ipv4_dns")
53 fi
54 if [[ $cur_gateway != -- ]]; then
55 # undocumented in t11 man nmcli. guessed randomly
56 args+=(ipv4.gateway 0.0.0.0)
57 fi
58 if (( ${#args[@]} >= 1 )); then
59 m nmcli con mod "$nm_con" "${args[@]}"
60 if $reup; then
61 m nmcli con up "$nm_con"
62 fi
63 else
64 echo "$0: found expected state, nothing to do."
65 fi
66 exit 0
67 set-nm
68 }
69
70 detect-net() {
71
72 # this assumes we have wifi up
73 if [[ $(timeout 1 dig +short @10.2.0.1 -x 10.2.0.2 2>&1 ||:) == kd.b8.nz. ]] \
74 && ip n show 10.2.0.1 | grep . &>/dev/null; then
75 net=home
76 elif ip r show default | grep 'via 10.0.3.1 dev wlan0' &>/dev/null && [[ $(timeout 1 dig +short @10.0.3.1 -x 10.0.3.1) == cmc1.lan. ]]; then
77 net=work
78 else
79 echo "$0: error could not detect network"
80 exit 1
81 fi
82
83 }
84
85 set-nm() {
86 m nmcli con mod "$nm_con" ipv4.method manual ipv4.addresses $ip ipv4.gateway $gateway ipv4.dns $dns
87 state=$(nmcli con show "$nm_con" 2>/dev/null | awk '$1 == "GENERAL.STATE:" {print $2}')
88 if [[ $state == activated ]]; then
89 m nmcli con up "$nm_con"
90 fi
91
92 }
93
94 get-ip() {
95
96 case $net in
97 home)
98
99 while read -r ip_suf host mac; do
100 if [[ ! $ip_suf || $ip_suf == \#* ]]; then
101 continue
102 fi
103 if [[ $mac != usb ]]; then
104 continue
105 fi
106 if [[ $host == ${HOSTNAME}c ]]; then
107
108 ip=10.2.0.$ip_suf/16
109 gateway=10.2.0.1
110 dns=8.8.8.4,8.8.8.8
111 break
112 fi
113 done </p/c/host-info
114
115 if [[ ! $ip_suf ]]; then
116 echo "$0: error: failed to find ${HOSTNAME}c ip suffix in /p/c/host-info"
117 exit 1
118 fi
119 ;;
120 work)
121
122 if ! ip r show default | grep 'via 192.168.0.1 dev eth' &>/dev/null; then
123 if [[ $cur_method != manual ]]; then
124 echo "$0: error. Need to be on wired network to get our ip"
125 exit 1
126 fi
127 set-dynamic
128 sleep 10
129 fi
130 myip=$(timeout 1 dig +short @192.168.0.25 $HOSTNAME.office.fsf.org)
131 if [[ ! $myip ]]; then
132 echo "$0: error: didnt detect home network and failed to get office ip"
133 exit 1
134 fi
135 dns=192.168.0.10,192.168.0.25
136 gateway=192.168.0.1
137 ip=$myip/24
138
139 ;;
140 esac
141 }
142
143
144 get-cur-val() {
145 local key
146 key=$1
147 printf "%s\n" "$tmpstr" | awk '$1 == "'$key':" {print $2}'
148 }
149
150 get-cur() {
151 tmpstr=$(nmcli con show "$nm_con" 2>/dev/null)
152
153 cur_method=$(get-cur-val ipv4.method)
154 cur_ip=$(get-cur-val ipv4.addresses)
155 cur_gateway=$(get-cur-val ipv4.gateway)
156 cur_dns=$(get-cur-val ipv4.dns)
157 cur_state=$(get-cur-val GENERAL.STATE)
158 }
159
160
161 ## begin arg parsing ##
162
163 force=false
164 off=false
165 while [[ $1 ]]; do
166 case $1 in
167 -f)
168 force=true
169 ;;
170 off)
171 off=true
172 ;;
173 *)
174 echo "$0: error unexpected argument: $1" >&2
175 exit 1
176 ;;
177 esac
178 shift
179 done
180
181 ## end arg parsing ##
182
183 ## begin common setup / detection ##
184 shopt -s nullglob
185
186 wiredx=1
187 declare -a args
188
189 # device that has an eth0, but we aren't using it because it is
190 # broken. We could just hardcode a mac comparison with `cat
191 # /sys/class/net/eth0/address` but this is cooler.
192 if [[ -e /sys/class/net/eth0 ]]; then
193 bus_info=$(ethtool -i eth0 | awk '$1 == "bus-info:" { print $2 }')
194 if [[ $bus_info != usb* ]]; then
195 wiredx=2
196 fi
197 fi
198
199 eth_dev=eth$(( wiredx - 1 ))
200
201 nm_con=$(nmcli device show $eth_dev | \
202 awk '$1 == "GENERAL.CONNECTION:" {out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}' ||:)
203
204 if [[ ! $nm_con || $nm_con == -- ]]; then
205 nm_con="Wired connection $wiredx"
206 fi
207
208 if ! nmcli con | grep -q "^$nm_con " &>/dev/null; then
209 # Note: we could support creation through a file or via
210 # nmcli, but right now I'm ok with just having plugged in a device once
211 # since this os was installed.
212 echo "error: no existing connection: $nm_con found in output of nmcli con"
213 exit 0
214 fi
215
216
217 if ! type -p dig &>/dev/null; then
218 apt-get -y install dig
219 fi
220
221 if ! type -p ethtool &>/dev/null; then
222 apt-get -y install ethtool
223 fi
224
225
226 get-cur
227 ## end common setup / detection ##
228
229 if $off; then
230 set-dynamic
231 exit 0
232 fi
233
234 detect-net
235 get-ip
236
237 if ! $force && [[ "$cur_method $cur_gateway $cur_dns $cur_ip" == "manual $gateway $dns $ip" ]]; then
238 echo "$0: found expected state, nothing to do."
239 exit 0
240 fi
241
242 set-nm
243
244
245
246 # example of down cli
247 #nmcli con mod 'Wired connection 1' ipv4.method auto -ipv4.addresses 10.2.0.9/16 ipv4.gateway 0.0.0.0 -ipv4.dns "8.8.8.4,8.8.8.8"
248
249
250 # FYI: the result of running, for example
251 # nmcli con mod "Wired connection 1" \
252 # ipv4.method manual \
253 # ipv4.addresses "10.2.0.23/24" \
254 # ipv4.gateway "10.2.0.1" \
255 # ipv4.dns "8.8.8.4,8.8.8.8"
256
257 # creates a fille named "/etc/NetworkManager/system-connections/Wired connection 1.nmconnection",
258 # below.
259 #
260 # The nmcli man page says you should just edit files in that dir and
261 # then run nmcli con reload to reread them all to load your changes, but
262 # I've found that to be unreliable, the systemd journal would say
263 # something like "reload happened" then nothing would change in the
264 # connect that the file clearly modifies, so I switched over to using
265 # the command line and just ignoring those files.
266 #
267 # I see no reason to keep the same file name, or a bunch of
268 # setting that seem irrelevant, and empty sections don't seem to do
269 # anything according to the man page.
270 #
271
272 # [connection]
273 # id=Wired connection 1
274 # uuid=b0fb7694-dfe6-31a1-81fa-7c17b61515a7
275 # type=ethernet
276 # interface-name=eth1
277 # timestamp=1715728264
278
279 # [ethernet]
280
281 # [ipv4]
282 # address1=10.2.0.23/16,10.2.0.1
283 # dns=8.8.8.4;8.8.8.8;
284 # method=manual
285
286 # [ipv6]
287 # addr-gen-mode=stable-privacy
288 # method=auto
289
290 # [proxy]