-
Notifications
You must be signed in to change notification settings - Fork 185
/
Copy pathinstall.sh
executable file
·4168 lines (3508 loc) · 142 KB
/
install.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
#!/bin/bash
# shellcheck disable=SC2154,SC2024 # referenced but not assigned, sudo redirects
unset ALLSKY_VARIABLE_SET # To force variables.sh to be read
[[ -z ${ALLSKY_HOME} ]] && export ALLSKY_HOME="$( realpath "$( dirname "${BASH_ARGV0}" )" )"
ME="$( basename "${BASH_ARGV0}" )"
#shellcheck source-path=.
source "${ALLSKY_HOME}/variables.sh" || exit "${EXIT_ERROR_STOP}"
#shellcheck source-path=scripts
source "${ALLSKY_SCRIPTS}/functions.sh" || exit "${EXIT_ERROR_STOP}"
#shellcheck source-path=scripts
source "${ALLSKY_SCRIPTS}/installUpgradeFunctions.sh" || exit "${EXIT_ERROR_STOP}"
# Default may be 700 (HOME) or 750 (ALLSKY_HOME) so web server can't read it
chmod 755 "${HOME}" "${ALLSKY_HOME}" || exit "${EXIT_ERROR_STOP}"
cd "${ALLSKY_HOME}" || exit "${EXIT_ERROR_STOP}"
[[ ! -d ${ALLSKY_TMP} ]] && mkdir -p "${ALLSKY_TMP}"
# The ALLSKY_POST_INSTALL_ACTIONS contains information the user needs to act upon after installation.
rm -f "${ALLSKY_POST_INSTALL_ACTIONS}" # Shouldn't be there, but just in case.
rm -f "${ALLSKY_MESSAGES}" # Start out with no messages.
# In case it's left over from a prior install.
rm -f "${ALLSKY_REBOOT_NEEDED}"
SHORT_TITLE="Allsky Installer"
TITLE="${SHORT_TITLE} - ${ALLSKY_VERSION}"
FINAL_SUDOERS_FILE="/etc/sudoers.d/allsky"
OLD_RASPAP_DIR="/etc/raspap" # used to contain WebUI configuration files
SETTINGS_FILE_NAME="$( basename "${SETTINGS_FILE}" )"
FORCE_CREATING_DEFAULT_SETTINGS_FILE="false" # should a default settings file be created?
RESTORED_PRIOR_SETTINGS_FILE="false"
PRIOR_SETTINGS_FILE="" # Full pathname to the prior settings file, if it exists
COPIED_PRIOR_CONFIG_SH="false" # prior config.sh's settings copied to settings file?
COPIED_PRIOR_FTP_SH="false" # prior ftp-settings.sh's settings copied to settings file?
SUGGESTED_NEW_HOST_NAME="allsky" # Suggested new host name
NEW_HOST_NAME="" # User-specified host name
BRANCH="${GITHUB_MAIN_BRANCH}" # default branch
PASSED_DISPLAY_MSG_LOG="${DISPLAY_MSG_LOG}" # if set, we were given the log file name
# shellcheck disable=SC2034
DISPLAY_MSG_LOG="${DISPLAY_MSG_LOG:-${ALLSKY_LOGS}/install.log}" # send log entries here
LONG_BITS=$( getconf LONG_BIT ) # Size of a long, 32 or 64
REBOOT_NEEDED="true" # Is a reboot needed at end of installation?
CONFIGURATION_NEEDED="true" # Does Allsky need to be configured at end of installation?
ALLSKY_IMAGES_MOVED="false" # Did the user move ALLSKY_IMAGES, e.g., to an SSD?
SPACE=" "
NOT_RESTORED="NO PRIOR VERSION"
declare -r TMP_FILE="/tmp/x" # temporary file used by many functions
declare -r TAB="$( echo -e '\t' )"
declare -r NEW_STYLE_ALLSKY="newStyle"
declare -r OLD_STYLE_ALLSKY="oldStyle"
# Overlay variables
SENSOR_WIDTH=""
SENSOR_HEIGHT=""
FULL_OVERLAY_NAME=""
SHORT_OVERLAY_NAME=""
OVERLAY_NAME=""
##### Allsky versions. ${ALLSKY_VERSION} is set in variables.sh
#xxx currently not used: ALLSKY_BASE_VERSION="$( remove_point_release "${ALLSKY_VERSION}" )"
# Base of first version with combined configuration files and all lowercase setting names.
declare -r COMBINED_BASE_VERSION="v2024.12.06"
# Base of first version with CAMERA_TYPE instead of CAMERA in config.sh and
# "cameratype" in the settings file.
declare -r FIRST_CAMERA_TYPE_BASE_VERSION="v2023.05.01"
# First Allsky version that used the "version" file.
# It's also when ftp-settings.sh moved to the ${ALLSKY_CONFIG} directory.
declare -r FIRST_VERSION_VERSION="v2022.03.01"
# Versions before ${FIRST_VERSION_VERSION} didn't have version numbers.
declare -r PRE_FIRST_VERSION_VERSION="old"
##### Information on the prior Allsky version, if used
USE_PRIOR_ALLSKY="false"
PRIOR_ALLSKY_STYLE="" # Set to the style if they have a prior version
PRIOR_ALLSKY_VERSION="" # The version number of the prior version, if known
PRIOR_ALLSKY_BASE_VERSION="" # The base version number of the prior version, if known
PRIOR_CAMERA_TYPE=""
PRIOR_CAMERA_MODEL=""
PRIOR_CAMERA_NUMBER=""
# Holds status of installation if we need to exit and get back in.
declare -r STATUS_FILE="${ALLSKY_LOGS}/install_status.txt"
declare -r STATUS_FILE_TEMP="${ALLSKY_TMP}/temp_status.txt" # holds intermediate status
# status of rebooting due to locale change
declare -r STATUS_LOCALE_REBOOT="Rebooting to change locale"
declare -r STATUS_FINISH_REBOOT="Rebooting to finish installation"
declare -r STATUS_NO_FINISH_REBOOT="Did not reboot to finish installation"
declare -r STATUS_NO_REBOOT="User elected not to reboot"
# exiting due to desired locale not installed
declare -r STATUS_NO_LOCALE="Desired locale not found"
# status of exiting due to no camera found
declare -r STATUS_NO_CAMERA="No camera found"
declare -r STATUS_NO_LAT_LONG="Latitude and/or Longitude not entered"
declare -r STATUS_OK="OK" # Installation was completed.
declare -r STATUS_NOT_CONTINUE="User elected not to continue" # Exiting, but not an error
declare -r STATUS_CLEAR="Clear" # Clear the file
declare -r STATUS_ERROR="Error encountered"
declare -r STATUS_INT="Got interrupt"
STATUS_VARIABLES=() # Holds the variables and values to save
##### Set in installUpgradeFunctions.sh
# PRIOR_ALLSKY_DIR
# PRIOR_CONFIG_DIR
# PRIOR_REMOTE_WEBSITE_CONFIGURATION_FILE
# PRIOR_CONFIG_FILE, PRIOR_FTP_FILE
# PRIOR_PYTHON_VENV
# WEBSITE_CONFIG_VERSION, WEBSITE_ALLSKY_VERSION
# ALLSKY_DEFINES_INC, REPO_WEBUI_DEFINES_FILE
# REPO_SUDOERS_FILE, REPO_LIGHTTPD_FILE, REPO_AVI_FILE, REPO_OPTIONS_FILE
# LIGHTTPD_LOG_DIR, LIGHTTPD_LOG_FILE
# Plus others I probably forgot about...
############################################## functions
####
check_for_tester()
{
return # Currently this is disabled - not sure it's worth doing.
local TOLD_FILE MSG A
# shellcheck disable=SC2119
if [[ $( get_branch ) != "${GITHUB_MAIN_BRANCH}" ]]; then
DEBUG=1; DEBUG_ARG="--debug"; LOG_TYPE="--log"
TOLD_FILE="${ALLSKY_HOME}/told"
if [[ ! -f ${TOLD_FILE} ]]; then
MSG="\nTesters, until we go-live with this release, debugging is automatically on."
MSG+="\n\nPlease set Debug Level to 3 during testing."
MSG+="\n"
MSG+="\nMajor changes from prior release:"
MSG+="\n * xxxxxx."
MSG+="\n\nIf you want to continue with the installation, enter: yes"
title="*** MESSAGE FOR TESTERS ***"
A=$( whiptail --title "${title}" --inputbox "${MSG}" 26 "${WT_WIDTH}" \
3>&1 1>&2 2>&3 )
if [[ $? -ne 0 || ${A} != "yes" ]]; then
MSG="\nYou must type 'yes' to continue the installation."
MSG+="\nThis is to make sure you read it.\n"
display_msg info "${MSG}"
exit 0
fi
touch "${TOLD_FILE}"
fi
fi
}
####
# The last installation succeeded.
# See what the user wants to do.
last_installation_was_ok()
{
local MSG
MSG="The last installation completed successfully."
MSG+="\n\nDo you want to re-install from the beginning?"
MSG+="\n\nSelecting <No> will exit without making any changes."
if whiptail --title "${TITLE}" --yesno "${MSG}" 15 "${WT_WIDTH}" 3>&1 1>&2 2>&3; then
display_msg --log progress "Re-starting installation after successful install."
clear_status
else
display_msg --logonly progress "Not continuing after prior successful installation."
exit_installation 0 ""
fi
}
####
# The last installation succeeded but a reboot is needed
# See what the user wants to do.
last_installation_needed_reboot()
{
local MSG MSG2
MSG="The installation completed successfully but the following needs to happen"
MSG+=" before Allsky is ready to run:"
MSG2="\n"
MSG2+="\n 1. Verify your settings in the WebUI's 'Allsky Settings' page."
MSG2+="\n 2. Reboot the Pi."
MSG3="\n\nHave you already performed those steps?"
if whiptail --title "${TITLE}" --yesno "${MSG}${MSG2}${MSG3}" 15 "${WT_WIDTH}" \
3>&1 1>&2 2>&3; then
MSG="\nCongratulations, you successfully installed Allsky version ${ALLSKY_VERSION}!"
MSG+="\nAllsky is starting. Look in the WebUI's 'Live View' page to ensure"
MSG+="\nimages are being taken.\n"
display_msg --log progress "${MSG}"
start_Allsky
# Update status
sed -i \
-e "s/${STATUS_NO_FINISH_REBOOT}/${STATUS_OK}/" \
-e "s/MORE_STATUS.*//" \
"${STATUS_FILE}"
else
display_msg --log info "\nPlease perform the following steps:${MSG2}\n"
fi
exit_installation 0 "" ""
}
####
# The last installation didn't complete.
# Ask the user what they want to do.
last_installation_unknown_status()
{
local MSG
[[ -n ${MORE_STATUS} ]] && MORE_STATUS=" - ${MORE_STATUS}"
MSG="You have already begun the installation."
MSG+="\n\nThe last status was: ${STATUS_INSTALLATION}${MORE_STATUS}"
MSG+="\n\nDo you want to continue where you left off?"
if whiptail --title "${TITLE}" --yesno "${MSG}" 15 "${WT_WIDTH}" 3>&1 1>&2 2>&3; then
MSG="Continuing installation. Steps already performed will be skipped."
MSG+="\n The last status was: ${STATUS_INSTALLATION}${MORE_STATUS}"
display_msg --log progress "${MSG}"
#shellcheck disable=SC1090 # file doesn't exist in GitHub
source "${STATUS_FILE}" || exit 1
# Put all but the status variable in the list so we save them next time.
STATUS_VARIABLES=( "$( grep -v STATUS_INSTALLATION "${STATUS_FILE}" )" )
STATUS_VARIABLES+=("\n#### Prior variables above, new below.\n")
# If returning from a reboot for local,
# prompt for locale again to make sure it's there and still what they want.
if [[ ${STATUS_INSTALLATION} == "${STATUS_LOCALE_REBOOT}" ]]; then
unset get_desired_locale # forces a re-prompt
unset CURRENT_LOCALE # It will get re-calculated
fi
else
MSG="Do you want to restart the installation from the beginning?"
MSG+="\n\nSelecting <No> will exit the installation without making any changes."
if whiptail --title "${TITLE}" --yesno "${MSG}" 15 "${WT_WIDTH}" \
3>&1 1>&2 2>&3; then
display_msg --log progress "Restarting installation."
else
display_msg --log progress "Not continuing after prior partial installation."
exit_installation 0 ""
fi
fi
}
####
handle_prior_installation()
{
local MSG MSG2
# Initially just get the STATUS and MORE_STATUS.
# After that we may clear the file or get all the variables.
eval "$( grep "^STATUS_INSTALLATION" "${STATUS_FILE}" )"
[[ $? -ne 0 ]] && exit_installation 1 "" # "" means do NOT update the status file
if [[ ${STATUS_INSTALLATION} == "${STATUS_OK}" ]]; then
last_installation_was_ok
elif [[ ${STATUS_INSTALLATION} == "${STATUS_NO_FINISH_REBOOT}" ]]; then
last_installation_needed_reboot
else
last_installation_unknown_status
fi
}
####
do_initial_heading()
{
[[ ${SKIP} == "true" ]] && return
if [[ ${UPDATE} == "true" ]]; then
display_header "Updating Allsky"
return
fi
local MSG H X
declare -n v="${FUNCNAME[0]}"
if [[ ${v} == "true" ]]; then
display_header "Welcome back to the ${SHORT_TITLE}!"
else
MSG="Welcome to the ${SHORT_TITLE}!\n"
if [[ ${RESTORE} == "true" ]]; then
H="$( basename "${ALLSKY_HOME}" )"
X="$( basename "${RENAMED_DIR}" )"
MSG+="\nYour current '${H}' directory will be renamed to"
MSG+="\n ${X}"
X="$( basename "${PRIOR_ALLSKY_DIR}" )"
MSG+="\nand the prior Allsky in '${X}' will be"
MSG+=" renamed to back to '${H}'."
MSG+="\n\nFiles that were moved from the old release to the current one"
MSG+=" will be moved back."
MSG+="\nYou will manually need to restart Allsky after checking that"
MSG+=" the settings are correct in the WebUI."
elif [[ ${USE_PRIOR_ALLSKY} == "true" ]]; then
MSG+="\nYou will be asked if you want to use the images and darks"
MSG+=" from your prior version of Allsky."
else
MSG+="\nYou will be prompted for required information such as the type"
MSG+="\nof camera you have and the camera's latitude, logitude, and locale."
fi
if [[ ${RESTORE} != "true" ]]; then
MSG+="\n\nNOTE: your camera must be connected to the Pi before continuing."
fi
MSG+="\n\nContinue?"
if ! whiptail --title "${TITLE}" --yesno "${MSG}" 25 "${WT_WIDTH}" \
3>&1 1>&2 2>&3; then
display_msg "${LOG_TYPE}" info "User not ready to continue."
exit_installation 1 "${STATUS_CLEAR}" ""
fi
display_header "Welcome to the ${SHORT_TITLE}"
fi
declare -n v="${FUNCNAME[0]}"; [[ ${v} != "true" ]] && STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
}
####
usage_and_exit()
{
local RET C MSG
exec >&2
RET=${1}
if [[ ${RET} -eq 0 ]]; then
C="${YELLOW}"
else
C="${RED}"
fi
MSG="Usage: ${ME} [--help] [--debug [...]] [--fix |--update | --restore | --function function]"
echo -e "\n${C}${MSG}${NC}"
echo
echo "'--help' displays this message and exits."
echo "'--debug' displays debugging information. Can be called multiple times to increase level."
echo "'--fix' should only be used when instructed to by the Allsky Website."
echo "'--update' should only be used when instructed to by the Allsky Website."
echo "'--restore' restores ${PRIOR_ALLSKY_DIR} to ${ALLSKY_HOME}."
echo "'--function' executes the specified function and quits."
echo
exit_installation "${RET}"
}
####
# Get the branch of the release we are installing;
get_this_branch()
{
declare -n v="${FUNCNAME[0]}"; [[ ${v} == "true" ]] && return
local B # BRANCH is global
#shellcheck disable=SC2119
if ! B="$( get_branch )" ; then
display_msg --log warning "Unable to determine branch; assuming '${BRANCH}'."
else
BRANCH="${B}"
display_msg --logonly info "Using the '${BRANCH}' branch."
fi
STATUS_VARIABLES+=("BRANCH='${BRANCH}'\n")
STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
}
####
# Execute any specified function, then exit.
do_function()
{
local FUNCTION="${1}"
shift
# If we were passed a log file location, use it.
[[ -n ${PASSED_DISPLAY_MSG_LOG} ]] && DISPLAY_MSG_LOG="${PASSED_DISPLAY_MSG_LOG}"
if ! type "${FUNCTION}" > /dev/null; then
display_msg error "Unknown function: '${FUNCTION}'."
exit 1
fi
${FUNCTION} "$@"
exit $?
}
####
# Map the new ${CAMERA_TYPE} setting to the old ${CAMERA} setting.
CAMERA_TYPE_to_CAMERA()
{
local CAMERA_TYPE="${1}"
if [[ ${CAMERA_TYPE} == "ZWO" ]]; then
echo "ZWO"
elif [[ ${CAMERA_TYPE} == "RPi" ]]; then
echo "RPiHQ" # RPi cameras used to be called "RPiHQ".
else
if [[ -n ${CAMERA_TYPE} ]]; then
MSG="Unknown CAMERA_TYPE: '${CAMERA_TYPE}'"
else
MSG="'CAMERA_TYPE' not defined."
fi
display_msg --log error "${MSG}"
exit_installation 1 "${STATUS_ERROR}" "${MSG}"
fi
}
####
# Map the old ${CAMERA} setting to the new ${CAMERA_TYPE} setting.
CAMERA_to_CAMERA_TYPE()
{
local CAMERA="${1}"
if [[ ${CAMERA} == "ZWO" ]]; then
echo "ZWO"
elif [[ ${CAMERA} == "RPiHQ" ]]; then
echo "RPi"
else
if [[ -n ${CAMERA} ]]; then
MSG="Unknown CAMERA: '${CAMERA}'"
else
MSG="'CAMERA' not defined."
fi
display_msg --log error "Unknown CAMERA: '${CAMERA}'"
exit_installation 1 "${STATUS_CLEAR}" "${MSG}"
fi
}
#######
# Set up the file that contains information on all supported RPi cameras.
# Have separate function so it can be called from "--function".
setup_rpi_supported_cameras()
{
local CMD="${1}"
local notCMD
if [[ ! -f ${RPi_SUPPORTED_CAMERAS} ]]; then
local B="$( basename "${RPi_SUPPORTED_CAMERAS}" )"
if [[ -z ${CMD} ]]; then
notCMD="xxxxx" # won't match anything
CMD="all"
elif [[ ${CMD} == "raspistill" ]]; then
notCMD="libcamera"
else
notCMD="raspistill"
fi
local MSG="Creating ${RPi_SUPPORTED_CAMERAS} with '${CMD}' entries."
display_msg --logonly info "${MSG}"
# Remove comment and blank lines and lines for the command we are NOT using.
grep -v -E "^\$|^#|^${notCMD}" "${ALLSKY_REPO}/${B}.repo" > "${RPi_SUPPORTED_CAMERAS}"
fi
}
#######
CONNECTED_CAMERA_MODELS=""
NUM_CONNECTED_CAMERAS=0
CT=() # Camera Type array - what to display in whiptail
# Re-run every time in case a camera was connected or disconnected.
get_connected_cameras()
{
local CMD CMD_RET CC MSG NUM_RPI=0 NUM_ZWO=0
# true == ignore errors. ${CMD} will be "" if no command found.
CMD="$( determineCommandToUse "false" "" "true" 2> /dev/null )"
CMD_RET=$? # return of 2 means no command was found
[[ ${CMD_RET} -ne 0 ]] && CMD=""
setup_rpi_supported_cameras "${CMD}" # Will create full file is CMD == ""
# RPi format: RPi \t camera_number \t camera_sensor [\t optional_other_stuff]
# ZWO format: ZWO \t camera_number \t camera_model
# "true" == ignore errors
get_connected_cameras_info --cmd "${CMD}" "true" > "${CONNECTED_CAMERAS_INFO}" 2>/dev/null
# Get the RPi connected cameras, if any.
CC=""
if [[ -n ${CMD} ]]; then
local RPI_MODELS="$( get_connected_camera_models --full "RPi" )"
# Output from above is:
# RPi \t camera_number \t camera_model \t camera_sensor
if [[ -n ${RPI_MODELS} ]]; then
CC="RPi"
local CT_ CN_ MODEL SENSOR
# shellcheck disable=SC2034
while read -r CT_ CN_ MODEL SENSOR
do
MODEL="${MODEL//++/ }"
SENSOR="${SENSOR//++/ }"
local FULL_NAME="${MODEL} (${SENSOR})"
[[ -z ${FUNCTION} ]] && display_msg --log progress "Found" " RPi ${FULL_NAME}"
CT+=("${NUM_RPI};RPi;${MODEL}" "RPi ${FULL_NAME}")
((NUM_RPI++))
done <<<"${RPI_MODELS// /++}" # replace any spaces
fi
fi
# Get the ZWO connected cameras, if any.
local ZWO_MODELS="$( get_connected_camera_models "ZWO" )"
if [[ -n ${ZWO_MODELS} ]]; then
[[ -n ${CC} ]] && CC+=" "
CC+="ZWO"
for X in ${ZWO_MODELS// /++}
do
MODEL="${X//++/ }"
[[ -z ${FUNCTION} ]] && display_msg --log progress "Found" " ZWO ${MODEL}"
CT+=( "${NUM_ZWO};ZWO;${MODEL}" "ZWO ${MODEL}" )
((NUM_ZWO++))
done
fi
NUM_CONNECTED_CAMERAS=$(( NUM_RPI + NUM_ZWO ))
if [[ ${NUM_CONNECTED_CAMERAS} -eq 0 ]]; then
MSG="No connected cameras were detected. The installation will exit."
MSG+="\nMake sure a camera is plugged in and working prior to restarting"
MSG+=" the installation."
if [[ ${CMD_RET} -eq "${EXIT_ERROR_STOP}" ]]; then
# RPi command timed out.
MSG+="\n\nIf you have an RPi camera attached, double check the cable -"
MSG+=" it may be bad or not seated properly."
fi
whiptail --title "${TITLE}" --msgbox "${MSG}" 12 "${WT_WIDTH}" 3>&1 1>&2 2>&3
MSG="No connected cameras were detected."
local MSG2=""
if [[ ${CMD_RET} -eq 2 ]]; then
MSG2="No command to take RPi images was found"
MSG2+=" - make sure 'libcamera-apps' is installed if you have an RPi camera."
fi
display_msg --log error "${MSG}" "${MSG2}"
exit_installation 1 "${STATUS_NO_CAMERA}" ""
fi
declare -n v="${FUNCNAME[0]}";
[[ ${v} != "true" ]] && STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
# CONNECTED_CAMERAS_MODELS was set from a prior installation, if any.
# If it was set, warn the user if the prior models is different than
# the current ones, but it's not an error.
if [[ -n ${CONNECTED_CAMERA_MODELS} ]]; then
if [[ ${CONNECTED_CAMERA_MODELS} != "${CC}" ]]; then
MSG="Connected cameras were '${CONNECTED_CAMERA_MODELS}' during last installation"
MSG+=" but are '${CC}' now."
display_msg --log info "${MSG}"
STATUS_VARIABLES+=("CONNECTED_CAMERA_MODELS='${CC}'\n")
CONNECTED_CAMERA_MODELS="${CC}"
fi
return
fi
CONNECTED_CAMERA_MODELS="${CC}" # Either not set before or is different this time
}
#
# Prompt the user to select their camera type, if we can't determine it automatically.
# If they have a prior installation of Allsky that uses either CAMERA or CAMERA_TYPE in config.sh,
# we can use its value and not prompt.
CAMERA_TYPE=""
select_camera_type()
{
local MSG CAMERA NEW S CAMERA_INFO
# CAMERA_TYPE and NUM_CONNECTED_CAMERAS are global
if [[ ${USE_PRIOR_ALLSKY} == "true" ]]; then
# bash doesn't have ">=" so we have to use "! ... < "
if [[ ! ${PRIOR_ALLSKY_VERSION} < "${FIRST_CAMERA_TYPE_BASE_VERSION}" ]]; then
# New style Allsky using ${CAMERA_TYPE}.
CAMERA_TYPE="${PRIOR_CAMERA_TYPE}"
if [[ -n ${CAMERA_TYPE} ]]; then
MSG="Using Camera Type '${CAMERA_TYPE}' from prior Allsky; not prompting user."
display_msg --logonly info "${MSG}"
STATUS_VARIABLES+=("CAMERA_TYPE='${CAMERA_TYPE}'\n")
if [[ -n ${CAMERA_MODEL} ]]; then
STATUS_VARIABLES+=("CAMERA_MODEL='${CAMERA_MODEL}'\n")
fi
if [[ -n ${CAMERA_NUMBER} ]]; then
STATUS_VARIABLES+=("CAMERA_NUMBER='${CAMERA_NUMBER}'\n")
fi
STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
return
else
MSG="Camera Type not in prior new-style settings file."
display_msg --log error "${MSG}"
exit_installation 2 "${STATUS_NO_CAMERA}" "${MSG}"
fi
else
# Older style using ${CAMERA}
CAMERA="$( get_variable "CAMERA" "${PRIOR_CONFIG_FILE}" )"
if [[ -n ${CAMERA} ]]; then
CAMERA_TYPE="$( CAMERA_to_CAMERA_TYPE "${CAMERA}" )"
if [[ ${CAMERA} != "${CAMERA_TYPE}" ]]; then
NEW=" (now called ${CAMERA_TYPE})"
else
NEW=""
fi
display_msg --log progress "Using prior ${CAMERA} camera${NEW}."
STATUS_VARIABLES+=("CAMERA_TYPE='${CAMERA_TYPE}'\n")
# Old style doesn't have CAMERA_MODEL or CAMERA_NUMBER.
STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
return
else
MSG="CAMERA not in old-style '${PRIOR_CONFIG_FILE}'.sh."
display_msg --log warning "${MSG}"
fi
fi
fi
S=" is"
[[ ${NUM_CONNECTED_CAMERAS} -gt 1 ]] && S="s are"
MSG="\nThe following camera${S} connected to the Pi.\n"
[[ ${NUM_CONNECTED_CAMERAS} -gt 1 ]] && MSG+="Pick the one you want."
MSG+="\nIf it's not in the list, select <Cancel> and determine why."
if ! CAMERA_INFO=$( whiptail --title "${TITLE}" --notags --menu "${MSG}" 15 "${WT_WIDTH}" \
"${NUM_CONNECTED_CAMERAS}" "${CT[@]}" 3>&1 1>&2 2>&3 ) ; then
MSG="Camera selection required."
MSG+=" Please re-run the installation and select a camera to continue."
display_msg --log warning "${MSG}"
exit_installation 2 "${STATUS_NO_CAMERA}" "User did not select a camera."
fi
# CAMERA_INFO is: number;type;model
CAMERA_NUMBER="${CAMERA_INFO%%;*}" # before first ";"
CAMERA_MODEL="${CAMERA_INFO##*;}" # after last ";"
CAMERA_INFO="${CAMERA_INFO/${CAMERA_NUMBER};/}" # Now: type;model
CAMERA_TYPE="${CAMERA_INFO%;*}" # before ";"
display_msg --log progress "Using user-selected ${CAMERA_TYPE} ${CAMERA_MODEL} camera."
STATUS_VARIABLES+=("CAMERA_TYPE='${CAMERA_TYPE}'\n")
STATUS_VARIABLES+=("CAMERA_MODEL='${CAMERA_MODEL}'\n")
STATUS_VARIABLES+=("CAMERA_NUMBER='${CAMERA_NUMBER}'\n")
STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
}
####
# Wrapper function to call do_save_camera_capabilities and exit on error.
save_camera_capabilities()
{
declare -n v="${FUNCNAME[0]}"; [[ ${v} == "true" ]] && return
do_save_camera_capabilities "${1}"
[[ $? -ne 0 ]] && exit_with_image 1 "${STATUS_ERROR}" "${FUNCNAME[0]} failed."
STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
}
####
# Save the camera capabilities and use them to set the WebUI min, max, and defaults.
# This will error out and exit if no camera is installed,
# otherwise it will determine what capabilities the connected camera has,
# then create an "options" file specific to that camera.
# It will also create a default camera-specific "settings" file if one doesn't exist.
do_save_camera_capabilities()
{
if [[ -z ${CAMERA_TYPE} ]]; then
display_msg --log error "INTERNAL ERROR: CAMERA_TYPE not set in save_camera_capabilities()."
return 1
fi
local OPTIONSFILEONLY="${1}" # Set to "true" if we should ONLY create the options file.
local FORCE MSG OPTIONSONLY ERR M RET
# CAMERA_MODEL is global
# Create the camera type/model-specific options file and optionally a default settings file.
# --cameraTypeOnly tells makeChanges.sh to only change the camera info, then exit.
# It displays any error messages.
if [[ ${FORCE_CREATING_DEFAULT_SETTINGS_FILE} == "true" ]]; then
FORCE=" --force"
MSG=" and default settings"
else
FORCE=""
MSG=""
fi
if [[ ${OPTIONSFILEONLY} == "true" ]]; then
OPTIONSONLY=" --optionsOnly"
else
OPTIONSONLY=""
MSG="Setting up WebUI options${MSG} for ${CAMERA_TYPE} cameras."
display_msg --log progress "${MSG}"
fi
# Restore the prior settings file or camera-specific settings file(s) if present so
# the appropriate one can be used by makeChanges.sh.
[[ -n ${PRIOR_SETTINGS_FILE} ]] && restore_prior_settings_file
display_msg --log progress "Making new settings file '${SETTINGS_FILE}'."
CMD="makeChanges.sh${FORCE}${OPTIONSONLY}"
CMD+=" --cameraTypeOnly --from install --addNewSettings ${DEBUG_ARG}"
#shellcheck disable=SC2089
CMD+=" cameranumber 'Camera Number' '${PRIOR_CAMERA_NUMBER}' '${CAMERA_NUMBER}'"
#shellcheck disable=SC2089
CMD+=" cameramodel 'Camera Model' '${PRIOR_CAMERA_MODEL}' '${CAMERA_MODEL}'"
# cameratype needs to come last.
#shellcheck disable=SC2089
CMD+=" cameratype 'Camera Type' '${PRIOR_CAMERA_TYPE}' '${CAMERA_TYPE}'"
MSG="Executing ${CMD}"
display_msg "${LOG_TYPE}" info "${MSG}"
local TMP="${ALLSKY_LOGS}/makeChanges.log"
#shellcheck disable=SC2086,SC2090
M="$( eval "${ALLSKY_SCRIPTS}/"${CMD} 2> "${TMP}" )"
RET=$?
if [[ ${RET} -ne 0 ]]; then
if [[ ${RET} -eq ${EXIT_NO_CAMERA} ]]; then
MSG="No camera was found;"
MSG+=" one must be connected and working for the installation to succeed.\n"
MSG+="After connecting your camera, re-run the installation."
whiptail --title "${TITLE}" --msgbox "${MSG}" 12 "${WT_WIDTH}" 3>&1 1>&2 2>&3
display_msg --log error "No camera detected - installation aborted."
[[ -s ${TMP} ]] && display_msg --log error "$( < "${TMP}" )"
exit_with_image 1 "${STATUS_ERROR}" "No camera detected"
elif [[ ${OPTIONSFILEONLY} == "false" ]]; then
display_msg --log error "Unable to save camera capabilities."
[[ -s ${TMP} ]] && display_msg --log info "TMP=$( < "${TMP}" )"
[[ -n ${M} ]] && display_msg --log info "M=${M}"
fi
return 1
else
[[ -n ${M} ]] && display_msg --logonly info "${M}"
if [[ ! -f ${SETTINGS_FILE} ]]; then
display_msg --log error "Settings file not created; cannot continue."
return 1
fi
fi
#shellcheck disable=SC2012
MSG="$( /bin/ls -l "${ALLSKY_CONFIG}/settings"*.json 2>/dev/null | sed 's/^/ /' )"
display_msg --logonly info "Settings files:\n${MSG}"
# Make sure the settings file is linked to the camera-specific one.
MSG="$( check_settings_link "${SETTINGS_FILE}" )"
RET=$?
if [[ ${RET} -ne 0 ]]; then
if [[ ${RET} -eq "${EXIT_ERROR_STOP}" ]]; then
display_msg --log error "${MSG}"
return 1
else
display_msg --logonly info "${MSG}"
fi
fi
check_for_required_settings # Make sure the required settings are there.
CAMERA_MODEL="$( settings ".cameramodel" "${SETTINGS_FILE}" )"
if [[ -z ${CAMERA_MODEL} ]]; then
display_msg --log error "cameramodel not found in settings file."
return 1
fi
return 0
}
####
# Get a count of the number of the specified file in the specified directory.
get_count()
{
local DIR="${1}"
local FILENAME="${2}"
find "${DIR}" -maxdepth 1 -name "${FILENAME}" | wc -l
}
####
# Update various PHP define() variables.
update_php_defines()
{
declare -n v="${FUNCNAME[0]}"; [[ ${v} == "true" ]] && return
[[ ${SKIP} == "true" ]] && return
display_msg --log progress "Modifying variables for WebUI and Website."
local FILE="${ALLSKY_WEBUI}/includes/${ALLSKY_DEFINES_INC}"
sed -e "s;XX_HOME_XX;${HOME};g" \
-e "s;XX_ALLSKY_HOME_XX;${ALLSKY_HOME};g" \
-e "s;XX_ALLSKY_CONFIG_XX;${ALLSKY_CONFIG};g" \
-e "s;XX_ALLSKY_SCRIPTS_XX;${ALLSKY_SCRIPTS};g" \
-e "s;XX_ALLSKY_UTILITIES_XX;${ALLSKY_UTILITIES};g" \
-e "s;XX_ALLSKY_TMP_XX;${ALLSKY_TMP};g" \
-e "s;XX_ALLSKY_IMAGES_XX;${ALLSKY_IMAGES};g" \
-e "s;XX_ALLSKY_MESSAGES_XX;${ALLSKY_MESSAGES};g" \
-e "s;XX_ALLSKY_CHECK_LOG_XX;${ALLSKY_CHECK_LOG};g" \
-e "s;XX_ALLSKY_PRIOR_DIR_XX;${PRIOR_ALLSKY_DIR};g" \
-e "s;XX_ALLSKY_OLD_REMINDER_XX;${ALLSKY_OLD_REMINDER};g" \
-e "s;XX_ALLSKY_POST_INSTALL_ACTIONS_XX;${ALLSKY_POST_INSTALL_ACTIONS};g" \
-e "s;XX_ALLSKY_ABORTS_DIR_XX;${ALLSKY_ABORTS_DIR};g" \
-e "s;XX_ALLSKY_WEBUI_XX;${ALLSKY_WEBUI};g" \
-e "s;XX_ALLSKY_WEBSITE_XX;${ALLSKY_WEBSITE};g" \
-e "s;XX_ALLSKY_WEBSITE_LOCAL_CONFIG_NAME_XX;${ALLSKY_WEBSITE_CONFIGURATION_NAME};g" \
-e "s;XX_ALLSKY_WEBSITE_REMOTE_CONFIG_NAME_XX;${ALLSKY_REMOTE_WEBSITE_CONFIGURATION_NAME};g" \
-e "s;XX_ALLSKY_WEBSITE_LOCAL_CONFIG_XX;${ALLSKY_WEBSITE_CONFIGURATION_FILE};g" \
-e "s;XX_ALLSKY_WEBSITE_REMOTE_CONFIG_XX;${ALLSKY_REMOTE_WEBSITE_CONFIGURATION_FILE};g" \
-e "s;XX_ALLSKY_OVERLAY_XX;${ALLSKY_OVERLAY};g" \
-e "s;XX_ALLSKY_ENV_XX;${ALLSKY_ENV};g" \
-e "s;XX_MY_OVERLAY_TEMPLATES_XX;${MY_OVERLAY_TEMPLATES};g" \
-e "s;XX_ALLSKY_MODULES_XX;${ALLSKY_MODULES};g" \
-e "s;XX_ALLSKY_MODULE_LOCATION_XX;${ALLSKY_MODULE_LOCATION};g" \
-e "s;XX_ALLSKY_OWNER_XX;${ALLSKY_OWNER};g" \
-e "s;XX_ALLSKY_GROUP_XX;${ALLSKY_GROUP};g" \
-e "s;XX_WEBSERVER_OWNER_XX;${WEBSERVER_OWNER};g" \
-e "s;XX_WEBSERVER_GROUP_XX;${WEBSERVER_GROUP};g" \
-e "s;XX_ALLSKY_REPO_XX;${ALLSKY_REPO};g" \
-e "s;XX_ALLSKY_VERSION_XX;${ALLSKY_VERSION};g" \
-e "s;XX_ALLSKY_STATUS_XX;${ALLSKY_STATUS};g" \
-e "s;XX_RASPI_CONFIG_XX;${ALLSKY_CONFIG};g" \
"${REPO_WEBUI_DEFINES_FILE}" > "${FILE}"
chmod 644 "${FILE}"
# Don't save status if we did a fix.
if [[ ${FIX} == "false" ]]; then
STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
fi
}
####
# Recreate the options file.
# This can be used after installation if the options file gets hosed.
recreate_options_file()
{
CAMERA_TYPE="$( settings ".cameratype" )"
save_camera_capabilities "true"
set_permissions
}
####
# Update the sudoers file so the web server can execute certain commands with sudo.
do_sudoers()
{
declare -n v="${FUNCNAME[0]}"; [[ ${v} == "true" ]] && return
[[ ${SKIP} == "true" ]] && return
display_msg --logonly info "Creating/updating sudoers file."
sed \
-e "s;XX_ALLSKY_SCRIPTS_XX;${ALLSKY_SCRIPTS};" \
-e "s;XX_ALLSKY_UTILITIES_XX;${ALLSKY_UTILITIES};" \
"${REPO_SUDOERS_FILE}" > "${TMP_FILE}"
sudo install -m 0644 "${TMP_FILE}" "${FINAL_SUDOERS_FILE}" && rm -f "${TMP_FILE}"
STATUS_VARIABLES+=("${FUNCNAME[0]}='true'\n")
}
####
# Ask the user if they want to reboot.
# Call every time in case they change their mind.
WILL_REBOOT="false"
ask_reboot()
{
local TYPE="${1}"
local MSG AT
if [[ ${TYPE} == "locale" ]]; then
MSG="A reboot is needed for the locale change to take effect."
MSG+="\nYou must reboot before continuing the installation."
MSG+="\n\nReboot now?"
if whiptail --title "${TITLE}" --yesno "${MSG}" 18 "${WT_WIDTH}" 3>&1 1>&2 2>&3; then
MSG="\nAfter the reboot you MUST continue with the installation"
MSG+=" before anything will work."
MSG+="\nTo restart the installation, do the following:\n"
MSG+="\n cd ~/allsky"
MSG+="\n ./install.sh"
MSG+="\n\nThe installation will pick up where it left off."
whiptail --title "${TITLE}" --msgbox "${MSG}" 15 "${WT_WIDTH}" 3>&1 1>&2 2>&3
return 0
else
REBOOT_NEEDED="true"
WILL_REBOOT="false"
return 1
fi
fi
AT=" http://${NEW_HOST_NAME}.local\n"
AT+="or\n"
AT+=" http://$( hostname -I | sed -e 's/ .*$//' )"
if [[ ${REBOOT_NEEDED} == "false" ]]; then
MSG="\nAfter installation you can connect to the WebUI at:\n${AT}"
display_msg -log progress "${MSG}"
return 0
fi
MSG="*** Allsky installation is almost done. ***"
MSG+="\n\nWhen done, you must reboot the Raspberry Pi to finish the installation."
MSG+="\n\nAfter reboot you can connect to the WebUI at:\n"
MSG+="${AT}"
MSG+="\n\nReboot when installation is done?"
if whiptail --title "${TITLE}" --yesno "${MSG}" 18 "${WT_WIDTH}" 3>&1 1>&2 2>&3; then
WILL_REBOOT="true"
display_msg --logonly info "Pi will reboot after installation completes."
else
WILL_REBOOT="false"
display_msg --logonly info "User elected not to reboot."
MSG="If you have not already rebooted your Pi, please do so now"
MSG+=" by going to the <span class='WebUILink'>System</span> page."
MSG+="\n\nYou can then connect to the WebUI at:\n"
MSG+="${AT}"
"${ALLSKY_SCRIPTS}/addMessage.sh" --type info --msg "${MSG}"
fi
}
do_reboot()
{
exit_installation -1 "${1}" "${2}" # -1 means just log ending statement but don't exit.
sudo reboot now
}
####
# Run apt-get, first checking if it's locked.
FIRST_CALL="true"
run_aptGet()
{
local NUM_FAILS=0
while sudo fuser --silent /var/lib/dpkg/lock* 2>/dev/null ;
do
(( NUM_FAILS++ ))
if [[ ${NUM_FAILS} -eq 5 ]]; then
echo "apt-get is locked. Tried 5 times." >&2
echo "Wait a while and try the Allsky installation again." >&2
return 1
fi
sleep 3
done
# TODO: the above check doesn't seem to work very well, if at all.
# When we fail due to apt being locked, it's almost always on the
# first call to apt-get.
# If the first call fails, try it again.
local OUTPUT="$( sudo apt-get --assume-yes install "${@}" 2>&1 )"
local RET=$?
if [[ $? -ne 0 && ${FIRST_CALL} == "true" ]]; then
display_msg --logonly info "First call to apt-get failed; trying again."
sleep 3
sudo apt-get --assume-yes install "${@}"
RET=$?
elif [[ -n ${OUTPUT} ]]; then
echo -e "${OUTPUT}"
fi
FIRST_CALL="false"
return "${RET}"
}
####
# Check if the return code -ne 0.
# If not, display a message with partial contents from the log file.
check_success()
{
local RET=${1}
local MESSAGE="${2}"
local LOG="${3}"
local D=${4}
local MSG
if [[ ${RET} -ne 0 ]]; then
display_msg --log error "${MESSAGE}"
MSG="The full log file is in ${LOG}\nThe end of the file is:"
display_msg --log info "${MSG}"
indent "$( tail "${LOG}" )"
return 1
fi
[[ ${D} -gt 1 ]] && cat "${LOG}"
return 0
}
####
# Get checksums of local Website files.
# The file is used when installing a remote Website, not by this script,
# but we create it now before the user has changed anything.
get_checksums()
{
declare -n v="${FUNCNAME[0]}"
[[ -s ${ALLSKY_WEBSITE_CHECKSUM_FILE} ]] && return
get_website_checksums > "${ALLSKY_WEBSITE_CHECKSUM_FILE}"