-
Notifications
You must be signed in to change notification settings - Fork 180
/
install.sh
executable file
·3010 lines (2570 loc) · 107 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 # referenced but not assigned
[[ -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}"
# This file defines functions plus sets many variables.
#shellcheck source-path=scripts
source "${ALLSKY_SCRIPTS}/installUpgradeFunctions.sh" || exit "${EXIT_ERROR_STOP}"
if [[ ${EUID} -eq 0 ]]; then
display_msg error "This script must NOT be run as root, do NOT use 'sudo'."
exit 1
fi
# This script assumes the user already did the "git clone" into ${ALLSKY_HOME}.
# Some versions of Linux default to 750 so web server can't read it
chmod 755 "${ALLSKY_HOME}" || exit "${EXIT_ERROR_STOP}"
cd "${ALLSKY_HOME}" || exit "${EXIT_ERROR_STOP}"
# PRIOR_ALL_DIR is passed to us and is the location of an optional prior copy of Allsky.
PRIOR_CONFIG_DIR="${PRIOR_ALLSKY_DIR}/config"
PRIOR_CONFIG_FILE="${PRIOR_CONFIG_DIR}/config.sh"
PRIOR_FTP_FILE="${PRIOR_CONFIG_DIR}/ftp-settings.sh" # may change depending on old version
TITLE="Allsky Installer - ${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
RESTORED_PRIOR_CONFIG_SH="false" # prior config.sh restored?
RESTORED_PRIOR_FTP_SH="false" # prior ftp-settings.sh restored?
PRIOR_ALLSKY="" # Set to "new" or "old" if they have a prior version
PRIOR_ALLSKY_VERSION="" # The version number of the prior version, if known
SUGGESTED_NEW_HOST_NAME="allsky" # Suggested new host name
NEW_HOST_NAME="" # User-specified host name
BRANCH="${GITHUB_MAIN_BRANCH}" # default branch
# Repo files
REPO_SUDOERS_FILE="${ALLSKY_REPO}/sudoers.repo"
REPO_WEBUI_DEFINES_FILE="${ALLSKY_REPO}/allskyDefines.inc.repo"
REPO_LIGHTTPD_FILE="${ALLSKY_REPO}/lighttpd.conf.repo"
REPO_AVI_FILE="${ALLSKY_REPO}/avahi-daemon.conf.repo"
# The POST_INSTALLATION_ACTIONS contains information the user needs to act upon after the reboot.
rm -f "${POST_INSTALLATION_ACTIONS}" # Shouldn't be there, but just in case.
rm -f "${ALLSKY_MESSAGES}" # Start out with no messages.
# display_msg() will send "log" entries to this file.
# DISPLAY_MSG_LOG is used in display_msg()
# shellcheck disable=SC2034
DISPLAY_MSG_LOG="${ALLSKY_INSTALLATION_LOGS}/install.sh.log"
# Is a reboot needed at end of installation?
REBOOT_NEEDED="true"
# Does Allsky need to be configured at end of installation?
CONFIGURATION_NEEDED="true"
# Holds status of installation if we need to exit and get back in.
STATUS_FILE="${ALLSKY_INSTALLATION_LOGS}/status.txt"
STATUS_FILE_TEMP="${ALLSKY_TMP}/temp_status.txt" # holds intermediate status
STATUS_LOCALE_REBOOT="Rebooting to change locale" # status of rebooting due to locale change
STATUS_FINISH_REBOOT="Rebooting to finish installation"
STATUS_NO_FINISH_REBOOT="Did not reboot to finish installation"
STATUS_NO_REBOOT="User elected not to reboot"
STATUS_NO_LOCALE="Desired locale not found" # exiting due to desired locale not installed
STATUS_NO_CAMERA="No camera found" # status of exiting due to no camera found
STATUS_OK="OK" # Installation was completed.
STATUS_NOT_CONTINUE="User elected not to continue" # Exiting, but not an error
STATUS_CLEAR="Clear" # Clear the file
STATUS_ERROR="Error encountered"
STATUS_INT="Got interrupt"
STATUS_VARIABLES=() # Holds all the variables and values to save
LONG_BITS=$( getconf LONG_BIT ) # Size of a long, 32 or 64
# Check if any extra modules are installed
if [[ -n "$( find /opt/allsky/modules -type f -name "*.py" -print -quit 2> /dev/null )" ]]; then
EXTRA_MODULES_INSTALLED="true"
else
EXTRA_MODULES_INSTALLED="false"
fi
# TODO: check the CURRENT Allsky, or the PRIOR one?
# Check if we have a venv already. If not then the install/update will create it
# but we need to warn the user to reinstall the extra modules if they have them.
if [[ -d "${ALLSKY_PYTHON_VENV}" ]]; then
INSTALLED_VENV="false"
else
INSTALLED_VENV="true"
fi
############################################## functions
####
#
do_initial_heading()
{
if [[ ${UPDATE} == "true" ]]; then
display_header "Updating Allsky"
return
fi
if [[ ${do_initial_heading} == "true" ]]; then
display_header "Welcome back to the ${TITLE}!"
else
MSG="Welcome to the ${TITLE}!\n"
if [[ -n ${PRIOR_ALLSKY} ]]; then
MSG="${MSG}\nYou will be asked if you want to use the images and darks (if any) from"
MSG="${MSG} your prior version of Allsky."
if [[ ${PRIOR_ALLSKY} == "newStyle" ]]; then
MSG="${MSG}\nIf so, its settings will be used as well."
else
MSG="${MSG}\nIf so, we will attempt to use its settings as well, but may not be"
MSG="${MSG}\nable to use ALL prior settings depending on how old your prior Allsky is."
MSG="${MSG}\nIn that case, you'll be prompted for required information such as"
MSG="${MSG}\nthe camera's latitude, logitude, and locale."
fi
else
MSG="${MSG}\nYou will be prompted for required information such as the type"
MSG="${MSG}\nof camera you have and the camera's latitude, logitude, and locale."
fi
MSG="${MSG}\n\nNOTE: your camera must be connected to the Pi before continuing."
MSG="${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 ${TITLE}"
fi
[[ ${do_initial_heading} != "true" ]] && STATUS_VARIABLES+=("do_initial_heading='true'\n")
}
####
usage_and_exit()
{
RET=${1}
if [[ ${RET} -eq 0 ]]; then
C="${YELLOW}"
else
C="${RED}"
fi
# Don't show --testing option since users shouldn't use it.
echo
echo -e "${C}Usage: ${ME} [--help] [--debug [...]] [--update] [--function function]${NC}"
echo
echo "'--help' displays this message and exits."
echo
echo "'--debug' displays debugging information. Can be called multiple times to increase level."
echo
echo "'--update' should only be used when instructed to by the Allsky Website."
echo
echo "'--function' executes the specified function and quits."
echo
exit_installation "${RET}"
}
####
# Stop Allsky. If it's not running, nothing happens.
stop_allsky()
{
sudo systemctl stop allsky 2> /dev/null
}
####
# Get the branch of the release we are installing;
get_this_branch()
{
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+=("get_this_branch='true'\n")
STATUS_VARIABLES+=("BRANCH='${BRANCH}'\n")
}
####
##### Execute any specified function, then exit.
do_function()
{
local FUNCTION="${1}"
shift
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
display_msg --log error "Unknown CAMERA_TYPE: '${CAMERA_TYPE}'"
exit_installation 1 "${STATUS_ERROR}" "unknown CAMERA_TYPE: '${CAMERA_TYPE}'"
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
display_msg --log error "Unknown CAMERA: '${CAMERA}'"
exit_installation 1 "${STATUS_CLEAR}" "unknown CAMERA: '${CAMERA}'"
fi
}
#######
CONNECTED_CAMERAS=""
get_connected_cameras()
{
local CC
# If we can't determine the camera to use for RPi cameras it either means there is
# no RPi camera, or something's wrong.
if determineCommandToUse "false" "" > /dev/null 2>&1 ; then
display_msg --log progress "RPi camera found."
CC="RPi"
fi
if lsusb -d "03c3:" > /dev/null ; then
display_msg --log progress "ZWO camera found."
[[ -n ${CC} ]] && CC="${CC} "
CC="${CC}ZWO"
fi
if [[ -z ${CC} ]]; then
MSG="No connected cameras were detected. The installation will exit."
whiptail --title "${TITLE}" --msgbox "${MSG}" 12 "${WT_WIDTH}" 3>&1 1>&2 2>&3
MSG="No connected cameras were detected."
MSG="${MSG}\nMake sure a camera is plugged in and working prior to restarting"
MSG="${MSG} the installation."
display_msg --log error "${MSG}"
exit_installation 1 "${STATUS_NO_CAMERA}" ""
fi
if [[ -n ${CONNECTED_CAMERAS} ]]; then
# Set from a prior installation.
if [[ ${CONNECTED_CAMERAS} != "${CC}" ]]; then
MSG="Connected cameras were '${CONNECTED_CAMERAS}' during last installation"
MSG="${MSG} but are '${CC}' now."
display_msg --log info "${MSG}"
STATUS_VARIABLES+=("CONNECTED_CAMERAS='${CC}'\n")
fi
# Else the last one and this one are the same so don't save.
CONNECTED_CAMERAS="${CC}"
return
fi
[[ ${get_connected_cameras} != "true" ]] && STATUS_VARIABLES+=("get_connected_cameras='true'\n")
# Either not set before or is different this time
CONNECTED_CAMERAS="${CC}"
}
#
# 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()
{
if [[ -n ${PRIOR_ALLSKY} ]]; then
case "${PRIOR_ALLSKY_VERSION}" in
# New versions go here...
v2023.05.01*)
# New style Allsky using ${CAMERA_TYPE}.
CAMERA_TYPE="${PRIOR_CAMERA_TYPE}"
# Don't bother with a message since this is a "similar" release.
if [[ -n ${CAMERA_TYPE} ]]; then
MSG="Using Camera Type '${CAMERA_TYPE}' from prior Allsky."
STATUS_VARIABLES+=("select_camera_type='true'\n")
STATUS_VARIABLES+=("CAMERA_TYPE='${CAMERA_TYPE}'\n")
display_msg --logonly info "${MSG}"
return
else
MSG="Camera Type not in prior new-style settings file."
display_msg --log error "${MSG}"
fi
;;
"v2022.03.01" | "old")
local CAMERA="$( get_variable "CAMERA" "${PRIOR_CONFIG_FILE}" )"
if [[ -n ${CAMERA} ]]; then
CAMERA_TYPE="$( CAMERA_to_CAMERA_TYPE "${CAMERA}" )"
STATUS_VARIABLES+=("select_camera_type='true'\n")
STATUS_VARIABLES+=("CAMERA_TYPE='${CAMERA_TYPE}'\n")
if [[ ${CAMERA} != "${CAMERA_TYPE}" ]]; then
NEW=" (now called ${CAMERA_TYPE})"
else
NEW=""
fi
display_msg --log progress "Using prior ${CAMERA} camera${NEW}."
return
else
MSG="CAMERA not in prior old-style config.sh."
display_msg --log warning "${MSG}"
fi
;;
esac
fi
local CT=()
local NUM=0
if [[ ${CONNECTED_CAMERAS} == "RPi" ]]; then
CT+=("RPi" " Raspberry Pi (HQ, Module 3, and compatibles)")
((NUM++))
elif [[ ${CONNECTED_CAMERAS} == "ZWO" ]]; then
CT+=("ZWO" " ZWO ASI")
((NUM++))
elif [[ ${CONNECTED_CAMERAS} == "RPi ZWO" ]]; then
CT+=("RPi" " Raspberry Pi (HQ, Module 3, and compatibles)")
CT+=("ZWO" " ZWO ASI")
((NUM+=2))
else # shouldn't happen since we already checked
MSG="INTERNAL ERROR:"
if [[ -z ${CONNECTED_CAMERAS} ]]; then
MSG="${MSG} CONNECTED_CAMERAS is empty."
else
MSG="${MSG} CONNECTED_CAMERAS (${CONNECTED_CAMERAS}) is invalid."
fi
display_msg --log error "${MSG}"
exit_installation 2 "${STATUS_NO_CAMERA}" "${MSG}"
fi
local S=" is"
[[ ${NUM} -gt 1 ]] && S="s are"
MSG="\nThe following camera type${S} connected to the Pi.\n"
MSG="${MSG}Pick the one you want."
MSG="${MSG}\nIf it's not in the list, select <Cancel> and determine why."
CAMERA_TYPE=$(whiptail --title "${TITLE}" --menu "${MSG}" 15 "${WT_WIDTH}" "${NUM}" \
"${CT[@]}" 3>&1 1>&2 2>&3)
if [[ $? -ne 0 ]]; then
MSG="Camera selection required."
MSG="${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
display_msg --log progress "Using ${CAMERA_TYPE} camera."
STATUS_VARIABLES+=("select_camera_type='true'\n")
STATUS_VARIABLES+=("CAMERA_TYPE='${CAMERA_TYPE}'\n")
}
####
# If the raspistill command exists on post-Buster releases,
# rename it so it's not used.
check_for_raspistill()
{
STATUS_VARIABLES+=("check_for_raspistill='true'\n")
if W="$( which raspistill )" && [[ ${PI_OS} != "buster" ]]; then
display_msg --longonly info "Renaming 'raspistill' on ${PI_OS}."
sudo mv "${W}" "${W}-OLD"
fi
}
####
# Create the file that defines the WebUI variables.
create_webui_defines()
{
display_msg --log progress "Modifying locations for WebUI."
FILE="${ALLSKY_WEBUI}/includes/allskyDefines.inc"
sed -e "s;XX_HOME_XX;${HOME};" \
-e "s;XX_ALLSKY_HOME_XX;${ALLSKY_HOME};" \
-e "s;XX_ALLSKY_CONFIG_XX;${ALLSKY_CONFIG};" \
-e "s;XX_ALLSKY_SCRIPTS_XX;${ALLSKY_SCRIPTS};" \
-e "s;XX_ALLSKY_TMP_XX;${ALLSKY_TMP};" \
-e "s;XX_ALLSKY_IMAGES_XX;${ALLSKY_IMAGES};" \
-e "s;XX_ALLSKY_MESSAGES_XX;${ALLSKY_MESSAGES};" \
-e "s;XX_ALLSKY_WEBUI_XX;${ALLSKY_WEBUI};" \
-e "s;XX_ALLSKY_WEBSITE_XX;${ALLSKY_WEBSITE};" \
-e "s;XX_ALLSKY_WEBSITE_LOCAL_CONFIG_NAME_XX;${ALLSKY_WEBSITE_CONFIGURATION_NAME};" \
-e "s;XX_ALLSKY_WEBSITE_REMOTE_CONFIG_NAME_XX;${ALLSKY_REMOTE_WEBSITE_CONFIGURATION_NAME};" \
-e "s;XX_ALLSKY_WEBSITE_LOCAL_CONFIG_XX;${ALLSKY_WEBSITE_CONFIGURATION_FILE};" \
-e "s;XX_ALLSKY_WEBSITE_REMOTE_CONFIG_XX;${ALLSKY_REMOTE_WEBSITE_CONFIGURATION_FILE};" \
-e "s;XX_ALLSKY_OWNER_XX;${ALLSKY_OWNER};" \
-e "s;XX_ALLSKY_GROUP_XX;${ALLSKY_GROUP};" \
-e "s;XX_WEBSERVER_GROUP_XX;${WEBSERVER_GROUP};" \
-e "s;XX_ALLSKY_REPO_XX;${ALLSKY_REPO};" \
-e "s;XX_ALLSKY_VERSION_XX;${ALLSKY_VERSION};" \
-e "s;XX_RASPI_CONFIG_XX;${ALLSKY_CONFIG};" \
-e "s;XX_ALLSKY_OVERLAY_XX;${ALLSKY_OVERLAY};" \
-e "s;XX_ALLSKY_MODULES_XX;${ALLSKY_MODULES};" \
"${REPO_WEBUI_DEFINES_FILE}" > "${FILE}"
chmod 644 "${FILE}"
STATUS_VARIABLES+=("create_webui_defines='true'\n")
}
####
# Recreate the options file.
# This can be used after installation if the options file gets hosed.
recreate_options_file()
{
CAMERA_TYPE="$( get_variable "CAMERA_TYPE" "${ALLSKY_CONFIG}/config.sh" )"
save_camera_capabilities "true"
set_permissions
}
####
# 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.
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
# 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=""
display_msg --log progress "Setting up WebUI options${MSG} for ${CAMERA_TYPE} cameras."
fi
# Restore the prior settings file or camera-specific settings file(s) so
# the appropriate one can be used by makeChanges.sh.
[[ ${PRIOR_ALLSKY} != "" ]] && restore_prior_settings_file
display_msg --log progress "Making new settings file '${SETTINGS_FILE}'."
MSG="Executing makeChanges.sh${FORCE}${OPTIONSONLY} --cameraTypeOnly"
MSG="${MSG} ${DEBUG_ARG} 'cameraType' 'Camera Type' '${PRIOR_CAMERA_TYPE}' '${CAMERA_TYPE}'"
display_msg "${LOG_TYPE}" info "${MSG}"
#shellcheck disable=SC2086
MSG="$( "${ALLSKY_SCRIPTS}/makeChanges.sh" ${FORCE} ${OPTIONSONLY} --cameraTypeOnly \
${DEBUG_ARG} "cameraType" "Camera Type" "${PRIOR_CAMERA_TYPE}" "${CAMERA_TYPE}" 2>&1 )"
RET=$?
[[ -n ${MSG} ]] && display_msg "${LOG_TYPE}" info "${MSG}"
if [[ ${RET} -ne 0 ]]; then
if [[ ${RET} -eq ${EXIT_NO_CAMERA} ]]; then
MSG="No camera was found; one must be connected and working for the installation to succeed.\n"
MSG="${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."
exit_with_image 1 "${STATUS_ERROR}" "No camera detected"
elif [[ ${OPTIONSFILEONLY} == "false" ]]; then
display_msg --log error "Unable to save camera capabilities."
fi
return 1
fi
#shellcheck disable=SC2012
MSG="$( /bin/ls -l "${ALLSKY_CONFIG}/settings"*.json 2>/dev/null | sed 's/^/ /' )"
display_msg "${LOG_TYPE}" info "Settings files:\n${MSG}"
CAMERA_MODEL="$( settings ".cameraModel" "${SETTINGS_FILE}" )"
if [[ -z ${CAMERA_MODEL} ]]; then
display_msg --log warning "cameraModel not found in settings file."
fi
STATUS_VARIABLES+=("save_camera_capabilities='true'\n")
return 0
}
####
# Update the sudoers file so the web server can execute certain commands with sudo.
do_sudoers()
{
display_msg --log progress "Creating/updating sudoers file."
sed -e "s;XX_ALLSKY_SCRIPTS_XX;${ALLSKY_SCRIPTS};" "${REPO_SUDOERS_FILE}" > /tmp/x
sudo install -m 0644 /tmp/x "${FINAL_SUDOERS_FILE}" && rm -f /tmp/x
}
####
# Ask the user if they want to reboot
WILL_REBOOT="false"
ask_reboot()
{
local TYPE="${1}"
if [[ ${TYPE} == "locale" ]]; then
local MSG="A reboot is needed for the locale change to take effect."
MSG="${MSG}\nYou must reboot before continuing the installation."
MSG="${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="${MSG} before anything will work."
MSG="${MSG}\nTo restart the installation, do the following:\n"
MSG="${MSG}\n cd ~/allsky"
MSG="${MSG}\n ./install.sh"
MSG="${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"
return 1
fi
fi
local AT=" http://${NEW_HOST_NAME}.local\n"
AT="${AT}or\n"
AT="${AT} http://$(hostname -I | sed -e 's/ .*$//')"
if [[ ${REBOOT_NEEDED} == "false" ]]; then
MSG="\nAfter reboot you can connect to the WebUI at:\n${AT}"
display_msg -log progress "${MSG}"
return 0
fi
local MSG="*** Allsky installation is almost done. ***"
MSG="${MSG}\n\nWhen done, you must reboot the Raspberry Pi to finish the installation."
MSG="${MSG}\n\nAfter reboot you can connect to the WebUI at:\n"
MSG="${MSG}${AT}"
MSG="${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
display_msg --logonly info "User elected not to reboot; displayed warning message."
display_msg notice "You need to reboot the Pi before Allsky will work."
MSG="If you have not already rebooted your Pi, please do so now.\n"
MSG="${MSG}You can then connect to the WebUI at:\n"
MSG="${MSG}${AT}"
"${ALLSKY_SCRIPTS}/addMessage.sh" "info" "${MSG}"
fi
}
do_reboot()
{
exit_installation -1 "${1}" "${2}" # -1 means just log ending statement but don't exit.
sudo reboot now
}
####
# Check for size of RAM+swap during installation (Issue # 969).
# recheck_swap is used to check swap after the installation,
# and is referenced in the Allsky Documentation.
recheck_swap()
{
check_swap "prompt"
}
check_swap()
{
STATUS_VARIABLES+=("check_swap='true'\n")
local PROMPT="false"
[[ ${1} == "prompt" ]] && PROMPT="true"
# This can return "total_mem is unknown" if the OS is REALLY old.
local RAM_SIZE="$( vcgencmd get_config total_mem )"
if echo "${RAM_SIZE}" | grep --silent "unknown" ; then
# Note: This doesn't produce exact results. On a 4 GB Pi, it returns 3.74805.
RAM_SIZE=$(free --mebi | awk '{if ($1 == "Mem:") {print $2; exit 0} }') # in MB
else
RAM_SIZE="${RAM_SIZE//total_mem=/}"
fi
local DESIRED_COMBINATION=$((1024 * 5)) # desired minimum memory + swap
local SUGGESTED_SWAP_SIZE=0
for i in 512 1024 2048 4096 # 8192 and above don't need any swap
do
if [[ ${RAM_SIZE} -le ${i} ]]; then
SUGGESTED_SWAP_SIZE=$((DESIRED_COMBINATION - i))
break
fi
done
display_msg --logonly info "RAM_SIZE=${RAM_SIZE}, SUGGESTED_SWAP_SIZE=${SUGGESTED_SWAP_SIZE}."
# Not sure why, but displayed swap is often 1 MB less than what's in /etc/dphys-swapfile
local CURRENT_SWAP=$(free --mebi | awk '{if ($1 == "Swap:") {print $2 + 1; exit 0} }') # in MB
CURRENT_SWAP=${CURRENT_SWAP:-0}
if [[ ${CURRENT_SWAP} -lt ${SUGGESTED_SWAP_SIZE} || ${PROMPT} == "true" ]]; then
local SWAP_CONFIG_FILE="/etc/dphys-swapfile"
[[ -z ${FUNCTION} ]] && sleep 2 # give user time to read prior messages
local AMT M
if [[ ${CURRENT_SWAP} -eq 1 ]]; then
CURRENT_SWAP=0
AMT="no"
M="added"
else
AMT="${CURRENT_SWAP} MB of"
M="increased"
fi
MSG="\nYour Pi currently has ${AMT} swap space."
MSG="${MSG}\nBased on your memory size of ${RAM_SIZE} MB,"
if [[ ${CURRENT_SWAP} -ge ${SUGGESTED_SWAP_SIZE} ]]; then
SUGGESTED_SWAP_SIZE=${CURRENT_SWAP}
MSG="${MSG} there is no need to change anything, but you can if you would like."
else
MSG="${MSG} we suggest ${SUGGESTED_SWAP_SIZE} MB of swap"
MSG="${MSG} to decrease the chance of timelapse and other failures."
MSG="${MSG}\n\nDo you want swap space ${M}?"
MSG="${MSG}\n\nYou may change the amount of swap by changing the number below."
fi
local SWAP_SIZE=$(whiptail --title "${TITLE}" --inputbox "${MSG}" 18 "${WT_WIDTH}" \
"${SUGGESTED_SWAP_SIZE}" 3>&1 1>&2 2>&3)
# If the suggested swap was 0 and the user added a number but didn't first delete the 0,
# do it now so we don't have numbers like "0256".
[[ ${SWAP_SIZE:0:1} == "0" ]] && SWAP_SIZE="${SWAP_SIZE:1}"
if [[ -z ${SWAP_SIZE} || ${SWAP_SIZE} == "0" ]]; then
if [[ ${CURRENT_SWAP} -eq 0 && ${SUGGESTED_SWAP_SIZE} -gt 0 ]]; then
display_msg --log warning "With no swap space you run the risk of programs failing."
else
display_msg --log info "Swap will remain at ${CURRENT_SWAP}."
fi
else
display_msg --log progress "Setting swap space to ${SWAP_SIZE} MB."
sudo dphys-swapfile swapoff # Stops the swap file
sudo sed -i "/CONF_SWAPSIZE/ c CONF_SWAPSIZE=${SWAP_SIZE}" "${SWAP_CONFIG_FILE}"
local CURRENT_MAX="$(get_variable "CONF_MAXSWAP" "${SWAP_CONFIG_FILE}")"
# TODO: Can we determine the default max rather than hard-code it.
CURRENT_MAX="${CURRENT_MAX:-2048}"
if [[ ${CURRENT_MAX} -lt ${SWAP_SIZE} ]]; then
if [[ ${DEBUG} -gt 0 ]]; then
display_msg --log debug "Increasing max swap size to ${SWAP_SIZE} MB."
fi
sudo sed -i "/CONF_MAXSWAP/ c CONF_MAXSWAP=${SWAP_SIZE}" "${SWAP_CONFIG_FILE}"
fi
sudo dphys-swapfile setup > /dev/null # Sets up new swap file
sudo dphys-swapfile swapon # Turns on new swap file
fi
else
display_msg --log progress "Size of current swap (${CURRENT_SWAP} MB) is sufficient; no change needed."
fi
}
####
# Check if ${ALLSKY_TMP} exists, and if it does,
# save any *.jpg files (which we probably created), then remove everything else,
# then mount it.
check_and_mount_tmp()
{
local TMP_DIR="/tmp/IMAGES"
if [[ -d "${ALLSKY_TMP}" ]]; then
local IMAGES="$(find "${ALLSKY_TMP}" -name '*.jpg')"
if [[ -n ${IMAGES} ]]; then
mkdir "${TMP_DIR}"
# Need to allow for files with spaces in their names.
# TODO: there has to be a better way.
echo "${IMAGES}" | \
while read -r image
do
mv "${image}" "${TMP_DIR}"
done
fi
rm -f "${ALLSKY_TMP}"/*
else
mkdir "${ALLSKY_TMP}"
fi
# Now mount and restore any images that were there before
sudo systemctl daemon-reload 2> /dev/null
sudo mount -a
if [[ -d ${TMP_DIR} ]]; then
mv "${TMP_DIR}"/* "${ALLSKY_TMP}"
rmdir "${TMP_DIR}"
fi
}
####
# Check if prior ${ALLSKY_TMP} was a memory filesystem.
# If not, offer to make it one.
check_tmp()
{
local INITIAL_FSTAB_STRING="tmpfs ${ALLSKY_TMP} tmpfs"
# Check if currently a memory filesystem.
if grep --quiet "^${INITIAL_FSTAB_STRING}" /etc/fstab; then
MSG="${ALLSKY_TMP} is currently a memory filesystem; no change needed."
display_msg --log progress "${MSG}"
# If there's a prior Allsky version and it's tmp directory is mounted,
# try to unmount it, but that often gives an error that it's busy,
# which isn't really a problem since it'll be unmounted at the reboot.
# We know from the grep above that /etc/fstab has ${ALLSKY_TMP}
# but the mount point is currently in the PRIOR Allsky.
local D="${PRIOR_ALLSKY_DIR}/tmp"
if [[ -d "${D}" ]] && mount | grep --silent "${D}" ; then
# The Samba daemon is one known cause of "target busy".
sudo umount -f "${D}" 2> /dev/null ||
(
sudo systemctl restart smbd 2> /dev/null
sudo umount -f "${D}" 2> /dev/null
)
fi
STATUS_VARIABLES+=("check_tmp='true'\n")
# If the new Allsky's ${ALLSKY_TMP} is already mounted, don't do anything.
# This would be the case during an upgrade.
if mount | grep --silent "${ALLSKY_TMP}" ; then
display_msg --logonly info "${ALLSKY_TMP} already mounted."
return 0
fi
check_and_mount_tmp # works on new ${ALLSKY_TMP}
return 0
fi
local SIZE=75 # MB - should be enough
MSG="Making ${ALLSKY_TMP} reside in memory can drastically decrease the amount of writes to the SD card, increasing its life."
MSG="${MSG}\n\nDo you want to make it reside in memory?"
MSG="${MSG}\n\nNote: anything in it will be deleted whenever the Pi is rebooted, but that's not an issue since the directory only contains temporary files."
if whiptail --title "${TITLE}" --yesno "${MSG}" 15 "${WT_WIDTH}" 3>&1 1>&2 2>&3; then
local STRING="${INITIAL_FSTAB_STRING} size=${SIZE}M,noatime,lazytime,nodev,nosuid,mode=775,uid=${ALLSKY_OWNER},gid=${WEBSERVER_GROUP}"
if ! echo "${STRING}" | sudo tee -a /etc/fstab > /dev/null ; then
display_msg --log error "Unable to update /etc/fstab"
return 1
fi
check_and_mount_tmp
display_msg --log progress "${ALLSKY_TMP} is now in memory."
else
display_msg --log info "${ALLSKY_TMP} will remain on disk."
mkdir -p "${ALLSKY_TMP}"
fi
STATUS_VARIABLES+=("check_tmp='true'\n")
}
####
check_success()
{
local RET=${1}
local MESSAGE="${2}"
local LOG="${3}"
local D=${4}
if [[ ${RET} -ne 0 ]]; then
display_msg --log error "${MESSAGE}"
MSG="The full log file is in ${LOG}"
MSG="${MSG}\nThe end of the file is:"
display_msg --log info "${MSG}"
indent "$( tail "${LOG}" )"
return 1
fi
[[ ${D} -gt 1 ]] && cat "${LOG}"
return 0
}
####
# Install the web server.
install_webserver_et_al()
{
sudo systemctl stop hostapd 2> /dev/null
sudo systemctl stop lighttpd 2> /dev/null
if [[ ${install_webserver_et_al} == "true" ]]; then
display_msg --log progress "Preparing the web server."
else
display_msg --log progress "Installing the web server."
TMP="${ALLSKY_INSTALLATION_LOGS}/lighttpd.install.log"
(
sudo apt-get update && \
sudo apt-get --assume-yes install lighttpd php-cgi php-gd hostapd dnsmasq avahi-daemon
) > "${TMP}" 2>&1
if ! check_success $? "lighttpd installation failed" "${TMP}" "${DEBUG}" ; then
exit_with_image 1 "${STATUS_ERROR}" "lighttpd installation failed"
fi
FINAL_LIGHTTPD_FILE="/etc/lighttpd/lighttpd.conf"
sed \
-e "s;XX_ALLSKY_WEBUI_XX;${ALLSKY_WEBUI};g" \
-e "s;XX_ALLSKY_HOME_XX;${ALLSKY_HOME};g" \
-e "s;XX_ALLSKY_IMAGES_XX;${ALLSKY_IMAGES};g" \
-e "s;XX_ALLSKY_CONFIG_XX;${ALLSKY_CONFIG};g" \
-e "s;XX_ALLSKY_WEBSITE_XX;${ALLSKY_WEBSITE};g" \
-e "s;XX_ALLSKY_OVERLAY_XX;${ALLSKY_OVERLAY};g" \
-e "s;XX_ALLSKY_DOCUMENTATION_XX;${ALLSKY_DOCUMENTATION};g" \
"${REPO_LIGHTTPD_FILE}" > /tmp/x
sudo install -m 0644 /tmp/x "${FINAL_LIGHTTPD_FILE}" && rm -f /tmp/x
fi
# Ignore output since it may already be enabled.
sudo lighty-enable-mod fastcgi-php > /dev/null 2>&1
# Remove any old log files.
# Start off with a 0-length log file the user can write to.
local D="/var/log/lighttpd"
sudo chmod 755 "${D}"
sudo rm -fr "${D}"/*
local LIGHTTPD_LOG="${D}/error.log"
sudo touch "${LIGHTTPD_LOG}"
sudo chmod 664 "${LIGHTTPD_LOG}"
sudo chown "${WEBSERVER_GROUP}:${ALLSKY_GROUP}" "${LIGHTTPD_LOG}"
sudo systemctl start lighttpd
# Starting it added an entry so truncate the file so it's 0-length
sleep 1; truncate -s 0 "${LIGHTTPD_LOG}"
STATUS_VARIABLES+=("install_webserver_et_al='true'\n")
}
####
# Prompt for a new hostname if needed,
# and update all the files that contain the hostname.
# The default hostname in Pi OS is "raspberrypi"; if it's still that,
# prompt to update. If it's anything else that means the user
# already changed it to something so don't overwrite their change.
prompt_for_hostname()
{
local CURRENT_HOSTNAME=$(tr -d " \t\n\r" < /etc/hostname)
if [[ ${CURRENT_HOSTNAME} != "raspberrypi" ]]; then
display_msg --logonly info "Using current hostname of '${CURRENT_HOSTNAME}'."
NEW_HOST_NAME="${CURRENT_HOSTNAME}"
STATUS_VARIABLES+=("prompt_for_hostname='true'\n")
STATUS_VARIABLES+=("NEW_HOST_NAME='${NEW_HOST_NAME}'\n")
return
fi
MSG="Please enter a hostname for your Pi."
MSG="${MSG}\n\nIf you have more than one Pi on your network they MUST all have unique names."
MSG="${MSG}\n\nThe current hostname is '${CURRENT_HOSTNAME}'; the suggested name is below:\n"
NEW_HOST_NAME=$(whiptail --title "${TITLE}" --inputbox "${MSG}" 15 "${WT_WIDTH}" \
"${SUGGESTED_NEW_HOST_NAME}" 3>&1 1>&2 2>&3)
if [[ $? -ne 0 ]]; then
MSG="You must specify a host name."
MSG="${MSG} Please re-run the installation and select one."
display_msg --log warning "${MSG}"
exit_installation 2 "No host name selected"
else
STATUS_VARIABLES+=("prompt_for_hostname='true'\n")
STATUS_VARIABLES+=("NEW_HOST_NAME='${NEW_HOST_NAME}'\n")
fi
if [[ ${CURRENT_HOSTNAME} != "${NEW_HOST_NAME}" ]]; then
echo "${NEW_HOST_NAME}" | sudo tee /etc/hostname > /dev/null
sudo sed -i "s/127.0.1.1.*${CURRENT_HOSTNAME}/127.0.1.1\t${NEW_HOST_NAME}/" /etc/hosts
# else, they didn't change the default name, but that's their problem...
fi
# Set up the avahi daemon if needed.
FINAL_AVI_FILE="/etc/avahi/avahi-daemon.conf"
[[ -f ${FINAL_AVI_FILE} ]] && grep -i --quiet "host-name=${NEW_HOST_NAME}" "${FINAL_AVI_FILE}"
if [[ $? -ne 0 ]]; then
# New NEW_HOST_NAME is not found in the file, or the file doesn't exist,
# so need to configure it.
display_msg --log progress "Configuring avahi-daemon."
sed "s/XX_HOST_NAME_XX/${NEW_HOST_NAME}/g" "${REPO_AVI_FILE}" > /tmp/x
sudo install -m 0644 /tmp/x "${FINAL_AVI_FILE}" && rm -f /tmp/x
fi
}
####
# Set permissions on various web-related items.
set_permissions()
{
display_msg --log progress "Setting permissions on web-related files."
# Make sure the currently running user has can write to the webserver root
# and can run sudo on anything.
G="$(id "${ALLSKY_OWNER}")"
if ! echo "${G}" | grep --silent "(sudo)"; then
display_msg --log progress "Adding ${ALLSKY_OWNER} to sudo group."
### TODO: Hmmm. We need to run "sudo" to add to the group,
### but we don't have "sudo" permissions yet... so this will likely fail:
sudo adduser --quiet "${ALLSKY_OWNER}" "sudo"
fi
if ! echo "${G}" | grep --silent "(${WEBSERVER_GROUP})"; then
display_msg --log progress "Adding ${ALLSKY_OWNER} to ${WEBSERVER_GROUP} group."
sudo adduser --quiet "${ALLSKY_OWNER}" "${WEBSERVER_GROUP}"
# TODO: We had a case where the login shell wasn't in the group after "adduser"
# until the user logged out and back in.
# And this was AFTER he ran install.sh and rebooted.
# Not sure what to do about this...
fi
# Remove any old entries; we now use /etc/sudoers.d/allsky instead of /etc/sudoers.
# TODO: Can remove this in the next release
sudo sed -i -e "/allsky/d" -e "/${WEBSERVER_GROUP}/d" /etc/sudoers
do_sudoers
# The web server needs to be able to create and update many of the files in ${ALLSKY_CONFIG}.
# Not all, but go ahead and chgrp all of them so we don't miss any new ones.
sudo find "${ALLSKY_CONFIG}/" -type f -exec chmod 664 '{}' \;
sudo find "${ALLSKY_CONFIG}/" -type d -exec chmod 775 '{}' \;
sudo chgrp -R "${WEBSERVER_GROUP}" "${ALLSKY_CONFIG}"
# The files should already be the correct permissions/owners, but just in case, set them.
# We don't know what permissions may have been on the old website, so use "sudo".
sudo find "${ALLSKY_WEBUI}/" -type f -exec chmod 644 '{}' \;
sudo find "${ALLSKY_WEBUI}/" -type d -exec chmod 755 '{}' \;
chmod 755 "${ALLSKY_WEBUI}/includes/createAllskyOptions.php"
if [[ -d "${ALLSKY_WEBSITE}" ]]; then
sudo find "${ALLSKY_WEBUI}/" -type d -name thumbnails \! -perm 775 -exec chmod 775 '{}' \;
sudo find "${ALLSKY_WEBUI}/" -type d -name thumbnails \! -group "${WEBSERVER_GROUP}" -exec chgrp "${WEBSERVER_GROUP}" '{}' \;
fi
chmod 775 "${ALLSKY_TMP}"
sudo chgrp "${WEBSERVER_GROUP}" "${ALLSKY_TMP}"
# This is actually an Allsky Website file, but in case we restored the old website,
# set its permissions.
chgrp -f "${WEBSERVER_GROUP}" "${ALLSKY_WEBSITE_CONFIGURATION_FILE}"
}
####
# Check if there's a WebUI in the old-style location,
# or if the directory exists but there doesn't appear to be a WebUI in it.
# The installation (sometimes?) creates the directory.
OLD_WEBUI_LOCATION_EXISTS_AT_START="false"
does_old_WebUI_location_exist()
{
[[ -d ${OLD_WEBUI_LOCATION} ]] && OLD_WEBUI_LOCATION_EXISTS_AT_START="true"
STATUS_VARIABLES+=("does_old_WebUI_location_exist='true'\n")
STATUS_VARIABLES+=("OLD_WEBUI_LOCATION_EXISTS_AT_START='${OLD_WEBUI_LOCATION_EXISTS_AT_START}'\n")
}
# If the old WebUI location is there:
# but it wasn't when the installation started,
# that means the installation created it so remove it.
#
# Let the user know if there's an old WebUI, or something unknown there.
check_old_WebUI_location()
{
STATUS_VARIABLES+=("check_old_WebUI_location='true'\n")
[[ ! -d ${OLD_WEBUI_LOCATION} ]] && return
if [[ ${OLD_WEBUI_LOCATION_EXISTS_AT_START} == "false" ]]; then
# Installation created the directory so get rid of it.
sudo rm -fr "${OLD_WEBUI_LOCATION}"
return