-
Notifications
You must be signed in to change notification settings - Fork 56
/
setup.sh
executable file
·1779 lines (1451 loc) · 77.7 KB
/
setup.sh
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
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
# Copyright (c) 2024 Felix Bartels
# Copyright (c) 2024 Coruscant11
# Copyright (c) 2024 escapefreeg
# Copyright (c) 2024 Rohan Barar
# Copyright (c) 2024 Oskar Manhart
# Copyright (c) 2024 Sebastien Bürky
# All rights reserved.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# shellcheck disable=SC2034 # Silence warnings regarding unused variables globally.
### GLOBAL CONSTANTS ###
# ANSI ESCAPE SEQUENCES
readonly BOLD_TEXT="\033[1m" # Bold
readonly CLEAR_TEXT="\033[0m" # Clear
readonly COMMAND_TEXT="\033[0;37m" # Grey
readonly DONE_TEXT="\033[0;32m" # Green
readonly ERROR_TEXT="\033[1;31m" # Bold + Red
readonly EXIT_TEXT="\033[1;41;37m" # Bold + White + Red Background
readonly FAIL_TEXT="\033[0;91m" # Bright Red
readonly INFO_TEXT="\033[0;33m" # Orange/Yellow
readonly SUCCESS_TEXT="\033[1;42;37m" # Bold + White + Green Background
readonly WARNING_TEXT="\033[1;33m" # Bold + Orange/Yellow
# ERROR CODES
readonly EC_FAILED_CD="1" # Failed to change directory to location of script.
readonly EC_BAD_ARGUMENT="2" # Unsupported argument passed to script.
readonly EC_EXISTING_INSTALL="3" # Existing conflicting WinApps installation.
readonly EC_NO_CONFIG="4" # Absence of a valid WinApps configuration file.
readonly EC_MISSING_DEPS="5" # Missing dependencies.
readonly EC_NO_SUDO="6" # Insufficient privilages to invoke superuser access.
readonly EC_NOT_IN_GROUP="7" # Current user not in group 'libvirt' and/or 'kvm'.
readonly EC_VM_OFF="8" # Windows 'libvirt' VM powered off.
readonly EC_VM_PAUSED="9" # Windows 'libvirt' VM paused.
readonly EC_VM_ABSENT="10" # Windows 'libvirt' VM does not exist.
readonly EC_CONTAINER_OFF="11" # Windows Docker container is not running.
readonly EC_NO_IP="12" # Windows does not have an IP address.
readonly EC_BAD_PORT="13" # Windows is unreachable via RDP_PORT.
readonly EC_RDP_FAIL="14" # FreeRDP failed to establish a connection with Windows.
readonly EC_APPQUERY_FAIL="15" # Failed to query Windows for installed applications.
readonly EC_INVALID_FLAVOR="16" # Backend specified is not 'libvirt', 'docker' or 'podman'.
# PATHS
# 'BIN'
readonly SYS_BIN_PATH="/usr/local/bin" # UNIX path to 'bin' directory for a '--system' WinApps installation.
readonly USER_BIN_PATH="${HOME}/.local/bin" # UNIX path to 'bin' directory for a '--user' WinApps installation.
readonly USER_BIN_PATH_WIN='\\tsclient\home\.local\bin' # WINDOWS path to 'bin' directory for a '--user' WinApps installation.
# 'SOURCE'
readonly SYS_SOURCE_PATH="${SYS_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--system' WinApps installation.
readonly USER_SOURCE_PATH="${USER_BIN_PATH}/winapps-src" # UNIX path to WinApps source directory for a '--system' WinApps installation.
# 'APP'
readonly SYS_APP_PATH="/usr/share/applications" # UNIX path to 'applications' directory for a '--system' WinApps installation.
readonly USER_APP_PATH="${HOME}/.local/share/applications" # UNIX path to 'applications' directory for a '--user' WinApps installation.
readonly USER_APP_PATH_WIN='\\tsclient\home\.local\share\applications' # WINDOWS path to 'applications' directory for a '--user' WinApps installation.
# 'APPDATA'
readonly SYS_APPDATA_PATH="/usr/local/share/winapps" # UNIX path to 'application data' directory for a '--system' WinApps installation.
readonly USER_APPDATA_PATH="${HOME}/.local/share/winapps" # UNIX path to 'application data' directory for a '--user' WinApps installation.
readonly USER_APPDATA_PATH_WIN='\\tsclient\home\.local\share\winapps' # WINDOWS path to 'application data' directory for a '--user' WinApps installation.
# 'Installed Batch Script'
readonly BATCH_SCRIPT_PATH="${USER_APPDATA_PATH}/installed.bat" # UNIX path to a batch script used to search Windows for applications.
readonly BATCH_SCRIPT_PATH_WIN="${USER_APPDATA_PATH_WIN}\\installed.bat" # WINDOWS path to a batch script used to search Windows for applications.
# 'Installed File'
readonly TMP_INST_FILE_PATH="${USER_APPDATA_PATH}/installed.tmp" # UNIX path to a temporary file containing the names of detected officially supported applications.
readonly TMP_INST_FILE_PATH_WIN="${USER_APPDATA_PATH_WIN}\\installed.tmp" # WINDOWS path to a temporary file containing the names of detected officially supported applications.
readonly INST_FILE_PATH="${USER_APPDATA_PATH}/installed" # UNIX path to a file containing the names of detected officially supported applications.
readonly INST_FILE_PATH_WIN="${USER_APPDATA_PATH_WIN}\\installed" # WINDOWS path to a file containing the names of detected officially supported applications.
# 'PowerShell Script'
readonly PS_SCRIPT_PATH="./install/ExtractPrograms.ps1" # UNIX path to a PowerShell script used to store the names, executable paths and icons (base64) of detected applications.
readonly PS_SCRIPT_HOME_PATH="${USER_APPDATA_PATH}/ExtractPrograms.ps1" # UNIX path to a copy of the PowerShell script within the user's home directory to enable access by Windows.
readonly PS_SCRIPT_HOME_PATH_WIN="${USER_APPDATA_PATH_WIN}\\ExtractPrograms.ps1" # WINDOWS path to a copy of the PowerShell script within the user's home directory to enable access by Windows.
# 'Detected File'
readonly DETECTED_FILE_PATH="${USER_APPDATA_PATH}/detected" # UNIX path to a file containing the output generated by the PowerShell script, formatted to define bash arrays.
readonly DETECTED_FILE_PATH_WIN="${USER_APPDATA_PATH_WIN}\\detected" # WINDOWS path to a file containing the output generated by the PowerShell script, formatted to define bash arrays.
# 'FreeRDP Connection Test File'
readonly TEST_PATH="${USER_APPDATA_PATH}/FreeRDP_Connection_Test" # UNIX path to temporary file whose existence is used to confirm a successful RDP connection was established.
readonly TEST_PATH_WIN="${USER_APPDATA_PATH_WIN}\\FreeRDP_Connection_Test" # WINDOWS path to temporary file whose existence is used to confirm a successful RDP connection was established.
# 'WinApps Configuration File'
readonly CONFIG_PATH="${HOME}/.config/winapps/winapps.conf" # UNIX path to the WinApps configuration file.
# 'Inquirer Bash Script'
readonly INQUIRER_PATH="./install/inquirer.sh" # UNIX path to the 'inquirer' script, which is used to produce selection menus.
# REMOTE DESKTOP CONFIGURATION
readonly VM_NAME="RDPWindows" # Name of the Windows VM (FOR 'libvirt' ONLY).
readonly RDP_PORT=3389 # Port used for RDP on Windows.
readonly DOCKER_IP="127.0.0.1" # Localhost.
### GLOBAL VARIABLES ###
# USER INPUT
OPT_SYSTEM=0 # Set to '1' if the user specifies '--system'.
OPT_USER=0 # Set to '1' if the user specifies '--user'.
OPT_UNINSTALL=0 # Set to '1' if the user specifies '--uninstall'.
OPT_AOSA=0 # Set to '1' if the user specifies '--setupAllOfficiallySupportedApps'.
# WINAPPS CONFIGURATION FILE
RDP_USER="" # Imported variable.
RDP_PASS="" # Imported variable.
RDP_DOMAIN="" # Imported variable.
RDP_IP="" # Imported variable.
WAFLAVOR="docker" # Imported variable.
RDP_SCALE=100 # Imported variable.
RDP_FLAGS="" # Imported variable.
MULTIMON="false" # Imported variable.
DEBUG="true" # Imported variable.
FREERDP_COMMAND="" # Imported variable.
MULTI_FLAG="" # Set based on value of $MULTIMON.
# PERMISSIONS AND DIRECTORIES
SUDO="" # Set to "sudo" if the user specifies '--system', or "" if the user specifies '--user'.
BIN_PATH="" # Set to $SYS_BIN_PATH if the user specifies '--system', or $USER_BIN_PATH if the user specifies '--user'.
APP_PATH="" # Set to $SYS_APP_PATH if the user specifies '--system', or $USER_APP_PATH if the user specifies '--user'.
APPDATA_PATH="" # Set to $SYS_APPDATA_PATH if the user specifies '--system', or $USER_APPDATA_PATH if the user specifies '--user'.
SOURCE_PATH="" # Set to $SYS_SOURCE_PATH if the user specifies '--system', or $USER_SOURCE_PATH if the user specifies '--user'.
# INSTALLATION PROCESS
INSTALLED_EXES=() # List of executable file names of officially supported applications that have already been configured during the current installation process.
### TRAPS ###
set -o errtrace # Ensure traps are inherited by all shell functions and subshells.
trap "waTerminateScript" ERR # Catch non-zero return values.
### FUNCTIONS ###
# Name: 'waTerminateScript'
# Role: Terminates the script when a non-zero return value is encountered.
# shellcheck disable=SC2317 # Silence warning regarding this function being unreachable.
function waTerminateScript() {
# Store the non-zero exit status received by the trap.
local EXIT_STATUS=$?
# Display the exit status.
echo -e "${EXIT_TEXT}Exiting with status '${EXIT_STATUS}'.${CLEAR_TEXT}"
# Terminate the script.
exit "$EXIT_STATUS"
}
# Name: 'waUsage'
# Role: Displays usage information for the script.
function waUsage() {
echo -e "Usage:
${COMMAND_TEXT}./setup.sh --user${CLEAR_TEXT} # Install WinApps and selected applications in ${HOME}
${COMMAND_TEXT}./setup.sh --system${CLEAR_TEXT} # Install WinApps and selected applications in /usr
${COMMAND_TEXT}./setup.sh --user --setupAllOfficiallySupportedApps${CLEAR_TEXT} # Install WinApps and all officially supported applications in ${HOME}
${COMMAND_TEXT}./setup.sh --system --setupAllOfficiallySupportedApps${CLEAR_TEXT} # Install WinApps and all officially supported applications in /usr
${COMMAND_TEXT}./setup.sh --user --uninstall${CLEAR_TEXT} # Uninstall everything in ${HOME}
${COMMAND_TEXT}./setup.sh --system --uninstall${CLEAR_TEXT} # Uninstall everything in /usr
${COMMAND_TEXT}./setup.sh --help${CLEAR_TEXT} # Display this usage message."
}
# Name: 'waGetSourceCode'
# Role: Grab the WinApps source code using Git.
function waGetSourceCode() {
# Declare variables.
local SCRIPT_DIR_PATH="" # Stores the absolute path of the directory containing the script.
# Determine the absolute path to the directory containing the script.
SCRIPT_DIR_PATH=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")")
# Check if winapps is currently installed on $SOURCE_PATH
if [ -f "$SCRIPT_DIR_PATH/winapps" ] && [ "$SCRIPT_DIR_PATH" -ne "$SOURCE_PATH" ]; then
# Display a warning.
echo -e "${WARNING_TEXT}[WARNING]${CLEAR_TEXT} You are running a WinApps installation located outside of default location '${SOURCE_PATH}'. A new installation will be created."
echo -e "${WARNING_TEXT}[WARNING]${CLEAR_TEXT} You might want to remove your old installation on '${SCRIPT_DIR_PATH}'."
fi
if [[ ! -d "$SOURCE_PATH" ]]; then
$SUDO git clone --recurse-submodules --remote-submodules https://github.com/winapps-org/winapps.git "$SOURCE_PATH"
else
echo -e "${INFO_TEXT}WinApps installation already present at ${CLEAR_TEXT}${COMMAND_TEXT}${SOURCE_PATH}${CLEAR_TEXT}${INFO_TEXT}. Updating...${CLEAR_TEXT}"
$SUDO git -C "$SOURCE_PATH" pull --no-rebase
fi
# Silently change the working directory.
if ! cd "$SOURCE_PATH" &>/dev/null; then
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}DIRECTORY CHANGE FAILURE.${CLEAR_TEXT}"
# Display error details.
echo -e "${INFO_TEXT}Failed to change the working directory to ${CLEAR_TEXT}${COMMAND_TEXT}${SOURCE_PATH}${CLEAR_TEXT}${INFO_TEXT}.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Ensure:"
echo -e " - ${COMMAND_TEXT}${SOURCE_PATH}${CLEAR_TEXT} exists."
echo -e " - ${COMMAND_TEXT}${SOURCE_PATH}${CLEAR_TEXT} has been cloned and checked out properly."
echo -e " - The current user has sufficient permissions to access and write to ${COMMAND_TEXT}${SOURCE_PATH}${CLEAR_TEXT}."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_FAILED_CD"
fi
}
# Name: 'waGetInquirer'
# Role: Loads the inquirer script, even if the source isn't cloned yet
function waGetInquirer() {
local INQUIRER=$INQUIRER_PATH
if [ ! -d "$SYS_SOURCE_PATH" ] && [ ! -d "$USER_SOURCE_PATH" ]; then
INQUIRER="/tmp/waInquirer.sh"
rm -f "$INQUIRER"
curl -o "$INQUIRER" "https://raw.githubusercontent.com/winapps-org/winapps/main/install/inquirer.sh"
fi
# shellcheck source=/dev/null # Exclude this file from being checked by ShellCheck.
source "$INQUIRER"
}
# Name: 'waCheckInput'
# Role: Sanitises input and guides users through selecting appropriate options if no arguments are provided.
function waCheckInput() {
# Declare variables.
local OPTIONS=() # Stores the options.
local SELECTED_OPTION # Stores the option selected by the user.
if [[ $# -gt 0 ]]; then
# Parse arguments.
for argument in "$@"; do
case "$argument" in
"--user")
OPT_USER=1
;;
"--system")
OPT_SYSTEM=1
;;
"--setupAllOfficiallySupportedApps")
OPT_AOSA=1
;;
"--uninstall")
OPT_UNINSTALL=1
;;
"--help")
waUsage
exit 0
;;
*)
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}INVALID ARGUMENT.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Unsupported argument${CLEAR_TEXT} ${COMMAND_TEXT}${argument}${CLEAR_TEXT}${INFO_TEXT}.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
waUsage
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_BAD_ARGUMENT"
;;
esac
done
else
# Install vs. uninstall?
OPTIONS=("Install" "Uninstall")
inqMenu "Install or uninstall WinApps?" OPTIONS SELECTED_OPTION
# Set flags.
if [[ $SELECTED_OPTION == "Uninstall" ]]; then
OPT_UNINSTALL=1
fi
# User vs. system?
OPTIONS=("Current User" "System")
inqMenu "Configure WinApps for the current user '$(whoami)' or the whole system?" OPTIONS SELECTED_OPTION
# Set flags.
if [[ $SELECTED_OPTION == "Current User" ]]; then
OPT_USER=1
elif [[ $SELECTED_OPTION == "System" ]]; then
OPT_SYSTEM=1
fi
# Automatic vs. manual?
if [ "$OPT_UNINSTALL" -eq 0 ]; then
OPTIONS=("Manual (Default)" "Automatic")
inqMenu "Automatically install supported applications or choose manually?" OPTIONS SELECTED_OPTION
# Set flags.
if [[ $SELECTED_OPTION == "Automatic" ]]; then
OPT_AOSA=1
fi
fi
# Newline.
echo ""
fi
# Simultaneous 'User' and 'System'.
if [ "$OPT_SYSTEM" -eq 1 ] && [ "$OPT_USER" -eq 1 ]; then
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}CONFLICTING ARGUMENTS.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}You cannot specify both${CLEAR_TEXT} ${COMMAND_TEXT}--user${CLEAR_TEXT} ${INFO_TEXT}and${CLEAR_TEXT} ${COMMAND_TEXT}--system${CLEAR_TEXT} ${INFO_TEXT}simultaneously.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
waUsage
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_BAD_ARGUMENT"
fi
# Simultaneous 'Uninstall' and 'AOSA'.
if [ "$OPT_UNINSTALL" -eq 1 ] && [ "$OPT_AOSA" -eq 1 ]; then
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}CONFLICTING ARGUMENTS.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}You cannot specify both${CLEAR_TEXT} ${COMMAND_TEXT}--uninstall${CLEAR_TEXT} ${INFO_TEXT}and${CLEAR_TEXT} ${COMMAND_TEXT}--aosa${CLEAR_TEXT} ${INFO_TEXT}simultaneously.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
waUsage
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_BAD_ARGUMENT"
fi
# No 'User' or 'System'.
if [ "$OPT_SYSTEM" -eq 0 ] && [ "$OPT_USER" -eq 0 ]; then
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}INSUFFICIENT ARGUMENTS.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}You must specify either${CLEAR_TEXT} ${COMMAND_TEXT}--user${CLEAR_TEXT} ${INFO_TEXT}or${CLEAR_TEXT} ${COMMAND_TEXT}--system${CLEAR_TEXT} ${INFO_TEXT}to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
waUsage
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_BAD_ARGUMENT"
fi
}
# Name: 'waConfigurePathsAndPermissions'
# Role: Sets paths and adjusts permissions as specified.
function waConfigurePathsAndPermissions() {
if [ "$OPT_USER" -eq 1 ]; then
SUDO=""
SOURCE_PATH="$USER_SOURCE_PATH"
BIN_PATH="$USER_BIN_PATH"
APP_PATH="$USER_APP_PATH"
APPDATA_PATH="$USER_APPDATA_PATH"
elif [ "$OPT_SYSTEM" -eq 1 ]; then
SUDO="sudo"
SOURCE_PATH="$SYS_SOURCE_PATH"
BIN_PATH="$SYS_BIN_PATH"
APP_PATH="$SYS_APP_PATH"
APPDATA_PATH="$SYS_APPDATA_PATH"
# Preemptively obtain superuser privileges.
sudo -v || {
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}AUTHENTICATION FAILURE.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Failed to gain superuser privileges.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please check your password and try again."
echo "If you continue to experience issues, contact your system administrator."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_NO_SUDO"
}
fi
}
# Name: 'waCheckExistingInstall'
# Role: Identifies any existing WinApps installations that may conflict with the new installation.
function waCheckExistingInstall() {
# Print feedback.
echo -n "Checking for existing conflicting WinApps installations... "
# Check for an existing 'user' installation.
if [[ -f "${USER_BIN_PATH}/winapps" || -d "${USER_SOURCE_PATH}/winapps" ]]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}EXISTING 'USER' WINAPPS INSTALLATION.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}A previous WinApps installation was detected for the current user.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo -e "Please remove the existing WinApps installation using ${COMMAND_TEXT}./setup.sh --user --uninstall${CLEAR_TEXT}."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_EXISTING_INSTALL"
fi
# Check for an existing 'system' installation.
if [[ -f "${SYS_BIN_PATH}/winapps" || -d "${SYS_SOURCE_PATH}/winapps" ]]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}EXISTING 'SYSTEM' WINAPPS INSTALLATION.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}A previous system-wide WinApps installation was detected.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo -e "Please remove the existing WinApps installation using ${COMMAND_TEXT}./setup.sh --system --uninstall${CLEAR_TEXT}."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_EXISTING_INSTALL"
fi
# Print feedback.
echo -e "${DONE_TEXT}Done!${CLEAR_TEXT}"
}
# Name: 'waFixScale'
# Role: Since FreeRDP only supports '/scale' values of 100, 140 or 180, find the closest supported argument to the user's configuration.
function waFixScale() {
# Define variables.
local OLD_SCALE=100
local VALID_SCALE_1=100
local VALID_SCALE_2=140
local VALID_SCALE_3=180
# Check for an unsupported value.
if [ "$RDP_SCALE" != "$VALID_SCALE_1" ] && [ "$RDP_SCALE" != "$VALID_SCALE_2" ] && [ "$RDP_SCALE" != "$VALID_SCALE_3" ]; then
# Save the unsupported scale.
OLD_SCALE="$RDP_SCALE"
# Calculate the absolute differences.
local DIFF_1=$(( RDP_SCALE > VALID_SCALE_1 ? RDP_SCALE - VALID_SCALE_1 : VALID_SCALE_1 - RDP_SCALE ))
local DIFF_2=$(( RDP_SCALE > VALID_SCALE_2 ? RDP_SCALE - VALID_SCALE_2 : VALID_SCALE_2 - RDP_SCALE ))
local DIFF_3=$(( RDP_SCALE > VALID_SCALE_3 ? RDP_SCALE - VALID_SCALE_3 : VALID_SCALE_3 - RDP_SCALE ))
# Set the final scale to the valid scale value with the smallest absolute difference.
if (( DIFF_1 <= DIFF_2 && DIFF_1 <= DIFF_3 )); then
RDP_SCALE="$VALID_SCALE_1"
elif (( DIFF_2 <= DIFF_1 && DIFF_2 <= DIFF_3 )); then
RDP_SCALE="$VALID_SCALE_2"
else
RDP_SCALE="$VALID_SCALE_3"
fi
# Print feedback.
echo -e "${WARNING_TEXT}[WARNING]${CLEAR_TEXT} Unsupported RDP_SCALE value '${OLD_SCALE}' detected. Defaulting to '${RDP_SCALE}'."
fi
}
# Name: 'waLoadConfig'
# Role: Loads settings specified within the WinApps configuration file.
function waLoadConfig() {
# Print feedback.
echo -n "Attempting to load WinApps configuration file... "
if [ ! -f "$CONFIG_PATH" ]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING CONFIGURATION FILE.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}A valid WinApps configuration file was not found.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo -e "Please create a configuration file at ${COMMAND_TEXT}${CONFIG_PATH}${CLEAR_TEXT}."
echo -e "See https://github.com/winapps-org/winapps?tab=readme-ov-file#step-3-create-a-winapps-configuration-file"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_NO_CONFIG"
else
# Load the WinApps configuration file.
# shellcheck source=/dev/null # Exclude this file from being checked by ShellCheck.
source "$CONFIG_PATH"
fi
# Print feedback.
echo -e "${DONE_TEXT}Done!${CLEAR_TEXT}"
}
# Name: 'waCheckScriptDependencies'
# Role: Terminate script if dependencies are missing.
function waCheckScriptDependencies() {
# 'Git'
if ! command -v git &>/dev/null; then
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'git' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install git${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install git${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S git${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask dev-vcs/git${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
# 'curl'
if ! command -v curl &>/dev/null; then
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'curl' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install curl${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install curl${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S curl${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask net-misc/curl${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
# 'Dialog'.
if ! command -v dialog &>/dev/null; then
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'dialog' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install dialog${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install dialog${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S dialog${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask dialog${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
}
# Name: 'waCheckInstallDependencies'
# Role: Terminate script if dependencies required to install WinApps are missing.
function waCheckInstallDependencies() {
# Declare variables.
local FREERDP_MAJOR_VERSION="" # Stores the major version of the installed copy of FreeRDP.
# Print feedback.
echo -n "Checking whether dependencies are installed... "
# 'libnotify'
if ! command -v notify-send &>/dev/null; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'libnotify' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install libnotify-bin${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install libnotify${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S libnotify${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask x11-libs/libnotify${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
# 'Netcat'
if ! command -v nc &>/dev/null; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'netcat' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install netcat${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install nmap-ncat${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S gnu-netcat${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask net-analyzer/netcat${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
# 'FreeRDP' (Version 3).
# Attempt to set a FreeRDP command if the command variable is empty.
if [ -z "$FREERDP_COMMAND" ]; then
# Check common commands used to launch FreeRDP.
if command -v xfreerdp &>/dev/null; then
# Check FreeRDP major version is 3 or greater.
FREERDP_MAJOR_VERSION=$(xfreerdp --version | head -n 1 | grep -o -m 1 '\b[0-9]\S*' | head -n 1 | cut -d'.' -f1)
if [[ $FREERDP_MAJOR_VERSION =~ ^[0-9]+$ ]] && ((FREERDP_MAJOR_VERSION >= 3)); then
FREERDP_COMMAND="xfreerdp"
fi
fi
# Check for xfreerdp3 command as a fallback option.
if [ -z "$FREERDP_COMMAND" ]; then
if command -v xfreerdp3 &>/dev/null; then
# Check FreeRDP major version is 3 or greater.
FREERDP_MAJOR_VERSION=$(xfreerdp3 --version | head -n 1 | grep -o -m 1 '\b[0-9]\S*' | head -n 1 | cut -d'.' -f1)
if [[ $FREERDP_MAJOR_VERSION =~ ^[0-9]+$ ]] && ((FREERDP_MAJOR_VERSION >= 3)); then
FREERDP_COMMAND="xfreerdp3"
fi
fi
fi
# Check for FreeRDP flatpak as a fallback option.
if [ -z "$FREERDP_COMMAND" ]; then
if command -v flatpak &>/dev/null; then
if flatpak list --columns=application | grep -q "^com.freerdp.FreeRDP$"; then
# Check FreeRDP major version is 3 or greater.
FREERDP_MAJOR_VERSION=$(flatpak list --columns=application,version | grep "^com.freerdp.FreeRDP" | awk '{print $2}' | cut -d'.' -f1)
if [[ $FREERDP_MAJOR_VERSION =~ ^[0-9]+$ ]] && ((FREERDP_MAJOR_VERSION >= 3)); then
FREERDP_COMMAND="flatpak run --command=xfreerdp com.freerdp.FreeRDP"
fi
fi
fi
fi
fi
if ! command -v "$FREERDP_COMMAND" &>/dev/null && [ "$FREERDP_COMMAND" != "flatpak run --command=xfreerdp com.freerdp.FreeRDP" ]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'FreeRDP' version 3 to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install freerdp3-x11${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install freerdp${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S freerdp${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask net-misc/freerdp${CLEAR_TEXT}"
echo ""
echo "You can also install FreeRDP as a Flatpak."
echo "Install Flatpak, add the Flathub repository and then install FreeRDP:"
echo -e "${COMMAND_TEXT}flatpak install flathub com.freerdp.FreeRDP${CLEAR_TEXT}"
echo -e "${COMMAND_TEXT}sudo flatpak override --filesystem=home com.freerdp.FreeRDP${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
# 'libvirt'/'virt-manager' + 'iproute2'.
if [ "$WAFLAVOR" = "libvirt" ]; then
if ! command -v virsh &>/dev/null; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'Virtual Machine Manager' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install virt-manager${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install virt-manager${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S virt-manager${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask app-emulation/virt-manager${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
if ! command -v ip &>/dev/null; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'iproute2' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Debian/Ubuntu-based systems:"
echo -e " ${COMMAND_TEXT}sudo apt install iproute2${CLEAR_TEXT}"
echo "Red Hat/Fedora-based systems:"
echo -e " ${COMMAND_TEXT}sudo dnf install iproute${CLEAR_TEXT}"
echo "Arch Linux systems:"
echo -e " ${COMMAND_TEXT}sudo pacman -S iproute2${CLEAR_TEXT}"
echo "Gentoo Linux systems:"
echo -e " ${COMMAND_TEXT}sudo emerge --ask net-misc/iproute2${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
elif [ "$WAFLAVOR" = "docker" ]; then
if ! command -v docker &>/dev/null; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'Docker Engine' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please visit https://docs.docker.com/engine/install/ for more information."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
elif [ "$WAFLAVOR" = "podman" ]; then
if ! command -v podman-compose &>/dev/null || ! command -v podman &>/dev/null; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}MISSING DEPENDENCIES.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Please install 'podman' and 'podman-compose' to proceed.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please visit https://podman.io/docs/installation for more information."
echo "Please visit https://github.com/containers/podman-compose for more information."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_MISSING_DEPS"
fi
fi
# Print feedback.
echo -e "${DONE_TEXT}Done!${CLEAR_TEXT}"
}
# Name: 'waCheckGroupMembership'
# Role: Ensures the current user is part of the required groups.
function waCheckGroupMembership() {
# Print feedback.
echo -n "Checking whether the user '$(whoami)' is part of the required groups... "
# Declare variables.
local USER_GROUPS="" # Stores groups the current user belongs to.
# Identify groups the current user belongs to.
USER_GROUPS=$(groups "$(whoami)")
if ! (echo "$USER_GROUPS" | grep -q -E "\blibvirt\b") || ! (echo "$USER_GROUPS" | grep -q -E "\bkvm\b"); then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}GROUP MEMBERSHIP CHECK ERROR.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}The current user '$(whoami)' is not part of group 'libvirt' and/or group 'kvm'.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please run the below commands, followed by a system reboot:"
echo -e "${COMMAND_TEXT}sudo usermod -a -G libvirt $(whoami)${CLEAR_TEXT}"
echo -e "${COMMAND_TEXT}sudo usermod -a -G kvm $(whoami)${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_NOT_IN_GROUP"
fi
# Print feedback.
echo -e "${DONE_TEXT}Done!${CLEAR_TEXT}"
}
# Name: 'waCheckVMRunning'
# Role: Checks the state of the Windows 'libvirt' VM to ensure it is running.
function waCheckVMRunning() {
# Print feedback.
echo -n "Checking the status of the Windows VM... "
# Declare variables.
local VM_STATE="" # Stores the state of the Windows VM.
# Obtain VM Status
VM_PAUSED=0
virsh list --state-paused | grep -wq "$VM_NAME" || VM_PAUSED="$?"
VM_RUNNING=0
virsh list --state-running | grep -wq "$VM_NAME" || VM_RUNNING="$?"
VM_SHUTOFF=0
virsh list --state-shutoff | grep -wq "$VM_NAME" || VM_SHUTOFF="$?"
if [[ $VM_SHUTOFF == "0" ]]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}WINDOWS VM NOT RUNNING.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}The Windows VM '${VM_NAME}' is powered off.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please run the below command to start the Windows VM:"
echo -e "${COMMAND_TEXT}virsh start ${VM_NAME}${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_VM_OFF"
elif [[ $VM_PAUSED == "0" ]]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}WINDOWS VM NOT RUNNING.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}The Windows VM '${VM_NAME}' is paused.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please run the below command to resume the Windows VM:"
echo -e "${COMMAND_TEXT}virsh resume ${VM_NAME}${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_VM_PAUSED"
elif [[ $VM_RUNNING != "0" ]]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}WINDOWS VM DOES NOT EXIST.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}The Windows VM '${VM_NAME}' could not be found.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please ensure a Windows VM with the name '${VM_NAME}' exists."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_VM_ABSENT"
fi
# Print feedback.
echo -e "${DONE_TEXT}Done!${CLEAR_TEXT}"
}
# Name: 'waCheckContainerRunning'
# Role: Throw an error if the Docker/Podman container is not running.
function waCheckContainerRunning() {
# Print feedback.
echo -n "Checking container status... "
# Declare variables.
local CONTAINER_STATE=""
local COMPOSE_COMMAND=""
# Determine the state of the container.
CONTAINER_STATE=$("$WAFLAVOR" ps --all --filter name="WinApps" --format '{{.Status}}')
CONTAINER_STATE=${CONTAINER_STATE,,} # Convert the string to lowercase.
CONTAINER_STATE=${CONTAINER_STATE%% *} # Extract the first word.
# Determine the compose command.
case "$WAFLAVOR" in
"docker") COMPOSE_COMMAND="docker compose" ;;
"podman") COMPOSE_COMMAND="podman-compose" ;;
esac
# Check container state.
if [[ "$CONTAINER_STATE" != "up" ]]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}CONTAINER NOT RUNNING.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}Windows is not running.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please ensure Windows is powered on:"
echo -e "${COMMAND_TEXT}${COMPOSE_COMMAND} --file ~/.config/winapps/compose.yaml start${CLEAR_TEXT}"
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_CONTAINER_OFF"
fi
# Print feedback.
echo -e "${DONE_TEXT}Done!${CLEAR_TEXT}"
}
# Name: 'waCheckPortOpen'
# Role: Assesses whether the RDP port on Windows is open.
function waCheckPortOpen() {
# Print feedback.
echo -n "Checking for an open RDP Port on Windows... "
# Declare variables.
local VM_MAC="" # Stores the MAC address of the Windows VM.
# Obtain Windows VM IP Address (FOR 'libvirt' ONLY)
# Note: 'RDP_IP' should not be empty if 'WAFLAVOR' is 'docker', since it is set to localhost before this function is called.
if [ -z "$RDP_IP" ] && [ "$WAFLAVOR" = "libvirt" ]; then
VM_MAC=$(virsh domiflist "$VM_NAME" | grep -oE "([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})") # VM MAC address.
RDP_IP=$(ip neigh show | grep "$VM_MAC" | grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}") # VM IP address.
if [ -z "$RDP_IP" ]; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.
echo -e "${ERROR_TEXT}ERROR:${CLEAR_TEXT} ${BOLD_TEXT}NETWORK CONFIGURATION ERROR.${CLEAR_TEXT}"
# Display the error details.
echo -e "${INFO_TEXT}The IP address of the Windows VM '${VM_NAME}' could not be found.${CLEAR_TEXT}"
# Display the suggested action(s).
echo "--------------------------------------------------------------------------------"
echo "Please ensure networking is properly configured for the Windows VM."
echo "--------------------------------------------------------------------------------"
# Terminate the script.
return "$EC_NO_IP"
fi
fi
# Check for an open RDP port.
if ! timeout 5 nc -z "$RDP_IP" "$RDP_PORT" &>/dev/null; then
# Complete the previous line.
echo -e "${FAIL_TEXT}Failed!${CLEAR_TEXT}\n"
# Display the error type.