forked from YouROK/TorrServer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstallTorrServerLinux.sh
More file actions
executable file
·2061 lines (1802 loc) · 60.5 KB
/
installTorrServerLinux.sh
File metadata and controls
executable file
·2061 lines (1802 loc) · 60.5 KB
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
set -euo pipefail
#############################################
# GLOBAL VARIABLES
#############################################
# Installation settings
DEFAULT_USERNAME="torrserver"
DEFAULT_INSTALL_DIR="/opt/torrserver"
DEFAULT_SERVICE_NAME="torrserver"
DEFAULT_PORT="8090"
# Runtime variables
username="${DEFAULT_USERNAME}"
dirInstall="${DEFAULT_INSTALL_DIR}"
serviceName="${DEFAULT_SERVICE_NAME}"
scriptname=$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")
# Flags
SILENT_MODE=0
USE_ROOT_USER=0
ROOT_PROMPTED=0
# Command-line state
parsedCommand=""
specificVersion=""
downgradeRelease=""
changeUserName=""
# Service configuration
servicePort=""
isAuth=""
isRdb=""
isLog=""
isBbr=""
isAuthUser=""
isAuthPass=""
# Constants
readonly REPO_URL="https://github.com/YouROK/TorrServer"
readonly REPO_API_URL="https://api.github.com/repos/YouROK/TorrServer"
readonly VERSION_PREFIX="MatriX"
readonly BINARY_NAME_PREFIX="TorrServer-linux"
readonly MIN_GLIBC_VERSION="2.32"
readonly MIN_VERSION_REQUIRING_GLIBC=136
# Color support
declare -A colors=([black]=0 [red]=1 [green]=2 [yellow]=3 [blue]=4 [magenta]=5 [cyan]=6 [white]=7)
supports_color_output=0
if command -v tput >/dev/null 2>&1 && [[ -t 1 ]]; then
if [[ $(tput colors 2>/dev/null) -ge 8 ]]; then
supports_color_output=1
fi
fi
# Language
lang="en"
#############################################
# TRANSLATION SYSTEM
#############################################
# Message dictionary
declare -A MSG_EN=(
# General
[lang_choice]="Choose Language:"
[lang_english]="English"
[lang_russian]="Русский"
[your_lang]="Your language (Ваш язык): "
[have_fun]="Have Fun!"
# Script info
[script_title]="TorrServer install and configuration script for Linux"
# Checks
[need_root]="Script must run as root or user with sudo privileges. Example: sudo $scriptname"
[unsupported_arch]="Unsupported Arch. Can't continue."
[unsupported_os]="It looks like you are running this installer on a system other than Debian, Ubuntu, Fedora, CentOS, Amazon Linux, Oracle Linux or Arch Linux."
# User management
[user_exists]="User %s exists!"
[user_added]="User %s has been added to system!"
[user_add_failed]="Failed to add %s user!"
[user_removed]="User %s has been removed from system!"
[user_remove_failed]="Failed to remove %s user!"
[user_not_found]="%s - no such user!"
# Version
[downloading]="Downloading TorrServer"
[target_version]="Target version:"
[installed_version]="installed:"
[target_label]="target:"
[version_not_found]="ERROR: Version %s not found in releases"
[check_versions]="Please check available versions at: $REPO_URL/releases"
[already_installed]="You already have TorrServer %s installed"
[have_latest]="You have latest TorrServer %s"
[update_found]="TorrServer update found!"
[will_install]="Will install TorrServer version %s"
# Installation
[installing_packages]="Installing missing packages…"
[install_configure]="Install and configure TorrServer…"
[starting_service]="Starting TorrServer…"
[install_complete]="TorrServer %s installed to %s"
[access_web]="You can now open your browser at http://%s:%s to access TorrServer web GUI."
[use_auth]="Use user \"%s\" with password \"%s\" for authentication"
# Prompts
[want_update]="Want to update TorrServer? (Yes/No) "
[want_install]="Want to install or configure TorrServer? (Yes|No) Type Delete to uninstall. "
[want_reconfigure]="Do you want to reconfigure TorrServer settings? (Yes/No) "
[change_port]="Change TorrServer web-port? (Yes/No) "
[enter_port]="Enter port number: "
[enable_auth]="Enable server authorization? (Yes/No) "
[prompt_user]="User: "
[prompt_password]="Password: "
[change_auth_credentials]="Change authentication username and password? (Yes/No) "
[enable_rdb]="Start TorrServer in public read-only mode? (Yes/No) "
[enable_log]="Enable TorrServer log output to file? (Yes/No) "
[enable_bbr]="Enable BBR (recommended for better download speed)? (Yes/No) "
[confirm_delete]="Are you sure you want to delete TorrServer? (Yes/No) "
[prompt_run_as_root]="Run service as root user? (Yes/No) "
# Uninstall
[install_dir_label]="TorrServer install dir -"
[uninstall_warning]="This action will delete TorrServer including all it's torrents, settings and files on path above!"
[uninstalled]="TorrServer uninstalled!"
# Status
[found_in]="TorrServer found in"
[not_found]="TorrServer not found. It's not installed or have zero size."
[no_version_info]="No version information available. Can be server issue."
[config_updated]="Configuration updated successfully"
[store_auth]="Store %s:%s to %s"
[use_existing_auth]="Use existing auth from %s - %s"
[set_readonly]="Set database to read-only mode…"
[readonly_hint]="To change remove --rdb option from %s or rerun install script without parameters"
[log_location]="TorrServer log stored at %s"
[bbr_enabled]="BBR TCP congestion control enabled"
[bbr_already_configured]="BBR is already configured"
[bbr_configured_not_available]="BBR is configured but not available in this kernel"
[bbr_config_failed]="Warning: Failed to configure BBR"
[bbr_not_available]="BBR is not available in this kernel"
[bbr_requires_kernel]="BBR requires Linux kernel 4.9+ with tcp_bbr module"
[bbr_write_failed]="Failed to write to %s"
[bbr_current_values]="Current: qdisc=%s, congestion_control=%s"
[bbr_settings_will_apply]="BBR settings are in %s and will apply after reboot"
[bbr_settings_not_added]="BBR settings were not added to %s"
[bbr_activate_failed]="Warning: Could not activate BBR - module not available"
[bbr_no_optimization]="Service will start without BBR optimization"
[bbr_activate_failed_cc]="Warning: Could not activate BBR (currently: %s)"
[systemctl_missing]="systemctl is not available. Skipping service management commands."
[systemctl_failed]="Warning: systemctl %s failed"
[service_start_failed]="Warning: TorrServer service failed to start. Check systemctl status for details."
[user_change_success]="Service user changed to %s"
[user_change_permissions]="Updated ownership of %s to %s:%s"
[user_change_missing]="TorrServer installation not found in %s. Run install first."
[user_change_invalid]="Only %s or %s are allowed for --change-user"
# glibc
[glibc_error]="ERROR: TorrServer version %s requires glibc >= $MIN_GLIBC_VERSION"
[glibc_current]="Your system has glibc %s"
[glibc_upgrade]="Please install a version < $MIN_VERSION_REQUIRING_GLIBC or upgrade your system"
[glibc_detected]="Detected glibc version: %s"
[glibc_ok]="OK: glibc version meets requirements for TorrServer %s"
[glibc_no_requirement]="TorrServer version %s: no special glibc requirements"
[glibc_warning]="Warning: Could not detect glibc version"
[glibc_may_fail]="TorrServer version %s requires glibc >= $MIN_GLIBC_VERSION"
[glibc_install_may_fail]="Installation may fail if your system doesn't meet this requirement"
[update_cancelled]="Update cancelled due to glibc incompatibility"
[downgrade_cancelled]="Downgrade cancelled due to glibc incompatibility"
# OS version errors
[os_not_supported]="Your %s version is not supported."
[os_script_supports]="Script supports only %s %s"
# User mode
[running_as_root]="Service will run as root user"
[running_as_user]="Service will run as %s user"
# Error messages
[error_username_required]="Error: Username required for --change-user"
[error_version_required]="Error: Version number required for downgrade"
[error_version_example]="Example: %s -d 101"
[error_unknown_option]="Unknown option: %s"
[installing_specific_version]="Installing specific version: %s"
[service_reconfigured_user]="Service reconfigured for user: %s"
[install_first_required]="Please install TorrServer first using: %s --install"
)
declare -A MSG_RU=(
# General
[lang_choice]="Choose Language:"
[lang_english]="English"
[lang_russian]="Русский"
[your_lang]="Your language (Ваш язык): "
[have_fun]="Have Fun!"
# Script info
[script_title]="Скрипт установки, удаления и настройки TorrServer для Linux"
# Checks
[need_root]="Вам нужно запустить скрипт от root или пользователя с правами sudo. Пример: sudo $scriptname"
[unsupported_arch]="Не поддерживаемая архитектура. Продолжение невозможно."
[unsupported_os]="Похоже, что вы запускаете этот установщик в системе отличной от Debian, Ubuntu, Fedora, CentOS, Amazon Linux, Oracle Linux или Arch Linux."
# User management
[user_exists]="пользователь %s найден!"
[user_added]="пользователь %s добавлен!"
[user_add_failed]="не удалось добавить пользователя %s!"
[user_removed]="Пользователь %s удален!"
[user_remove_failed]="не удалось удалить пользователя %s!"
[user_not_found]="пользователь %s не найден!"
# Version
[downloading]="Загружаем TorrServer"
[target_version]="Устанавливаемая версия:"
[installed_version]="установлен:"
[target_label]="устанавливаемая:"
[version_not_found]="ОШИБКА: Версия %s не найдена в релизах"
[check_versions]="Проверьте доступные версии по адресу: $REPO_URL/releases"
[already_installed]="TorrServer %s уже установлен"
[have_latest]="Установлен TorrServer последней версии %s"
[update_found]="Доступно обновление сервера"
[will_install]="Будет установлена версия TorrServer %s"
# Installation
[installing_packages]="Устанавливаем недостающие пакеты…"
[install_configure]="Устанавливаем и настраиваем TorrServer…"
[starting_service]="Запускаем службу TorrServer…"
[install_complete]="TorrServer %s установлен в директории %s"
[access_web]="Теперь вы можете открыть браузер по адресу http://%s:%s для доступа к вебу TorrServer"
[use_auth]="Для авторизации используйте пользователя «%s» с паролем «%s»"
# Prompts
[want_update]="Хотите обновить TorrServer? (Yes/No) "
[want_install]="Хотите установить, обновить или настроить TorrServer? (Yes|No) Для удаления введите «Delete» "
[want_reconfigure]="Хотите перенастроить параметры TorrServer? (Yes/No) "
[change_port]="Хотите изменить порт для TorrServer? (Yes/No) "
[enter_port]="Введите номер порта: "
[enable_auth]="Включить авторизацию на сервере? (Yes/No) "
[prompt_user]="Пользователь: "
[prompt_password]="Пароль: "
[change_auth_credentials]="Изменить имя пользователя и пароль для авторизации? (Yes/No) "
[enable_rdb]="Запускать TorrServer в публичном режиме без возможности изменения настроек через веб сервера? (Yes/No) "
[enable_log]="Включить запись журнала работы TorrServer в файл? (Yes/No) "
[enable_bbr]="Включить BBR (рекомендуется для лучшей скорости загрузки)? (Yes/No) "
[confirm_delete]="Вы уверены что хотите удалить программу? (Yes/No) "
[prompt_run_as_root]="Запускать службу от пользователя root? (Yes/No) "
# Uninstall
[install_dir_label]="Директория c TorrServer -"
[uninstall_warning]="Это действие удалит все данные TorrServer включая базу данных торрентов и настройки по указанному выше пути!"
[uninstalled]="TorrServer удален из системы!"
# Status
[found_in]="TorrServer найден в директории"
[not_found]="TorrServer не найден, возможно он не установлен или размер бинарника равен 0."
[no_version_info]="Информация о версии недоступна. Возможно сервер не доступен."
[config_updated]="Конфигурация успешно обновлена"
[store_auth]="Сохраняем %s:%s в %s"
[use_existing_auth]="Используйте реквизиты из %s для авторизации - %s"
[set_readonly]="База данных устанавливается в режим «только для чтения»…"
[readonly_hint]="Для изменения отредактируйте %s, убрав опцию --rdb или запустите интерактивную установку без параметров повторно"
[log_location]="лог TorrServer располагается по пути %s"
[bbr_enabled]="Включено управление перегрузкой TCP BBR"
[bbr_already_configured]="BBR уже настроен"
[bbr_configured_not_available]="BBR настроен, но недоступен в этом ядре"
[bbr_config_failed]="Предупреждение: Не удалось настроить BBR"
[bbr_not_available]="BBR недоступен в этом ядре"
[bbr_requires_kernel]="BBR требует Linux kernel 4.9+ с модулем tcp_bbr"
[bbr_write_failed]="Не удалось записать в %s"
[bbr_current_values]="Текущие значения: qdisc=%s, congestion_control=%s"
[bbr_settings_will_apply]="Настройки BBR находятся в %s и вступят в силу после перезагрузки"
[bbr_settings_not_added]="Настройки BBR не были добавлены в %s"
[bbr_activate_failed]="Предупреждение: Не удалось активировать BBR - модуль недоступен"
[bbr_no_optimization]="Служба запустится без оптимизации BBR"
[bbr_activate_failed_cc]="Предупреждение: Не удалось активировать BBR (текущее: %s)"
[systemctl_missing]="systemctl недоступен. Пропускаем команды управления службой."
[systemctl_failed]="Предупреждение: команда systemctl %s завершилась ошибкой"
[service_start_failed]="Предупреждение: служба TorrServer не запустилась. Проверьте systemctl status для деталей."
[user_change_success]="Сервис TorrServer теперь запускается от пользователя %s"
[user_change_permissions]="Обновлены права на %s: %s:%s"
[user_change_missing]="Установка TorrServer не найдена в %s. Сначала выполните установку."
[user_change_invalid]="Параметр --change-user принимает только %s или %s"
# glibc
[glibc_error]="ОШИБКА: TorrServer версии %s требует glibc >= $MIN_GLIBC_VERSION"
[glibc_current]="В вашей системе установлена glibc %s"
[glibc_upgrade]="Пожалуйста, установите версию < $MIN_VERSION_REQUIRING_GLIBC или обновите систему"
[glibc_detected]="Обнаружена версия glibc: %s"
[glibc_ok]="OK: версия glibc соответствует требованиям для TorrServer %s"
[glibc_no_requirement]="TorrServer версии %s: нет особых требований к glibc"
[glibc_warning]="Предупреждение: Не удалось определить версию glibc"
[glibc_may_fail]="TorrServer версии %s требует glibc >= $MIN_GLIBC_VERSION"
[glibc_install_may_fail]="Установка может завершиться неудачей, если система не соответствует требованиям"
[update_cancelled]="Обновление отменено из-за несовместимости glibc"
[downgrade_cancelled]="Понижение версии отменено из-за несовместимости glibc"
# OS version errors
[os_not_supported]="Ваша версия %s не поддерживается."
[os_script_supports]="Скрипт поддерживает только %s %s"
# User mode
[running_as_root]="Служба будет запущена от пользователя root"
[running_as_user]="Служба будет запущена от пользователя %s"
# Error messages
[error_username_required]="Ошибка: Требуется имя пользователя для --change-user"
[error_version_required]="Ошибка: Требуется номер версии для понижения версии"
[error_version_example]="Пример: %s -d 101"
[error_unknown_option]="Неизвестная опция: %s"
[installing_specific_version]="Установка конкретной версии: %s"
[service_reconfigured_user]="Служба перенастроена для пользователя: %s"
[install_first_required]="Пожалуйста, сначала установите TorrServer используя: %s --install"
)
# Translation function
msg() {
local key="$1"
shift
local message=""
if [[ $lang == "ru" ]]; then
message="${MSG_RU[$key]:-$key}"
else
message="${MSG_EN[$key]:-$key}"
fi
# Apply printf formatting if additional arguments provided
if [[ $# -gt 0 ]]; then
# shellcheck disable=SC2059
printf "$message" "$@"
else
printf '%s\n' "$message"
fi
}
#############################################
# UTILITY FUNCTIONS
#############################################
colorize() {
if [[ $supports_color_output -eq 1 ]]; then
printf "%s%s%s" "$(tput setaf "${colors[$1]:-7}")" "$2" "$(tput op)"
else
printf "%s" "$2"
fi
}
isRoot() {
[[ $EUID -eq 0 ]]
}
getBinaryName() {
echo "${BINARY_NAME_PREFIX}-${architecture}"
}
getVersionTag() {
local version="$1"
echo "${VERSION_PREFIX}.${version}"
}
buildDownloadUrl() {
local target_version="$1"
local binary_name="$2"
if [[ "$target_version" == "latest" ]]; then
echo "${REPO_URL}/releases/latest/download/${binary_name}"
else
echo "${REPO_URL}/releases/download/${target_version}/${binary_name}"
fi
}
getLang() {
lang=$(locale | grep LANG | cut -d= -f2 | tr -d '"' | cut -d_ -f1)
if [[ $lang != "ru" ]]; then
lang="en"
fi
}
getIP() {
local ip="localhost"
if command -v dig >/dev/null 2>&1; then
ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null || echo "")
if [[ -z "$ip" ]]; then
ip="localhost"
fi
elif command -v host >/dev/null 2>&1; then
local host_output=""
host_output=$(host myip.opendns.com resolver1.opendns.com 2>/dev/null || true)
ip=$(printf "%s\n" "$host_output" | tail -n1 | awk '{print $NF}')
if [[ -z "$ip" ]]; then
ip="localhost"
fi
fi
serverIP="$ip"
}
promptYesNo() {
local prompt="$1"
local default="${2:-n}"
if [[ $SILENT_MODE -eq 1 ]]; then
if [[ "$default" == "y" ]]; then
return 0
else
return 1
fi
fi
local answer
IFS= read -r -p " $prompt " answer </dev/tty
if [[ "$answer" =~ ^[YyДд] ]]; then
return 0
else
return 1
fi
}
promptYesNoDelete() {
local prompt="$1"
local default="${2:-n}"
if [[ $SILENT_MODE -eq 1 ]]; then
if [[ "$default" == "y" ]]; then
echo "yes"
else
echo "no"
fi
return
fi
local answer
IFS= read -r -p " $prompt " answer </dev/tty
answer=$(echo "$answer" | tr '[:upper:]' '[:lower:]' | xargs)
# Check for Delete (case-insensitive, supports both English and Russian)
if [[ "$answer" == "delete" ]] || [[ "$answer" == "удалить" ]] || [[ "$answer" == "удаление" ]]; then
echo "delete"
elif [[ "$answer" =~ ^[YyДд] ]]; then
echo "yes"
else
echo "no"
fi
}
promptInput() {
local prompt="$1"
local default="$2"
if [[ $SILENT_MODE -eq 1 ]]; then
echo "$default"
return
fi
local answer
IFS= read -r -p " $prompt " answer </dev/tty
echo "${answer:-$default}"
}
systemctlCmd() {
local quiet=0
if [[ ${1:-} == "--quiet" ]]; then
quiet=1
shift
fi
if ! command -v systemctl >/dev/null 2>&1; then
if [[ $quiet -eq 0 && $SILENT_MODE -eq 0 ]]; then
echo " - $(msg systemctl_missing)"
fi
return 1
fi
local rc
systemctl "$@" >/dev/null 2>&1
rc=$?
if [[ $rc -ne 0 ]]; then
if [[ $quiet -eq 0 && $SILENT_MODE -eq 0 ]]; then
printf " - %s\n" "$(msg systemctl_failed "$*")"
fi
return $rc
fi
return 0
}
#############################################
# VERSION MANAGEMENT
#############################################
getLatestRelease() {
curl -s "${REPO_API_URL}/releases/latest" |
grep -iE '"tag_name":|"version":' |
sed -E 's/.*"([^"]+)".*/\1/' |
head -n1
}
getSpecificRelease() {
local version="$1"
local tag_name
tag_name=$(getVersionTag "$version")
local response
response=$(curl -s "${REPO_API_URL}/releases/tags/$tag_name")
if echo "$response" | grep -q '"tag_name"'; then
echo "$tag_name"
else
echo ""
fi
}
getTargetVersion() {
if [[ -n "$specificVersion" ]]; then
local target_release
target_release=$(getSpecificRelease "$specificVersion")
if [[ -z "$target_release" ]]; then
echo " - $(colorize red "$(msg version_not_found "$specificVersion")")"
echo " - $(msg check_versions)"
exit 1
fi
echo "$target_release"
else
getLatestRelease
fi
}
downloadBinary() {
local url="$1"
local destination="$2"
local version_info="$3"
local curl_args=(-L)
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg downloading) $version_info..."
curl_args+=(--progress-bar -#)
else
curl_args+=(-s -S)
fi
curl "${curl_args[@]}" -o "$destination" "$url"
chmod +x "$destination"
}
#############################################
# GLIBC COMPATIBILITY
#############################################
getGlibcVersion() {
local glibc_version
# Try ldd --version (most reliable)
if command -v ldd >/dev/null 2>&1; then
glibc_version=$(ldd --version 2>/dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+' | head -n1)
if [[ -n "$glibc_version" ]]; then
echo "$glibc_version"
return 0
fi
fi
# Try getconf GNU_LIBC_VERSION
if command -v getconf >/dev/null 2>&1; then
glibc_version=$(getconf GNU_LIBC_VERSION 2>/dev/null | grep -oE '[0-9]+\.[0-9]+')
if [[ -n "$glibc_version" ]]; then
echo "$glibc_version"
return 0
fi
fi
# Try rpm package manager
if command -v rpm >/dev/null 2>&1; then
glibc_version=$(rpm -q glibc 2>/dev/null | grep -oE '[0-9]+\.[0-9]+' | head -n1)
if [[ -n "$glibc_version" ]]; then
echo "$glibc_version"
return 0
fi
fi
# Try dpkg package manager
if command -v dpkg >/dev/null 2>&1; then
glibc_version=$(dpkg -l libc6 2>/dev/null | awk '/^ii/ {print $3}' | grep -oE '[0-9]+\.[0-9]+' | head -n1)
if [[ -n "$glibc_version" ]]; then
echo "$glibc_version"
return 0
fi
fi
return 1
}
compareVersions() {
local ver1="$1"
local ver2="$2"
local sorted_first
sorted_first=$(printf '%s\n' "$ver1" "$ver2" | sort -V | head -n1)
[[ "$sorted_first" == "$ver2" ]]
}
checkGlibcCompatibility() {
local target_version="$1"
local version_number
# Extract numeric version
if [[ "$target_version" =~ ${VERSION_PREFIX}\.([0-9]+) ]]; then
version_number="${BASH_REMATCH[1]}"
elif [[ "$target_version" =~ ^[0-9]+$ ]]; then
version_number="$target_version"
else
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg glibc_warning)"
fi
return 0
fi
# Check if version requires glibc 2.32+
if [[ $version_number -ge $MIN_VERSION_REQUIRING_GLIBC ]]; then
local current_glibc
current_glibc=$(getGlibcVersion)
if [[ -z "$current_glibc" ]]; then
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg glibc_warning)"
echo " - $(msg glibc_may_fail "$target_version")"
echo " - $(msg glibc_install_may_fail)"
fi
return 0
fi
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg glibc_detected "$current_glibc")"
fi
if ! compareVersions "$current_glibc" "$MIN_GLIBC_VERSION"; then
echo " - $(colorize red "$(msg glibc_error "$target_version")")"
echo " - $(msg glibc_current "$current_glibc")"
echo " - $(msg glibc_upgrade)"
return 1
fi
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(colorize green "$(msg glibc_ok "$target_version")")"
fi
else
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg glibc_no_requirement "$target_version")"
fi
fi
return 0
}
#############################################
# USER MANAGEMENT
#############################################
addUser() {
if ! isRoot; then
return 1
fi
if [[ $username == "root" ]]; then
return 0
fi
if id "$username" >/dev/null 2>&1; then
if [[ $SILENT_MODE -eq 0 ]]; then
printf " - %s\n" "$(msg user_exists "$username")"
fi
return 0
else
if useradd --home-dir "$dirInstall" --create-home --shell /bin/false -c "TorrServer" "$username" 2>/dev/null; then
chmod 755 "$dirInstall"
if [[ $SILENT_MODE -eq 0 ]]; then
printf " - %s\n" "$(msg user_added "$username")"
fi
return 0
else
if [[ $SILENT_MODE -eq 0 ]]; then
printf " - %s\n" "$(msg user_add_failed "$username")"
fi
return 1
fi
fi
}
delUser() {
if ! isRoot; then
return 1
fi
if [[ $username == "root" ]]; then
return 0
fi
if id "$username" >/dev/null 2>&1; then
if userdel --remove "$username" 2>/dev/null; then
if [[ $SILENT_MODE -eq 0 ]]; then
printf " - %s\n" "$(msg user_removed "$username")"
fi
return 0
else
if [[ $SILENT_MODE -eq 0 ]]; then
printf " - %s\n" "$(msg user_remove_failed "$username")"
fi
return 1
fi
else
if [[ $SILENT_MODE -eq 0 ]]; then
printf " - %s\n" "$(msg user_not_found "$username")"
fi
return 1
fi
}
#############################################
# OS DETECTION & PACKAGES
#############################################
installPackages() {
local pkg_type="$1"
shift
local packages=("$@")
case "$pkg_type" in
deb)
local missing=()
for pkg in "${packages[@]}"; do
if ! dpkg -s "$pkg" >/dev/null 2>&1; then
missing+=("$pkg")
fi
done
if [[ ${#missing[@]} -gt 0 ]]; then
if [[ $SILENT_MODE -eq 0 ]]; then
echo " $(msg installing_packages)"
fi
apt update >/dev/null 2>&1
apt -y install "${missing[@]}"
fi
;;
rpm)
local pkg_manager="$1"
shift
packages=("$@")
local needs_update=0
for pkg in "${packages[@]}"; do
if [[ -z "$(rpm -qa "$pkg" 2>/dev/null)" ]]; then
needs_update=1
break
fi
done
if [[ $needs_update -eq 1 ]]; then
if [[ "$pkg_manager" == "dnf" ]]; then
dnf makecache -q >/dev/null 2>&1 || true
elif [[ "$pkg_manager" == "yum" ]]; then
yum makecache fast -q >/dev/null 2>&1 || true
fi
for pkg in "${packages[@]}"; do
if [[ -z "$(rpm -qa "$pkg" 2>/dev/null)" ]]; then
$pkg_manager -y install "$pkg"
fi
done
fi
;;
arch)
local missing=()
for pkg in "${packages[@]}"; do
if ! pacman -Q "$pkg" >/dev/null 2>&1; then
missing+=("$pkg")
fi
done
if [[ ${#missing[@]} -gt 0 ]]; then
pacman -Sy --noconfirm >/dev/null 2>&1
pacman -S --noconfirm "${missing[@]}"
fi
;;
esac
}
getRpmPackageManager() {
local version_id="$1"
if [[ "$version_id" =~ ^[0-9]+$ ]] && [[ $version_id -ge 8 ]] && command -v dnf >/dev/null 2>&1; then
echo "dnf"
elif command -v dnf >/dev/null 2>&1; then
echo "dnf"
else
echo "yum"
fi
}
validateOSVersion() {
local os_name="$1"
local supported_versions="$2"
local version_id="$3"
local major_version
major_version=$(echo "$version_id" | cut -d '.' -f1)
if [[ ! $major_version =~ ^($supported_versions)$ ]]; then
echo ""
echo " $(msg os_not_supported "$os_name")"
echo ""
echo " $(msg os_script_supports "$os_name" "$supported_versions")"
echo ""
exit 1
fi
}
checkOS() {
if [[ -e /etc/debian_version ]]; then
# shellcheck source=/dev/null
source /etc/os-release
if [[ $ID == "debian" || $ID == "raspbian" ]]; then
local current_version_id
current_version_id="${VERSION_ID:-}"
if [[ -n "$current_version_id" && $current_version_id -lt 6 ]]; then
validateOSVersion "Debian" ">=6" "$current_version_id"
fi
elif [[ $ID == "ubuntu" ]]; then
local current_version_id
current_version_id="${VERSION_ID:-}"
local major
major=$(echo "$current_version_id" | cut -d '.' -f1)
if [[ -n "$current_version_id" && $major -lt 10 ]]; then
validateOSVersion "Ubuntu" ">=10" "$current_version_id"
fi
fi
installPackages deb curl iputils-ping dnsutils
elif [[ -e /etc/system-release ]]; then
# shellcheck source=/dev/null
source /etc/os-release
local pkg_manager
case "$ID" in
fedora)
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
installPackages rpm "$pkg_manager" curl iputils bind-utils
;;
centos|redhat)
validateOSVersion "CentOS/RedHat" "7|8|9|10" "$VERSION_ID"
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
installPackages rpm "$pkg_manager" curl iputils bind-utils
;;
rocky)
validateOSVersion "RockyLinux" "8|9|10" "$VERSION_ID"
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
installPackages rpm "$pkg_manager" curl iputils bind-utils
;;
almalinux)
validateOSVersion "AlmaLinux" "8|9|10" "$VERSION_ID"
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
installPackages rpm "$pkg_manager" curl iputils bind-utils
;;
ol)
validateOSVersion "Oracle Linux" "8|9|10" "$VERSION_ID"
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
installPackages rpm "$pkg_manager" curl iputils bind-utils
;;
amzn)
if [[ $VERSION_ID != "2" ]]; then
validateOSVersion "Amazon Linux" "2" "$VERSION_ID"
fi
installPackages rpm yum curl iputils bind-utils
;;
esac
elif [[ -e /etc/arch-release ]]; then
installPackages arch curl iputils bind-tools
else
echo " $(msg unsupported_os)"
exit 1
fi
}
checkArch() {
case $(uname -m) in
i386|i686) architecture="386" ;;
x86_64) architecture="amd64" ;;
aarch64) architecture="arm64" ;;
armv7|armv7l) architecture="arm7" ;;
armv6|armv6l) architecture="arm5" ;;
*)
echo " $(msg unsupported_arch)"
exit 1
;;
esac
}
initialCheck() {
if ! isRoot; then
echo " $(msg need_root)"
exit 1
fi
checkOS
checkArch
}
#############################################
# INSTALLATION FUNCTIONS
#############################################
checkInstalled() {
# Set username based on USE_ROOT_USER flag
if [[ $USE_ROOT_USER -eq 1 ]]; then
username="root"
else
username="${DEFAULT_USERNAME}"
if ! addUser; then
username="root"
fi
fi
local binName
binName=$(getBinaryName)
if [[ -f "$dirInstall/$binName" ]] && [[ $(stat -c%s "$dirInstall/$binName" 2>/dev/null) -ne 0 ]]; then
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg found_in) $dirInstall"
fi
return 0
else
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg not_found)"
fi
return 1
fi
}
checkInstalledVersion() {
local binName
binName=$(getBinaryName)
local target_version
target_version=$(getTargetVersion)
local installed_version
installed_version="$("$dirInstall/$binName" --version 2>/dev/null | awk '{print $2}')"
if [[ -z "$target_version" ]]; then
echo " - $(msg no_version_info)"
exit 1
fi
if [[ "$target_version" == "$installed_version" ]]; then
if [[ -n "$specificVersion" ]]; then
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg already_installed "$target_version")"
fi
else
if [[ $SILENT_MODE -eq 0 ]]; then
echo " - $(msg have_latest "$target_version")"
fi
fi
return 0
else
if [[ $SILENT_MODE -eq 0 ]]; then
if [[ -n "$specificVersion" ]]; then
echo " - $(msg will_install "$target_version")"
else
echo " - $(msg update_found)"
fi
echo " $(msg installed_version) \"$installed_version\""
echo " $(msg target_label) \"$target_version\""
fi
return 1
fi
}
createServiceFile() {
cat << EOF > "$dirInstall/$serviceName.service"
[Unit]
Description=TorrServer - stream torrent to http
Wants=network-online.target
After=network.target
[Service]
User=$username
Group=$username
Type=simple
NonBlocking=true
EnvironmentFile=$dirInstall/$serviceName.config
ExecStart=${dirInstall}/$(getBinaryName) \$DAEMON_OPTIONS
ExecReload=/bin/kill -HUP \${MAINPID}
ExecStop=/bin/kill -INT \${MAINPID}
TimeoutSec=30
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target