1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
|
#!/bin/sh
# ArchSetup - Craig Jennings <craigmartinjennings@gmail.com>
# License: GNU GPLv3
# Commentary
#
# There are two levels of errors:
# * CRASH: Issues that will halt forward progress, aborting this script.
# * ERROR: Issues not serious enough to halt the script.
# Both are printed on screen and in the $logfile.
# Stderr is also printed to the $logfile for all relevant info.
#
# This script creates a tmpfs RAM disk for all compilation. This speeds up
# building and installing, and all source code no longer exists after reboot.
#
# # Code
# uncomment to stop on any error
# set -e
### Constants
username="cjennings"
password="welcome" # will be changed on first login. :)
dwm_repo="https://git.cjennings.net/dwm.git"
dmenu_repo="https://git.cjennings.net/dmenu.git"
st_repo="https://git.cjennings.net/st.git"
slock_repo="https://git.cjennings.net/slock.git"
dotfiles_repo="https://git.cjennings.net/dotfiles"
dotemacs_repo="https://git.cjennings.net/dotemacs.git"
dotfiles_home="/home/$username/.dotfiles"
logfile="/var/log/archsetup-$(date +'%Y-%m-%d-%H-%M-%S').log"
source_dir="/home/$username/.local/src" # aur/git source goes here
packages_before="/var/log/archsetup-preexisting-package-list.txt"
packages_after="/var/log/archsetup-post-install-package-list.txt"
archsetup_packages="/var/log/archsetup-installed-packages.txt"
### Intro
intro() {
printf "\n\nArchSetup launched @ %s\n" "$(date +'%D %T')"| tee -a "$logfile"
STARTTIME=$(date +%s)
errors_encountered=0
# begin with a clean logfile
[ -f "$logfile" ] && rm -f "$logfile"
touch "$logfile"
# count the arch packages before install
pacman -Q > "$packages_before" || \
error "crash" "generating pre-install package list" "$?"
}
### General Functions
# Error
error () {
# $1 = type ERROR, noted but the script will continue to run.
# anything else will produce CRASH, which halts the script
# $2 = what was happening (e.g., "adding $username to group $groupname")
# $3 = the error code (i.e., "$?")
errors_encountered=$((errors_encountered+1))
case "$1" in
"error")
printf "ERROR: %s failed with error code %s @ %s\n" \
"$2" "$3" "$(date +'%T')" | tee -a "$logfile"
return 1;
;;
*)
printf "CRASH: %s failed with error: %s @ %s. Script halted.\n" \
"$2" "$3" "$(date +'%T')" | tee -a "$logfile"
exit 1;
;;
esac
}
# Display
display () {
# $1 = type (TITLE, ACTION)
# $2 = description (answers: "what are you trying to do?")
case "$1" in
"title")
printf "\n##### %s\n" "$2" | tee -a "$logfile"
return 1;
;;
"subtitle")
printf "\n%s\n" "$2" | tee -a "$logfile"
;;
"task")
printf "...%s @ %s\n" "$2" "$(date +'%T')" | tee -a "$logfile"
return 1;
;;
*)
printf "CRASH: display () called with incorrect arguments.\n"
printf "...called %s type, %s action @ %s\n" \
"$1" "$2" "$(date +'%T')" | tee -a "$logfile"
exit 1;
;;
esac
}
# Pacman Install
pacman_install() {
action="installing $1 via pacman" && display "task" "$action"
if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then
action="retrying $1" && display "task" "$action"
if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then
action="retrying $1 once more" && display "task" "$action"
(pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1) ||
error "error" "$action" "$?"
fi
fi
}
# Git Install
git_install() {
prog_name="$(basename "$1" .git)"
build_dir="$source_dir/$prog_name"
action="building & installing $prog_name from source"
display "task" "$action"
if ! (sudo -u "$username" git clone --depth 1 "$1" "$build_dir" >> "$logfile" 2>&1); then
error "error" "cloning source code for $prog_name" "$?"
(cd "$build_dir" && sudo -u "$username" git pull --force origin master >> "$logfile" 2>&1) || \
error "error" "pulling source code for $prog_name" "$?"
fi
(cd "$build_dir" && make install >> "$logfile" 2>&1) || \
error "error" "building $prog_name from source code" "$?"
}
# AUR Install
aur_install() {
action="installing $1 via the AUR" && display "task" "$action"
if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then
action="retrying $1" && display "task" "$action"
if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then
action="retrying $1 once more" && display "task" "$action"
(sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1) ||
error "error" "$action" "$?"
fi
fi
}
# PIP Install
pip_install() {
[ -x "$(command -v "pip")" ] || pacman_install python-pip
action="installing $1 via PIP" && display "task" "$action"
(yes | sudo -u "$username" pip install "$1" >> "$logfile" 2>&1) || \
error "error" "$action" "$?"
}
### Prerequisites
prerequisites() {
# why these software packages are 'required'
# linux-firmware - ensuring hardware can be detected properly
# base_devel - required tools to compile
# ca_certificates - for validation of keyrings, etc.
# coreutils - comparing package lists
# curl - to transfer source code
# git - tools required to work with git source respositories
# go - required to build yay, the aur installer
# ntp - must communicate with other servers in synchronized manner
# python - required for python pip installs
# stow - places the dotfiles (see: https://bit.ly/41GmysO)
# tar - extract unix archives
# vi - should things go wrong, we'll need an editor
# zsh - we need a shell interpreter for yay; this one's mine
display "title" "Prerequisites"
display "subtitle" "Bootstrapping"
action="ensuring current Arch Linux keyring" && display "task" "$action"
(pacman -Syy) >> "$logfile" 2>&1 || error "crash" "$action" "$?"
(pacman -S --noconfirm archlinux-keyring) >> "$logfile" 2>&1 || \
error "crash" "$action" "$?"
display "task" "verifying Arch Linux keys"
(pacman-key --populate archlinux >> "$logfile" 2>&1) || \
error "crash" "verifying Arch Linux keys" "$?"
action="refreshing the package cache" && display "task" "$action"
(pacman -Syu --noconfirm >> "$logfile" 2>&1) || error "crash" "$action" "$?"
display "subtitle" "Required Software"
for software in linux-firmware base-devel ca-certificates \
coreutils curl git go ntp openssh python \
stow tar vi zsh; do
pacman_install "$software"
done
display "subtitle" "Environment Configuration"
# sync the time on this machine
action="synchronizing system time" && display "task" "$action"
(ntpdate 0.us.pool.ntp.org >> "$logfile" 2>&1) || error "error" "$action" "$?"
action="configuring compiler to use all processor cores" && display "task" "$action"
sed -i "s/-j2/-j$(nproc)/;s/^#MAKEFLAGS/MAKEFLAGS/" /etc/makepkg.conf >> "$logfile" 2>&1
# enable pacman concurrent downloads and color
action="enabling concurrent downloads" && display "task" "$action"
sed -i "s/^#ParallelDownloads.*$/ParallelDownloads = 10/;s/^#Color$/Color/" /etc/pacman.conf
action="Package Mirrors" && display "subtitle" "$action"
pacman_install reflector
action="configuring reflector" && display "task" "$action"
(printf '
--connection-timeout 3 \
--download-timeout 3 \
--protocol https \
--age 12 \
--latest 20 \
--score 10 \
--fastest 5 \
--sort score \
--save /etc/pacman.d/mirrorlist
' > /etc/xdg/reflector/reflector.conf >> "$logfile" 2>&1) || \
error "error" "$action" "$?"
action="updating repository mirrors" && display "task" "$action"
(reflector --connection-timeout 3 \
--download-timeout 3 \
--protocol https \
--age 12 \
--latest 20 \
--score 10 \
--fastest 5 \
--sort score \
--save /etc/pacman.d/mirrorlist > /dev/null 2>&1)
action="enabling the reflector timer" && display "task" "$action"
(systemctl enable reflector.timer >> "$logfile" 2>&1) || \
error "error" "$action" "$?"
action="replacing sudoers file if new package version exists" && display "task" "$action"
[ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers >> "$logfile" 2>&1
action="creating a directory to build/install software from git/AUR."
(mkdir -p $source_dir) || error "crash" "creating the directory $source_dir"
}
### Create User
create_user () {
display "title" "User Creation"
display "task" "checking if user exists"
# halt if $username exists
( id -u "$username" >/dev/null 2>&1; ) && \
error "crash" "user '$username' already exists!"
# create $username with home, group, shell, password
action="creating user and home directory" && display "task" "$action"
(useradd -m -G wheel -s /bin/zsh "$username" >> "$logfile" 2>&1) || \
error "crash" "adding user '$username" "$?"
display "task" "assigning the password"
echo "$username:$password" | chpasswd # any text is allowable! be careful!
display "task" "configuring shell"
# zsh cache required: $username will install via yay; zsh will run those commands
mkdir -p "/home/$username/.cache/zsh/" | tee -a "$logfile"
# give $username sudo nopasswd rights (required for aur installs)
display "task" "granting permissions"
(echo "%$username ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers) \
|| error "error" "$action" "$?"
# mount as ramdisk to speed aur/git build/installs
(sudo mount -t tmpfs -o size=4G archsetup $source_dir >> "$logfile" 2>&1) || \
error "crash" "mounting the RAM disk for archsetup" "$?"
(chown -R "$username":wheel "$(dirname "$source_dir")" >> "$logfile" 2>&1) || \
error "crash" "changing ownership of $source_dir" "$?"
}
### User Customizations
user_customizations() {
action="User Customizations" && display "title" "$action"
action="cloning dotfiles" && display "task" "$action"
(git clone --depth 1 $dotfiles_repo "$dotfiles_home" \
>> "$logfile" 2>&1) || error "error" "$action" "$?"
action="moving dotfiles into place" && display "task" "$action"
(cd "$dotfiles_home" && stow --no-folding --adopt * \
>> "$logfile" 2>&1 ) || error "error" "$action" "$?"
action="restoring dotfile versions" && display "task" "$action"
(cd "$dotfiles_home" && git restore . \
>> "$logfile" 2>&1 ) || error "error" "$action" "$?"
action="creating common directories" && display "task" "$action"
# Create default directories and grant permissions
{
mkdir -p -m 751 /home/$username/code
mkdir -p -m 751 /home/$username/documents
mkdir -p -m 751 /home/$username/downloads/torrents/complete
mkdir -p -m 751 /home/$username/downloads/torrents/incomplete
mkdir -p -m 751 /home/$username/downloads/torrents/files
mkdir -p -m 751 /home/$username/downloads/ebooks
mkdir -p -m 751 /home/$username/music
mkdir -p -m 751 /home/$username/projects
mkdir -p -m 751 /home/$username/pictures/screenshots
mkdir -p -m 751 /home/$username/videos
mkdir -p -m 751 /home/$username/vms
chown -R $username: /home/$username
mkdir -p -m 751 /media/backup
mkdir -p -m 751 /media/remote0
mkdir -p -m 751 /media/remote1
mkdir -p -m 751 /media/remote2
chown -R $username: /media
} >> "$logfile" 2>&1
}
### AUR Installer
aur_installer () {
display "title" "AUR Installer"
yay_repo="https://aur.archlinux.org/yay.git"
build_dir="$source_dir/yay"
display "task" "fetching source code for yay"
if ! (sudo -u "$username" git clone --depth 1 "$yay_repo" "$build_dir" >> "$logfile" 2>&1); then
error "error" "cloning source code for yay"
(sudo -u "$username" -D "$build_dir" git pull --force origin master >> "$logfile" 2>&1) || \
error "crash" "changing directories to $build_dir and pulling source code" "$?"
fi
action="packaging and installing yay"; display "task" "$action"
(cd "$build_dir" && sudo -u "$username" makepkg --noconfirm -si >> "$logfile" 2>&1) || \
error "crash" "$action" "$?"
}
### Essential Services
essential_services() {
display "title" "Essential Services"
# Randomness
display "subtitle" "Randomness"
pacman_install rng-tools
systemctl enable rngd >> "$logfile" 2>&1 || error "error" "$action" "$?"
systemctl start rngd >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Networking
display "subtitle" "Networking"
pacman_install networkmanager
# Power
display "subtitle" "Power"
pacman_install upower
systemctl enable upower >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Secure Shell
display "subtitle" "Secure Shell"
pacman_install openssh
action="enabling the openssh service to run at boot" && display "task" "$action"
systemctl enable sshd >> "$logfile" 2>&1 || error "error" "$action" "$?"
action="starting the openssh service" && display "task" "$action"
systemctl start sshd >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Firewall
# deny all connections by default, then allow the following:
# http/s : 80/tcp, 443/tcp
# tor : 9040,9050,9051,9053,9119/tcp
# email : IMAP, IMAPS
# mDNS printer discovery : 5353/udp
# ssh : ssh
# syncthing : 22000/tcp, 22000/udp, 21027/udp
# torrents : transmission
# calibre content server : 8080/tcp
display "subtitle" "Firewall"
pacman_install ufw
action="configuring ufw to deny by default" && display "task" "$action"
ufw default deny incoming >> "$logfile" 2>&1 || error "error" "$action"
# note on the numbered protocols
# "80,443,8080/tcp" ## http and https traffic
# "9040,9050,9051,9053,9119/tcp" ## tor network
# "55353/udp" ## DNS
# "22000/tcp" "22000/udp" "21027/udp" ## syncthing
for protocol in \
"80,443,8080/tcp" \
"9040,9050,9051,9053,9119/tcp" \
"IMAP" "IMAPS" \
"55353/udp" \
"ssh" \
"22000/tcp" "22000/udp" "21027/udp" \
"transmission" \
; do
action="adding ufw rule to allow $protocol" && display "task" "$action"
(ufw allow $protocol >> "$logfile" 2>&1) || error "error" "$action" "$?"
done
action="adding limits to protect from brute force attacks" && display "task" "$action"
(ufw limit 22/tcp >> "$logfile" 2>&1 && \
ufw limit 443/tcp >> "$logfile" 2>&1) || \
error "error" "action"
action="enabling firewall service to launch on boot" && display "task" "$action"
systemctl enable ufw.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
action="starting firewall service" && display "task" "$action"
systemctl start ufw.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Service Discovery
display "subtitle" "Network Service Discovery"
pacman_install nss-mdns # GNU Name Service Switch host name resolution
pacman_install avahi # service discovery on a local network using mdns
action="configuring avahi" && display "task" "$action"
systemctl disable systemd-resolved.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
systemctl enable avahi-daemon.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Job Scheduling
display "subtitle" "Job Scheduling"
pacman_install cronie
action="enabling cronie to launch at boot" && display "task" "$action"
systemctl enable cronie >> "$logfile" 2>&1 || error "error" "$action" "$?"
aur_install at
action "enabling the batch delayed command scheduler" && display "task" "$action"
systemctl enable atd >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Package Repository Cache Maintenance
display "subtitle" "Package Repository Cache Maintenance"
systemctl enable --now paccache.timer >> "$logfile" 2>&1 || error "error" "$action" "$?"
}
### Xorg Display Manager
xorg() {
action="Xorg Display Server Dependencies" && display "subtitle" "$action"
pacman_install libglvnd
action="Xorg Display Server" && display "subtitle" "$action"
for software in xorg-server xorg-xinit xorg-xsetroot \
xsel xorg-xbacklight xf86-input-libinput \
xorg-xdpyinfo xorg-xprop xorg-xwininfo \
xorg-xinput xorg-xkill ; do
pacman_install $software
done
}
### DWM Window Manager
dwm() {
action="DWM Window Manager Dependencies" && display "subtitle" "$action"
for software in coreutils fontconfig freetype2 glibc libx11 libxft libxinerama; do
pacman_install $software
done;
action="DWM Window Manager" && display "subtitle" "$action"
git_install $dwm_repo
git_install $dmenu_repo
git_install $st_repo
git_install $slock_repo
aur_install pinentry-dmenu # password entry that leverages dmenu
}
### Desktop Environment
desktop_environment() {
display "title" "Desktop Environment"
# Fonts
action="Fonts" && display "subtitle" "$action"
pacman_install noto-fonts-emoji
pacman_install ttf-firacode-nerd
pacman_install ttf-hack-nerd
pacman_install ttf-jetbrains-mono-nerd
pacman_install ttf-meslo-nerd
pacman_install ttf-nerd-fonts-symbols-mono
aur_install ttf-all-the-icons
aur_install ttf-lato
aur_install ttf-ms-fonts
aur_install ttf-ubraille
# System Utilities
action="System Utilities" && display "subtitle" "$action"
pacman_install dmidecode
pacman_install dosfstools
pacman_install exfat-utils
pacman_install lshw
pacman_install ntfs-3g
pacman_install sshfs
pacman_install testdisk
pacman_install udisks2
aur_install downgrade
aur_install inxi
# File Associations
action="File/Application Associations" && display "subtitle" "$action"
pacman_install perl-file-mimeinfo
pacman_install xdg-utils
# Authentication Tools
action="Authentication Tools" && display "subtitle" "$action"
pacman_install gnupg
pacman_install polkit
pacman_install gnome-keyring
# ensure correct permissions on .gpg directory
# the colon means the user's group will have perms
[ -d /home/"$username"/.gnupg ] || mkdir /home/"$username"/.gnupg
chown -R "$username": /home/"$username"/.gnupg
find /home/"$username"/.gnupg -type f -exec chmod 600 {} \;
find /home/"$username"/.gnupg -type d -exec chmod 700 {} \;
# Power Management
action="Power Management" && display "subtitle" "$action"
pacman_install acpi
pacman_install powertop
# Audio System
action="Audio System" && display "subtitle" "$action"
for software in alsa-utils pipewire wireplumber pipewire-pulse \
pipewire-docs pamixer pulsemixer ffmpeg; do
pacman_install $software
done;
# disable the pc speaker beep
rmmod pcspkr >> "$logfile" 2>&1
echo "blacklist pcspkr" >/etc/modprobe.d/nobeep.conf >> "$logfile" 2>&1
# Keyboard Shortcut Manager
action="Keyboard Shortcut Manager" && display "subtitle" "$action"
pacman_install sxhkd
# Notifications
action="Notification System" && display "subtitle" "$action"
pacman_install libnotify
pacman_install dunst
# Bluetooth Devices
action="Bluetooth System" && display "subtitle" "$action"
for software in bluez bluez-utils blueman; do
pacman_install $software
done
action="enabling bluetooth to launch at boot" && display "task" "$action"
systemctl enable bluetooth.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Command Line Utilities
action="Command Line Utilities" && display "subtitle" "$action"
for software in htop mc ncdu tmux fzf zip unzip atool wget detox \
lsof usbutils moreutils; do
pacman_install "$software"
done;
for software in task-spooler speedtest-go gotop-bin rar; do
aur_install "$software"
done;
# Help And Documentation
action="Help and Documentation" && display "subtitle" "$action"
pacman_install man
pacman_install arch-wiki-docs
pacman_install tealdeer
aur_install cht.sh-git
# Sync Services
action="Sync Services" && display "subtitle" "$action"
pacman_install syncthing
systemctl enable syncthing@$username.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
# Desktop Environment Utilities
action="Desktop Environment Utilities" && display "subtitle" "$action"
for software in brightnessctl xautolock network-manager-applet xclip \
conky nitrogen qalculate-gtk; do
pacman_install $software
done;
aur_install python-pulsectl
aur_install caffeine-ng
aur_install colorpicker
# Theme and Cursor
action="UI Theme" && display "subtitle" "$action"
for software in picom lxappearance gnome-themes-extra gtk-engine-murrine; do
pacman_install $software
done;
for software in vimix-icon-theme vimix-cursors vimix-gtk-themes \
qt5ct adwaita-color-schemes; do
aur_install $software
done;
# Browsers
action="Browsers" && display "subtitle" "$action"
pacman_install firefox
## TESTING IF NEEDED aur_install librewolf-bin
aur_install tor-browser-bin
aur_install google-chrome
# Install Printing
action="Print System" && display "subtitle" "$action"
pacman_install cups # the printing service
pacman_install cups-pdf # allows printing to pdf
pacman_install foomatic-db-engine # generates printer drivers, queues, and jobs
pacman_install foomatic-db-ppds # printer driver descriptions
pacman_install foomatic-db-nonfree-ppds # non-free printer driver descriptions
pacman_install gutenprint # printer driver engine for older computers
pacman_install foomatic-db-gutenprint-ppds # gutenprint prebuilt ppd files
action="enabling printing service to launch at boot" && display "task" "$action"
(systemctl enable cups.service >> "$logfile" 2>&1) || error "error" "$action" "$?"
}
### Developer Workstation
developer_workstation () {
action="Developer Workstation" && display "title" "$action"
action="Programming Languages and Utilities" && display "subtitle" "$action"
# C
pacman_install clang # C/C++ compiler
pacman_install cmake # make system
pacman_install gdb # the GNU debugger
pacman_install splint # C programming static analysis
pacman_install valgrind # memory management utility
# java
pacman_install jdk-openjdk # Java Development Kit
pacman_install openjdk-doc # ...and the documentation
# Lisps
pacman_install guile # GNU Scheme
pacman_install sbcl # Steel Bank Common Lisp
pacman_install racket # Racket + SICP mit-scheme emulation
# Rust
pacman_install rust # Rust programming language
# Python
pacman_install pyright # Python language server
pacman_install pyenv # Python environment manager
# Shell
pacman_install shellcheck # Shell script linter
pacman_install shfmt # Shell script formatter
# Go
pacman_install delve # Go programming language debugger
pacman_install go-tools # Go language utilities
pacman_install gopls # Go language server
pacman_install staticcheck # Go programming language linter
# Typescript
pacman_install jq # JSON processor
pacman_install typescript # Typescript programming language
pacman_install nodejs # Node-js JavaScript runtime environment
pacman_install npm # Node-js package manager
aur_install nvm # Node-js version manager
# HTML
pacman_install tidy # HTML formatter
pacman_install prettier # Multi-language formatter
# General Utilities
pacman_install meld # Visual diff
pacman_install ripgrep # Fast grep utility
aur_install the_silver_searcher # Another fast grep utility
action="Programming Editors" && display "subtitle" "$action"
pacman_install mg # mini emacs
pacman_install neovim # mega vi
pacman_install pycharm-community-edition # python ide
pacman_install code # vscode oss version
action="Emacs Dependencies" && display "subtitle" "$action"
pacman_install emacs
# supporting utilities used by my emacs configuration
aur_install exercism-bin # command line tool for exercism.io
aur_install isync # email sync
aur_install mu # email indexer and utilities
aur_install multimarkdown # markdown conversion
aur_install proselint # grammar checker
aur_install gist # command-line gist poster
pacman_install aspell # spell check system
pacman_install aspell-en # spell check english files
pacman_install fd # a faster find for dired/dirvish
pacman_install ffmpegthumbnailer # video previews in dired/dirvish
pacman_install imagemagick # image previews for dired/dirvish
pacman_install libgccjit # native compilation for Emacs
pacman_install mediainfo # generating media info in dired/dirvish
pacman_install mpv # video viewer
pacman_install mailutils # Emacs' IMAP mail support backend
pacman_install msmtp # mail transport for Mu4e
pacman_install msmtp-mta # mail transport for Mu4e
pacman_install python-lsp-server # python language support
pacman_install rlwrap # adds readline support to programs (SBCL-related)
pacman_install sdcv # stardict dictionary system
pacman_install yt-dlp # video download
action="setting up emacs configuration files" && display "task" "$action"
(sudo -u "$username" git clone --recurse-submodules $dotemacs_repo /home/$username/.emacs.d >> \
"$logfile" 2>&1) || error "error" "$action" "$?"
action="Android Utilities" && display "subtitle" "$action"
pacman_install android-file-transfer
pacman_install android-tools
action="DevOps Utilities" && display "subtitle" "$action"
action="installing devops virtualization and automation tools" && display "task" "$action"
pacman_install vagrant
pacman_install ansible
# distrobox related
pacman_install podman
pacman_install distrobox
aur_install boxbuddy
aur_install ptyxis
# boxes
pacman_install gnome-boxes
# virtualbox related
# ensure headers exist before installing virtualbox*dkms
pacman_install linux-headers
pacman_install linux-lts-headers
pacman_install virtualbox
pacman_install virtualbox-guest-iso
pacman_install virtualbox-host-dkms
# docker
action="adding user to vboxusers group" && display "task" "$action"
(gpasswd -a $username vboxusers >> "$logfile" 2>&1) || error "error" "$action" "$?"
pacman_install docker
pacman_install docker-compose
action="adding user to docker group" && display "task" "$action"
(gpasswd -a $username docker >> "$logfile" 2>&1) || error "error" "$action" "$?"
action="enabling docker service to launch on boot" && display "task" "$action"
systemctl enable docker.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
}
### Supplemental Software
supplemental_software() {
display "title" "Supplemental Software"
# pacman installs
pacman_install devtools # tools for arch linux package maintenance
pacman_install arandr # xrandr gui for monitor settings
pacman_install arch-install-scripts # for making arch installers
pacman_install archinstall # the archinstall python program
pacman_install aria2 # fast downloader
pacman_install bc # arbitrary precision calculator
pacman_install calibre # ebook manager/viewer
pacman_install dash # posix compliant /bin/sh
pacman_install dfc # better display of available space on mounted filesystems
pacman_install docx2txt # recovers text from docx files
pacman_install entr # run arbitrary commands when files change
pacman_install faac # open source mpeg 3 and aac encoder
pacman_install faad2 # processes an aac stream
pacman_install figlet # words into ascii art
pacman_install filezilla # ftp gui
pacman_install gparted # disk partition utility
pacman_install gst-plugin-pipewire # gstreamer audio plugin for pipewire
pacman_install gst-plugins-base # gstreamer base audio plugins
pacman_install gst-plugins-good # gstreamer extra audio plugins
pacman_install gstreamer # pipeline based multimedia framework
pacman_install gucharmap # gui display of character maps
pacman_install gzip # compression tool
pacman_install handbrake # video transcoder
pacman_install ledger # CLI accounting software
pacman_install libconfig # library for processing structured config files
pacman_install libmad # mpeg audio decoder
pacman_install libmpeg2 # library for decoding mpeg video streams
pacman_install maim # screenshot utility
pacman_install mediainfo # technical and tag information about media files
pacman_install mosh # alt SSH terminal with roaming and responsiveness support
pacman_install mpc # command line interface to mpd
pacman_install mpd # the music player daemon
pacman_install ncmpcpp # and mpd client to play music
pacman_install neofetch # cli system information tool
pacman_install obs-studio # desktop recording software
pacman_install obsidian # personal knowledgebase
pacman_install odt2txt # converts from open document to text
pacman_install p7zip # p7zip compression tool
pacman_install pandoc # universal document converter
pacman_install perl-image-exiftool # reads/writes exif info for raw photo files
pacman_install poppler-glib # poppler-glib document viewer library
pacman_install pv # monitor progress of data through pipeline
pacman_install ranger # terminal file manager
pacman_install rclone # syncs files from gdrive, s3, dropbox, etc.
pacman_install signal-desktop # secure messenger
pacman_install smartmontools # monitors hard drives
pacman_install texlive-meta # latex
pacman_install thunderbird # email, calendar, rss feeds
pacman_install transmission-cli # bittorrent client
pacman_install transmission-remote-gtk # bittorrent client
pacman_install unclutter # hides mouse cursor when not being used
pacman_install w3m # text based browser
pacman_install wavpack # audio compression format
pacman_install webkit2gtk # web content engine for GTK
pacman_install xcb-util-cursor # calibre dependency (calibre installed manually)
pacman_install xdotool # command line xorg automation tool
pacman_install xz # general purpose data compression tool
pacman_install zathura # document viewer
pacman_install zathura-cb # zathura plugin for comics
pacman_install zathura-djvu # zathura plugin for djvu books
pacman_install zathura-pdf-mupdf # zathura plugin for pdf
pacman_install zlib # compression library
# aur installs
aur_install dtrx # extraction tool
aur_install figlet-fonts # fonts for figlet
aur_install hfsprogs # file system tools for Mac OS
aur_install mcomix # image viewer for comic books
aur_install nsxiv # image viewer
aur_install shell-gpt # gpt in your terminal
aur_install tageditor # metadata editor for mkv, webm and related video files
aur_install tidal-dl # tidal-dl:tidal as yt-dlp:youtube
aur_install ueberzug # allows for displaying images in terminals
## TESTING IF NEEDED aur_install tremc # curses interface for transmission
aur_install zsh-fast-syntax-highlighting-git # Optimized and extended zsh-syntax-highlighting
# git installs
git_install https://github.com/clamiax/snore.git # sleep with feedback
}
### Boot-Related
silent_boot() {
action="Silent Boot" && display "title" "$action"
action="removing distro and date/time from initial screen" && display "task" "$action"
(cat /dev/null >/etc/issue) || error "error" "$action" "$?"
action="preventing kernel messages on the console" && display "task" "$action"
(echo "kernel.printk = 3 3 3 3" >/etc/sysctl.d/20-quiet-printk.conf) || \
error "error" "$action" "$?"
action="delegating fsck messages from udev to systemd" && display "task" "$action"
sed -i "s/.*HOOKS=(base udev autodetect keyboard keymap modconf block filesystems fsck).*/HOOKS=(base systemd autodetect keyboard keymap modconf block filesystems fsck)/" /etc/mkinitcpio.conf || error "error" "running sed on mkinitcpio.conf to hide fsck messages" "$?"
mkinitcpio -P >> "$logfile" 2>&1 || error "error" "running mkinitcpio -P to silence fsck messages" "$?"
action="instructing systemd to check filesystems" && display "task" "$action"
servicefile=/usr/lib/systemd/system/systemd-fsck-root.service
[ -f $servicefile ] && echo "StandardOutput=null" >>$servicefile && \
echo "StandardError=journal+console" >>$servicefile
servicefile=/usr/lib/systemd/system/systemd-fsck@.service
[ -f $servicefile ] && echo "StandardOutput=null" >>$servicefile && \
echo "StandardError=journal+console" >>$servicefile
action="removing hostname from login prompt" && display "task" "$action"
sed -i "s/--noclear/--nohostname --noclear/g" /usr/lib/systemd/system/getty@.service \
|| error "error" "$action" "$?"
sed -i "s/--noclear/--nohostname --noclear/g" /usr/lib/systemd/system/container-getty@.service \
|| error "error" "$action" "$?"
sed -i "s/--noclear/--nohostname --noclear/g" /usr/lib/systemd/system/console-getty.service \
|| error "error" "$action" "$?"
action="silencing the unneeded and chatty watchdog module" && display "task" "$action"
echo "blacklist iTCO_wdt" >/etc/modprobe.d/nowatchdog.conf || error "error" "$action" "$?"
# SYSTEMD BOOT: eliminate timeout and silence boot text
if [ -f /boot/loader/loader.conf ]; then
action="eliminating timeout and silencing boot test on systemd boot" && display "task" "$action"
echo "timeout=0" >/boot/loader/loader.conf
# the file in this location was named based on the time of the install, so we must use find to identify it.
kernelfile=$(find /boot/loader/entries/ -name "*.conf")
# hush boot output via kernel parameters
sed -i "/.*options root=PARTUUID.*/ s/$/quiet rd.systemd.show_status=auto rd.udev.log_level=2 nvme.noacpi=1 mem_sleep_default=deep nowatchdog/" "$kernelfile"
fi
# GRUB: reset timeouts and adjust log levels
if [ -f /etc/default/grub ]; then
action="resetting timeouts and adjusting log levels on grub boot" && display "task" "$action"
sed -i "s/.*GRUB_TIMEOUT=.*/GRUB_TIMEOUT=0/g" /etc/default/grub
sed -i "s/.*GRUB_DEFAULT=.*/GRUB_DEFAULT=0/g" /etc/default/grub
sed -i "s/.*GRUB_RECORDFAIL_TIMEOUT=.*/GRUB_RECORDFAIL_TIMEOUT=$GRUB_TIMEOUT/g" /etc/default/grub
sed -i "s/.*GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"rw quiet loglevel=2 rd.systemd.show_status=auto rd.udev.log_level=2 nvme.noacpi=1 mem_sleep_default=deep nowatchdog\"/g" /etc/default/grub
grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1 || error "error" "" "$?"
fi
}
### Bugfixes
bugfixes() {
# Avoid issues with xf86-video-intel driver and electron apps
pacman -Rns --noconfirm xf86-video-intel >> "$logfile" 2>&1 || error "error" "" "$?"
}
### Outro
outro() {
action="Cleanup" && display "title" "$action"
action="forcing user password change on first login" && display "task" "$action"
chage -d 0 "$username" >> "$logfile" 2>&1 || error "error" "$action" "$?"
display "subtitle" "Statistics"
action="identifying newly installed packages" && display "task" "$action"
pacman -Q > "$packages_after" || error "error" "$action" "$?"
(comm -13 --nocheck-order "$packages_before" "$packages_after" > "$archsetup_packages") || \
error "error" "$action" "$?"
action="comparing timestamps" && display "task" "$action"
ENDTIME=$(date +%s)
totalsecs=$(($ENDTIME - $STARTTIME))
mins=$(($totalsecs / 60))
secs=$(($totalsecs % 60))
new_packages=$(cat $archsetup_packages | wc -l)
printf "\n"
printf "Completion time : %s\n" "$(date +'%D %T')" | tee -a "$logfile"
printf "Elapsed time : %s minutes, %s seconds\n" $mins $secs | tee -a "$logfile"
printf "Errors encountered : %s\n" $errors_encountered | tee -a "$logfile"
printf "Log file location : %s\n" "$logfile"
printf "Packages installed : %s\n" "$new_packages"
printf "\n"
printf "Please reboot before working with your new workstation.\n\n"
}
### Installation Steps
intro # take start stats
prerequisites # install software required to install software
create_user # create user in wheel with :nopasswd sudo
user_customizations # dotfiles
aur_installer # install yay (comment out if using zfsarch install first)
essential_services # ssh, firewall, printing, etc
xorg # display manager
dwm # window manager
desktop_environment # commonly used applications
developer_workstation # development tools and utilities
supplemental_software # everything else
# silent_boot # make booting a bit less noisy
bugfixes # avoiding known issues
outro # take end stats; show summary
exit 0
|