#!/usr/bin/env bash # # SyncDesk pentru Linux - instalare dintr-o singura comanda. # # Se serveste de la https://syncdesk.ro/instalare.sh, iar versiunea, adresele si sumele de # control de mai jos sunt puse de server la fiecare cerere, din release-ul activ. # Deci nu se invecheste: cine ruleaza comanda peste sase luni ia versiunea de # atunci, nu pe asta. # set -euo pipefail VERSIUNE="1.6.8" URL_DEB="https://syncdesk.ro/download/linux" URL_RPM="https://syncdesk.ro/download/linux-rpm" SHA_DEB="c3dfa4ef049076f815e2b7bf4f68bf9a09946f41d6f90dbcbfc9925f699626d0" SHA_RPM="8c85cce67d10b9676635be90be94c41b16607a65fdd3b1dbc4ecd0ad067c9b2d" SITE="https://syncdesk.ro" API="https://api.syncdesk.ro" MIN_GLIBC="2.29" MIN_GLIBCXX="3.4.21" DISTRIBUTII="Debian 11+, Ubuntu 20.04+, Fedora, RHEL/AlmaLinux/Rocky 9+" BINAR="/usr/bin/syncdesk" SERVICIU="syncdesk" PAROLA="" TOKEN="" FARA_PAROLA=0 SCHIMBA_PAROLA=0 DEZINSTALEAZA=0 GENEREAZA=0 GENERATA=0 # Culori doar cand scriem intr-un terminal. Trecut printr-o teava sau intr-un # fisier de jurnal, textul ramane curat. if [ -t 1 ]; then C_OK=$'\033[32m'; C_ERR=$'\033[31m'; C_ATT=$'\033[33m'; C_TARE=$'\033[1m'; C_0=$'\033[0m' else C_OK=""; C_ERR=""; C_ATT=""; C_TARE=""; C_0="" fi spune() { printf '%s\n' " $*"; } pas() { printf '\n%s\n' "${C_TARE}==> $*${C_0}"; } bine() { printf '%s\n' " ${C_OK}OK${C_0} $*"; } atentie(){ printf '%s\n' " ${C_ATT}!${C_0} $*"; } mor() { printf '\n%s\n\n' "${C_ERR}Nu pot continua:${C_0} $*" >&2; exit 1; } # --------------------------------------------------------------------- parola # # CAPCANA, MASURATA PE 22.08.2026. A scapat o instalare intreaga cu o parola pe care # serviciul n-o vazuse niciodata: # # 1. `--password` NU scrie in fisier: vorbeste prin IPC cu procesul `--server`. Iar # `--server` nu porneste in aceeasi clipa cu serviciul, il porneste `--service` # dupa cateva secunde. Pana atunci comanda intoarce „Connection refused # (os error 111)". Reprodus pe Debian 11: refuzata la o secunda dupa # `systemctl restart`, „Done!" la 16 secunde. # 2. BINARUL IESE CU 0 SI ATUNCI. Deci `|| mor` nu prindea absolut nimic, si # scriptul scria „OK pusa" sub o parola care nu era pusa nicaieri. # 3. `--get-id` NU e dovada ca serviciul e gata: cade inapoi pe fisierul de # configurare si raspunde imediat, chiar si cu IPC-ul mort. De-aia asteptarea # dupa ID trecea, iar parola pica la doua randuri distanta. # # Deci ne uitam la CE SCRIE, nu la codul de iesire, si reincercam. Asteptarea dupa # `--server` e chiar incercarea, nu un `sleep` ales la nimereala. PAROLA_RASPUNS="" pune_parola() { p="$1" i=0 while [ "$i" -lt 60 ]; do PAROLA_RASPUNS="$("$BINAR" --password "$p" 2>&1 || true)" case "$PAROLA_RASPUNS" in *Done!*) return 0 ;; esac i=$((i + 1)) [ "$i" -eq 5 ] && spune "serviciul inca nu raspunde, mai astept..." sleep 1 done return 1 } # 16 semne din /dev/urandom, fara cele care se citesc gresit la telefon (O/0, l/1) si # fara ghilimele, ca sa se poata lipi oriunde. # # `pipefail` e oprit doar aici, cu buna stiinta: `head` inchide teava dupa 16 octeti, # `tr` primeste SIGPIPE, si cu pipefail pornit intreg scriptul ar fi murit exact la # pasul asta, desi parola se generase corect. genereaza_parola() { set +o pipefail LC_ALL=C tr -dc 'A-HJ-NP-Za-km-z2-9' < /dev/urandom | head -c 16 set -o pipefail } arata_parola() { if [ "$GENERATA" -eq 1 ]; then printf ' %-10s %s\n' "Parola:" "${C_TARE}${PAROLA}${C_0}" printf ' %-10s %s\n' "" "generata acum - noteaz-o, nu se mai poate citi de nicaieri" else # Parola data de om nu se tipareste inapoi. Daca a scris-o pe nevazute, tocmai # ca sa nu ramana pe ecran a scris-o asa; iar daca a dat-o cu --parola, o stie. printf ' %-10s %s\n' "Parola:" "cea pe care ai dat-o tu" fi } # --------------------------------------------- parola tastata la terminal # # Ca `passwd`: se scrie pe nevazute, de doua ori. Doua capcane, amandoua serioase: # # 1. INTRAREA STANDARD E CHIAR SCRIPTUL. Rulat prin `curl ... | sudo bash`, bash isi # citeste propriul text de pe intrare. Un `read` obisnuit ar fi inghitit randurile # care urmeaza in script, nu ce tasteaza omul. De-aia citim de la /dev/tty, adica # de-a dreptul de la terminal, nu de pe intrare. # 2. CTRL-C IN MIJLOCUL CITIRII lasa terminalul fara ecou: shell-ul merge mai departe, # dar nu mai arata ce scrii in el. Salvam starea terminalului si o punem la loc. # # Cand nu exista terminal (cron, o teava, un pipeline de configurare) nu intrebam nimic, # generam. Un script care asteapta la nesfarsit un raspuns care nu vine e mai rau decat # unul care alege singur. are_terminal() { { : < /dev/tty; } 2>/dev/null } TTY_STARE="" repune_terminalul() { [ -n "$TTY_STARE" ] || return 0 stty "$TTY_STARE" < /dev/tty 2>/dev/null || true TTY_STARE="" } RASPUNS="" citeste_pe_nevazute() { RASPUNS="" TTY_STARE="$(stty -g < /dev/tty 2>/dev/null || true)" trap 'repune_terminalul; printf "\n" > /dev/tty; exit 130' INT printf '%s' " $1" > /dev/tty IFS= read -rs RASPUNS < /dev/tty || true printf '\n' > /dev/tty trap - INT repune_terminalul } # Ce nu primim, si de ce. Spatiile de la capete si semnele de control nu se vad pe ecran # nici atunci cand parola s-ar vedea, deci ar iesi o parola pe care omul n-are cum s-o # scrie a doua oara. Pe un server fara ecran parola e singurul drum inauntru. de_ce_nu_e_buna() { p="$1" if [ "${#p}" -lt 8 ]; then printf '%s' "Prea scurta: are ${#p} semne, trebuie cel putin 8." return 0 fi case "$p" in ' '*|*' ') printf '%s' "Incepe sau se termina cu spatiu, iar spatiile de la capete nu se vad nicaieri. Scrie una fara ele." return 0 ;; esac # Parola pleaca pe INTRAREA lui `grep`, nu ca argument al lui: un argument s-ar # vedea in `ps` la orice utilizator de pe masina. if printf '%s' "$p" | LC_ALL=C grep -q '[[:cntrl:]]'; then printf '%s' "Are in ea un semn care nu se poate tipari, poate un Tab. Foloseste litere, cifre si semne obisnuite." return 0 fi return 0 } # Trei incercari, ca la `passwd`. Enter gol la prima intrebare inseamna „genereaza tu # una": e fix ce facea comanda inainte sa intrebe, deci cine o stia asa nu se impiedica. cere_parola() { incercari=0 while [ "$incercari" -lt 3 ]; do incercari=$((incercari + 1)) citeste_pe_nevazute "Parola noua (nu se vede ce tastezi; Enter gol = o generez eu): " p1="$RASPUNS" if [ -z "$p1" ]; then PAROLA="$(genereaza_parola)" GENERATA=1 spune "bine, o generez eu." return 0 fi citeste_pe_nevazute "Inca o data, ca sa fim siguri: " p2="$RASPUNS" RASPUNS="" if [ "$p1" != "$p2" ]; then p1=""; p2="" atentie "Nu se potrivesc. Mai incearca." continue fi motiv="$(de_ce_nu_e_buna "$p1")" if [ -n "$motiv" ]; then p1=""; p2="" atentie "$motiv" continue fi PAROLA="$p1" GENERATA=0 p1=""; p2="" return 0 done return 1 } # Ajutorul e scris aici, nu citit din propriul fisier cu `sed`: rulat prin # `curl | bash`, scriptul n-are fisier de citit, iar `$0` e „bash". ajutor() { cat <<'AJUTOR' SyncDesk pentru Linux - instalare dintr-o singura comanda. curl -fsSL https://syncdesk.ro/instalare.sh | sudo bash sau, daca vrei sa te uiti intai la el (recomandat, si nu doar la noi): curl -fsSL https://syncdesk.ro/instalare.sh -o instalare.sh less instalare.sh sudo bash instalare.sh Optiuni: --parola parola permanenta. Fara ea, generam una si o afisam. --fara-parola nu pune parola permanenta. Atunci te poti conecta doar cu codul afisat pe ecranul masinii, deci NU si cand nu e nimeni in fata ei. --token inroleaza device-ul in firma careia ii apartine tokenul. --schimba-parola nu instaleaza nimic: schimba parola permanenta pe o masina pe care SyncDesk e deja instalat. Daca esti la un terminal, ti-o cere pe nevazute si de doua ori, ca `passwd`. Daca nu esti (cron, o teava), genereaza una si o arata. Pe serverele fara ecran asta e singura cale, fiindca nu exista interfata din care s-o schimbi. --genereaza nu intreba nimic, genereaza parola si arat-o. E ce se intampla oricum cand comanda nu ruleaza la un terminal. --dezinstaleaza scoate SyncDesk de tot: serviciul, programul, si datele lui (configurarea si jurnalele), inclusiv din casele utilizatorilor. Nu descarca nimic. --help asta. Parola scrisa la terminal nu se vede si nu ramane in istoricul shell-ului, spre deosebire de --parola. Cu --parola o vede si `ps`, cat tine comanda. Pe un server deja instalat, fara sa reinstalezi nimic: curl -fsSL https://syncdesk.ro/instalare.sh | sudo bash -s -- --schimba-parola curl -fsSL https://syncdesk.ro/instalare.sh | sudo bash -s -- --dezinstaleaza AJUTOR } # ---------------------------------------------------------------- argumentele while [ $# -gt 0 ]; do case "$1" in --parola) PAROLA="${2:-}"; [ -n "$PAROLA" ] || mor "--parola vrea o valoare."; shift 2 ;; --token) TOKEN="${2:-}"; [ -n "$TOKEN" ] || mor "--token vrea o valoare."; shift 2 ;; --fara-parola) FARA_PAROLA=1; shift ;; --genereaza) GENEREAZA=1; shift ;; --schimba-parola) SCHIMBA_PAROLA=1; shift ;; --dezinstaleaza) DEZINSTALEAZA=1; shift ;; # `--ajutor` ramane, dar nu mai e tiparit in ajutor: a fost forma documentata # pana in 22.08.2026 si poate fi deja scrisa in notitele cuiva. `--help` e cea # din ajutor acum, fiindca asa se cheama peste tot pe Linux. --help|-h|--ajutor) ajutor; exit 0 ;; *) mor "Argument necunoscut: $1. Incearca --help." ;; esac done if [ -n "$PAROLA" ] && [ "$FARA_PAROLA" -eq 1 ]; then mor "--parola si --fara-parola se bat cap in cap. Alege una." fi if [ -n "$PAROLA" ] && [ "$GENEREAZA" -eq 1 ]; then mor "--parola si --genereaza se bat cap in cap: ori o dai tu, ori o generez eu." fi if [ "$GENEREAZA" -eq 1 ] && [ "$FARA_PAROLA" -eq 1 ]; then mor "--genereaza si --fara-parola se bat cap in cap." fi # ------------------------------------------------------- doar schimbarea parolei # Nu descarca si nu instaleaza nimic. Pe un server fara ecran nu exista interfata din # care sa schimbi parola permanenta, iar `--password` dat de mana are exact capcana # scrisa mai sus: iese cu 0 si cand n-a facut nimic. if [ "$SCHIMBA_PAROLA" -eq 1 ]; then printf '\n%s\n' "${C_TARE}SyncDesk - schimb parola permanenta${C_0}" [ "$(id -u)" -eq 0 ] || mor "Ruleaza cu sudo: parola se pune prin serviciul de sistem." [ -x "$BINAR" ] || mor "SyncDesk nu e instalat pe masina asta; $BINAR lipseste. Instaleaza-l intai: curl -fsSL $SITE/instalare.sh | sudo bash" [ "$FARA_PAROLA" -eq 0 ] || mor "--schimba-parola si --fara-parola se bat cap in cap." pas "Ma uit la serviciu" systemctl is-active --quiet "$SERVICIU" \ || mor "Serviciul $SERVICIU nu merge, deci n-are cine sa primeasca parola. Porneste-l si reia: systemctl start $SERVICIU" bine "merge" # Intrebam abia dupa ce stim ca serviciul raspunde: n-are rost sa ceri unui om o # parola pe care apoi n-ai unde s-o pui. pas "Parola noua" if [ -z "$PAROLA" ]; then if [ "$GENEREAZA" -eq 0 ] && are_terminal; then cere_parola || mor "Trei incercari, niciuna buna. Nu s-a schimbat nimic: parola veche e in continuare buna." else PAROLA="$(genereaza_parola)" GENERATA=1 fi fi [ ${#PAROLA} -ge 8 ] || mor "Parola trebuie sa aiba cel putin 8 semne." pune_parola "$PAROLA" \ || mor "Serviciul nu a confirmat parola noua. Ce a raspuns: ${PAROLA_RASPUNS:-nimic} Parola veche ramane buna; nu s-a schimbat nimic. Vezi ce face serviciul: systemctl status $SERVICIU" bine "schimbata" printf '\n%s\n\n' "${C_TARE}Gata.${C_0}" printf ' %-10s %s\n' "ID:" "${C_TARE}$("$BINAR" --get-id 2>/dev/null | tr -d '[:space:]')${C_0}" arata_parola printf '\n' spune "Sesiunile deschise acum nu se inchid singure; parola noua e ceruta de la" spune "urmatoarea conectare." printf '\n' exit 0 fi # ------------------------------------------------------------- dezinstalarea # Nu descarca nimic si nu are nevoie de retea. # # DE CE NU AJUNGE `apt purge` SINGUR, masurat pe Debian 11 pe 23.08.2026: # # - `apt remove` lasa in urma configurarea SI jurnalele, in toate casele. # - `apt purge` sterge doar `/root/.config/syncdesk`. Dar procesul `--server` nu # ruleaza neaparat ca root: cand masina are o sesiune deschisa, `--service` il # porneste sub utilizatorul acela, care isi capata propria configurare in casa # lui. Aia RAMANE dupa purge, cu tot cu parola permanenta si cheia device-ului. # - pe .rpm nu exista purge deloc, deci nu se sterge nici macar configurarea # lui root. # # Deci stergem noi, peste ce face pachetul, si ne uitam la urma daca chiar nu a mai # ramas nimic. Un „gata" care nu s-a uitat nu valoreaza nimic; asta am invatat ieri, # la parola. if [ "$DEZINSTALEAZA" -eq 1 ]; then printf '\n%s\n' "${C_TARE}SyncDesk - dezinstalare${C_0}" [ "$(id -u)" -eq 0 ] || mor "Ruleaza cu sudo: serviciul de sistem se scoate cu drepturi." # ID-ul se citeste ACUM, cat mai exista de unde. Dupa stergere nu se mai poate afla # de nicaieri, iar device-ul ramane in panou pana il scoate cineva de mana. ID_VECHI="" if [ -x "$BINAR" ]; then ID_VECHI="$("$BINAR" --get-id 2>/dev/null | tr -d '[:space:]' || true)" fi pas "Opresc serviciul" systemctl stop "$SERVICIU" >/dev/null 2>&1 || true systemctl disable "$SERVICIU" >/dev/null 2>&1 || true bine "oprit" pas "Scot pachetul" if command -v apt-get >/dev/null 2>&1; then DEBIAN_FRONTEND=noninteractive apt-get purge -y syncdesk >/dev/null 2>&1 \ && bine "scos (apt)" || atentie "apt n-a gasit pachetul; sterg fisierele oricum" elif command -v dnf >/dev/null 2>&1; then dnf remove -y syncdesk >/dev/null 2>&1 \ && bine "scos (dnf)" || atentie "dnf n-a gasit pachetul; sterg fisierele oricum" elif command -v yum >/dev/null 2>&1; then yum remove -y syncdesk >/dev/null 2>&1 \ && bine "scos (yum)" || atentie "yum n-a gasit pachetul; sterg fisierele oricum" elif command -v zypper >/dev/null 2>&1; then zypper --non-interactive remove syncdesk >/dev/null 2>&1 \ && bine "scos (zypper)" || atentie "zypper n-a gasit pachetul; sterg fisierele oricum" else atentie "nu recunosc managerul de pachete; sterg fisierele de mana" fi pas "Sterg ce ramane in urma" # Unitatea si legaturile, daca pachetul n-a apucat sa le scoata (instalare pe # jumatate, sau scos deja din alta parte). rm -f /usr/bin/syncdesk \ /usr/lib/systemd/system/syncdesk.service \ /etc/systemd/system/syncdesk.service \ /usr/lib/systemd/user/syncdesk.service \ /usr/share/applications/syncdesk.desktop \ /usr/share/applications/syncdesk-link.desktop 2>/dev/null || true rm -rf /usr/share/syncdesk 2>/dev/null || true # Configurarea si jurnalele, in TOATE casele, nu doar a lui root. for CASA in /root /home/*; do [ -d "$CASA" ] || continue rm -rf "$CASA/.config/syncdesk" "$CASA/.local/share/logs/SyncDesk" 2>/dev/null || true done # Soclurile de IPC. Numele are majuscule, dupa numele aplicatiei. rm -rf /tmp/SyncDesk-* /tmp/syncdesk-* 2>/dev/null || true systemctl daemon-reload >/dev/null 2>&1 || true bine "sters" pas "Ma uit ce a mai ramas" RAMAS="" for F in /usr/bin/syncdesk /usr/share/syncdesk \ /usr/lib/systemd/system/syncdesk.service /etc/systemd/system/syncdesk.service; do [ -e "$F" ] && RAMAS="${RAMAS:+$RAMAS }$F" done for CASA in /root /home/*; do [ -d "$CASA/.config/syncdesk" ] && RAMAS="${RAMAS:+$RAMAS }$CASA/.config/syncdesk" [ -d "$CASA/.local/share/logs/SyncDesk" ] && RAMAS="${RAMAS:+$RAMAS }$CASA/.local/share/logs/SyncDesk" done if [ -n "$RAMAS" ]; then atentie "au ramas: $RAMAS Sterge-le de mana; restul e scos." else bine "nimic" fi printf '\n%s\n\n' "${C_TARE}Gata.${C_0}" if [ -n "$ID_VECHI" ]; then spune "Device-ul ${C_TARE}$ID_VECHI${C_0} ramane in panou pana il stergi de acolo:" spune "$SITE/firma/dispozitive" fi # MASURAT, nu presupus: dupa o stergere completa (verificat cu `find /`), # reinstalarea a primit ACELASI ID. La noi ID-ul nu tine de fisierul de # configurare, e un hash determinist din `hostname|MAC` (`get_auto_id` in # libs/hbb_common/src/config.rs). Se schimba doar daca se schimba numele masinii # sau placa de retea. spune "Daca reinstalezi pe aceeasi masina, revine cu ${C_TARE}acelasi ID${C_0}: el se" spune "calculeaza din numele masinii si adresa MAC, nu din ce am sters acum." spune "Parola permanenta si cheia device-ului insa NU revin; alea erau in date." printf '\n' exit 0 fi printf '\n%s\n' "${C_TARE}SyncDesk $VERSIUNE - instalare${C_0}" # ------------------------------------------------------------------ verificari pas "Ma uit pe ce instalez" [ "$(id -u)" -eq 0 ] || mor "Ruleaza cu sudo: instalarea pune un serviciu de sistem." ARH="$(uname -m)" case "$ARH" in x86_64|amd64) : ;; aarch64|arm64) mor "Deocamdata construim doar pentru x86_64. Pe $ARH nu avem inca pachet." ;; *) mor "Arhitectura $ARH nu e acoperita. Avem pachete doar pentru x86_64." ;; esac bine "arhitectura: $ARH" # Verificam ca systemd CHIAR RULEAZA, nu doar ca exista comanda `systemctl`. # Diferenta nu e teoretica: pe WSL, si in containerele obisnuite, binarul e la locul # lui dar init-ul e altul. Testat pe WSL Ubuntu 24.04 cu prima varianta a scriptului - # trecea de verificare, descarca 22 MB, instala pachetul, si abia apoi murea la # pornirea serviciului. Adica lasa in urma o instalare pe jumatate. # `/run/systemd/system` exista doar cand systemd e chiar init-ul masinii. [ -d /run/systemd/system ] \ || mor "Pe masina asta nu ruleaza systemd (WSL, sau un container). Fara el serviciul nu poate porni singur, deci n-ai putea ajunge la calculator cand nu e nimeni logat pe el - adica exact ce vrei de la un server. Pe o masina Linux adevarata sau intr-o masina virtuala merge." if command -v curl >/dev/null 2>&1; then ADU() { curl -fsSL "$1" -o "$2"; } elif command -v wget >/dev/null 2>&1; then ADU() { wget -qO "$2" "$1"; } else mor "Imi trebuie curl sau wget ca sa aduc pachetul. Instaleaza unul din ele si reia." fi # Managerul de pachete da si formatul, si comanda de instalare. MANAGER="" if command -v apt-get >/dev/null 2>&1; then FORMAT="deb"; URL="$URL_DEB"; SUMA="$SHA_DEB"; MANAGER="apt" bine "distributie din familia Debian (apt)" elif command -v dnf >/dev/null 2>&1; then FORMAT="rpm"; URL="$URL_RPM"; SUMA="$SHA_RPM"; MANAGER="dnf" bine "distributie din familia Fedora (dnf)" elif command -v yum >/dev/null 2>&1; then FORMAT="rpm"; URL="$URL_RPM"; SUMA="$SHA_RPM"; MANAGER="yum" bine "distributie din familia RHEL (yum)" elif command -v zypper >/dev/null 2>&1; then FORMAT="rpm"; URL="$URL_RPM"; SUMA="$SHA_RPM"; MANAGER="zypper" bine "openSUSE (zypper)" else mor "Nu recunosc managerul de pachete. Pe distributiile fara .deb sau .rpm ramane varianta AppImage, dar aceea NU instaleaza serviciu, deci nu porneste singura la boot: $SITE/download" fi # Bibliotecile de sistem. De ce inainte de descarcare: un pachet care se instaleaza si # apoi nu porneste e mai rau decat unul care refuza sa se instaleze. Un binar compilat pe # o distributie noua cere versiuni de simboluri care pe una veche nu exista, iar apt nu # are de unde sti asta - instaleaza fara sa crance, si abia `syncdesk --get-id` scoate un # perete de „version GLIBC_2.34 not found". Masurat pe un VPS cu Debian 11. # # `sort -V` compara versiuni ca lumea (2.9 < 2.31), spre deosebire de comparatia de siruri. cel_putin() { # $1 = ceruta, $2 = gasita -> adevarat daca gasita >= ceruta [ "$( { echo "$1"; echo "$2"; } | sort -V | head -n 1 )" = "$1" ] } GLIBC="" if command -v getconf >/dev/null 2>&1; then GLIBC="$(getconf GNU_LIBC_VERSION 2>/dev/null | awk '{print $2}')" fi if [ -z "$GLIBC" ] && command -v ldd >/dev/null 2>&1; then GLIBC="$(ldd --version 2>/dev/null | head -n 1 | awk '{print $NF}')" fi PREA_VECHI="" case "$GLIBC" in ''|*[!0-9.]*) atentie "n-am putut afla versiunea de glibc; merg mai departe pe raspunderea ta" ;; *) cel_putin "$MIN_GLIBC" "$GLIBC" || PREA_VECHI="glibc $GLIBC (imi trebuie $MIN_GLIBC)" ;; esac # libstdc++ isi tine versiunile chiar in fisier, ca siruri. `grep -a` merge si fara # `strings`, care pe un server minimal deseori nu e instalat. LIBSTDCPP="" for c in /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /usr/lib64/libstdc++.so.6 /lib/x86_64-linux-gnu/libstdc++.so.6; do if [ -e "$c" ]; then LIBSTDCPP="$c"; break; fi done if [ -n "$LIBSTDCPP" ]; then GLIBCXX="$(grep -ao 'GLIBCXX_3\.4\.[0-9]*' "$LIBSTDCPP" 2>/dev/null | sed 's/GLIBCXX_//' | sort -V | tail -n 1)" if [ -n "$GLIBCXX" ] && ! cel_putin "$MIN_GLIBCXX" "$GLIBCXX"; then PREA_VECHI="${PREA_VECHI:+$PREA_VECHI, }libstdc++ $GLIBCXX (imi trebuie $MIN_GLIBCXX)" fi fi if [ -n "$PREA_VECHI" ]; then mor "Distributia asta e prea veche pentru pachetul nostru: $PREA_VECHI. Nu instalez nimic - pachetul ar intra, dar programul n-ar porni. Merge pe: $DISTRIBUTII. Lucram la o versiune construita pe o baza mai veche, ca sa mearga si aici." fi bine "biblioteci de sistem: glibc ${GLIBC:-necunoscut}${GLIBCXX:+, libstdc++ $GLIBCXX}" if [ -x "$BINAR" ]; then VECHE="$("$BINAR" --version 2>/dev/null || true)" [ -n "$VECHE" ] && atentie "SyncDesk $VECHE e deja instalat; il actualizez la $VERSIUNE." fi # ------------------------------------------------------------------- descarcare pas "Aduc pachetul" TEMP="$(mktemp -d)" # Curatam si daca iesim prost, ca sa nu ramana 23 MB in /tmp la fiecare incercare. trap 'rm -rf "$TEMP"' EXIT FISIER="$TEMP/syncdesk.$FORMAT" JURNAL="$TEMP/jurnal.txt" ADU "$URL" "$FISIER" || mor "Nu am putut descarca $URL" bine "descarcat ($(du -h "$FISIER" | cut -f1))" # Suma de control e calculata de server pe fisierul chiar publicat, nu scrisa de # mana undeva - deci prinde si un fisier trunchiat de o retea proasta, si unul # schimbat pe drum. if [ -n "$SUMA" ]; then GASIT="" if command -v sha256sum >/dev/null 2>&1; then GASIT="$(sha256sum "$FISIER" | cut -d' ' -f1)" elif command -v shasum >/dev/null 2>&1; then GASIT="$(shasum -a 256 "$FISIER" | cut -d' ' -f1)" else atentie "n-am cu ce calcula suma de control (lipsesc sha256sum si shasum); sar peste verificare" fi if [ -n "$GASIT" ]; then [ "$GASIT" = "$SUMA" ] || mor "Suma de control nu se potriveste. asteptata: $SUMA gasita: $GASIT Nu instalez nimic. Incearca din nou; daca se repeta, scrie-ne." bine "suma de control se potriveste" fi fi # -------------------------------------------------------------------- instalare pas "Instalez" # Iesirea managerului de pachete merge intr-un jurnal, nu pe ecran: la mers bine e # zgomot, iar la mers prost e chiar ce trebuie citit - si atunci il aratam. cade() { printf '\n%s\n' "${C_ERR}Instalarea a esuat.${C_0} Ultimele randuri:" >&2 tail -n 15 "$JURNAL" >&2 || true mor "$1" } case "$MANAGER" in apt) export DEBIAN_FRONTEND=noninteractive # OBLIGATORIU inaintea instalarii, si nu e un moft. Apt rezolva dependintele # dupa lista LUI de pachete; pe o masina care n-a mai facut `apt update` de # luni de zile, lista aia cere de la oglinda versiuni care intre timp au fost # inlocuite. Debian security tine doar versiunea curenta, deci raspunde 404 si # instalarea cade la jumatate, DUPA ce pachetul nostru a fost deja descarcat. # Masurat pe un VPS cu Debian 11 si 142 de zile de uptime: 114 pachete de adus, # picat la `libcups2 2.3.3op2-3+deb11u9`, 404. # # Nu improspatam lista in colectorul de inventar din client - acolo regula e # exact pe dos, fiindca ruleaza singur si repetat si s-ar calca in picioare cu # apt-ul administratorului. Aici suntem un instalator pornit cu sudo, care # oricum e pe cale sa instaleze o suta de pachete. spune "improspatez lista de pachete" if ! apt-get update >"$JURNAL" 2>&1; then atentie "n-am putut improspata toata lista (poate o sursa straina e cazuta); incerc oricum" fi # `apt-get install` pe un fisier local rezolva singur dependintele lipsa. # Pe apt vechi (sub 1.1) nu stie sa primeasca un fisier, si atunci cadem pe # dpkg urmat de `-f install`, care face acelasi lucru in doi pasi. if ! apt-get install -y "$FISIER" >>"$JURNAL" 2>&1; then dpkg -i "$FISIER" >>"$JURNAL" 2>&1 || true apt-get -f install -y >>"$JURNAL" 2>&1 \ || cade "Ruleaza 'apt-get -f install' si uita-te la ce spune." fi ;; # `--refresh` la dnf are acelasi rol ca `apt-get update` de mai sus. yum si zypper # isi improspateaza singure metadatele expirate inainte de instalare. # Pachetele noastre nu sunt semnate cu o cheie GPG, deci verificarea semnaturii # ar refuza instalarea. Autenticitatea o da suma de control de mai sus, # calculata de acelasi server de la care ai luat si scriptul. dnf) dnf install -y --refresh --nogpgcheck "$FISIER" >"$JURNAL" 2>&1 || cade "dnf n-a putut instala pachetul." ;; yum) yum install -y --nogpgcheck "$FISIER" >"$JURNAL" 2>&1 || cade "yum n-a putut instala pachetul." ;; zypper) zypper --non-interactive install --allow-unsigned-rpm "$FISIER" >"$JURNAL" 2>&1 || cade "zypper n-a putut instala pachetul." ;; esac [ -x "$BINAR" ] || mor "Pachetul s-a instalat, dar nu gasesc $BINAR. Ceva nu e in regula cu el." bine "instalat" # --------------------------------------------------------------------- serviciu pas "Pornesc serviciul" systemctl enable "$SERVICIU" >/dev/null 2>&1 || true systemctl restart "$SERVICIU" >/dev/null 2>&1 \ || mor "Serviciul nu a pornit. Vezi ce spune: systemctl status $SERVICIU" # Serviciul isi ia ID-ul de la serverul nostru la prima pornire, deci nu e gata in # aceeasi clipa. Asteptam ID-ul, nu un numar de secunde ales la nimereala. ID="" incercari=0 while [ "$incercari" -lt 40 ]; do ID="$("$BINAR" --get-id 2>/dev/null | tr -d '[:space:]' || true)" case "$ID" in ''|*[!0-9]*) ID=""; incercari=$((incercari + 1)); sleep 1 ;; *) break ;; esac done [ -n "$ID" ] || mor "Serviciul merge, dar nu a primit inca un ID. Verifica daca masina poate iesi la sync.syncdesk.ro pe portul 21116 (TCP si UDP), apoi ruleaza: $BINAR --get-id" bine "ID: $ID" # ----------------------------------------------------------------------- firma if [ -n "$TOKEN" ]; then pas "Inrolez device-ul in firma" if "$BINAR" --option api-server "$API/f/$TOKEN" >/dev/null 2>&1; then systemctl restart "$SERVICIU" >/dev/null 2>&1 || true bine "trimis spre firma; apare in panou la primul semn de viata (sub un minut)" else atentie "n-am putut scrie adresa firmei, deci device-ul ramane neatribuit. Restul instalarii e in regula; atribuie-l de mana din panou." fi fi # ---------------------------------------------------------------------- parola if [ "$FARA_PAROLA" -eq 1 ]; then pas "Parola permanenta" atentie "sarita, la cererea ta. Fara ea te poti conecta doar cu codul afisat pe ecranul masinii, deci NU si cand nu e nimeni in fata ei." else pas "Pun parola permanenta" if [ -z "$PAROLA" ]; then PAROLA="$(genereaza_parola)" GENERATA=1 fi [ ${#PAROLA} -ge 8 ] || mor "Parola generata a iesit prea scurta. Pune una de mana: $BINAR --password 'parola-ta'" # Cu --token, serviciul tocmai a fost repornit doua randuri mai sus, deci `--server` # e cu atat mai sigur nepornit inca. Reincercarea acopera si cazul asta. pune_parola "$PAROLA" \ || mor "Serviciul nu a confirmat parola, deci NU e pusa. Ce a raspuns: ${PAROLA_RASPUNS:-nimic} Restul instalarii e in regula. Incearca peste un minut: $BINAR --password 'parola-ta' Trebuie sa scrie «Done!». Orice altceva inseamna ca nu s-a pus." bine "pusa" fi # ------------------------------------------------------------------------ gata printf '\n%s\n\n' "${C_TARE}Gata.${C_0}" printf ' %-10s %s\n' "ID:" "${C_TARE}${ID}${C_0}" if [ "$FARA_PAROLA" -eq 0 ]; then arata_parola fi printf '\n' spune "Serverul asta n-are ecran de aratat, deci conecteaza-te la el in modul" spune "${C_TARE}Terminal${C_0}: scrii ID-ul, deschizi meniul de langa butonul Conectare" spune "si alegi Terminal. Primesti un shell, fara nimic grafic." printf '\n' spune "Daca vrei totusi ecran pe masina asta: $SITE/documentatie/linux#fara-ecran" printf '\n' spune "Cand vrei alta parola, fara sa reinstalezi nimic:" spune " ${C_TARE}curl -fsSL $SITE/instalare.sh | sudo bash -s -- --schimba-parola${C_0}" spune "Cand vrei sa-l scoti de tot, cu date cu tot:" spune " ${C_TARE}curl -fsSL $SITE/instalare.sh | sudo bash -s -- --dezinstaleaza${C_0}" printf '\n'