code cleanup
[distro-setup] / distro-begin
1 #!/bin/bash -l
2 # Copyright (C) 2016 Ian Kelling
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 # for setting up a new machine
17 # usage: $0 [-r] HOSTNAME
18
19 # tips:
20 # run any sudo command first so your pass is cached
21 # set the scrollback to unlimited in case something goes wrong
22
23
24 ####### begin setup environment #######
25
26
27 ### make ssh interactive shell run better. for when running line interactively line by line
28 sudo bash -c 'source /a/c/.bashrc && source /a/exe/ssh-emacs-setup'
29
30
31 ##### setup error handling
32 interactive=true # set this to false to force set -x
33 [[ $- == *i* ]] || interactive=false
34 if ! $interactive; then
35 set -x
36 set -e -o pipefail
37 fi
38 set -E
39 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?"' ERR
40 for x in /a/bin/errhandle/*-function; do
41 source $x
42 done
43 set +e
44 $interactive || errcatch
45
46 ### setup logging
47 exec &> >(sudo tee -a /var/log/distro-begin)
48 echo "$0: $(date): starting now)"
49
50
51 ### sanity checking
52 if [[ $EUID == 0 ]]; then
53 if getent passwd iank || getent passwd ian ; then
54 echo "$0: error: running as root. unprivileged user exists. use it."
55 exit 1
56 else
57 echo "$0: warning: running as root. I will setup users then exit"
58 fi
59 fi
60
61
62 ### arg parsing
63 recompile=false
64 while [[ $1 == -* ]]; do
65 case $1 in
66 -r) recompile=true; shift ;;
67 esac
68 done
69 if [[ $1 ]]; then
70 export HOSTNAME=$1
71 fi
72
73
74 ##### variables/env setup
75 script_dir="$(readlink -f "$BASH_SOURCE")"; script_dir=${script_dir%/*}
76 source $script_dir/pkgs
77 set +x
78 source /a/bin/distro-functions/src/identify-distros
79 $interactive || set -x
80 for f in iank-dev htpc kd x2 frodo tp li lj demohost kw fz; do
81 eval "$f() { [[ $HOSTNAME == $f ]]; }"
82 done
83 has_p() { ! linode; } # when tp is tracis, then not tp either
84 has_x() { ! linode; }
85 linode() { lj || li; }
86 has_btrfs() { ! linode; }
87 home_network() { ! linode; }
88 encrypted() { has_p; }
89 shopt -s extglob
90 export GLOBIGNORE=*/.:*/..
91 umask 022
92 PATH="/a/exe:$PATH"
93 sed="sed --follow-symlinks"
94
95 ####### end setup environment #######
96
97
98
99
100 ##### begin setup encryption scripts ######
101 if encrypted; then
102 # I tried making a service which was dependent on reboot.target,
103 # but it happened too late in the shutdown process.
104 sudo dd of=/etc/systemd/system/keyscripton.service <<'EOF'
105 [Unit]
106 Description=Turn on automatic decryption of drives on boot
107 # tried using graphical.target, but it made my display manager restart before rebooting.
108 # generally, I don't think targets order shutdown like they do startup.
109 # So, I did systemd-analyze plot > something.svg, and picked a reliably started
110 # service that happens late in the game.
111 After=ntp.service
112 DefaultDependencies=no
113 # not sure if needed, makes sure we shut down before reboot.target
114 Conflicts=reboot.target
115
116 [Service]
117 Type=oneshot
118 RemainAfterExit=yes
119 ExecStart=/bin/true
120 ExecStop=/a/exe/keyscript-on
121
122 [Install]
123 WantedBy=keyscriptoff.service
124 EOF
125 sudo systemctl daemon-reload # needed if the file was already there
126 sudo systemctl stop keyscripton.service
127 # sudo systemctl start keyscripton.service
128 sudo systemctl enable keyscripton.service
129
130 sudo dd of=/etc/systemd/system/keyscriptoff.service <<'EOF'
131 [Unit]
132 Description=Turn off automatic decryption of drives on boot
133
134 [Service]
135 Type=oneshot
136 ExecStart=/a/exe/keyscript-off
137
138 [Install]
139 WantedBy=multi-user.target
140 EOF
141 sudo systemctl daemon-reload # needed if the file was already there
142 sudo systemctl enable keyscriptoff.service
143 sudo systemctl start keyscriptoff.service
144 fi
145 ##### end setup encryption scripts ######
146
147
148 # disabled until its fixed up
149 # install-myqueue
150
151 # todo, it would be nice to cut down on some of the output
152
153 ##### fedora prereq/fundamental settings
154 if isfedora; then
155 # comment out line disallowing calling sudo in scripts
156 sudo $sed -i 's/^Defaults *requiretty/#\0 # ian commented/' /etc/sudoers
157 # turn on magic sysrq commands
158 echo 1 > sudo dd of=/proc/sys/kernel/sysrq
159 echo "kernel.sysrq = 1" > /etc/sysctl.d/90-sysrq.conf
160 # selinux is not user friendly. Like, you enable samba, but you haven't run the magic selinux commands so it doesn't work
161 # and you have no idea why.
162 sudo $sed -i 's/^\(SELINUX=\).*/\1disabled/' /etc/selinux/config
163 selinuxenabled && sudo setenforce 0
164 fi
165
166
167 #### rerun my fai-time scripts
168 # already ran for pxe installs, but used for vps & updates
169 distro=$(distro-name)
170 case $distro in
171 ubuntu|debian|trisquel)
172 sudo bash -c ". /a/bin/fai/fai-wrapper && /a/bin/fai/fai/config/scripts/GRUB_PC/11-iank"
173 ;;
174 *)
175 sudo bash -c ". /a/bin/fai/fai-wrapper &&
176 /a/bin/fai/fai/config/distro-install-common/end"
177 ;;
178 esac
179
180 ###### setup hostname
181 sudo $sed -i '/^127\.0\.1\.1/d' /etc/hosts
182 echo "127.0.1.1 $HOSTNAME.b8.nz $HOSTNAME" | sudo tee -a /etc/hosts
183
184
185 ##### exit first stage if running as root
186 if [[ $EUID == 0 ]]; then
187 echo "$0: running as root. exiting now that users are setup"
188 exit 0
189 fi
190
191
192 #### setup bash for root
193 for x in /a/c/{.bashrc,brc,.bash_profile,.profile,.inputrc,path_add_function}; do
194 sudo -i <<EOF
195 PATH="/a/exe:$PATH"
196 lnf $x /root
197 EOF
198 done
199
200 ###### do conflink
201 # li needs the bind group before conflink
202 if [[ $HOSTNAME == li ]]; then
203 getent group bind &>/dev/null || sudo groupadd -r bind
204 fi
205 # this needs to be before installing pacserve so we have gpg conf.
206 conflink
207
208 ###### bash environment setup
209 set +x
210 errallow
211 source /etc/profile.d/environment.sh
212 source ~/.bashrc
213 $interactive || errcatch
214 $interactive || set -x
215
216
217 #### setup passwordless sudo
218 tu /etc/sudoers <<EOF
219 $USER ALL=(ALL) NOPASSWD: ALL
220 Defaults env_keep += SUDOD
221 # makes ubuntu be like debian
222 # https://unix.stackexchange.com/a/91572
223 Defaults always_set_home
224 # default setting is to have minimum umask of 0022
225 # This lets us have user-specific umasks which are more permissive.
226 # I did this for transmission and set it's umask gecos on install,
227 # see there for more info.
228 Defaults !umask
229 EOF
230
231
232 #### setup firefox backport
233 ## ian: disabled. backports are not being published atm due to rust packaging issue
234 # if isdeb; then
235 # codename=$(debian-codename)
236 # if isdebian-stable && has_x; then
237 # s dd of=/etc/apt/sources.list.d/mozilla-iceweasel.list <<EOF
238 # deb http://mozilla.debian.net/ $codename-backports firefox-release
239 # deb-src http://mozilla.debian.net/ $codename-backports firefox-release
240 # EOF
241 # p update
242 # # take care of mozilla signing errors in previous command
243 # pi pkg-mozilla-archive-keyring
244 # fi
245 # p update
246 # fi
247
248
249 ###### arch aur wrapper setup
250 if isarch; then
251 #https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages
252 sudo pacman -S --noconfirm --needed base-devel jq
253 # pacaur seems to be the best, although it + cower has a few minor bugs,
254 # its design goals seem good, so, going for it.
255
256 aurpi() {
257 for p in "$@"; do
258 tempdir=$(mktemp -d)
259 pushd $tempdir
260 aurex "$p"
261 makepkg -sri --skippgpcheck --noconfirm
262 popd
263 rm -rf $tempdir
264 done
265 }
266 aurpi cower pacaur
267
268 pi pacserve
269
270 x=$(mktemp); /usr/bin/pacman.conf-insert_pacserve >$x
271 sudo dd of=/etc/pacman.conf if=$x; rm $x
272 sudo systemctl enable pacserve.service
273 sudo systemctl start pacserve.service
274
275 fi
276
277 #### update all packages
278 pup
279
280
281 ###### p1 packages install ######
282 if isarch; then
283 # requirement for trash-cli.
284 # background: strange error if just installing trash-cli: "pyalpm requires python",
285 # so I see that it requires python2, and installing that manually fixes it.
286 # I didn\'t see this on earlier installation, main thing which changed was
287 # pacserve, so not sure if it\'s related.
288 pi python2
289 fi
290 pi ${p1[@]}
291
292
293 ######## fix evbug bug ######
294 case $distro in
295 trisquel|ubuntu)
296 # noticed in flidas.
297 #https://bugs.launchpad.net/ubuntu/+source/module-init-tools/+bug/240553
298 #https://wiki.debian.org/KernelModuleBlacklisting
299 #common advice when searching is to use /etc/modprobe.d/blacklist.conf,
300 #but that file won't work and will get automatically reverted
301 sudo rmmod evbug ||: # might not be loaded yet
302 file=/etc/modprobe.d/evbug.conf
303 line="blacklist evbug"
304 if ! grep -xFq "$line" $file; then
305 sudo dd of=$file 2>/dev/null <<<"$line"
306 sudo depmod -a
307 sudo update-initramfs -u
308 fi
309 ;;
310 esac
311
312
313 ###### link files
314 # convenient to just do all file linking in one place
315 s lnf -T /a/bin /b
316 s lnf -T /nocow/t /t
317 if has_p; then
318 lnf -T /p/News ~/News
319 fi
320 s lnf /q/root/.editor-backups /q/root/.undo-tree-history \
321 /a/opt /a/c/.emacs.d $HOME/mw_vars /k/backup /root
322 rootsshsync
323 s lnf /a/c/.vim /a/c/.vimrc /a/c/.gvimrc /root
324 if has_p; then
325 # for dovecot
326 lnf -T /i/k/mboxes ~/mail
327 fi
328
329
330
331
332 ##### install xinput
333 if has_x; then
334 case $(distro-name) in
335 trisquel|ubuntu|debian)
336 pi xinput
337 ;;
338 fedora)
339 pi xinput_calibrator
340 ;;
341 arch)
342 pi xorg-xinput
343 ;;
344 esac
345
346 #### install redshift
347 case $(distro-name) in
348 trisquel|ubuntu|debian)
349 # recommends gets us geoclue (for darkening automatically at night i assume),
350 # which recommends modemmanager, which is annoying to fix for the model01 keyboard.
351 pi --no-install-recommends gtk-redshift
352 ;;&
353 fedora)
354 pi redshift-gtk
355 ;;&
356 arch)
357 pi redshift
358 ;;&
359 esac
360 fi
361
362
363 #### arch specific early packages
364 case $(distro-name) in
365 arch)
366 # pkgfile is like apt-cache
367 pi pkgfile
368 s pkgfile --update
369 ;;
370 esac
371
372 #### fedora specific packages
373 case $(distro-name) in
374 fedora)
375 # todo, this could probably come later
376 p -y groupinstall development-tools c-development books admin-tools
377 pi man-pages
378 ;;
379 # other distros unknown
380 esac
381
382 #### enable trim
383 # enable trim for volume delete, other rare commands
384 sudo $sed -ri 's/( *issue_discards\b).*/\1 = 1/' /etc/lvm/lvm.conf
385 if encrypted; then
386 if isdeb; then
387 sudo cp /usr/share/doc/util-linux/examples/fstrim.{service,timer} /etc/systemd/system
388 fi
389 # does weekly trim
390 sudo systemctl enable fstrim.timer
391 fi
392
393 ##### make extra dirs
394 dirs=(/mnt/{1,2,3,4,5,6,7,8,9} /nocow/t)
395 s mkdir -p "${dirs[@]}"
396 s chown $USER:$USER "${dirs[@]}"
397
398 ###### setup /i
399 tu /etc/fstab <<'EOF'
400 /i/w /w none bind,noauto 0 0
401 /i/k /k none bind,noauto 0 0
402 EOF
403 if ! mountpoint /kr; then
404 s mkdir -p /kr
405 s chown $USER:traci /kr
406 fi
407 if home_network; then
408 if [[ $HOSTNAME == frodo ]]; then
409 tu /etc/fstab <<'EOF'
410 /k /kr none bind,noauto 0 0
411 EOF
412 else
413 tu /etc/fstab <<'EOF'
414 frodo:/k /kr nfs noauto 0 0
415 EOF
416 fi
417 fi
418 s mkdir -p /q /i/{w,k}
419 for dir in /{i,w,k}; do
420 if mountpoint $dir; then continue; fi # already mounted
421 s mkdir -p $dir
422 s chown $USER:$USER $dir
423 done
424 # not needed for all hosts, but rather just keep it uniform
425 s mkdir -p /mnt/iroot
426 # debian auto mounting of multi-disk encrypted btrfs is busted. It is
427 # in jessie, and in stretch as of 11/26/2016 I have 4 disks in cryptab,
428 # based on 3 of those, it creates .device units for /dev/mapper/dev...
429 # then waits endlessly for them on bootup, after the /dev/mapper disks
430 # have already been created and exist. todo: create a simple repro
431 # for this in a vm and report it upstream.
432 if has_btrfs || home_network; then
433 pi nfs-common
434 s dd of=/root/imount <<'EOF'
435 #!/bin/bash
436 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
437 set -eE -o pipefail
438 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
439 for dir in /i /mnt/iroot /k /kr /w; do
440 if ! mountpoint $dir &>/dev/null && \
441 awk '{print $2}' /etc/fstab | grep -xF $dir &>/dev/null; then
442 if awk '{print $3}' /etc/fstab | grep -xF nfs &>/dev/null; then
443 mount $dir || echo "warning: failed to mount nfs on $dir"
444 else
445 mount $dir
446 fi
447 fi
448 done
449 EOF
450 s chmod +x /root/imount
451
452 s dd of=/etc/systemd/system/imount.service <<EOF
453 [Unit]
454 Description=Mount /i and related mountpoints
455 Before=syncthing@$USER.service
456
457 [Service]
458 Type=oneshot
459 ExecStart=/root/imount
460
461 [Install]
462 RequiredBy=syncthing@$USER.service
463 # note /kr needs networking, this target is the simplest way to
464 # time it when the network should be up, but not do something
465 # dumb like delay startup until the network is up. It happens
466 # at some time after network.target
467 WantedBy=multi-user.target
468 EOF
469 sudo systemctl daemon-reload # needed if the file was already there
470 sudo systemctl enable imount.service
471 sudo systemctl start imount.service
472 fi
473
474 ##### setup /nocow.
475 # a nocow dir that is common to multiple distros installed on the same system
476 dir=/nocow
477 if has_btrfs; then
478 if ! mountpoint $dir; then
479 subvol=/mnt/root/nocow
480 if [[ ! -e $subvol ]]; then
481 s btrfs subvolume create $subvol
482 s chown root:1000 $subvol
483 s chattr +C $subvol
484 fi
485
486 first_root_crypt=$(awk '$2 == "/" {print $1}' /etc/mtab)
487 tu /etc/fstab <<EOF
488 $first_root_crypt /nocow btrfs noatime,subvol=nocow 0 0
489 EOF
490 s mkdir -p $dir
491 s chown $USER:$USER $dir
492 s mount $dir
493 fi
494 else
495 sudo mkdir -p $dir
496 fi
497
498
499 ###### fix mouse on jessie
500 # it comes with stretch and arch, but not jessie.
501 # propogate /etc/udev/hwdb.d
502 if which systemd-hwdb; then
503 s systemd-hwdb update
504 ser restart systemd-udev-trigger
505 fi
506
507
508 ##### setup email
509 if isdeb; then
510 mail-setup exim4
511 else
512 # todo: probably broken
513 mail-setup postfix
514 fi
515
516 #### ubuntu nicety
517 if isubuntu; then
518 # disable crash report annoying dialogs.
519 s dd of=/etc/default/apport <<<'enabled=0'
520 fi
521
522 ###### setup time zone
523 # fai sets this an old way that doesn't work for stretch.
524 # no harm in setting it universally here.
525 # using debconf-set-selection, the area gets reset to ETC
526 # on my linode test machine after doing a dpkg-reconfigure, or a reinstall,
527 # so we are using expect :(
528 # I got a random error when running this, so I added a sleep
529 # rather than trying to write a whole detect and wait loop.
530 # E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
531 # E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?
532 sleep 1
533 # todo: this is not idempotent, it fails when running twice, due to prepopulated values.
534 # check into unsetting them using debconf-set-selection.
535 s apt-get -y install --no-install-recommends expect
536 s expect <<EOF ||:
537 set force_conservative 0
538 spawn dpkg-reconfigure tzdata -freadline
539 expect -nocase timeout {exit 1} "Geographic area:"
540 send "\02512\r"
541 expect -nocase timeout {exit 1} "Time zone:"
542 send "\0255\r"
543 expect eof
544 exit
545 EOF
546
547
548 ##### install emacs
549 if has_x; then
550 if isarch; then
551 # emacs git build was broken last time i checked,
552 x=$(mktemp -d)
553 pushd $x
554 aurex emacs-git
555 makepkg -si --noconfirm
556 popd
557 rm -rf $x
558 pi hunspell hunspell-en
559 else
560 if $recompile; then
561 /a/bin/buildscripts/emacs
562 else
563 /a/bin/buildscripts/emacs --no-r || /a/bin/buildscripts/emacs
564 fi
565 fi
566 fi
567
568 ##### install laptop hardware packages
569 if tp || x2; then
570 case $distro in
571 debian)
572 pi task-laptop
573 ;;
574 ubuntu|trisquel)
575 # the exact packages that task-laptop would install, since ubuntu
576 # doesn\'t have this virtual in practice package.
577 pi avahi-autoipd bluetooth powertop iw wireless-tools wpasupplicant
578 ;;
579 # todo: other distros unknown
580 esac
581 fi
582
583
584 ##### install xmonad
585 if has_x; then
586 pi ${p2[@]}
587 # note: on older ubuntu I used cabal xmonad + xfce, using cabal versin
588 # see /w/archive/programming/xmonad-cabal.sh
589 if isarch; then
590 # xorg-xmessage for displaying error messages.
591 # optional dependency in arch, standard elsewhere.
592 pi xorg-server xorg-xmessage xmonad-contrib xorg-xsetroot xorg-xinit
593 else
594 pi suckless-tools
595 fi
596 fi
597
598
599 ##### setup X autostart
600 if has_x; then
601 if isarch; then
602 # https://wiki.archlinux.org/index.php/Xinitrc
603 for homedir in /home/*; do
604 cp /etc/X11/xinit/xinitrc $homedir/.xinitrc
605 $sed -ri '/^ *twm\b/,$d' $homedir/.xinitrc
606 tee -a $homedir/.xinitrc <<'EOF'
607 /a/bin/desktop-20-autostart.sh
608 xsetroot -cursor_name left_ptr
609 exec xmonad
610 EOF
611 done
612 else
613 # todo, figure this out for arch if we ever try out gnome.
614 # install for multiple display managers in case we use one
615 if isdeb; then
616 dir=/etc/gdm3
617 elif isfedora; then
618 # fedora didn\'t have the 3.
619 dir=/etc/gdm
620 fi
621 s mkdir -p $dir/PostLogin
622 s command cp /a/bin/distro-setup/desktop-20-autostart.sh $dir/PostLogin/Default
623 s mkdir /etc/lightdm/lightdm.conf.d
624 s dd of=/etc/lightdm/lightdm.conf.d/12-iank.conf <<'EOF'
625 [SeatDefaults]
626 session-setup-script=/a/bin/distro-setup/desktop-20-autostart.sh
627 EOF
628 fi
629 fi
630
631
632 #### refix interactive ssh terminal
633 # the first pup command can kill off our /etc/ mod, so rerun this
634 /a/exe/ssh-emacs-setup
635
636
637 echo "$0: $(date): ending now"
638 exit 0